From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001 From: upstream source tree Date: Sun, 15 Mar 2015 20:14:05 -0400 Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository. --- libjava/classpath/gnu/CORBA/Asynchron.java | 185 + libjava/classpath/gnu/CORBA/BigDecimalHelper.java | 191 + .../classpath/gnu/CORBA/ByteArrayComparator.java | 90 + .../classpath/gnu/CORBA/CDR/AbstractCdrInput.java | 1768 ++++++ .../classpath/gnu/CORBA/CDR/AbstractCdrOutput.java | 1047 ++++ .../classpath/gnu/CORBA/CDR/AbstractDataInput.java | 392 ++ .../gnu/CORBA/CDR/AbstractDataOutput.java | 185 + libjava/classpath/gnu/CORBA/CDR/AligningInput.java | 131 + .../classpath/gnu/CORBA/CDR/AligningOutput.java | 148 + .../classpath/gnu/CORBA/CDR/ArrayValueHelper.java | 254 + .../gnu/CORBA/CDR/BigEndianInputStream.java | 61 + .../gnu/CORBA/CDR/BigEndianOutputStream.java | 62 + .../classpath/gnu/CORBA/CDR/BufferedCdrOutput.java | 156 + .../classpath/gnu/CORBA/CDR/BufferredCdrInput.java | 153 + .../gnu/CORBA/CDR/EncapsulationStream.java | 147 + libjava/classpath/gnu/CORBA/CDR/HeadlessInput.java | 749 +++ libjava/classpath/gnu/CORBA/CDR/IDLTypeHelper.java | 169 + .../gnu/CORBA/CDR/LittleEndianInputStream.java | 634 +++ .../gnu/CORBA/CDR/LittleEndianOutputStream.java | 253 + .../gnu/CORBA/CDR/UnknownExceptionCtxHandler.java | 292 + libjava/classpath/gnu/CORBA/CDR/VMVio.java | 101 + libjava/classpath/gnu/CORBA/CDR/Vio.java | 1474 +++++ libjava/classpath/gnu/CORBA/CDR/gnuRuntime.java | 338 ++ .../classpath/gnu/CORBA/CDR/gnuValueStream.java | 71 + .../classpath/gnu/CORBA/CdrEncapsCodecImpl.java | 358 ++ libjava/classpath/gnu/CORBA/CollocatedOrbs.java | 160 + libjava/classpath/gnu/CORBA/Connected_objects.java | 255 + libjava/classpath/gnu/CORBA/CorbaList.java | 115 + .../classpath/gnu/CORBA/DefaultSocketFactory.java | 79 + .../classpath/gnu/CORBA/DefinitionKindHolder.java | 91 + .../classpath/gnu/CORBA/DuplicateNameHolder.java | 106 + libjava/classpath/gnu/CORBA/DynAn/AbstractAny.java | 177 + .../classpath/gnu/CORBA/DynAn/DivideableAny.java | 512 ++ .../gnu/CORBA/DynAn/NameValuePairHolder.java | 94 + libjava/classpath/gnu/CORBA/DynAn/RecordAny.java | 405 ++ .../classpath/gnu/CORBA/DynAn/UndivideableAny.java | 493 ++ .../gnu/CORBA/DynAn/ValueChangeListener.java | 50 + libjava/classpath/gnu/CORBA/DynAn/gnuDynAny.java | 945 ++++ .../gnu/CORBA/DynAn/gnuDynAnyFactory.java | 356 ++ libjava/classpath/gnu/CORBA/DynAn/gnuDynArray.java | 337 ++ libjava/classpath/gnu/CORBA/DynAn/gnuDynEnum.java | 244 + libjava/classpath/gnu/CORBA/DynAn/gnuDynFixed.java | 252 + .../classpath/gnu/CORBA/DynAn/gnuDynSequence.java | 254 + .../classpath/gnu/CORBA/DynAn/gnuDynStruct.java | 109 + libjava/classpath/gnu/CORBA/DynAn/gnuDynUnion.java | 437 ++ libjava/classpath/gnu/CORBA/DynAn/gnuDynValue.java | 380 ++ .../classpath/gnu/CORBA/DynAn/gnuDynValueBox.java | 389 ++ libjava/classpath/gnu/CORBA/DynAnySeqHolder.java | 116 + .../classpath/gnu/CORBA/EmptyExceptionHolder.java | 131 + .../classpath/gnu/CORBA/ForwardRequestHelper.java | 152 + libjava/classpath/gnu/CORBA/GIOP/CancelHeader.java | 70 + libjava/classpath/gnu/CORBA/GIOP/CharSets_OSF.java | 238 + libjava/classpath/gnu/CORBA/GIOP/CloseMessage.java | 106 + .../gnu/CORBA/GIOP/CodeSetServiceContext.java | 222 + .../classpath/gnu/CORBA/GIOP/ContextHandler.java | 76 + libjava/classpath/gnu/CORBA/GIOP/ErrorMessage.java | 114 + .../classpath/gnu/CORBA/GIOP/MessageHeader.java | 465 ++ libjava/classpath/gnu/CORBA/GIOP/ReplyHeader.java | 145 + .../classpath/gnu/CORBA/GIOP/RequestHeader.java | 156 + .../classpath/gnu/CORBA/GIOP/ServiceContext.java | 301 + .../gnu/CORBA/GIOP/v1_0/CancelHeader.java | 72 + .../classpath/gnu/CORBA/GIOP/v1_0/ReplyHeader.java | 141 + .../gnu/CORBA/GIOP/v1_0/RequestHeader.java | 159 + .../classpath/gnu/CORBA/GIOP/v1_2/ReplyHeader.java | 118 + .../gnu/CORBA/GIOP/v1_2/RequestHeader.java | 222 + libjava/classpath/gnu/CORBA/GeneralHolder.java | 178 + libjava/classpath/gnu/CORBA/HolderLocator.java | 184 + libjava/classpath/gnu/CORBA/IOR.java | 824 +++ .../Interceptor/ClientRequestInterceptors.java | 139 + .../CORBA/Interceptor/ForwardRequestHolder.java | 106 + .../gnu/CORBA/Interceptor/IORInterceptors.java | 189 + .../gnu/CORBA/Interceptor/Registrator.java | 472 ++ .../Interceptor/ServerRequestInterceptors.java | 139 + .../CORBA/Interceptor/gnuClientRequestInfo.java | 337 ++ .../gnu/CORBA/Interceptor/gnuIcCurrent.java | 255 + .../gnu/CORBA/Interceptor/gnuIorInfo.java | 156 + .../CORBA/Interceptor/gnuServerRequestInfo.java | 476 ++ libjava/classpath/gnu/CORBA/IorDelegate.java | 425 ++ libjava/classpath/gnu/CORBA/IorObject.java | 118 + libjava/classpath/gnu/CORBA/IorProvider.java | 52 + libjava/classpath/gnu/CORBA/Minor.java | 282 + .../classpath/gnu/CORBA/NameDynAnyPairHolder.java | 115 + .../gnu/CORBA/NameDynAnyPairSeqHolder.java | 115 + .../classpath/gnu/CORBA/NameValuePairHolder.java | 105 + .../gnu/CORBA/NameValuePairSeqHolder.java | 105 + .../CORBA/NamingService/Binding_iterator_impl.java | 141 + libjava/classpath/gnu/CORBA/NamingService/Ext.java | 232 + .../NamingService/NameComponentComparator.java | 98 + .../gnu/CORBA/NamingService/NameParser.java | 527 ++ .../gnu/CORBA/NamingService/NameTransformer.java | 326 ++ .../gnu/CORBA/NamingService/NameValidator.java | 79 + .../gnu/CORBA/NamingService/NamingMap.java | 190 + .../NamingService/NamingServiceTransient.java | 146 + .../gnu/CORBA/NamingService/TransientContext.java | 443 ++ libjava/classpath/gnu/CORBA/ObjectCreator.java | 590 ++ libjava/classpath/gnu/CORBA/OctetHolder.java | 129 + libjava/classpath/gnu/CORBA/OrbFocused.java | 375 ++ libjava/classpath/gnu/CORBA/OrbFunctional.java | 1794 ++++++ libjava/classpath/gnu/CORBA/OrbRestricted.java | 583 ++ libjava/classpath/gnu/CORBA/Poa/AOM.java | 406 ++ .../classpath/gnu/CORBA/Poa/AccessiblePolicy.java | 62 + .../classpath/gnu/CORBA/Poa/DynamicImpHandler.java | 85 + .../gnu/CORBA/Poa/ForwardRequestHolder.java | 107 + .../classpath/gnu/CORBA/Poa/ForwardedServant.java | 209 + .../gnu/CORBA/Poa/InvalidPolicyHolder.java | 106 + libjava/classpath/gnu/CORBA/Poa/LocalDelegate.java | 385 ++ libjava/classpath/gnu/CORBA/Poa/LocalRequest.java | 687 +++ .../gnu/CORBA/Poa/LocalServerRequest.java | 199 + libjava/classpath/gnu/CORBA/Poa/ORB_1_4.java | 293 + .../gnu/CORBA/Poa/ServantDelegateImpl.java | 232 + .../classpath/gnu/CORBA/Poa/StandardPolicies.java | 128 + .../gnu/CORBA/Poa/gnuAdapterActivator.java | 81 + .../classpath/gnu/CORBA/Poa/gnuForwardRequest.java | 90 + .../gnu/CORBA/Poa/gnuIdAssignmentPolicy.java | 80 + .../gnu/CORBA/Poa/gnuIdUniquenessPolicy.java | 80 + .../gnu/CORBA/Poa/gnuImplicitActivationPolicy.java | 80 + .../classpath/gnu/CORBA/Poa/gnuLifespanPolicy.java | 80 + libjava/classpath/gnu/CORBA/Poa/gnuPOA.java | 1817 ++++++ libjava/classpath/gnu/CORBA/Poa/gnuPOAManager.java | 272 + libjava/classpath/gnu/CORBA/Poa/gnuPoaCurrent.java | 179 + .../gnu/CORBA/Poa/gnuRequestProcessingPolicy.java | 80 + .../classpath/gnu/CORBA/Poa/gnuServantObject.java | 825 +++ .../gnu/CORBA/Poa/gnuServantRetentionPolicy.java | 80 + .../classpath/gnu/CORBA/Poa/gnuThreadPolicy.java | 80 + libjava/classpath/gnu/CORBA/RawReply.java | 95 + .../classpath/gnu/CORBA/ResponseHandlerImpl.java | 189 + .../classpath/gnu/CORBA/SafeForDirectCalls.java | 50 + .../classpath/gnu/CORBA/ServiceDetailHolder.java | 91 + .../classpath/gnu/CORBA/ServiceRequestAdapter.java | 167 + .../classpath/gnu/CORBA/SetOverrideTypeHolder.java | 90 + libjava/classpath/gnu/CORBA/SimpleDelegate.java | 318 ++ libjava/classpath/gnu/CORBA/SocketRepository.java | 148 + .../classpath/gnu/CORBA/StreamBasedRequest.java | 60 + libjava/classpath/gnu/CORBA/StreamHolder.java | 123 + libjava/classpath/gnu/CORBA/StubLocator.java | 110 + libjava/classpath/gnu/CORBA/TypeCodeHelper.java | 304 + libjava/classpath/gnu/CORBA/TypeKindNamer.java | 183 + libjava/classpath/gnu/CORBA/Unexpected.java | 128 + libjava/classpath/gnu/CORBA/Version.java | 222 + libjava/classpath/gnu/CORBA/WCharHolder.java | 128 + libjava/classpath/gnu/CORBA/WStringHolder.java | 131 + libjava/classpath/gnu/CORBA/_PolicyImplBase.java | 232 + libjava/classpath/gnu/CORBA/gnuAny.java | 907 +++ libjava/classpath/gnu/CORBA/gnuCodecFactory.java | 90 + libjava/classpath/gnu/CORBA/gnuContext.java | 202 + libjava/classpath/gnu/CORBA/gnuContextList.java | 81 + libjava/classpath/gnu/CORBA/gnuEnvironment.java | 72 + libjava/classpath/gnu/CORBA/gnuExceptionList.java | 82 + libjava/classpath/gnu/CORBA/gnuNVList.java | 127 + libjava/classpath/gnu/CORBA/gnuNamedValue.java | 112 + libjava/classpath/gnu/CORBA/gnuRequest.java | 1423 +++++ libjava/classpath/gnu/CORBA/gnuValueHolder.java | 135 + .../gnu/CORBA/interfaces/SocketFactory.java | 95 + .../classpath/gnu/CORBA/interfaces/package.html | 49 + .../gnu/CORBA/typecodes/AliasTypeCode.java | 148 + .../gnu/CORBA/typecodes/ArrayTypeCode.java | 272 + .../gnu/CORBA/typecodes/FixedTypeCode.java | 152 + .../gnu/CORBA/typecodes/GeneralTypeCode.java | 249 + .../gnu/CORBA/typecodes/PrimitiveTypeCode.java | 201 + .../gnu/CORBA/typecodes/RecordTypeCode.java | 252 + .../gnu/CORBA/typecodes/RecursiveTypeCode.java | 84 + .../gnu/CORBA/typecodes/StringTypeCode.java | 89 + libjava/classpath/gnu/CORBA/typecodes/package.html | 48 + libjava/classpath/gnu/classpath/.cvsignore | 1 + .../classpath/gnu/classpath/Configuration.java.in | 114 + .../gnu/classpath/NotImplementedException.java | 61 + libjava/classpath/gnu/classpath/Pair.java | 126 + libjava/classpath/gnu/classpath/Pointer.java | 47 + libjava/classpath/gnu/classpath/Pointer32.java | 52 + libjava/classpath/gnu/classpath/Pointer64.java | 52 + .../classpath/gnu/classpath/ServiceFactory.java | 653 +++ .../classpath/ServiceProviderLoadingAction.java | 149 + .../classpath/gnu/classpath/SystemProperties.java | 173 + .../classpath/gnu/classpath/debug/Component.java | 175 + .../gnu/classpath/debug/PreciseFilter.java | 105 + .../gnu/classpath/debug/Simple1LineFormatter.java | 161 + .../gnu/classpath/debug/SystemLogger.java | 102 + .../gnu/classpath/debug/TeeInputStream.java | 98 + .../gnu/classpath/debug/TeeOutputStream.java | 93 + .../classpath/gnu/classpath/debug/TeeReader.java | 98 + .../classpath/gnu/classpath/debug/TeeWriter.java | 93 + libjava/classpath/gnu/classpath/jdwp/Jdwp.java | 416 ++ .../gnu/classpath/jdwp/JdwpConstants.java | 901 +++ .../gnu/classpath/jdwp/event/BreakpointEvent.java | 117 + .../classpath/jdwp/event/ClassPrepareEvent.java | 147 + .../gnu/classpath/jdwp/event/ClassUnloadEvent.java | 96 + .../classpath/gnu/classpath/jdwp/event/Event.java | 180 + .../gnu/classpath/jdwp/event/EventManager.java | 305 + .../gnu/classpath/jdwp/event/EventRequest.java | 383 ++ .../gnu/classpath/jdwp/event/ExceptionEvent.java | 157 + .../gnu/classpath/jdwp/event/MethodEntryEvent.java | 118 + .../gnu/classpath/jdwp/event/MethodExitEvent.java | 115 + .../gnu/classpath/jdwp/event/SingleStepEvent.java | 121 + .../gnu/classpath/jdwp/event/ThreadEndEvent.java | 104 + .../gnu/classpath/jdwp/event/ThreadStartEvent.java | 109 + .../gnu/classpath/jdwp/event/VmDeathEvent.java | 83 + .../gnu/classpath/jdwp/event/VmInitEvent.java | 94 + .../jdwp/event/filters/ClassExcludeFilter.java | 75 + .../jdwp/event/filters/ClassMatchFilter.java | 112 + .../jdwp/event/filters/ClassOnlyFilter.java | 109 + .../jdwp/event/filters/ConditionalFilter.java | 82 + .../classpath/jdwp/event/filters/CountFilter.java | 95 + .../jdwp/event/filters/ExceptionOnlyFilter.java | 123 + .../jdwp/event/filters/FieldOnlyFilter.java | 112 + .../classpath/jdwp/event/filters/IEventFilter.java | 65 + .../jdwp/event/filters/InstanceOnlyFilter.java | 101 + .../jdwp/event/filters/LocationOnlyFilter.java | 94 + .../classpath/jdwp/event/filters/StepFilter.java | 126 + .../jdwp/event/filters/ThreadOnlyFilter.java | 101 + .../jdwp/exception/AbsentInformationException.java | 56 + .../jdwp/exception/InvalidClassException.java | 63 + .../exception/InvalidClassLoaderException.java | 62 + .../jdwp/exception/InvalidCountException.java | 61 + .../jdwp/exception/InvalidEventTypeException.java | 63 + .../jdwp/exception/InvalidFieldException.java | 63 + .../jdwp/exception/InvalidFrameException.java | 63 + .../jdwp/exception/InvalidLocationException.java | 62 + .../jdwp/exception/InvalidMethodException.java | 63 + .../jdwp/exception/InvalidObjectException.java | 63 + .../jdwp/exception/InvalidSlotException.java | 62 + .../jdwp/exception/InvalidStringException.java | 68 + .../jdwp/exception/InvalidTagException.java | 57 + .../jdwp/exception/InvalidThreadException.java | 63 + .../exception/InvalidThreadGroupException.java | 63 + .../classpath/jdwp/exception/JdwpException.java | 86 + .../exception/JdwpIllegalArgumentException.java | 62 + .../jdwp/exception/JdwpInternalErrorException.java | 62 + .../jdwp/exception/NativeMethodException.java | 63 + .../jdwp/exception/NotImplementedException.java | 58 + .../jdwp/exception/TypeMismatchException.java | 62 + .../classpath/jdwp/exception/VmDeadException.java | 55 + .../classpath/gnu/classpath/jdwp/id/ArrayId.java | 62 + .../classpath/jdwp/id/ArrayReferenceTypeId.java | 59 + .../gnu/classpath/jdwp/id/ClassLoaderId.java | 82 + .../gnu/classpath/jdwp/id/ClassObjectId.java | 82 + .../classpath/jdwp/id/ClassReferenceTypeId.java | 59 + .../jdwp/id/InterfaceReferenceTypeId.java | 59 + .../classpath/gnu/classpath/jdwp/id/JdwpId.java | 151 + .../gnu/classpath/jdwp/id/NullObjectId.java | 79 + .../classpath/gnu/classpath/jdwp/id/ObjectId.java | 131 + .../gnu/classpath/jdwp/id/ReferenceTypeId.java | 91 + .../classpath/gnu/classpath/jdwp/id/StringId.java | 82 + .../gnu/classpath/jdwp/id/ThreadGroupId.java | 82 + .../classpath/gnu/classpath/jdwp/id/ThreadId.java | 85 + .../jdwp/processor/ArrayReferenceCommandSet.java | 176 + .../jdwp/processor/ArrayTypeCommandSet.java | 105 + .../processor/ClassLoaderReferenceCommandSet.java | 108 + .../processor/ClassObjectReferenceCommandSet.java | 97 + .../jdwp/processor/ClassTypeCommandSet.java | 205 + .../gnu/classpath/jdwp/processor/CommandSet.java | 74 + .../jdwp/processor/EventRequestCommandSet.java | 220 + .../classpath/jdwp/processor/FieldCommandSet.java | 67 + .../jdwp/processor/InterfaceTypeCommandSet.java | 68 + .../classpath/jdwp/processor/MethodCommandSet.java | 157 + .../jdwp/processor/ObjectReferenceCommandSet.java | 255 + .../classpath/jdwp/processor/PacketProcessor.java | 221 + .../jdwp/processor/ReferenceTypeCommandSet.java | 341 ++ .../jdwp/processor/StackFrameCommandSet.java | 170 + .../jdwp/processor/StringReferenceCommandSet.java | 99 + .../processor/ThreadGroupReferenceCommandSet.java | 179 + .../jdwp/processor/ThreadReferenceCommandSet.java | 265 + .../jdwp/processor/VirtualMachineCommandSet.java | 472 ++ .../gnu/classpath/jdwp/transport/ITransport.java | 88 + .../jdwp/transport/JdwpCommandPacket.java | 149 + .../classpath/jdwp/transport/JdwpConnection.java | 307 ++ .../gnu/classpath/jdwp/transport/JdwpPacket.java | 277 + .../classpath/jdwp/transport/JdwpReplyPacket.java | 137 + .../classpath/jdwp/transport/SocketTransport.java | 196 + .../jdwp/transport/TransportException.java | 75 + .../classpath/jdwp/transport/TransportFactory.java | 115 + .../gnu/classpath/jdwp/util/JdwpString.java | 95 + .../gnu/classpath/jdwp/util/LineTable.java | 95 + .../gnu/classpath/jdwp/util/Location.java | 168 + .../gnu/classpath/jdwp/util/MethodResult.java | 86 + .../gnu/classpath/jdwp/util/MonitorInfo.java | 76 + .../gnu/classpath/jdwp/util/NullObject.java | 50 + .../gnu/classpath/jdwp/util/Signature.java | 151 + .../gnu/classpath/jdwp/util/VariableTable.java | 110 + .../gnu/classpath/jdwp/value/ArrayValue.java | 92 + .../gnu/classpath/jdwp/value/BooleanValue.java | 99 + .../gnu/classpath/jdwp/value/ByteValue.java | 99 + .../gnu/classpath/jdwp/value/CharValue.java | 99 + .../gnu/classpath/jdwp/value/DoubleValue.java | 99 + .../gnu/classpath/jdwp/value/FloatValue.java | 99 + .../gnu/classpath/jdwp/value/IntValue.java | 99 + .../gnu/classpath/jdwp/value/LongValue.java | 99 + .../gnu/classpath/jdwp/value/ObjectValue.java | 102 + .../gnu/classpath/jdwp/value/ShortValue.java | 99 + .../gnu/classpath/jdwp/value/StringValue.java | 103 + .../classpath/gnu/classpath/jdwp/value/Value.java | 155 + .../gnu/classpath/jdwp/value/ValueFactory.java | 247 + .../gnu/classpath/jdwp/value/VoidValue.java | 82 + .../toolkit/DefaultDaemonThreadFactory.java | 59 + libjava/classpath/gnu/java/awt/AWTUtilities.java | 898 +++ libjava/classpath/gnu/java/awt/BitMaskExtent.java | 79 + .../gnu/java/awt/BitwiseXORComposite.java | 295 + libjava/classpath/gnu/java/awt/Buffers.java | 225 + .../gnu/java/awt/ClasspathGraphicsEnvironment.java | 67 + .../classpath/gnu/java/awt/ClasspathToolkit.java | 231 + .../gnu/java/awt/ComponentDataBlitOp.java | 156 + .../gnu/java/awt/ComponentReshapeEvent.java | 85 + libjava/classpath/gnu/java/awt/EmbeddedWindow.java | 138 + libjava/classpath/gnu/java/awt/EventModifier.java | 107 + .../gnu/java/awt/GradientPaintContext.java | 164 + .../classpath/gnu/java/awt/LowPriorityEvent.java | 48 + .../gnu/java/awt/color/CieXyzConverter.java | 73 + .../gnu/java/awt/color/ClutProfileConverter.java | 152 + .../gnu/java/awt/color/ColorLookUpTable.java | 429 ++ .../gnu/java/awt/color/ColorSpaceConverter.java | 69 + .../gnu/java/awt/color/GrayProfileConverter.java | 137 + .../gnu/java/awt/color/GrayScaleConverter.java | 110 + .../gnu/java/awt/color/LinearRGBConverter.java | 152 + .../gnu/java/awt/color/ProfileHeader.java | 398 ++ .../gnu/java/awt/color/PyccConverter.java | 71 + .../gnu/java/awt/color/RgbProfileConverter.java | 244 + .../gnu/java/awt/color/SrgbConverter.java | 152 + libjava/classpath/gnu/java/awt/color/TagEntry.java | 121 + .../gnu/java/awt/color/ToneReproductionCurve.java | 177 + libjava/classpath/gnu/java/awt/color/package.html | 46 + .../awt/dnd/GtkMouseDragGestureRecognizer.java | 172 + .../awt/dnd/peer/gtk/GtkDragSourceContextPeer.java | 184 + .../awt/dnd/peer/gtk/GtkDropTargetContextPeer.java | 125 + .../java/awt/dnd/peer/gtk/GtkDropTargetPeer.java | 68 + .../java/awt/doc-files/BitwiseXORComposite-1.png | Bin 0 -> 8845 bytes .../classpath/gnu/java/awt/font/FontDelegate.java | 329 ++ .../classpath/gnu/java/awt/font/FontFactory.java | 90 + .../gnu/java/awt/font/GNUGlyphVector.java | 663 +++ .../gnu/java/awt/font/OpenTypeFontPeer.java | 565 ++ .../gnu/java/awt/font/autofit/AutoHinter.java | 83 + .../gnu/java/awt/font/autofit/AxisHints.java | 112 + .../gnu/java/awt/font/autofit/Constants.java | 86 + .../classpath/gnu/java/awt/font/autofit/Edge.java | 82 + .../gnu/java/awt/font/autofit/GlyphHints.java | 640 +++ .../gnu/java/awt/font/autofit/HintScaler.java | 53 + .../classpath/gnu/java/awt/font/autofit/Latin.java | 1363 +++++ .../gnu/java/awt/font/autofit/LatinAxis.java | 62 + .../gnu/java/awt/font/autofit/LatinBlue.java | 61 + .../gnu/java/awt/font/autofit/LatinMetrics.java | 66 + .../gnu/java/awt/font/autofit/Script.java | 62 + .../gnu/java/awt/font/autofit/ScriptMetrics.java | 53 + .../gnu/java/awt/font/autofit/Segment.java | 97 + .../classpath/gnu/java/awt/font/autofit/Utils.java | 255 + .../classpath/gnu/java/awt/font/autofit/Width.java | 64 + .../gnu/java/awt/font/opentype/CharGlyphMap.java | 1027 ++++ .../gnu/java/awt/font/opentype/GlyphNamer.java | 1135 ++++ .../gnu/java/awt/font/opentype/Hinter.java | 63 + .../java/awt/font/opentype/MacResourceFork.java | 235 + .../gnu/java/awt/font/opentype/NameDecoder.java | 702 +++ .../gnu/java/awt/font/opentype/OpenTypeFont.java | 882 +++ .../awt/font/opentype/OpenTypeFontFactory.java | 140 + .../gnu/java/awt/font/opentype/Scaler.java | 205 + .../gnu/java/awt/font/opentype/truetype/Fixed.java | 176 + .../awt/font/opentype/truetype/GlyphLoader.java | 447 ++ .../awt/font/opentype/truetype/GlyphLocator.java | 187 + .../awt/font/opentype/truetype/GlyphMeasurer.java | 228 + .../gnu/java/awt/font/opentype/truetype/Point.java | 287 + .../awt/font/opentype/truetype/TrueTypeScaler.java | 380 ++ .../awt/font/opentype/truetype/VirtualMachine.java | 1815 ++++++ .../gnu/java/awt/font/opentype/truetype/Zone.java | 291 + .../font/opentype/truetype/ZonePathIterator.java | 393 ++ .../truetype/doc-files/ZonePathIterator-1.dia | Bin 0 -> 1572 bytes .../truetype/doc-files/ZonePathIterator-1.png | Bin 0 -> 11278 bytes .../classpath/gnu/java/awt/image/AsyncImage.java | 300 + .../gnu/java/awt/image/ImageConverter.java | 528 ++ .../classpath/gnu/java/awt/image/ImageDecoder.java | 188 + .../classpath/gnu/java/awt/image/XBMDecoder.java | 155 + libjava/classpath/gnu/java/awt/image/package.html | 46 + .../gnu/java/awt/java2d/AbstractGraphics2D.java | 2094 +++++++ .../classpath/gnu/java/awt/java2d/ActiveEdges.java | 197 + .../gnu/java/awt/java2d/AlphaCompositeContext.java | 316 ++ .../gnu/java/awt/java2d/CubicSegment.java | 184 + .../classpath/gnu/java/awt/java2d/ImagePaint.java | 192 + .../classpath/gnu/java/awt/java2d/LineSegment.java | 118 + .../gnu/java/awt/java2d/PixelCoverage.java | 132 + .../classpath/gnu/java/awt/java2d/Pixelizer.java | 56 + .../classpath/gnu/java/awt/java2d/PolyEdge.java | 171 + .../gnu/java/awt/java2d/PolyEdgeComparator.java | 70 + .../classpath/gnu/java/awt/java2d/QuadSegment.java | 260 + .../gnu/java/awt/java2d/RasterGraphics.java | 118 + .../classpath/gnu/java/awt/java2d/Scanline.java | 91 + .../gnu/java/awt/java2d/ScanlineConverter.java | 451 ++ .../gnu/java/awt/java2d/ScanlineCoverage.java | 630 +++ libjava/classpath/gnu/java/awt/java2d/Segment.java | 158 + .../classpath/gnu/java/awt/java2d/ShapeCache.java | 90 + .../gnu/java/awt/java2d/ShapeWrapper.java | 119 + .../gnu/java/awt/java2d/TextCacheKey.java | 153 + .../gnu/java/awt/java2d/TexturePaintContext.java | 211 + libjava/classpath/gnu/java/awt/package.html | 46 + .../gnu/java/awt/peer/ClasspathDesktopPeer.java | 301 + .../gnu/java/awt/peer/ClasspathFontPeer.java | 865 +++ .../gnu/java/awt/peer/EmbeddedWindowPeer.java | 47 + .../gnu/java/awt/peer/GLightweightPeer.java | 461 ++ .../gnu/java/awt/peer/GnomeDesktopPeer.java | 155 + .../gnu/java/awt/peer/KDEDesktopPeer.java | 135 + .../java/awt/peer/NativeEventLoopRunningEvent.java | 58 + .../gnu/java/awt/peer/gtk/AsyncImage.java | 283 + .../java/awt/peer/gtk/BufferedImageGraphics.java | 538 ++ .../gnu/java/awt/peer/gtk/CairoGraphics2D.java | 2176 ++++++++ .../gnu/java/awt/peer/gtk/CairoSurface.java | 428 ++ .../java/awt/peer/gtk/CairoSurfaceGraphics.java | 355 ++ .../gnu/java/awt/peer/gtk/ComponentGraphics.java | 941 ++++ .../java/awt/peer/gtk/ComponentGraphicsCopy.java | 122 + .../gnu/java/awt/peer/gtk/FreetypeGlyphVector.java | 630 +++ .../gnu/java/awt/peer/gtk/GdkFontPeer.java | 545 ++ .../awt/peer/gtk/GdkGraphicsConfiguration.java | 156 + .../java/awt/peer/gtk/GdkGraphicsEnvironment.java | 172 + .../gnu/java/awt/peer/gtk/GdkPixbufDecoder.java | 785 +++ .../gnu/java/awt/peer/gtk/GdkRobotPeer.java | 99 + .../java/awt/peer/gtk/GdkScreenGraphicsDevice.java | 362 ++ .../gnu/java/awt/peer/gtk/GtkButtonPeer.java | 93 + .../gnu/java/awt/peer/gtk/GtkCanvasPeer.java | 60 + .../java/awt/peer/gtk/GtkCheckboxMenuItemPeer.java | 74 + .../gnu/java/awt/peer/gtk/GtkCheckboxPeer.java | 255 + .../gnu/java/awt/peer/gtk/GtkChoicePeer.java | 142 + .../gnu/java/awt/peer/gtk/GtkClipboard.java | 436 ++ .../java/awt/peer/gtk/GtkClipboardNotifier.java | 129 + .../gnu/java/awt/peer/gtk/GtkComponentPeer.java | 920 +++ .../gnu/java/awt/peer/gtk/GtkContainerPeer.java | 138 + .../classpath/gnu/java/awt/peer/gtk/GtkCursor.java | 72 + .../gnu/java/awt/peer/gtk/GtkDialogPeer.java | 63 + .../java/awt/peer/gtk/GtkEmbeddedWindowPeer.java | 73 + .../gnu/java/awt/peer/gtk/GtkFileDialogPeer.java | 229 + .../gnu/java/awt/peer/gtk/GtkFramePeer.java | 254 + .../gnu/java/awt/peer/gtk/GtkGenericPeer.java | 145 + .../classpath/gnu/java/awt/peer/gtk/GtkImage.java | 541 ++ .../gnu/java/awt/peer/gtk/GtkImageConsumer.java | 169 + .../gnu/java/awt/peer/gtk/GtkLabelPeer.java | 102 + .../gnu/java/awt/peer/gtk/GtkListPeer.java | 187 + .../gnu/java/awt/peer/gtk/GtkMainThread.java | 188 + .../gnu/java/awt/peer/gtk/GtkMenuBarPeer.java | 113 + .../java/awt/peer/gtk/GtkMenuComponentPeer.java | 104 + .../gnu/java/awt/peer/gtk/GtkMenuItemPeer.java | 116 + .../gnu/java/awt/peer/gtk/GtkMenuPeer.java | 126 + .../gnu/java/awt/peer/gtk/GtkMouseInfoPeer.java | 65 + .../gnu/java/awt/peer/gtk/GtkPanelPeer.java | 67 + .../gnu/java/awt/peer/gtk/GtkPopupMenuPeer.java | 68 + .../gnu/java/awt/peer/gtk/GtkScrollPanePeer.java | 111 + .../gnu/java/awt/peer/gtk/GtkScrollbarPeer.java | 92 + .../gnu/java/awt/peer/gtk/GtkSelection.java | 675 +++ .../gnu/java/awt/peer/gtk/GtkTextAreaPeer.java | 223 + .../gnu/java/awt/peer/gtk/GtkTextFieldPeer.java | 200 + .../gnu/java/awt/peer/gtk/GtkToolkit.java | 766 +++ .../gnu/java/awt/peer/gtk/GtkVolatileImage.java | 207 + .../gnu/java/awt/peer/gtk/GtkWindowPeer.java | 437 ++ .../java/awt/peer/gtk/VolatileImageGraphics.java | 325 ++ .../classpath/gnu/java/awt/peer/gtk/package.html | 46 + .../peer/headless/HeadlessGraphicsEnvironment.java | 118 + .../java/awt/peer/headless/HeadlessToolkit.java | 385 ++ libjava/classpath/gnu/java/awt/peer/package.html | 46 + .../gnu/java/awt/peer/qt/MainQtThread.java | 84 + .../gnu/java/awt/peer/qt/NativeWrapper.java | 43 + .../classpath/gnu/java/awt/peer/qt/QMatrix.java | 72 + .../gnu/java/awt/peer/qt/QPainterPath.java | 140 + libjava/classpath/gnu/java/awt/peer/qt/QPen.java | 70 + .../gnu/java/awt/peer/qt/QtAudioClip.java | 110 + .../gnu/java/awt/peer/qt/QtButtonPeer.java | 75 + .../gnu/java/awt/peer/qt/QtCanvasPeer.java | 65 + .../gnu/java/awt/peer/qt/QtCheckboxPeer.java | 111 + .../gnu/java/awt/peer/qt/QtChoicePeer.java | 93 + .../gnu/java/awt/peer/qt/QtComponentGraphics.java | 120 + .../gnu/java/awt/peer/qt/QtComponentPeer.java | 834 +++ .../gnu/java/awt/peer/qt/QtContainerPeer.java | 112 + .../gnu/java/awt/peer/qt/QtDialogPeer.java | 73 + .../gnu/java/awt/peer/qt/QtEmbeddedWindowPeer.java | 64 + .../gnu/java/awt/peer/qt/QtFileDialogPeer.java | 83 + .../gnu/java/awt/peer/qt/QtFontMetrics.java | 125 + .../classpath/gnu/java/awt/peer/qt/QtFontPeer.java | 197 + .../gnu/java/awt/peer/qt/QtFramePeer.java | 164 + .../classpath/gnu/java/awt/peer/qt/QtGraphics.java | 714 +++ .../java/awt/peer/qt/QtGraphicsEnvironment.java | 105 + .../classpath/gnu/java/awt/peer/qt/QtImage.java | 641 +++ .../gnu/java/awt/peer/qt/QtImageConsumer.java | 147 + .../java/awt/peer/qt/QtImageDirectGraphics.java | 145 + .../gnu/java/awt/peer/qt/QtImageGraphics.java | 139 + .../gnu/java/awt/peer/qt/QtLabelPeer.java | 62 + .../classpath/gnu/java/awt/peer/qt/QtListPeer.java | 188 + .../gnu/java/awt/peer/qt/QtMenuBarPeer.java | 101 + .../gnu/java/awt/peer/qt/QtMenuComponentPeer.java | 94 + .../gnu/java/awt/peer/qt/QtMenuItemPeer.java | 100 + .../classpath/gnu/java/awt/peer/qt/QtMenuPeer.java | 149 + .../gnu/java/awt/peer/qt/QtPanelPeer.java | 56 + .../gnu/java/awt/peer/qt/QtPopupMenuPeer.java | 76 + .../gnu/java/awt/peer/qt/QtRepaintThread.java | 156 + .../gnu/java/awt/peer/qt/QtScreenDevice.java | 115 + .../awt/peer/qt/QtScreenDeviceConfiguration.java | 145 + .../gnu/java/awt/peer/qt/QtScrollPanePeer.java | 90 + .../gnu/java/awt/peer/qt/QtScrollbarPeer.java | 80 + .../gnu/java/awt/peer/qt/QtTextAreaPeer.java | 179 + .../gnu/java/awt/peer/qt/QtTextFieldPeer.java | 159 + .../classpath/gnu/java/awt/peer/qt/QtToolkit.java | 470 ++ .../gnu/java/awt/peer/qt/QtVolatileImage.java | 434 ++ .../gnu/java/awt/peer/qt/QtWindowPeer.java | 105 + .../gnu/java/awt/peer/swing/SwingButtonPeer.java | 261 + .../gnu/java/awt/peer/swing/SwingCanvasPeer.java | 64 + .../gnu/java/awt/peer/swing/SwingCheckboxPeer.java | 256 + .../gnu/java/awt/peer/swing/SwingComponent.java | 99 + .../java/awt/peer/swing/SwingComponentPeer.java | 1136 ++++ .../java/awt/peer/swing/SwingContainerPeer.java | 378 ++ .../gnu/java/awt/peer/swing/SwingFramePeer.java | 197 + .../gnu/java/awt/peer/swing/SwingLabelPeer.java | 242 + .../gnu/java/awt/peer/swing/SwingListPeer.java | 364 ++ .../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/SwingTextAreaPeer.java | 487 ++ .../java/awt/peer/swing/SwingTextFieldPeer.java | 411 ++ .../gnu/java/awt/peer/swing/SwingToolkit.java | 181 + .../gnu/java/awt/peer/swing/SwingWindowPeer.java | 99 + .../classpath/gnu/java/awt/peer/swing/package.html | 71 + .../classpath/gnu/java/awt/peer/x/GLGraphics.java | 134 + .../gnu/java/awt/peer/x/KeyboardMapping.java | 419 ++ .../gnu/java/awt/peer/x/PixmapVolatileImage.java | 185 + .../classpath/gnu/java/awt/peer/x/XDialogPeer.java | 61 + .../classpath/gnu/java/awt/peer/x/XEventPump.java | 486 ++ .../classpath/gnu/java/awt/peer/x/XFontPeer.java | 770 +++ .../classpath/gnu/java/awt/peer/x/XFramePeer.java | 145 + .../classpath/gnu/java/awt/peer/x/XGraphics2D.java | 508 ++ .../java/awt/peer/x/XGraphicsConfiguration.java | 200 + .../gnu/java/awt/peer/x/XGraphicsDevice.java | 200 + .../gnu/java/awt/peer/x/XGraphicsEnvironment.java | 203 + libjava/classpath/gnu/java/awt/peer/x/XImage.java | 178 + .../classpath/gnu/java/awt/peer/x/XToolkit.java | 667 +++ .../classpath/gnu/java/awt/peer/x/XWindowPeer.java | 303 + .../gnu/java/awt/peer/x/ZPixmapDataBuffer.java | 67 + .../gnu/java/awt/print/JavaPrinterGraphics.java | 518 ++ .../gnu/java/awt/print/JavaPrinterJob.java | 403 ++ .../gnu/java/awt/print/PostScriptGraphics2D.java | 1349 +++++ .../gnu/java/awt/print/SpooledDocument.java | 90 + .../classpath/gnu/java/beans/BeanInfoEmbryo.java | 171 + .../gnu/java/beans/DefaultExceptionListener.java | 66 + .../gnu/java/beans/DummyAppletContext.java | 165 + .../classpath/gnu/java/beans/DummyAppletStub.java | 115 + .../classpath/gnu/java/beans/ExplicitBeanInfo.java | 149 + .../gnu/java/beans/IntrospectionIncubator.java | 441 ++ libjava/classpath/gnu/java/beans/TODO | 1 + .../gnu/java/beans/decoder/AbstractContext.java | 70 + .../decoder/AbstractCreatableObjectContext.java | 113 + .../java/beans/decoder/AbstractElementHandler.java | 316 ++ .../java/beans/decoder/AbstractObjectContext.java | 127 + .../gnu/java/beans/decoder/ArrayContext.java | 122 + .../gnu/java/beans/decoder/ArrayHandler.java | 118 + .../gnu/java/beans/decoder/AssemblyException.java | 57 + .../gnu/java/beans/decoder/BooleanHandler.java | 67 + .../gnu/java/beans/decoder/ByteHandler.java | 59 + .../gnu/java/beans/decoder/CharHandler.java | 62 + .../gnu/java/beans/decoder/ClassHandler.java | 66 + .../gnu/java/beans/decoder/ConstructorContext.java | 102 + .../classpath/gnu/java/beans/decoder/Context.java | 137 + .../gnu/java/beans/decoder/DecoderContext.java | 124 + .../gnu/java/beans/decoder/DoubleHandler.java | 59 + .../gnu/java/beans/decoder/DummyContext.java | 116 + .../gnu/java/beans/decoder/DummyHandler.java | 156 + .../gnu/java/beans/decoder/ElementHandler.java | 130 + .../gnu/java/beans/decoder/FloatHandler.java | 59 + .../java/beans/decoder/GrowableArrayContext.java | 138 + .../gnu/java/beans/decoder/IndexContext.java | 130 + .../gnu/java/beans/decoder/IntHandler.java | 59 + .../gnu/java/beans/decoder/JavaHandler.java | 93 + .../gnu/java/beans/decoder/LongHandler.java | 59 + .../gnu/java/beans/decoder/MethodContext.java | 107 + .../gnu/java/beans/decoder/MethodFinder.java | 177 + .../gnu/java/beans/decoder/NullHandler.java | 62 + .../gnu/java/beans/decoder/ObjectContext.java | 100 + .../gnu/java/beans/decoder/ObjectHandler.java | 169 + .../gnu/java/beans/decoder/PersistenceParser.java | 485 ++ .../gnu/java/beans/decoder/PropertyContext.java | 137 + .../gnu/java/beans/decoder/ShortHandler.java | 58 + .../gnu/java/beans/decoder/SimpleHandler.java | 111 + .../java/beans/decoder/StaticMethodContext.java | 95 + .../gnu/java/beans/decoder/StringHandler.java | 54 + .../gnu/java/beans/decoder/VoidHandler.java | 140 + .../classpath/gnu/java/beans/decoder/package.html | 46 + .../gnu/java/beans/editors/ColorEditor.java | 100 + .../gnu/java/beans/editors/FontEditor.java | 77 + .../java/beans/editors/NativeBooleanEditor.java | 76 + .../gnu/java/beans/editors/NativeByteEditor.java | 61 + .../gnu/java/beans/editors/NativeDoubleEditor.java | 61 + .../gnu/java/beans/editors/NativeFloatEditor.java | 61 + .../gnu/java/beans/editors/NativeIntEditor.java | 61 + .../gnu/java/beans/editors/NativeLongEditor.java | 61 + .../gnu/java/beans/editors/NativeShortEditor.java | 61 + .../gnu/java/beans/editors/StringEditor.java | 61 + libjava/classpath/gnu/java/beans/editors/TODO | 4 + .../classpath/gnu/java/beans/editors/package.html | 46 + .../beans/encoder/ArrayPersistenceDelegate.java | 153 + .../beans/encoder/ClassPersistenceDelegate.java | 80 + .../encoder/CollectionPersistenceDelegate.java | 84 + .../classpath/gnu/java/beans/encoder/Context.java | 88 + .../java/beans/encoder/GenericScannerState.java | 257 + .../java/beans/encoder/IgnoringScannerState.java | 133 + .../java/beans/encoder/MapPersistenceDelegate.java | 81 + .../classpath/gnu/java/beans/encoder/ObjectId.java | 132 + .../encoder/PrimitivePersistenceDelegate.java | 74 + .../java/beans/encoder/ReportingScannerState.java | 131 + libjava/classpath/gnu/java/beans/encoder/Root.java | 198 + .../gnu/java/beans/encoder/ScanEngine.java | 860 +++ .../gnu/java/beans/encoder/ScannerState.java | 236 + .../gnu/java/beans/encoder/StAXWriter.java | 233 + .../classpath/gnu/java/beans/encoder/Writer.java | 174 + .../beans/encoder/elements/ArrayInstantiation.java | 74 + .../gnu/java/beans/encoder/elements/Array_Get.java | 62 + .../gnu/java/beans/encoder/elements/Array_Set.java | 57 + .../beans/encoder/elements/ClassResolution.java | 67 + .../gnu/java/beans/encoder/elements/Element.java | 157 + .../gnu/java/beans/encoder/elements/List_Get.java | 56 + .../gnu/java/beans/encoder/elements/List_Set.java | 56 + .../beans/encoder/elements/MethodInvocation.java | 62 + .../java/beans/encoder/elements/NullObject.java | 61 + .../encoder/elements/ObjectInstantiation.java | 68 + .../beans/encoder/elements/ObjectReference.java | 68 + .../encoder/elements/PrimitiveInstantiation.java | 69 + .../beans/encoder/elements/StaticFieldAccess.java | 66 + .../encoder/elements/StaticMethodInvocation.java | 67 + .../beans/encoder/elements/StringReference.java | 63 + libjava/classpath/gnu/java/beans/package.html | 46 + .../gnu/java/io/ASN1ParsingException.java | 56 + .../classpath/gnu/java/io/Base64InputStream.java | 220 + .../gnu/java/io/ClassLoaderObjectInputStream.java | 73 + .../classpath/gnu/java/io/NullOutputStream.java | 56 + .../gnu/java/io/ObjectIdentityMap2Int.java | 292 + .../gnu/java/io/ObjectIdentityWrapper.java | 100 + libjava/classpath/gnu/java/io/PlatformHelper.java | 129 + libjava/classpath/gnu/java/io/package.html | 46 + libjava/classpath/gnu/java/lang/ArrayHelper.java | 78 + .../classpath/gnu/java/lang/CPStringBuilder.java | 1161 ++++ libjava/classpath/gnu/java/lang/CharData.java | 1705 ++++++ libjava/classpath/gnu/java/lang/ClassHelper.java | 205 + .../gnu/java/lang/InstrumentationImpl.java | 241 + libjava/classpath/gnu/java/lang/MainThread.java | 83 + .../gnu/java/lang/management/BeanImpl.java | 447 ++ .../lang/management/ClassLoadingMXBeanImpl.java | 98 + .../lang/management/CompilationMXBeanImpl.java | 105 + .../management/GarbageCollectorMXBeanImpl.java | 84 + .../gnu/java/lang/management/MemoryMXBeanImpl.java | 281 + .../lang/management/MemoryManagerMXBeanImpl.java | 112 + .../java/lang/management/MemoryPoolMXBeanImpl.java | 226 + .../lang/management/OperatingSystemMXBeanImpl.java | 95 + .../java/lang/management/RuntimeMXBeanImpl.java | 197 + .../gnu/java/lang/management/ThreadMXBeanImpl.java | 350 ++ .../gnu/java/lang/management/package.html | 46 + libjava/classpath/gnu/java/lang/package.html | 46 + .../java/lang/reflect/ClassSignatureParser.java | 92 + .../java/lang/reflect/FieldSignatureParser.java | 103 + .../java/lang/reflect/GenericSignatureParser.java | 631 +++ .../java/lang/reflect/MethodSignatureParser.java | 167 + .../classpath/gnu/java/lang/reflect/TypeImpl.java | 63 + .../gnu/java/lang/reflect/TypeSignature.java | 290 + .../classpath/gnu/java/lang/reflect/package.html | 46 + libjava/classpath/gnu/java/locale/.cvsignore | 1 + .../classpath/gnu/java/locale/LocaleHelper.java | 147 + libjava/classpath/gnu/java/locale/package.html | 46 + libjava/classpath/gnu/java/math/Fixed.java | 220 + libjava/classpath/gnu/java/math/GMP.java | 474 ++ libjava/classpath/gnu/java/math/MPN.java | 771 +++ libjava/classpath/gnu/java/math/package.html | 46 + .../classpath/gnu/java/net/CRLFInputStream.java | 178 + .../classpath/gnu/java/net/CRLFOutputStream.java | 182 + .../gnu/java/net/DefaultContentHandlerFactory.java | 94 + .../gnu/java/net/DefaultProxySelector.java | 80 + .../gnu/java/net/EmptyX509TrustManager.java | 69 + .../classpath/gnu/java/net/GetLocalHostAction.java | 64 + .../classpath/gnu/java/net/HeaderFieldHelper.java | 136 + .../classpath/gnu/java/net/IndexListParser.java | 183 + .../classpath/gnu/java/net/LineInputStream.java | 223 + .../gnu/java/net/PlainDatagramSocketImpl.java | 486 ++ .../classpath/gnu/java/net/PlainSocketImpl.java | 678 +++ libjava/classpath/gnu/java/net/URLParseError.java | 57 + .../gnu/java/net/loader/FileResource.java | 82 + .../gnu/java/net/loader/FileURLLoader.java | 145 + .../gnu/java/net/loader/JarURLLoader.java | 215 + .../gnu/java/net/loader/JarURLResource.java | 94 + .../gnu/java/net/loader/RemoteResource.java | 78 + .../gnu/java/net/loader/RemoteURLLoader.java | 101 + .../classpath/gnu/java/net/loader/Resource.java | 110 + .../classpath/gnu/java/net/loader/URLLoader.java | 148 + .../gnu/java/net/loader/URLStreamHandlerCache.java | 85 + .../gnu/java/net/local/LocalServerSocket.java | 171 + .../classpath/gnu/java/net/local/LocalSocket.java | 312 ++ .../gnu/java/net/local/LocalSocketAddress.java | 100 + .../gnu/java/net/local/LocalSocketImpl.java | 334 ++ libjava/classpath/gnu/java/net/package.html | 46 + .../gnu/java/net/protocol/file/Connection.java | 376 ++ .../gnu/java/net/protocol/file/Handler.java | 91 + .../gnu/java/net/protocol/file/package.html | 46 + .../gnu/java/net/protocol/ftp/ActiveModeDTP.java | 251 + .../java/net/protocol/ftp/BlockInputStream.java | 149 + .../java/net/protocol/ftp/BlockOutputStream.java | 110 + .../net/protocol/ftp/CompressedInputStream.java | 214 + .../net/protocol/ftp/CompressedOutputStream.java | 227 + .../classpath/gnu/java/net/protocol/ftp/DTP.java | 91 + .../gnu/java/net/protocol/ftp/DTPInputStream.java | 87 + .../gnu/java/net/protocol/ftp/DTPOutputStream.java | 85 + .../gnu/java/net/protocol/ftp/FTPConnection.java | 1352 +++++ .../gnu/java/net/protocol/ftp/FTPException.java | 75 + .../gnu/java/net/protocol/ftp/FTPResponse.java | 111 + .../java/net/protocol/ftp/FTPURLConnection.java | 375 ++ .../gnu/java/net/protocol/ftp/Handler.java | 69 + .../gnu/java/net/protocol/ftp/PassiveModeDTP.java | 200 + .../java/net/protocol/ftp/StreamInputStream.java | 94 + .../java/net/protocol/ftp/StreamOutputStream.java | 84 + .../gnu/java/net/protocol/ftp/package.html | 60 + .../gnu/java/net/protocol/http/Authenticator.java | 58 + .../protocol/http/ByteArrayRequestBodyWriter.java | 106 + .../java/net/protocol/http/ChunkedInputStream.java | 223 + .../gnu/java/net/protocol/http/Cookie.java | 161 + .../gnu/java/net/protocol/http/CookieManager.java | 65 + .../gnu/java/net/protocol/http/Credentials.java | 87 + .../gnu/java/net/protocol/http/HTTPConnection.java | 897 +++ .../gnu/java/net/protocol/http/HTTPDateFormat.java | 440 ++ .../java/net/protocol/http/HTTPURLConnection.java | 693 +++ .../gnu/java/net/protocol/http/Handler.java | 72 + .../gnu/java/net/protocol/http/Headers.java | 424 ++ .../protocol/http/LimitedLengthInputStream.java | 216 + .../gnu/java/net/protocol/http/Request.java | 857 +++ .../java/net/protocol/http/RequestBodyWriter.java | 68 + .../gnu/java/net/protocol/http/Response.java | 223 + .../net/protocol/http/ResponseHeaderHandler.java | 56 + .../net/protocol/http/SimpleCookieManager.java | 137 + .../gnu/java/net/protocol/http/package.html | 76 + .../gnu/java/net/protocol/https/Handler.java | 75 + .../gnu/java/net/protocol/jar/Connection.java | 232 + .../gnu/java/net/protocol/jar/Handler.java | 217 + .../gnu/java/net/protocol/jar/package.html | 46 + .../classpath/gnu/java/nio/ChannelInputStream.java | 89 + .../gnu/java/nio/ChannelOutputStream.java | 67 + libjava/classpath/gnu/java/nio/ChannelReader.java | 217 + libjava/classpath/gnu/java/nio/ChannelWriter.java | 190 + .../gnu/java/nio/DatagramChannelImpl.java | 240 + .../gnu/java/nio/DatagramChannelSelectionKey.java | 68 + .../gnu/java/nio/EpollSelectionKeyImpl.java | 122 + .../classpath/gnu/java/nio/EpollSelectorImpl.java | 399 ++ .../classpath/gnu/java/nio/FileChannelImpl.java | 572 ++ libjava/classpath/gnu/java/nio/FileLockImpl.java | 102 + .../classpath/gnu/java/nio/InputStreamChannel.java | 88 + .../gnu/java/nio/KqueueSelectionKeyImpl.java | 187 + .../classpath/gnu/java/nio/KqueueSelectorImpl.java | 527 ++ libjava/classpath/gnu/java/nio/NIOConstants.java | 47 + .../classpath/gnu/java/nio/NIODatagramSocket.java | 71 + .../classpath/gnu/java/nio/NIOServerSocket.java | 106 + libjava/classpath/gnu/java/nio/NIOSocket.java | 79 + libjava/classpath/gnu/java/nio/NIOSocketImpl.java | 110 + .../gnu/java/nio/OutputStreamChannel.java | 87 + libjava/classpath/gnu/java/nio/PipeImpl.java | 178 + .../classpath/gnu/java/nio/SelectionKeyImpl.java | 111 + libjava/classpath/gnu/java/nio/SelectorImpl.java | 397 ++ .../gnu/java/nio/SelectorProviderImpl.java | 121 + .../gnu/java/nio/ServerSocketChannelImpl.java | 128 + .../java/nio/ServerSocketChannelSelectionKey.java | 65 + .../classpath/gnu/java/nio/SocketChannelImpl.java | 265 + .../gnu/java/nio/SocketChannelSelectionKey.java | 65 + .../java/nio/SocketChannelSelectionKeyImpl.java | 78 + libjava/classpath/gnu/java/nio/VMChannelOwner.java | 57 + .../classpath/gnu/java/nio/channels/package.html | 46 + .../gnu/java/nio/charset/ByteCharset.java | 193 + .../gnu/java/nio/charset/ByteDecodeLoopHelper.java | 164 + .../gnu/java/nio/charset/ByteEncodeLoopHelper.java | 165 + libjava/classpath/gnu/java/nio/charset/Cp424.java | 86 + libjava/classpath/gnu/java/nio/charset/Cp437.java | 87 + libjava/classpath/gnu/java/nio/charset/Cp737.java | 87 + libjava/classpath/gnu/java/nio/charset/Cp775.java | 87 + libjava/classpath/gnu/java/nio/charset/Cp850.java | 87 + libjava/classpath/gnu/java/nio/charset/Cp852.java | 87 + libjava/classpath/gnu/java/nio/charset/Cp855.java | 87 + libjava/classpath/gnu/java/nio/charset/Cp857.java | 88 + libjava/classpath/gnu/java/nio/charset/Cp860.java | 88 + libjava/classpath/gnu/java/nio/charset/Cp861.java | 88 + libjava/classpath/gnu/java/nio/charset/Cp862.java | 88 + libjava/classpath/gnu/java/nio/charset/Cp863.java | 88 + libjava/classpath/gnu/java/nio/charset/Cp864.java | 88 + libjava/classpath/gnu/java/nio/charset/Cp865.java | 88 + libjava/classpath/gnu/java/nio/charset/Cp866.java | 88 + libjava/classpath/gnu/java/nio/charset/Cp869.java | 88 + libjava/classpath/gnu/java/nio/charset/Cp874.java | 87 + .../gnu/java/nio/charset/EncodingHelper.java | 161 + .../classpath/gnu/java/nio/charset/ISO_8859_1.java | 165 + .../gnu/java/nio/charset/ISO_8859_13.java | 102 + .../gnu/java/nio/charset/ISO_8859_15.java | 109 + .../classpath/gnu/java/nio/charset/ISO_8859_2.java | 108 + .../classpath/gnu/java/nio/charset/ISO_8859_3.java | 107 + .../classpath/gnu/java/nio/charset/ISO_8859_4.java | 108 + .../classpath/gnu/java/nio/charset/ISO_8859_5.java | 106 + .../classpath/gnu/java/nio/charset/ISO_8859_6.java | 110 + .../classpath/gnu/java/nio/charset/ISO_8859_7.java | 109 + .../classpath/gnu/java/nio/charset/ISO_8859_8.java | 108 + .../classpath/gnu/java/nio/charset/ISO_8859_9.java | 108 + libjava/classpath/gnu/java/nio/charset/KOI_8.java | 100 + libjava/classpath/gnu/java/nio/charset/MS874.java | 87 + .../gnu/java/nio/charset/MacCentralEurope.java | 87 + .../gnu/java/nio/charset/MacCroatian.java | 87 + .../gnu/java/nio/charset/MacCyrillic.java | 87 + .../classpath/gnu/java/nio/charset/MacDingbat.java | 87 + .../classpath/gnu/java/nio/charset/MacGreek.java | 87 + .../classpath/gnu/java/nio/charset/MacIceland.java | 87 + .../classpath/gnu/java/nio/charset/MacRoman.java | 87 + .../classpath/gnu/java/nio/charset/MacRomania.java | 87 + .../classpath/gnu/java/nio/charset/MacSymbol.java | 87 + .../classpath/gnu/java/nio/charset/MacThai.java | 87 + .../classpath/gnu/java/nio/charset/MacTurkish.java | 87 + .../classpath/gnu/java/nio/charset/Provider.java | 271 + .../classpath/gnu/java/nio/charset/US_ASCII.java | 162 + libjava/classpath/gnu/java/nio/charset/UTF_16.java | 80 + .../classpath/gnu/java/nio/charset/UTF_16BE.java | 84 + .../gnu/java/nio/charset/UTF_16Decoder.java | 167 + .../gnu/java/nio/charset/UTF_16Encoder.java | 145 + .../classpath/gnu/java/nio/charset/UTF_16LE.java | 83 + libjava/classpath/gnu/java/nio/charset/UTF_8.java | 311 ++ .../gnu/java/nio/charset/UnicodeLittle.java | 74 + .../gnu/java/nio/charset/Windows1250.java | 101 + .../gnu/java/nio/charset/Windows1251.java | 99 + .../gnu/java/nio/charset/Windows1252.java | 98 + .../gnu/java/nio/charset/Windows1253.java | 99 + .../gnu/java/nio/charset/Windows1254.java | 99 + .../gnu/java/nio/charset/Windows1255.java | 99 + .../gnu/java/nio/charset/Windows1256.java | 99 + .../gnu/java/nio/charset/Windows1257.java | 99 + .../gnu/java/nio/charset/Windows1258.java | 99 + .../gnu/java/nio/charset/iconv/IconvCharset.java | 85 + .../gnu/java/nio/charset/iconv/IconvDecoder.java | 110 + .../gnu/java/nio/charset/iconv/IconvEncoder.java | 110 + .../gnu/java/nio/charset/iconv/IconvMetaData.java | 450 ++ .../gnu/java/nio/charset/iconv/IconvProvider.java | 110 + .../classpath/gnu/java/nio/charset/package.html | 46 + libjava/classpath/gnu/java/nio/package.html | 46 + .../java/rmi/RMIMarshalledObjectInputStream.java | 71 + .../java/rmi/RMIMarshalledObjectOutputStream.java | 78 + .../rmi/activation/ActivationSystemTransient.java | 406 ++ .../gnu/java/rmi/activation/BidiTable.java | 163 + .../rmi/activation/DefaultActivationGroup.java | 159 + .../rmi/activation/DefaultActivationSystem.java | 118 + libjava/classpath/gnu/java/rmi/dgc/DGCImpl.java | 182 + .../classpath/gnu/java/rmi/dgc/DGCImpl_Skel.java | 144 + .../classpath/gnu/java/rmi/dgc/DGCImpl_Stub.java | 158 + .../gnu/java/rmi/dgc/LeaseRenewingTask.java | 234 + libjava/classpath/gnu/java/rmi/dgc/package.html | 46 + libjava/classpath/gnu/java/rmi/package.html | 46 + .../gnu/java/rmi/registry/RegistryImpl.java | 154 + .../gnu/java/rmi/registry/RegistryImpl_Skel.java | 227 + .../gnu/java/rmi/registry/RegistryImpl_Stub.java | 293 + .../classpath/gnu/java/rmi/registry/package.html | 46 + .../gnu/java/rmi/server/ActivatableRef.java | 179 + .../gnu/java/rmi/server/ActivatableServerRef.java | 227 + .../gnu/java/rmi/server/CombinedClassLoader.java | 135 + .../gnu/java/rmi/server/ConnectionRunnerPool.java | 156 + .../gnu/java/rmi/server/ProtocolConstants.java | 62 + .../gnu/java/rmi/server/RMIClassLoaderImpl.java | 357 ++ .../java/rmi/server/RMIDefaultSocketFactory.java | 59 + .../classpath/gnu/java/rmi/server/RMIHashes.java | 99 + .../gnu/java/rmi/server/RMIIncomingThread.java | 58 + .../gnu/java/rmi/server/RMIObjectInputStream.java | 118 + .../gnu/java/rmi/server/RMIObjectOutputStream.java | 114 + .../gnu/java/rmi/server/RMIVoidValue.java | 51 + .../gnu/java/rmi/server/UnicastConnection.java | 231 + .../java/rmi/server/UnicastConnectionManager.java | 468 ++ .../classpath/gnu/java/rmi/server/UnicastRef.java | 524 ++ .../gnu/java/rmi/server/UnicastRemoteCall.java | 525 ++ .../gnu/java/rmi/server/UnicastRemoteStub.java | 50 + .../gnu/java/rmi/server/UnicastServer.java | 321 ++ .../gnu/java/rmi/server/UnicastServerRef.java | 481 ++ libjava/classpath/gnu/java/rmi/server/package.html | 46 + libjava/classpath/gnu/java/security/.cvsignore | 1 + .../gnu/java/security/Configuration.java.in | 56 + libjava/classpath/gnu/java/security/Engine.java | 282 + libjava/classpath/gnu/java/security/OID.java | 512 ++ .../classpath/gnu/java/security/PolicyFile.java | 687 +++ .../classpath/gnu/java/security/Properties.java | 348 ++ libjava/classpath/gnu/java/security/Registry.java | 465 ++ libjava/classpath/gnu/java/security/Requires.java | 59 + .../java/security/action/GetPropertyAction.java | 89 + .../security/action/GetSecurityPropertyAction.java | 93 + .../java/security/action/SetAccessibleAction.java | 77 + .../gnu/java/security/action/package.html | 46 + libjava/classpath/gnu/java/security/ber/BER.java | 46 + .../java/security/ber/BEREncodingException.java | 54 + .../classpath/gnu/java/security/ber/BERReader.java | 103 + .../classpath/gnu/java/security/ber/BERValue.java | 82 + .../classpath/gnu/java/security/ber/package.html | 46 + .../classpath/gnu/java/security/der/BitString.java | 332 ++ libjava/classpath/gnu/java/security/der/DER.java | 86 + .../java/security/der/DEREncodingException.java | 54 + .../classpath/gnu/java/security/der/DERReader.java | 439 ++ .../classpath/gnu/java/security/der/DERValue.java | 189 + .../classpath/gnu/java/security/der/DERWriter.java | 355 ++ .../classpath/gnu/java/security/der/package.html | 46 + .../classpath/gnu/java/security/hash/BaseHash.java | 183 + .../gnu/java/security/hash/HashFactory.java | 135 + .../classpath/gnu/java/security/hash/Haval.java | 807 +++ .../gnu/java/security/hash/IMessageDigest.java | 127 + libjava/classpath/gnu/java/security/hash/MD2.java | 256 + libjava/classpath/gnu/java/security/hash/MD4.java | 337 ++ libjava/classpath/gnu/java/security/hash/MD5.java | 371 ++ .../gnu/java/security/hash/RipeMD128.java | 257 + .../gnu/java/security/hash/RipeMD160.java | 291 + .../classpath/gnu/java/security/hash/Sha160.java | 241 + .../classpath/gnu/java/security/hash/Sha256.java | 252 + .../classpath/gnu/java/security/hash/Sha384.java | 279 + .../classpath/gnu/java/security/hash/Sha512.java | 281 + .../classpath/gnu/java/security/hash/Tiger.java | 864 +++ .../gnu/java/security/hash/Whirlpool.java | 608 ++ .../gnu/java/security/jce/hash/HavalSpi.java | 54 + .../gnu/java/security/jce/hash/MD2Spi.java | 55 + .../gnu/java/security/jce/hash/MD4Spi.java | 55 + .../gnu/java/security/jce/hash/MD5Spi.java | 54 + .../security/jce/hash/MessageDigestAdapter.java | 133 + .../gnu/java/security/jce/hash/RipeMD128Spi.java | 54 + .../gnu/java/security/jce/hash/RipeMD160Spi.java | 54 + .../gnu/java/security/jce/hash/Sha160Spi.java | 54 + .../gnu/java/security/jce/hash/Sha256Spi.java | 54 + .../gnu/java/security/jce/hash/Sha384Spi.java | 54 + .../gnu/java/security/jce/hash/Sha512Spi.java | 54 + .../gnu/java/security/jce/hash/TigerSpi.java | 55 + .../gnu/java/security/jce/hash/WhirlpoolSpi.java | 54 + .../gnu/java/security/jce/prng/HavalRandomSpi.java | 54 + .../gnu/java/security/jce/prng/MD2RandomSpi.java | 54 + .../gnu/java/security/jce/prng/MD4RandomSpi.java | 54 + .../gnu/java/security/jce/prng/MD5RandomSpi.java | 54 + .../java/security/jce/prng/RipeMD128RandomSpi.java | 54 + .../java/security/jce/prng/RipeMD160RandomSpi.java | 54 + .../security/jce/prng/SecureRandomAdapter.java | 184 + .../java/security/jce/prng/Sha160RandomSpi.java | 54 + .../java/security/jce/prng/Sha256RandomSpi.java | 54 + .../java/security/jce/prng/Sha384RandomSpi.java | 54 + .../java/security/jce/prng/Sha512RandomSpi.java | 54 + .../gnu/java/security/jce/prng/TigerRandomSpi.java | 54 + .../java/security/jce/prng/WhirlpoolRandomSpi.java | 54 + .../gnu/java/security/jce/sig/DSSKeyFactory.java | 221 + .../security/jce/sig/DSSKeyPairGeneratorSpi.java | 146 + .../gnu/java/security/jce/sig/DSSParameters.java | 220 + .../security/jce/sig/DSSParametersGenerator.java | 125 + .../java/security/jce/sig/DSSRawSignatureSpi.java | 56 + .../java/security/jce/sig/EncodedKeyFactory.java | 430 ++ .../security/jce/sig/KeyPairGeneratorAdapter.java | 95 + .../gnu/java/security/jce/sig/MD2withRSA.java | 56 + .../gnu/java/security/jce/sig/MD5withRSA.java | 56 + .../gnu/java/security/jce/sig/RSAKeyFactory.java | 231 + .../security/jce/sig/RSAKeyPairGeneratorSpi.java | 96 + .../security/jce/sig/RSAPSSRawSignatureSpi.java | 56 + .../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 + .../java/security/jce/sig/SignatureAdapter.java | 250 + .../gnu/java/security/key/IKeyPairCodec.java | 124 + .../gnu/java/security/key/IKeyPairGenerator.java | 73 + .../gnu/java/security/key/KeyPairCodecFactory.java | 360 ++ .../java/security/key/KeyPairGeneratorFactory.java | 120 + .../gnu/java/security/key/dss/DSSKey.java | 213 + .../java/security/key/dss/DSSKeyPairGenerator.java | 382 ++ .../security/key/dss/DSSKeyPairPKCS8Codec.java | 249 + .../java/security/key/dss/DSSKeyPairRawCodec.java | 347 ++ .../java/security/key/dss/DSSKeyPairX509Codec.java | 276 + .../gnu/java/security/key/dss/DSSPrivateKey.java | 205 + .../gnu/java/security/key/dss/DSSPublicKey.java | 203 + .../gnu/java/security/key/dss/FIPS186.java | 262 + .../gnu/java/security/key/rsa/GnuRSAKey.java | 178 + .../java/security/key/rsa/GnuRSAPrivateKey.java | 313 ++ .../gnu/java/security/key/rsa/GnuRSAPublicKey.java | 190 + .../java/security/key/rsa/RSAKeyPairGenerator.java | 246 + .../security/key/rsa/RSAKeyPairPKCS8Codec.java | 299 + .../java/security/key/rsa/RSAKeyPairRawCodec.java | 300 + .../java/security/key/rsa/RSAKeyPairX509Codec.java | 250 + libjava/classpath/gnu/java/security/package.html | 46 + .../gnu/java/security/pkcs/PKCS7Data.java | 69 + .../gnu/java/security/pkcs/PKCS7SignedData.java | 485 ++ .../gnu/java/security/pkcs/SignerInfo.java | 429 ++ .../classpath/gnu/java/security/pkcs/package.html | 46 + .../classpath/gnu/java/security/prng/BasePRNG.java | 178 + .../gnu/java/security/prng/EntropySource.java | 61 + .../classpath/gnu/java/security/prng/IRandom.java | 174 + .../java/security/prng/LimitReachedException.java | 57 + .../gnu/java/security/prng/MDGenerator.java | 127 + .../gnu/java/security/prng/PRNGFactory.java | 92 + .../gnu/java/security/prng/RandomEvent.java | 81 + .../java/security/prng/RandomEventListener.java | 50 + .../security/provider/CollectionCertStoreImpl.java | 102 + .../gnu/java/security/provider/DefaultPolicy.java | 68 + .../classpath/gnu/java/security/provider/Gnu.java | 306 + .../provider/PKIXCertPathValidatorImpl.java | 693 +++ .../security/provider/X509CertificateFactory.java | 295 + .../gnu/java/security/provider/package.html | 46 + .../gnu/java/security/sig/BaseSignature.java | 219 + .../gnu/java/security/sig/ISignature.java | 160 + .../gnu/java/security/sig/ISignatureCodec.java | 59 + .../java/security/sig/SignatureCodecFactory.java | 226 + .../gnu/java/security/sig/SignatureFactory.java | 101 + .../gnu/java/security/sig/dss/DSSSignature.java | 275 + .../security/sig/dss/DSSSignatureRawCodec.java | 164 + .../security/sig/dss/DSSSignatureX509Codec.java | 193 + .../gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java | 274 + .../gnu/java/security/sig/rsa/EMSA_PKCS1_V1_5.java | 243 + .../gnu/java/security/sig/rsa/EMSA_PSS.java | 371 ++ .../classpath/gnu/java/security/sig/rsa/RSA.java | 324 ++ .../security/sig/rsa/RSAPKCS1V1_5Signature.java | 224 + .../sig/rsa/RSAPKCS1V1_5SignatureRawCodec.java | 153 + .../sig/rsa/RSAPKCS1V1_5SignatureX509Codec.java | 128 + .../gnu/java/security/sig/rsa/RSAPSSSignature.java | 255 + .../security/sig/rsa/RSAPSSSignatureRawCodec.java | 134 + .../java/security/sig/rsa/RSASignatureFactory.java | 176 + .../gnu/java/security/util/ByteArray.java | 111 + .../java/security/util/ByteBufferOutputStream.java | 118 + .../classpath/gnu/java/security/util/DerUtil.java | 64 + .../gnu/java/security/util/ExpirableObject.java | 150 + .../gnu/java/security/util/FormatUtil.java | 140 + .../gnu/java/security/util/IntegerUtil.java | 109 + libjava/classpath/gnu/java/security/util/PRNG.java | 141 + .../classpath/gnu/java/security/util/Prime.java | 164 + .../classpath/gnu/java/security/util/Sequence.java | 133 + .../gnu/java/security/util/SimpleList.java | 155 + libjava/classpath/gnu/java/security/util/Util.java | 629 +++ .../classpath/gnu/java/security/util/package.html | 46 + .../gnu/java/security/x509/GnuPKIExtension.java | 59 + .../gnu/java/security/x509/PolicyNodeImpl.java | 216 + libjava/classpath/gnu/java/security/x509/Util.java | 204 + .../java/security/x509/X500DistinguishedName.java | 558 ++ .../classpath/gnu/java/security/x509/X509CRL.java | 485 ++ .../gnu/java/security/x509/X509CRLEntry.java | 273 + .../java/security/x509/X509CRLSelectorImpl.java | 137 + .../gnu/java/security/x509/X509CertPath.java | 303 + .../java/security/x509/X509CertSelectorImpl.java | 196 + .../gnu/java/security/x509/X509Certificate.java | 757 +++ .../security/x509/ext/AuthorityKeyIdentifier.java | 133 + .../java/security/x509/ext/BasicConstraints.java | 129 + .../gnu/java/security/x509/ext/CRLNumber.java | 97 + .../security/x509/ext/CertificatePolicies.java | 205 + .../java/security/x509/ext/ExtendedKeyUsage.java | 95 + .../gnu/java/security/x509/ext/Extension.java | 297 + .../gnu/java/security/x509/ext/GeneralName.java | 232 + .../gnu/java/security/x509/ext/GeneralNames.java | 89 + .../gnu/java/security/x509/ext/GeneralSubtree.java | 156 + .../security/x509/ext/IssuerAlternativeNames.java | 77 + .../gnu/java/security/x509/ext/KeyUsage.java | 92 + .../java/security/x509/ext/NameConstraints.java | 161 + .../java/security/x509/ext/PolicyConstraint.java | 107 + .../gnu/java/security/x509/ext/PolicyMappings.java | 104 + .../security/x509/ext/PrivateKeyUsagePeriod.java | 105 + .../gnu/java/security/x509/ext/ReasonCode.java | 85 + .../security/x509/ext/SubjectAlternativeNames.java | 77 + .../security/x509/ext/SubjectKeyIdentifier.java | 84 + .../gnu/java/security/x509/ext/package.html | 46 + .../classpath/gnu/java/security/x509/package.html | 46 + .../gnu/java/text/AttributedFormatBuffer.java | 251 + .../classpath/gnu/java/text/BaseBreakIterator.java | 124 + .../gnu/java/text/CharacterBreakIterator.java | 213 + libjava/classpath/gnu/java/text/FormatBuffer.java | 136 + .../gnu/java/text/FormatCharacterIterator.java | 533 ++ .../classpath/gnu/java/text/LineBreakIterator.java | 194 + .../gnu/java/text/SentenceBreakIterator.java | 247 + .../gnu/java/text/StringFormatBuffer.java | 127 + .../classpath/gnu/java/text/WordBreakIterator.java | 250 + libjava/classpath/gnu/java/text/package.html | 46 + libjava/classpath/gnu/java/util/Base64.java | 342 ++ .../classpath/gnu/java/util/DoubleEnumeration.java | 138 + .../classpath/gnu/java/util/EmptyEnumeration.java | 90 + libjava/classpath/gnu/java/util/LRUCache.java | 77 + .../gnu/java/util/WeakIdentityHashMap.java | 862 +++ libjava/classpath/gnu/java/util/ZoneInfo.java | 1160 ++++ libjava/classpath/gnu/java/util/jar/JarUtils.java | 451 ++ libjava/classpath/gnu/java/util/package.html | 46 + .../gnu/java/util/prefs/FileBasedFactory.java | 65 + .../gnu/java/util/prefs/FileBasedPreferences.java | 273 + .../gnu/java/util/prefs/GConfBasedFactory.java | 78 + .../gnu/java/util/prefs/GConfBasedPreferences.java | 419 ++ .../gnu/java/util/prefs/MemoryBasedFactory.java | 64 + .../java/util/prefs/MemoryBasedPreferences.java | 144 + .../classpath/gnu/java/util/prefs/NodeReader.java | 221 + .../classpath/gnu/java/util/prefs/NodeWriter.java | 319 ++ .../gnu/java/util/prefs/gconf/GConfNativePeer.java | 286 + libjava/classpath/gnu/java/util/prefs/package.html | 46 + .../gnu/java/util/regex/BacktrackStack.java | 124 + .../classpath/gnu/java/util/regex/CharIndexed.java | 134 + .../gnu/java/util/regex/CharIndexedCharArray.java | 48 + .../java/util/regex/CharIndexedCharSequence.java | 119 + .../java/util/regex/CharIndexedInputStream.java | 253 + .../gnu/java/util/regex/CharIndexedString.java | 46 + .../java/util/regex/CharIndexedStringBuffer.java | 47 + libjava/classpath/gnu/java/util/regex/RE.java | 2675 +++++++++ .../classpath/gnu/java/util/regex/REException.java | 198 + .../gnu/java/util/regex/REFilterInputStream.java | 153 + libjava/classpath/gnu/java/util/regex/REMatch.java | 362 ++ .../gnu/java/util/regex/REMatchEnumeration.java | 141 + .../classpath/gnu/java/util/regex/RESyntax.java | 537 ++ libjava/classpath/gnu/java/util/regex/REToken.java | 244 + .../classpath/gnu/java/util/regex/RETokenAny.java | 115 + .../gnu/java/util/regex/RETokenBackRef.java | 100 + .../classpath/gnu/java/util/regex/RETokenChar.java | 162 + .../classpath/gnu/java/util/regex/RETokenEnd.java | 151 + .../java/util/regex/RETokenEndOfPreviousMatch.java | 88 + .../gnu/java/util/regex/RETokenEndSub.java | 79 + .../gnu/java/util/regex/RETokenIndependent.java | 85 + .../gnu/java/util/regex/RETokenLookAhead.java | 88 + .../gnu/java/util/regex/RETokenLookBehind.java | 136 + .../gnu/java/util/regex/RETokenNamedProperty.java | 410 ++ .../gnu/java/util/regex/RETokenOneOf.java | 332 ++ .../gnu/java/util/regex/RETokenPOSIX.java | 195 + .../gnu/java/util/regex/RETokenRange.java | 119 + .../gnu/java/util/regex/RETokenRepeated.java | 639 +++ .../gnu/java/util/regex/RETokenStart.java | 153 + .../gnu/java/util/regex/RETokenWordBoundary.java | 141 + .../classpath/gnu/java/util/regex/UncheckedRE.java | 114 + .../gnu/javax/activation/viewers/ImageViewer.java | 138 + .../gnu/javax/activation/viewers/TextEditor.java | 119 + .../gnu/javax/activation/viewers/TextViewer.java | 81 + .../classpath/gnu/javax/crypto/RSACipherImpl.java | 299 + .../gnu/javax/crypto/assembly/Assembly.java | 272 + .../gnu/javax/crypto/assembly/Cascade.java | 348 ++ .../gnu/javax/crypto/assembly/CascadeStage.java | 93 + .../javax/crypto/assembly/CascadeTransformer.java | 123 + .../javax/crypto/assembly/DeflateTransformer.java | 177 + .../gnu/javax/crypto/assembly/Direction.java | 78 + .../javax/crypto/assembly/LoopbackTransformer.java | 100 + .../gnu/javax/crypto/assembly/ModeStage.java | 112 + .../gnu/javax/crypto/assembly/Operation.java | 73 + .../javax/crypto/assembly/PaddingTransformer.java | 164 + .../classpath/gnu/javax/crypto/assembly/Stage.java | 202 + .../gnu/javax/crypto/assembly/Transformer.java | 421 ++ .../crypto/assembly/TransformerException.java | 140 + .../classpath/gnu/javax/crypto/cipher/Anubis.java | 491 ++ .../gnu/javax/crypto/cipher/BaseCipher.java | 249 + .../gnu/javax/crypto/cipher/Blowfish.java | 611 ++ .../classpath/gnu/javax/crypto/cipher/Cast5.java | 987 ++++ .../gnu/javax/crypto/cipher/CipherFactory.java | 129 + libjava/classpath/gnu/javax/crypto/cipher/DES.java | 652 +++ .../gnu/javax/crypto/cipher/IBlockCipher.java | 195 + .../gnu/javax/crypto/cipher/IBlockCipherSpi.java | 124 + .../classpath/gnu/javax/crypto/cipher/Khazad.java | 449 ++ .../gnu/javax/crypto/cipher/NullCipher.java | 108 + .../gnu/javax/crypto/cipher/Rijndael.java | 704 +++ .../classpath/gnu/javax/crypto/cipher/Serpent.java | 1781 ++++++ .../classpath/gnu/javax/crypto/cipher/Square.java | 425 ++ .../gnu/javax/crypto/cipher/TripleDES.java | 257 + .../classpath/gnu/javax/crypto/cipher/Twofish.java | 737 +++ .../gnu/javax/crypto/cipher/WeakKeyException.java | 59 + .../gnu/javax/crypto/jce/DiffieHellmanImpl.java | 171 + .../classpath/gnu/javax/crypto/jce/GnuCrypto.java | 598 ++ .../classpath/gnu/javax/crypto/jce/GnuSasl.java | 124 + .../javax/crypto/jce/PBKDF2SecretKeyFactory.java | 218 + .../javax/crypto/jce/cipher/AES128KeyWrapSpi.java | 54 + .../javax/crypto/jce/cipher/AES192KeyWrapSpi.java | 54 + .../javax/crypto/jce/cipher/AES256KeyWrapSpi.java | 54 + .../gnu/javax/crypto/jce/cipher/AESKeyWrapSpi.java | 88 + .../gnu/javax/crypto/jce/cipher/AESSpi.java | 92 + .../gnu/javax/crypto/jce/cipher/ARCFourSpi.java | 183 + .../gnu/javax/crypto/jce/cipher/AnubisSpi.java | 54 + .../gnu/javax/crypto/jce/cipher/BlowfishSpi.java | 54 + .../gnu/javax/crypto/jce/cipher/Cast5Spi.java | 54 + .../gnu/javax/crypto/jce/cipher/CipherAdapter.java | 531 ++ .../gnu/javax/crypto/jce/cipher/DESSpi.java | 54 + .../jce/cipher/KeyWrappingAlgorithmAdapter.java | 423 ++ .../gnu/javax/crypto/jce/cipher/KhazadSpi.java | 54 + .../gnu/javax/crypto/jce/cipher/NullCipherSpi.java | 54 + .../gnu/javax/crypto/jce/cipher/PBES2.java | 1379 +++++ .../gnu/javax/crypto/jce/cipher/RijndaelSpi.java | 54 + .../gnu/javax/crypto/jce/cipher/SerpentSpi.java | 54 + .../gnu/javax/crypto/jce/cipher/SquareSpi.java | 54 + .../crypto/jce/cipher/TripleDESKeyWrapSpi.java | 54 + .../gnu/javax/crypto/jce/cipher/TripleDESSpi.java | 54 + .../gnu/javax/crypto/jce/cipher/TwofishSpi.java | 54 + .../crypto/jce/key/AnubisKeyGeneratorImpl.java | 50 + .../crypto/jce/key/AnubisSecretKeyFactoryImpl.java | 47 + .../crypto/jce/key/BlowfishKeyGeneratorImpl.java | 50 + .../jce/key/BlowfishSecretKeyFactoryImpl.java | 47 + .../crypto/jce/key/Cast5KeyGeneratorImpl.java | 50 + .../crypto/jce/key/Cast5SecretKeyFactoryImpl.java | 47 + .../javax/crypto/jce/key/DESKeyGeneratorImpl.java | 68 + .../crypto/jce/key/DESSecretKeyFactoryImpl.java | 82 + .../crypto/jce/key/DESedeSecretKeyFactoryImpl.java | 82 + .../crypto/jce/key/KhazadKeyGeneratorImpl.java | 50 + .../crypto/jce/key/KhazadSecretKeyFactoryImpl.java | 47 + .../crypto/jce/key/RijndaelKeyGeneratorImpl.java | 50 + .../jce/key/RijndaelSecretKeyFactoryImpl.java | 47 + .../javax/crypto/jce/key/SecretKeyFactoryImpl.java | 87 + .../crypto/jce/key/SecretKeyGeneratorImpl.java | 111 + .../crypto/jce/key/SerpentKeyGeneratorImpl.java | 50 + .../jce/key/SerpentSecretKeyFactoryImpl.java | 47 + .../crypto/jce/key/SquareKeyGeneratorImpl.java | 50 + .../crypto/jce/key/SquareSecretKeyFactoryImpl.java | 47 + .../crypto/jce/key/TripleDESKeyGeneratorImpl.java | 50 + .../crypto/jce/key/TwofishKeyGeneratorImpl.java | 50 + .../jce/key/TwofishSecretKeyFactoryImpl.java | 47 + .../gnu/javax/crypto/jce/keyring/GnuKeyring.java | 507 ++ .../gnu/javax/crypto/jce/mac/HMacHavalSpi.java | 54 + .../gnu/javax/crypto/jce/mac/HMacMD2Spi.java | 54 + .../gnu/javax/crypto/jce/mac/HMacMD4Spi.java | 54 + .../gnu/javax/crypto/jce/mac/HMacMD5Spi.java | 54 + .../gnu/javax/crypto/jce/mac/HMacRipeMD128Spi.java | 54 + .../gnu/javax/crypto/jce/mac/HMacRipeMD160Spi.java | 54 + .../gnu/javax/crypto/jce/mac/HMacSHA160Spi.java | 54 + .../gnu/javax/crypto/jce/mac/HMacSHA256Spi.java | 54 + .../gnu/javax/crypto/jce/mac/HMacSHA384Spi.java | 54 + .../gnu/javax/crypto/jce/mac/HMacSHA512Spi.java | 54 + .../gnu/javax/crypto/jce/mac/HMacTigerSpi.java | 54 + .../gnu/javax/crypto/jce/mac/HMacWhirlpoolSpi.java | 54 + .../gnu/javax/crypto/jce/mac/MacAdapter.java | 136 + .../gnu/javax/crypto/jce/mac/OMacAnubisImpl.java | 50 + .../gnu/javax/crypto/jce/mac/OMacBlowfishImpl.java | 50 + .../gnu/javax/crypto/jce/mac/OMacCast5Impl.java | 50 + .../gnu/javax/crypto/jce/mac/OMacDESImpl.java | 50 + .../gnu/javax/crypto/jce/mac/OMacImpl.java | 140 + .../gnu/javax/crypto/jce/mac/OMacKhazadImpl.java | 50 + .../gnu/javax/crypto/jce/mac/OMacRijndaelImpl.java | 50 + .../gnu/javax/crypto/jce/mac/OMacSerpentImpl.java | 50 + .../gnu/javax/crypto/jce/mac/OMacSquareImpl.java | 50 + .../javax/crypto/jce/mac/OMacTripleDESImpl.java | 50 + .../gnu/javax/crypto/jce/mac/OMacTwofishImpl.java | 50 + .../gnu/javax/crypto/jce/mac/TMMH16Spi.java | 81 + .../gnu/javax/crypto/jce/mac/UHash32Spi.java | 54 + .../gnu/javax/crypto/jce/mac/UMac32Spi.java | 79 + .../crypto/jce/params/BlockCipherParameters.java | 149 + .../crypto/jce/params/DEREncodingException.java | 54 + .../gnu/javax/crypto/jce/params/DERReader.java | 139 + .../gnu/javax/crypto/jce/params/DERWriter.java | 143 + .../javax/crypto/jce/prng/ARCFourRandomSpi.java | 102 + .../gnu/javax/crypto/jce/prng/CSPRNGSpi.java | 97 + .../gnu/javax/crypto/jce/prng/FortunaImpl.java | 100 + .../gnu/javax/crypto/jce/prng/ICMRandomSpi.java | 206 + .../gnu/javax/crypto/jce/prng/UMacRandomSpi.java | 166 + .../gnu/javax/crypto/jce/sig/DHKeyFactory.java | 219 + .../crypto/jce/sig/DHKeyPairGeneratorSpi.java | 93 + .../gnu/javax/crypto/jce/sig/DHParameters.java | 222 + .../crypto/jce/sig/DHParametersGenerator.java | 152 + .../crypto/jce/spec/BlockCipherParameterSpec.java | 122 + .../javax/crypto/jce/spec/TMMHParameterSpec.java | 117 + .../javax/crypto/jce/spec/UMac32ParameterSpec.java | 73 + .../javax/crypto/key/BaseKeyAgreementParty.java | 168 + .../classpath/gnu/javax/crypto/key/GnuPBEKey.java | 95 + .../gnu/javax/crypto/key/GnuSecretKey.java | 131 + .../gnu/javax/crypto/key/IKeyAgreementParty.java | 100 + .../gnu/javax/crypto/key/IncomingMessage.java | 318 ++ .../javax/crypto/key/KeyAgreementException.java | 168 + .../gnu/javax/crypto/key/KeyAgreementFactory.java | 143 + .../gnu/javax/crypto/key/OutgoingMessage.java | 234 + .../javax/crypto/key/dh/DHKeyPairPKCS8Codec.java | 240 + .../gnu/javax/crypto/key/dh/DHKeyPairRawCodec.java | 336 ++ .../javax/crypto/key/dh/DHKeyPairX509Codec.java | 255 + .../crypto/key/dh/DiffieHellmanKeyAgreement.java | 119 + .../javax/crypto/key/dh/DiffieHellmanReceiver.java | 117 + .../javax/crypto/key/dh/DiffieHellmanSender.java | 126 + .../javax/crypto/key/dh/ElGamalKeyAgreement.java | 115 + .../gnu/javax/crypto/key/dh/ElGamalReceiver.java | 99 + .../gnu/javax/crypto/key/dh/ElGamalSender.java | 112 + .../gnu/javax/crypto/key/dh/GnuDHKey.java | 174 + .../javax/crypto/key/dh/GnuDHKeyPairGenerator.java | 235 + .../gnu/javax/crypto/key/dh/GnuDHPrivateKey.java | 200 + .../gnu/javax/crypto/key/dh/GnuDHPublicKey.java | 196 + .../classpath/gnu/javax/crypto/key/dh/RFC2631.java | 217 + .../gnu/javax/crypto/key/srp6/SRP6Host.java | 161 + .../javax/crypto/key/srp6/SRP6KeyAgreement.java | 141 + .../gnu/javax/crypto/key/srp6/SRP6SaslClient.java | 90 + .../gnu/javax/crypto/key/srp6/SRP6SaslServer.java | 90 + .../gnu/javax/crypto/key/srp6/SRP6TLSClient.java | 155 + .../gnu/javax/crypto/key/srp6/SRP6TLSServer.java | 177 + .../gnu/javax/crypto/key/srp6/SRP6User.java | 163 + .../gnu/javax/crypto/key/srp6/SRPAlgorithm.java | 131 + .../gnu/javax/crypto/key/srp6/SRPKey.java | 147 + .../javax/crypto/key/srp6/SRPKeyPairGenerator.java | 282 + .../javax/crypto/key/srp6/SRPKeyPairRawCodec.java | 334 ++ .../gnu/javax/crypto/key/srp6/SRPPrivateKey.java | 227 + .../gnu/javax/crypto/key/srp6/SRPPublicKey.java | 175 + .../javax/crypto/keyring/AuthenticatedEntry.java | 176 + .../gnu/javax/crypto/keyring/BaseKeyring.java | 158 + .../gnu/javax/crypto/keyring/BinaryDataEntry.java | 111 + .../gnu/javax/crypto/keyring/CertPathEntry.java | 112 + .../gnu/javax/crypto/keyring/CertificateEntry.java | 128 + .../gnu/javax/crypto/keyring/CompressedEntry.java | 93 + .../gnu/javax/crypto/keyring/EncryptedEntry.java | 191 + .../classpath/gnu/javax/crypto/keyring/Entry.java | 179 + .../gnu/javax/crypto/keyring/EnvelopeEntry.java | 439 ++ .../javax/crypto/keyring/GnuPrivateKeyring.java | 368 ++ .../gnu/javax/crypto/keyring/GnuPublicKeyring.java | 151 + .../gnu/javax/crypto/keyring/IKeyring.java | 162 + .../gnu/javax/crypto/keyring/IPrivateKeyring.java | 144 + .../gnu/javax/crypto/keyring/IPublicKeyring.java | 82 + .../crypto/keyring/MalformedKeyringException.java | 55 + .../crypto/keyring/MaskableEnvelopeEntry.java | 135 + .../javax/crypto/keyring/MeteredInputStream.java | 127 + .../crypto/keyring/PasswordAuthenticatedEntry.java | 286 + .../crypto/keyring/PasswordEncryptedEntry.java | 293 + .../crypto/keyring/PasswordProtectedEntry.java | 57 + .../gnu/javax/crypto/keyring/PrimitiveEntry.java | 112 + .../gnu/javax/crypto/keyring/PrivateKeyEntry.java | 194 + .../gnu/javax/crypto/keyring/Properties.java | 203 + .../gnu/javax/crypto/keyring/PublicKeyEntry.java | 162 + .../classpath/gnu/javax/crypto/kwa/AESKeyWrap.java | 168 + .../javax/crypto/kwa/BaseKeyWrappingAlgorithm.java | 145 + .../javax/crypto/kwa/IKeyWrappingAlgorithm.java | 160 + .../javax/crypto/kwa/KeyUnwrappingException.java | 67 + .../crypto/kwa/KeyWrappingAlgorithmFactory.java | 110 + .../gnu/javax/crypto/kwa/TripleDESKeyWrap.java | 292 + .../classpath/gnu/javax/crypto/mac/BaseMac.java | 127 + libjava/classpath/gnu/javax/crypto/mac/HMac.java | 263 + .../gnu/javax/crypto/mac/HMacFactory.java | 111 + libjava/classpath/gnu/javax/crypto/mac/IMac.java | 181 + .../classpath/gnu/javax/crypto/mac/MacFactory.java | 130 + .../gnu/javax/crypto/mac/MacInputStream.java | 124 + .../gnu/javax/crypto/mac/MacOutputStream.java | 123 + libjava/classpath/gnu/javax/crypto/mac/OMAC.java | 303 + libjava/classpath/gnu/javax/crypto/mac/TMMH16.java | 339 ++ .../classpath/gnu/javax/crypto/mac/UHash32.java | 758 +++ libjava/classpath/gnu/javax/crypto/mac/UMac32.java | 418 ++ .../classpath/gnu/javax/crypto/mode/BaseMode.java | 295 + libjava/classpath/gnu/javax/crypto/mode/CBC.java | 123 + libjava/classpath/gnu/javax/crypto/mode/CFB.java | 155 + libjava/classpath/gnu/javax/crypto/mode/CTR.java | 168 + libjava/classpath/gnu/javax/crypto/mode/EAX.java | 289 + libjava/classpath/gnu/javax/crypto/mode/ECB.java | 121 + .../gnu/javax/crypto/mode/IAuthenticatedMode.java | 56 + libjava/classpath/gnu/javax/crypto/mode/ICM.java | 181 + libjava/classpath/gnu/javax/crypto/mode/IMode.java | 123 + .../gnu/javax/crypto/mode/ModeFactory.java | 151 + libjava/classpath/gnu/javax/crypto/mode/OFB.java | 174 + .../classpath/gnu/javax/crypto/pad/BasePad.java | 193 + libjava/classpath/gnu/javax/crypto/pad/IPad.java | 127 + .../classpath/gnu/javax/crypto/pad/ISO10126.java | 109 + .../classpath/gnu/javax/crypto/pad/PKCS1_V1_5.java | 156 + libjava/classpath/gnu/javax/crypto/pad/PKCS7.java | 111 + .../classpath/gnu/javax/crypto/pad/PadFactory.java | 120 + libjava/classpath/gnu/javax/crypto/pad/SSL3.java | 90 + libjava/classpath/gnu/javax/crypto/pad/TBC.java | 118 + libjava/classpath/gnu/javax/crypto/pad/TLS1.java | 91 + .../javax/crypto/pad/WrongPaddingException.java | 48 + .../classpath/gnu/javax/crypto/prng/ARCFour.java | 137 + .../classpath/gnu/javax/crypto/prng/CSPRNG.java | 985 ++++ .../classpath/gnu/javax/crypto/prng/Fortuna.java | 349 ++ .../gnu/javax/crypto/prng/ICMGenerator.java | 306 + libjava/classpath/gnu/javax/crypto/prng/IPBE.java | 81 + .../classpath/gnu/javax/crypto/prng/PBKDF2.java | 184 + .../gnu/javax/crypto/prng/PRNGFactory.java | 115 + .../gnu/javax/crypto/prng/UMacGenerator.java | 186 + .../classpath/gnu/javax/crypto/sasl/AuthInfo.java | 129 + .../javax/crypto/sasl/AuthInfoProviderFactory.java | 67 + .../gnu/javax/crypto/sasl/ClientFactory.java | 168 + .../gnu/javax/crypto/sasl/ClientMechanism.java | 293 + .../crypto/sasl/ConfidentialityException.java | 82 + .../gnu/javax/crypto/sasl/IAuthInfoProvider.java | 116 + .../crypto/sasl/IAuthInfoProviderFactory.java | 55 + .../sasl/IllegalMechanismStateException.java | 84 + .../gnu/javax/crypto/sasl/InputBuffer.java | 272 + .../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 | 198 + .../javax/crypto/sasl/SaslEncodingException.java | 66 + .../gnu/javax/crypto/sasl/SaslInputStream.java | 393 ++ .../gnu/javax/crypto/sasl/SaslOutputStream.java | 175 + .../classpath/gnu/javax/crypto/sasl/SaslUtil.java | 75 + .../gnu/javax/crypto/sasl/ServerFactory.java | 158 + .../gnu/javax/crypto/sasl/ServerMechanism.java | 294 + .../crypto/sasl/UserAlreadyExistsException.java | 70 + .../crypto/sasl/anonymous/AnonymousClient.java | 102 + .../crypto/sasl/anonymous/AnonymousServer.java | 90 + .../javax/crypto/sasl/anonymous/AnonymousUtil.java | 83 + .../sasl/crammd5/CramMD5AuthInfoProvider.java | 166 + .../javax/crypto/sasl/crammd5/CramMD5Client.java | 168 + .../javax/crypto/sasl/crammd5/CramMD5Registry.java | 60 + .../javax/crypto/sasl/crammd5/CramMD5Server.java | 158 + .../gnu/javax/crypto/sasl/crammd5/CramMD5Util.java | 122 + .../javax/crypto/sasl/crammd5/PasswordFile.java | 240 + .../gnu/javax/crypto/sasl/plain/PasswordFile.java | 245 + .../crypto/sasl/plain/PlainAuthInfoProvider.java | 166 + .../gnu/javax/crypto/sasl/plain/PlainClient.java | 156 + .../gnu/javax/crypto/sasl/plain/PlainRegistry.java | 57 + .../gnu/javax/crypto/sasl/plain/PlainServer.java | 155 + .../classpath/gnu/javax/crypto/sasl/srp/CALG.java | 221 + .../gnu/javax/crypto/sasl/srp/ClientStore.java | 155 + .../classpath/gnu/javax/crypto/sasl/srp/IALG.java | 128 + .../classpath/gnu/javax/crypto/sasl/srp/KDF.java | 140 + .../gnu/javax/crypto/sasl/srp/PasswordFile.java | 627 +++ .../classpath/gnu/javax/crypto/sasl/srp/SRP.java | 255 + .../javax/crypto/sasl/srp/SRPAuthInfoProvider.java | 177 + .../gnu/javax/crypto/sasl/srp/SRPClient.java | 954 ++++ .../gnu/javax/crypto/sasl/srp/SRPRegistry.java | 165 + .../gnu/javax/crypto/sasl/srp/SRPServer.java | 842 +++ .../gnu/javax/crypto/sasl/srp/SecurityContext.java | 140 + .../gnu/javax/crypto/sasl/srp/ServerStore.java | 177 + .../gnu/javax/crypto/sasl/srp/StoreEntry.java | 75 + .../gnu/javax/imageio/IIOInputStream.java | 102 + .../gnu/javax/imageio/bmp/BMPDecoder.java | 168 + .../gnu/javax/imageio/bmp/BMPEncoder.java | 119 + .../gnu/javax/imageio/bmp/BMPException.java | 47 + .../gnu/javax/imageio/bmp/BMPFileHeader.java | 151 + .../gnu/javax/imageio/bmp/BMPImageReader.java | 148 + .../gnu/javax/imageio/bmp/BMPImageReaderSpi.java | 116 + .../gnu/javax/imageio/bmp/BMPImageWriter.java | 195 + .../gnu/javax/imageio/bmp/BMPImageWriterSpi.java | 148 + .../gnu/javax/imageio/bmp/BMPInfoHeader.java | 317 ++ .../gnu/javax/imageio/bmp/DecodeBF16.java | 99 + .../gnu/javax/imageio/bmp/DecodeBF32.java | 103 + .../gnu/javax/imageio/bmp/DecodeRGB1.java | 94 + .../gnu/javax/imageio/bmp/DecodeRGB24.java | 77 + .../gnu/javax/imageio/bmp/DecodeRGB4.java | 90 + .../gnu/javax/imageio/bmp/DecodeRGB8.java | 88 + .../gnu/javax/imageio/bmp/DecodeRLE4.java | 175 + .../gnu/javax/imageio/bmp/DecodeRLE8.java | 142 + .../gnu/javax/imageio/bmp/EncodeRGB1.java | 128 + .../gnu/javax/imageio/bmp/EncodeRGB16.java | 129 + .../gnu/javax/imageio/bmp/EncodeRGB24.java | 129 + .../gnu/javax/imageio/bmp/EncodeRGB32.java | 129 + .../gnu/javax/imageio/bmp/EncodeRGB4.java | 128 + .../gnu/javax/imageio/bmp/EncodeRGB8.java | 127 + .../gnu/javax/imageio/bmp/EncodeRLE4.java | 269 + .../gnu/javax/imageio/bmp/EncodeRLE8.java | 234 + .../classpath/gnu/javax/imageio/gif/GIFFile.java | 709 +++ .../gnu/javax/imageio/gif/GIFImageReader.java | 241 + .../gnu/javax/imageio/gif/GIFImageReaderSpi.java | 124 + libjava/classpath/gnu/javax/imageio/jpeg/DCT.java | 347 ++ .../gnu/javax/imageio/jpeg/HuffmanTable.java | 207 + .../gnu/javax/imageio/jpeg/JPEGComponent.java | 351 ++ .../gnu/javax/imageio/jpeg/JPEGDecoder.java | 625 +++ .../gnu/javax/imageio/jpeg/JPEGException.java | 48 + .../gnu/javax/imageio/jpeg/JPEGFrame.java | 108 + .../javax/imageio/jpeg/JPEGImageInputStream.java | 188 + .../gnu/javax/imageio/jpeg/JPEGImageReader.java | 141 + .../gnu/javax/imageio/jpeg/JPEGImageReaderSpi.java | 137 + .../gnu/javax/imageio/jpeg/JPEGMarker.java | 205 + .../imageio/jpeg/JPEGMarkerFoundException.java | 50 + .../classpath/gnu/javax/imageio/jpeg/JPEGScan.java | 151 + .../gnu/javax/imageio/jpeg/YCbCr_ColorSpace.java | 113 + .../classpath/gnu/javax/imageio/jpeg/ZigZag.java | 520 ++ .../classpath/gnu/javax/imageio/png/PNGChunk.java | 283 + .../classpath/gnu/javax/imageio/png/PNGData.java | 104 + .../gnu/javax/imageio/png/PNGDecoder.java | 331 ++ .../gnu/javax/imageio/png/PNGEncoder.java | 233 + .../gnu/javax/imageio/png/PNGException.java | 48 + .../classpath/gnu/javax/imageio/png/PNGFile.java | 257 + .../classpath/gnu/javax/imageio/png/PNGFilter.java | 237 + .../classpath/gnu/javax/imageio/png/PNGGamma.java | 85 + .../classpath/gnu/javax/imageio/png/PNGHeader.java | 257 + .../gnu/javax/imageio/png/PNGICCProfile.java | 116 + .../gnu/javax/imageio/png/PNGImageReader.java | 224 + .../gnu/javax/imageio/png/PNGImageReaderSpi.java | 128 + .../gnu/javax/imageio/png/PNGPalette.java | 127 + .../classpath/gnu/javax/imageio/png/PNGPhys.java | 112 + .../classpath/gnu/javax/imageio/png/PNGTime.java | 83 + .../gnu/javax/management/ListenerData.java | 136 + libjava/classpath/gnu/javax/management/Server.java | 2233 ++++++++ .../classpath/gnu/javax/management/Translator.java | 550 ++ .../gnu/javax/naming/giop/ContextContinuation.java | 956 ++++ .../gnu/javax/naming/giop/CorbalocParser.java | 441 ++ .../javax/naming/giop/GiopNamingEnumeration.java | 187 + .../naming/giop/GiopNamingServiceFactory.java | 179 + .../naming/giop/GiopNamingServiceURLContext.java | 840 +++ .../javax/naming/giop/ListBindingsEnumeration.java | 118 + .../gnu/javax/naming/giop/ListEnumeration.java | 118 + .../gnu/javax/naming/ictxImpl/trans/GnuName.java | 469 ++ .../url/corbaname/corbanameURLContextFactory.java | 53 + .../naming/jndi/url/rmi/ContextContinuation.java | 597 ++ .../jndi/url/rmi/ListBindingsEnumeration.java | 97 + .../javax/naming/jndi/url/rmi/ListEnumeration.java | 80 + .../javax/naming/jndi/url/rmi/RmiContinuation.java | 594 ++ .../naming/jndi/url/rmi/RmiNamingEnumeration.java | 130 + .../javax/naming/jndi/url/rmi/rmiURLContext.java | 637 +++ .../naming/jndi/url/rmi/rmiURLContextFactory.java | 66 + .../gnu/javax/net/ssl/AbstractSessionContext.java | 288 + .../classpath/gnu/javax/net/ssl/EntropySource.java | 62 + .../gnu/javax/net/ssl/NullManagerParameters.java | 56 + .../gnu/javax/net/ssl/PreSharedKeyManager.java | 54 + .../net/ssl/PreSharedKeyManagerParameters.java | 83 + .../gnu/javax/net/ssl/PrivateCredentials.java | 363 ++ .../gnu/javax/net/ssl/SRPManagerParameters.java | 81 + .../gnu/javax/net/ssl/SRPTrustManager.java | 99 + .../gnu/javax/net/ssl/SSLCipherSuite.java | 142 + .../gnu/javax/net/ssl/SSLProtocolVersion.java | 54 + .../gnu/javax/net/ssl/SSLRecordHandler.java | 100 + libjava/classpath/gnu/javax/net/ssl/Session.java | 366 ++ .../gnu/javax/net/ssl/SessionStoreException.java | 59 + .../gnu/javax/net/ssl/StaticTrustAnchors.java | 1940 +++++++ .../javax/net/ssl/provider/AbstractHandshake.java | 1205 ++++ .../gnu/javax/net/ssl/provider/Alert.java | 288 + .../gnu/javax/net/ssl/provider/AlertException.java | 101 + .../gnu/javax/net/ssl/provider/Builder.java | 66 + .../gnu/javax/net/ssl/provider/Certificate.java | 177 + .../javax/net/ssl/provider/CertificateBuilder.java | 94 + .../javax/net/ssl/provider/CertificateRequest.java | 155 + .../ssl/provider/CertificateRequestBuilder.java | 111 + .../net/ssl/provider/CertificateStatusRequest.java | 272 + .../net/ssl/provider/CertificateStatusType.java | 13 + .../javax/net/ssl/provider/CertificateType.java | 62 + .../gnu/javax/net/ssl/provider/CertificateURL.java | 388 ++ .../javax/net/ssl/provider/CertificateVerify.java | 83 + .../javax/net/ssl/provider/CipherAlgorithm.java | 47 + .../gnu/javax/net/ssl/provider/CipherSuite.java | 837 +++ .../javax/net/ssl/provider/CipherSuiteList.java | 283 + .../ssl/provider/ClientCertificateTypeList.java | 227 + .../net/ssl/provider/ClientDHE_PSKParameters.java | 122 + .../ssl/provider/ClientDiffieHellmanPublic.java | 129 + .../javax/net/ssl/provider/ClientHandshake.java | 1153 ++++ .../gnu/javax/net/ssl/provider/ClientHello.java | 240 + .../javax/net/ssl/provider/ClientHelloBuilder.java | 137 + .../gnu/javax/net/ssl/provider/ClientHelloV2.java | 158 + .../javax/net/ssl/provider/ClientKeyExchange.java | 132 + .../net/ssl/provider/ClientKeyExchangeBuilder.java | 75 + .../net/ssl/provider/ClientPSKParameters.java | 121 + .../net/ssl/provider/ClientRSA_PSKParameters.java | 122 + .../javax/net/ssl/provider/CompressionMethod.java | 69 + .../net/ssl/provider/CompressionMethodList.java | 281 + .../gnu/javax/net/ssl/provider/Constructed.java | 86 + .../gnu/javax/net/ssl/provider/ContentType.java | 89 + .../gnu/javax/net/ssl/provider/Debug.java | 66 + .../gnu/javax/net/ssl/provider/DelegatedTask.java | 93 + .../gnu/javax/net/ssl/provider/DiffieHellman.java | 289 + .../javax/net/ssl/provider/EmptyExchangeKeys.java | 77 + .../net/ssl/provider/EncryptedPreMasterSecret.java | 148 + .../gnu/javax/net/ssl/provider/ExchangeKeys.java | 54 + .../gnu/javax/net/ssl/provider/Extension.java | 246 + .../gnu/javax/net/ssl/provider/ExtensionList.java | 290 + .../gnu/javax/net/ssl/provider/Finished.java | 173 + .../gnu/javax/net/ssl/provider/Handshake.java | 299 + .../gnu/javax/net/ssl/provider/HelloRequest.java | 72 + .../net/ssl/provider/InputSecurityParameters.java | 334 ++ .../gnu/javax/net/ssl/provider/Jessie.java | 102 + .../net/ssl/provider/KeyExchangeAlgorithm.java | 57 + .../gnu/javax/net/ssl/provider/MacAlgorithm.java | 47 + .../gnu/javax/net/ssl/provider/MacException.java | 53 + .../javax/net/ssl/provider/MaxFragmentLength.java | 59 + .../net/ssl/provider/OutputSecurityParameters.java | 294 + .../provider/PreSharedKeyManagerFactoryImpl.java | 118 + .../javax/net/ssl/provider/ProtocolVersion.java | 200 + .../gnu/javax/net/ssl/provider/Random.java | 150 + .../gnu/javax/net/ssl/provider/Record.java | 198 + .../net/ssl/provider/SRPTrustManagerFactory.java | 223 + .../gnu/javax/net/ssl/provider/SSLContextImpl.java | 315 ++ .../gnu/javax/net/ssl/provider/SSLEngineImpl.java | 842 +++ .../gnu/javax/net/ssl/provider/SSLHMac.java | 158 + .../net/ssl/provider/SSLRSASignatureImpl.java | 234 + .../gnu/javax/net/ssl/provider/SSLRandom.java | 165 + .../ssl/provider/SSLServerSocketFactoryImpl.java | 108 + .../net/ssl/provider/SSLServerSocketImpl.java | 199 + .../net/ssl/provider/SSLSocketFactoryImpl.java | 143 + .../gnu/javax/net/ssl/provider/SSLSocketImpl.java | 740 +++ .../javax/net/ssl/provider/SSLv3HMacMD5Impl.java | 116 + .../javax/net/ssl/provider/SSLv3HMacSHAImpl.java | 116 + .../net/ssl/provider/ServerDHE_PSKParameters.java | 148 + .../gnu/javax/net/ssl/provider/ServerDHParams.java | 248 + .../javax/net/ssl/provider/ServerHandshake.java | 1377 +++++ .../gnu/javax/net/ssl/provider/ServerHello.java | 231 + .../javax/net/ssl/provider/ServerHelloBuilder.java | 131 + .../javax/net/ssl/provider/ServerHelloDone.java | 66 + .../javax/net/ssl/provider/ServerKeyExchange.java | 173 + .../net/ssl/provider/ServerKeyExchangeBuilder.java | 89 + .../net/ssl/provider/ServerKeyExchangeParams.java | 50 + .../gnu/javax/net/ssl/provider/ServerNameList.java | 311 ++ .../net/ssl/provider/ServerPSKParameters.java | 127 + .../javax/net/ssl/provider/ServerRSAParams.java | 163 + .../net/ssl/provider/ServerRSA_PSKParameters.java | 62 + .../gnu/javax/net/ssl/provider/SessionImpl.java | 192 + .../gnu/javax/net/ssl/provider/Signature.java | 157 + .../javax/net/ssl/provider/SignatureAlgorithm.java | 62 + .../net/ssl/provider/SimpleSessionContext.java | 144 + .../gnu/javax/net/ssl/provider/TLSHMac.java | 137 + .../gnu/javax/net/ssl/provider/TLSRandom.java | 252 + .../gnu/javax/net/ssl/provider/TruncatedHMAC.java | 76 + .../javax/net/ssl/provider/TrustedAuthorities.java | 297 + .../net/ssl/provider/UnresolvedExtensionValue.java | 81 + .../classpath/gnu/javax/net/ssl/provider/Util.java | 495 ++ .../javax/net/ssl/provider/X500PrincipalList.java | 272 + .../net/ssl/provider/X509KeyManagerFactory.java | 396 ++ .../net/ssl/provider/X509TrustManagerFactory.java | 295 + .../gnu/javax/print/CupsIppOperation.java | 99 + .../gnu/javax/print/CupsMediaMapping.java | 176 + .../gnu/javax/print/CupsPrintService.java | 104 + .../gnu/javax/print/CupsPrintServiceLookup.java | 260 + libjava/classpath/gnu/javax/print/CupsServer.java | 288 + .../gnu/javax/print/PrintAttributeException.java | 148 + .../gnu/javax/print/PrintFlavorException.java | 120 + .../gnu/javax/print/PrintUriException.java | 140 + .../classpath/gnu/javax/print/PrinterDialog.java | 1722 ++++++ .../gnu/javax/print/ipp/DocPrintJobImpl.java | 471 ++ .../gnu/javax/print/ipp/IppDelimiterTag.java | 99 + .../gnu/javax/print/ipp/IppException.java | 88 + .../javax/print/ipp/IppMultiDocPrintService.java | 87 + .../gnu/javax/print/ipp/IppPrintService.java | 924 ++++ .../classpath/gnu/javax/print/ipp/IppRequest.java | 875 +++ .../classpath/gnu/javax/print/ipp/IppResponse.java | 787 +++ .../gnu/javax/print/ipp/IppStatusCode.java | 185 + .../gnu/javax/print/ipp/IppUtilities.java | 553 ++ .../classpath/gnu/javax/print/ipp/IppValueTag.java | 170 + .../gnu/javax/print/ipp/MultiDocPrintJobImpl.java | 80 + .../javax/print/ipp/attribute/CharsetSyntax.java | 115 + .../print/ipp/attribute/DefaultValueAttribute.java | 59 + .../print/ipp/attribute/DetailedStatusMessage.java | 93 + .../print/ipp/attribute/DocumentAccessError.java | 93 + .../print/ipp/attribute/NaturalLanguageSyntax.java | 117 + .../print/ipp/attribute/RequestedAttributes.java | 132 + .../javax/print/ipp/attribute/StatusMessage.java | 92 + .../print/ipp/attribute/UnknownAttribute.java | 190 + .../ipp/attribute/defaults/CopiesDefault.java | 118 + .../attribute/defaults/DocumentFormatDefault.java | 106 + .../ipp/attribute/defaults/FinishingsDefault.java | 263 + .../attribute/defaults/JobHoldUntilDefault.java | 149 + .../ipp/attribute/defaults/JobPriorityDefault.java | 118 + .../ipp/attribute/defaults/JobSheetsDefault.java | 122 + .../print/ipp/attribute/defaults/MediaDefault.java | 105 + .../defaults/MultipleDocumentHandlingDefault.java | 152 + .../ipp/attribute/defaults/NumberUpDefault.java | 114 + .../defaults/OrientationRequestedDefault.java | 154 + .../attribute/defaults/PrintQualityDefault.java | 141 + .../defaults/PrinterResolutionDefault.java | 119 + .../print/ipp/attribute/defaults/SidesDefault.java | 150 + .../print/ipp/attribute/job/AttributesCharset.java | 93 + .../attribute/job/AttributesNaturalLanguage.java | 95 + .../attribute/job/JobDetailedStatusMessages.java | 92 + .../ipp/attribute/job/JobDocumentAccessErrors.java | 93 + .../gnu/javax/print/ipp/attribute/job/JobId.java | 87 + .../javax/print/ipp/attribute/job/JobMoreInfo.java | 87 + .../print/ipp/attribute/job/JobPrinterUri.java | 87 + .../print/ipp/attribute/job/JobStateMessage.java | 92 + .../gnu/javax/print/ipp/attribute/job/JobUri.java | 87 + .../ipp/attribute/printer/CharsetConfigured.java | 86 + .../ipp/attribute/printer/DocumentFormat.java | 111 + .../printer/MultipleOperationTimeOut.java | 86 + .../printer/NaturalLanguageConfigured.java | 86 + .../ipp/attribute/printer/PrinterCurrentTime.java | 107 + .../attribute/printer/PrinterDriverInstaller.java | 88 + .../ipp/attribute/printer/PrinterStateMessage.java | 94 + .../print/ipp/attribute/printer/PrinterUpTime.java | 86 + .../ipp/attribute/supported/CharsetSupported.java | 88 + .../attribute/supported/CompressionSupported.java | 161 + .../supported/DocumentFormatSupported.java | 92 + .../attribute/supported/FinishingsSupported.java | 302 + .../GeneratedNaturalLanguageSupported.java | 89 + .../attribute/supported/IppVersionsSupported.java | 122 + .../attribute/supported/JobHoldUntilSupported.java | 134 + .../attribute/supported/JobSheetsSupported.java | 148 + .../ipp/attribute/supported/MediaSupported.java | 116 + .../MultipleDocumentHandlingSupported.java | 176 + .../supported/MultipleDocumentJobsSupported.java | 119 + .../attribute/supported/OperationsSupported.java | 231 + .../supported/OrientationRequestedSupported.java | 178 + .../attribute/supported/PageRangesSupported.java | 117 + .../attribute/supported/PrintQualitySupported.java | 169 + .../supported/PrinterResolutionSupported.java | 142 + .../attribute/supported/PrinterUriSupported.java | 89 + .../ipp/attribute/supported/SidesSupported.java | 137 + .../supported/UriAuthenticationSupported.java | 142 + .../attribute/supported/UriSecuritySupported.java | 127 + .../classpath/gnu/javax/rmi/CORBA/CorbaInput.java | 297 + .../classpath/gnu/javax/rmi/CORBA/CorbaOutput.java | 219 + .../javax/rmi/CORBA/DefaultWriteObjectTester.java | 85 + .../gnu/javax/rmi/CORBA/DelegateFactory.java | 107 + .../rmi/CORBA/GetDelegateInstanceException.java | 55 + .../CORBA/PortableRemoteObjectDelegateImpl.java | 362 ++ .../gnu/javax/rmi/CORBA/RmiUtilities.java | 949 ++++ .../gnu/javax/rmi/CORBA/StubDelegateImpl.java | 310 ++ .../gnu/javax/rmi/CORBA/TieTargetRecord.java | 93 + .../gnu/javax/rmi/CORBA/UtilDelegateImpl.java | 744 +++ .../javax/rmi/CORBA/ValueHandlerDelegateImpl.java | 163 + .../gnu/javax/security/auth/Password.java | 283 + .../security/auth/callback/AWTCallbackHandler.java | 454 ++ .../auth/callback/AbstractCallbackHandler.java | 295 + .../auth/callback/CertificateCallback.java | 64 + .../auth/callback/ConsoleCallbackHandler.java | 299 + .../auth/callback/DefaultCallbackHandler.java | 109 + .../javax/security/auth/callback/GnuCallbacks.java | 64 + .../auth/callback/SwingCallbackHandler.java | 587 ++ .../security/auth/login/ConfigFileParser.java | 346 ++ .../security/auth/login/ConfigFileTokenizer.java | 246 + .../security/auth/login/GnuConfiguration.java | 466 ++ .../gnu/javax/sound/AudioSecurityManager.java | 112 + .../javax/sound/midi/alsa/AlsaInputPortDevice.java | 130 + .../sound/midi/alsa/AlsaMidiDeviceProvider.java | 216 + .../sound/midi/alsa/AlsaMidiSequencerDevice.java | 515 ++ .../sound/midi/alsa/AlsaOutputPortDevice.java | 131 + .../gnu/javax/sound/midi/alsa/AlsaPortDevice.java | 150 + .../sound/midi/dssi/DSSIMidiDeviceProvider.java | 171 + .../gnu/javax/sound/midi/dssi/DSSISynthesizer.java | 742 +++ .../sound/midi/file/ExtendedMidiFileFormat.java | 77 + .../javax/sound/midi/file/MidiDataInputStream.java | 83 + .../sound/midi/file/MidiDataOutputStream.java | 114 + .../gnu/javax/sound/midi/file/MidiFileReader.java | 378 ++ .../gnu/javax/sound/midi/file/MidiFileWriter.java | 197 + .../gnu/javax/sound/sampled/AU/AUReader.java | 210 + .../gnu/javax/sound/sampled/WAV/WAVReader.java | 236 + .../sound/sampled/gstreamer/GStreamerMixer.java | 248 + .../sampled/gstreamer/GStreamerMixerProvider.java | 71 + .../sampled/gstreamer/io/GstAudioFileReader.java | 185 + .../gstreamer/io/GstAudioFileReaderNativePeer.java | 284 + .../sampled/gstreamer/io/GstAudioFileWriter.java | 80 + .../sound/sampled/gstreamer/io/GstInputStream.java | 119 + .../sound/sampled/gstreamer/lines/GstDataLine.java | 151 + .../sampled/gstreamer/lines/GstNativeDataLine.java | 77 + .../sound/sampled/gstreamer/lines/GstPipeline.java | 415 ++ .../sampled/gstreamer/lines/GstSourceDataLine.java | 153 + .../gnu/javax/swing/plaf/gnu/GNULookAndFeel.java | 266 + .../gnu/javax/swing/plaf/gtk/icons/Error.png | Bin 0 -> 1335 bytes .../gnu/javax/swing/plaf/gtk/icons/Inform.png | Bin 0 -> 250 bytes .../gnu/javax/swing/plaf/gtk/icons/JavaCup.png | Bin 0 -> 512 bytes .../javax/swing/plaf/gtk/icons/JavaCupLarge.png | Bin 0 -> 4341 bytes .../gnu/javax/swing/plaf/gtk/icons/Question.png | Bin 0 -> 250 bytes .../gnu/javax/swing/plaf/gtk/icons/README | 20 + .../gnu/javax/swing/plaf/gtk/icons/TreeClosed.png | Bin 0 -> 390 bytes .../javax/swing/plaf/gtk/icons/TreeLeaf-normal.png | Bin 0 -> 1522 bytes .../gnu/javax/swing/plaf/gtk/icons/TreeLeaf.png | Bin 0 -> 1007 bytes .../gnu/javax/swing/plaf/gtk/icons/TreeOpen.png | Bin 0 -> 315 bytes .../gnu/javax/swing/plaf/gtk/icons/Warn.png | Bin 0 -> 1335 bytes .../javax/swing/plaf/gtk/icons/file-folders.png | Bin 0 -> 843 bytes .../gnu/javax/swing/plaf/gtk/icons/slider.png | Bin 0 -> 179 bytes .../javax/swing/plaf/metal/CustomizableTheme.java | 218 + .../text/html/CharacterAttributeTranslator.java | 192 + .../javax/swing/text/html/CombinedAttributes.java | 213 + .../swing/text/html/ImageViewIconFactory.java | 282 + .../gnu/javax/swing/text/html/css/BorderStyle.java | 64 + .../gnu/javax/swing/text/html/css/BorderWidth.java | 78 + .../gnu/javax/swing/text/html/css/CSSColor.java | 170 + .../swing/text/html/css/CSSLexicalException.java | 60 + .../gnu/javax/swing/text/html/css/CSSParser.java | 503 ++ .../swing/text/html/css/CSSParserCallback.java | 81 + .../swing/text/html/css/CSSParserException.java | 62 + .../gnu/javax/swing/text/html/css/CSSScanner.java | 718 +++ .../gnu/javax/swing/text/html/css/FontSize.java | 273 + .../gnu/javax/swing/text/html/css/FontStyle.java | 80 + .../gnu/javax/swing/text/html/css/FontWeight.java | 84 + .../gnu/javax/swing/text/html/css/Length.java | 283 + .../gnu/javax/swing/text/html/css/Selector.java | 245 + .../gnu/javax/swing/text/html/package.html | 50 + .../swing/text/html/parser/GnuParserDelegator.java | 179 + .../javax/swing/text/html/parser/HTML_401F.java | 3801 +++++++++++++ .../text/html/parser/SmallHtmlAttributeSet.java | 261 + .../gnu/javax/swing/text/html/parser/gnuDTD.java | 421 ++ .../swing/text/html/parser/htmlAttributeSet.java | 183 + .../swing/text/html/parser/htmlValidator.java | 622 +++ .../text/html/parser/models/PCDATAonly_model.java | 62 + .../html/parser/models/TableRowContentModel.java | 77 + .../javax/swing/text/html/parser/models/list.java | 384 ++ .../swing/text/html/parser/models/noTagModel.java | 75 + .../javax/swing/text/html/parser/models/node.java | 339 ++ .../swing/text/html/parser/models/package.html | 53 + .../swing/text/html/parser/models/transformer.java | 201 + .../gnu/javax/swing/text/html/parser/package.html | 51 + .../swing/text/html/parser/support/Parser.java | 1532 +++++ .../html/parser/support/gnuStringIntMapper.java | 112 + .../swing/text/html/parser/support/low/Buffer.java | 238 + .../text/html/parser/support/low/Constants.java | 433 ++ .../text/html/parser/support/low/Location.java | 83 + .../html/parser/support/low/ParseException.java | 51 + .../swing/text/html/parser/support/low/Queue.java | 142 + .../html/parser/support/low/ReaderTokenizer.java | 373 ++ .../swing/text/html/parser/support/low/Token.java | 169 + .../swing/text/html/parser/support/low/node.java | 78 + .../text/html/parser/support/low/package.html | 47 + .../text/html/parser/support/low/pattern.java | 105 + .../swing/text/html/parser/support/package.html | 47 + .../html/parser/support/parameterDefaulter.java | 106 + .../text/html/parser/support/textPreProcessor.java | 189 + .../classpath/gnu/javax/swing/tree/GnuPath.java | 65 + libjava/classpath/gnu/test/.cvsignore | 1 + libjava/classpath/gnu/test/Fail.java | 57 + libjava/classpath/gnu/test/Makefile.am | 5 + libjava/classpath/gnu/test/Pass.java | 57 + libjava/classpath/gnu/test/Result.java | 85 + libjava/classpath/gnu/test/Test.java | 57 + libjava/classpath/gnu/test/Unresolved.java | 57 + libjava/classpath/gnu/test/Unsupported.java | 59 + libjava/classpath/gnu/test/Untested.java | 57 + libjava/classpath/gnu/test/XFail.java | 57 + libjava/classpath/gnu/test/XPass.java | 56 + .../classpath/gnu/xml/aelfred2/JAXPFactory.java | 230 + libjava/classpath/gnu/xml/aelfred2/SAXDriver.java | 1609 ++++++ libjava/classpath/gnu/xml/aelfred2/XmlParser.java | 5831 ++++++++++++++++++++ libjava/classpath/gnu/xml/aelfred2/XmlReader.java | 373 ++ libjava/classpath/gnu/xml/aelfred2/package.html | 506 ++ libjava/classpath/gnu/xml/dom/Consumer.java | 352 ++ .../gnu/xml/dom/DTDAttributeTypeInfo.java | 83 + .../classpath/gnu/xml/dom/DTDElementTypeInfo.java | 111 + libjava/classpath/gnu/xml/dom/DomAttr.java | 411 ++ libjava/classpath/gnu/xml/dom/DomCDATASection.java | 90 + .../classpath/gnu/xml/dom/DomCharacterData.java | 344 ++ libjava/classpath/gnu/xml/dom/DomComment.java | 80 + libjava/classpath/gnu/xml/dom/DomDOMException.java | 174 + libjava/classpath/gnu/xml/dom/DomDoctype.java | 455 ++ libjava/classpath/gnu/xml/dom/DomDocument.java | 1555 ++++++ .../classpath/gnu/xml/dom/DomDocumentBuilder.java | 227 + .../gnu/xml/dom/DomDocumentBuilderFactory.java | 181 + .../gnu/xml/dom/DomDocumentConfiguration.java | 260 + .../classpath/gnu/xml/dom/DomDocumentFragment.java | 75 + libjava/classpath/gnu/xml/dom/DomElement.java | 582 ++ libjava/classpath/gnu/xml/dom/DomEntity.java | 146 + .../classpath/gnu/xml/dom/DomEntityReference.java | 130 + libjava/classpath/gnu/xml/dom/DomEvent.java | 351 ++ libjava/classpath/gnu/xml/dom/DomExtern.java | 116 + libjava/classpath/gnu/xml/dom/DomImpl.java | 277 + libjava/classpath/gnu/xml/dom/DomIterator.java | 380 ++ .../gnu/xml/dom/DomNSResolverContext.java | 90 + libjava/classpath/gnu/xml/dom/DomNamedNodeMap.java | 421 ++ libjava/classpath/gnu/xml/dom/DomNode.java | 2222 ++++++++ libjava/classpath/gnu/xml/dom/DomNodeIterator.java | 328 ++ libjava/classpath/gnu/xml/dom/DomNotation.java | 102 + libjava/classpath/gnu/xml/dom/DomNsNode.java | 226 + .../gnu/xml/dom/DomProcessingInstruction.java | 146 + libjava/classpath/gnu/xml/dom/DomText.java | 222 + .../classpath/gnu/xml/dom/DomXPathExpression.java | 147 + .../classpath/gnu/xml/dom/DomXPathNSResolver.java | 64 + libjava/classpath/gnu/xml/dom/DomXPathResult.java | 233 + .../classpath/gnu/xml/dom/ImplementationList.java | 70 + .../gnu/xml/dom/ImplementationSource.java | 167 + libjava/classpath/gnu/xml/dom/JAXPFactory.java | 308 ++ .../gnu/xml/dom/html2/DomHTMLAnchorElement.java | 188 + .../gnu/xml/dom/html2/DomHTMLAppletElement.java | 187 + .../gnu/xml/dom/html2/DomHTMLAreaElement.java | 138 + .../gnu/xml/dom/html2/DomHTMLBRElement.java | 68 + .../gnu/xml/dom/html2/DomHTMLBaseElement.java | 78 + .../gnu/xml/dom/html2/DomHTMLBaseFontElement.java | 88 + .../gnu/xml/dom/html2/DomHTMLBodyElement.java | 118 + .../gnu/xml/dom/html2/DomHTMLButtonElement.java | 119 + .../gnu/xml/dom/html2/DomHTMLCollection.java | 225 + .../gnu/xml/dom/html2/DomHTMLDListElement.java | 68 + .../gnu/xml/dom/html2/DomHTMLDirectoryElement.java | 68 + .../gnu/xml/dom/html2/DomHTMLDivElement.java | 68 + .../gnu/xml/dom/html2/DomHTMLDocument.java | 426 ++ .../gnu/xml/dom/html2/DomHTMLElement.java | 286 + .../gnu/xml/dom/html2/DomHTMLEmbedElement.java | 129 + .../gnu/xml/dom/html2/DomHTMLFieldSetElement.java | 64 + .../gnu/xml/dom/html2/DomHTMLFontElement.java | 88 + .../gnu/xml/dom/html2/DomHTMLFormElement.java | 149 + .../gnu/xml/dom/html2/DomHTMLFrameElement.java | 145 + .../gnu/xml/dom/html2/DomHTMLFrameSetElement.java | 78 + .../gnu/xml/dom/html2/DomHTMLHRElement.java | 98 + .../gnu/xml/dom/html2/DomHTMLHeadElement.java | 68 + .../gnu/xml/dom/html2/DomHTMLHeadingElement.java | 68 + .../gnu/xml/dom/html2/DomHTMLHtmlElement.java | 68 + .../gnu/xml/dom/html2/DomHTMLIFrameElement.java | 165 + .../gnu/xml/dom/html2/DomHTMLImageElement.java | 178 + .../classpath/gnu/xml/dom/html2/DomHTMLImpl.java | 66 + .../gnu/xml/dom/html2/DomHTMLInputElement.java | 265 + .../gnu/xml/dom/html2/DomHTMLIsIndexElement.java | 74 + .../gnu/xml/dom/html2/DomHTMLLIElement.java | 78 + .../gnu/xml/dom/html2/DomHTMLLabelElement.java | 84 + .../gnu/xml/dom/html2/DomHTMLLegendElement.java | 84 + .../gnu/xml/dom/html2/DomHTMLLinkElement.java | 148 + .../gnu/xml/dom/html2/DomHTMLMapElement.java | 78 + .../gnu/xml/dom/html2/DomHTMLMenuElement.java | 68 + .../gnu/xml/dom/html2/DomHTMLMetaElement.java | 98 + .../gnu/xml/dom/html2/DomHTMLModElement.java | 78 + .../gnu/xml/dom/html2/DomHTMLOListElement.java | 88 + .../gnu/xml/dom/html2/DomHTMLObjectElement.java | 320 ++ .../gnu/xml/dom/html2/DomHTMLOptGroupElement.java | 78 + .../gnu/xml/dom/html2/DomHTMLOptionElement.java | 130 + .../gnu/xml/dom/html2/DomHTMLParagraphElement.java | 68 + .../gnu/xml/dom/html2/DomHTMLParamElement.java | 98 + .../classpath/gnu/xml/dom/html2/DomHTMLParser.java | 264 + .../gnu/xml/dom/html2/DomHTMLPreElement.java | 68 + .../gnu/xml/dom/html2/DomHTMLQuoteElement.java | 68 + .../gnu/xml/dom/html2/DomHTMLScriptElement.java | 128 + .../gnu/xml/dom/html2/DomHTMLSelectElement.java | 210 + .../gnu/xml/dom/html2/DomHTMLStyleElement.java | 88 + .../xml/dom/html2/DomHTMLTableCaptionElement.java | 69 + .../gnu/xml/dom/html2/DomHTMLTableCellElement.java | 204 + .../gnu/xml/dom/html2/DomHTMLTableColElement.java | 119 + .../gnu/xml/dom/html2/DomHTMLTableElement.java | 397 ++ .../gnu/xml/dom/html2/DomHTMLTableRowElement.java | 228 + .../xml/dom/html2/DomHTMLTableSectionElement.java | 162 + .../gnu/xml/dom/html2/DomHTMLTextAreaElement.java | 181 + .../gnu/xml/dom/html2/DomHTMLTitleElement.java | 68 + .../gnu/xml/dom/html2/DomHTMLUListElement.java | 78 + .../classpath/gnu/xml/dom/ls/DomLSException.java | 57 + libjava/classpath/gnu/xml/dom/ls/DomLSInput.java | 159 + libjava/classpath/gnu/xml/dom/ls/DomLSOutput.java | 98 + libjava/classpath/gnu/xml/dom/ls/DomLSParser.java | 567 ++ .../classpath/gnu/xml/dom/ls/DomLSSerializer.java | 353 ++ .../gnu/xml/dom/ls/FilteredSAXEventSink.java | 353 ++ .../gnu/xml/dom/ls/ReaderInputStream.java | 236 + libjava/classpath/gnu/xml/dom/ls/SAXEventSink.java | 603 ++ .../gnu/xml/dom/ls/WriterOutputStream.java | 97 + libjava/classpath/gnu/xml/dom/package.html | 273 + .../classpath/gnu/xml/libxmlj/dom/GnomeAttr.java | 117 + .../gnu/xml/libxmlj/dom/GnomeCDATASection.java | 57 + .../gnu/xml/libxmlj/dom/GnomeCharacterData.java | 119 + .../gnu/xml/libxmlj/dom/GnomeComment.java | 57 + .../gnu/xml/libxmlj/dom/GnomeDOMException.java | 98 + .../gnu/xml/libxmlj/dom/GnomeDOMStringList.java | 84 + .../gnu/xml/libxmlj/dom/GnomeDocument.java | 562 ++ .../gnu/xml/libxmlj/dom/GnomeDocumentBuilder.java | 326 ++ .../libxmlj/dom/GnomeDocumentBuilderFactory.java | 118 + .../gnu/xml/libxmlj/dom/GnomeDocumentFragment.java | 57 + .../gnu/xml/libxmlj/dom/GnomeDocumentType.java | 98 + .../gnu/xml/libxmlj/dom/GnomeElement.java | 184 + .../classpath/gnu/xml/libxmlj/dom/GnomeEntity.java | 104 + .../gnu/xml/libxmlj/dom/GnomeEntityReference.java | 57 + .../gnu/xml/libxmlj/dom/GnomeNamedNodeMap.java | 92 + .../classpath/gnu/xml/libxmlj/dom/GnomeNode.java | 501 ++ .../gnu/xml/libxmlj/dom/GnomeNodeList.java | 66 + .../gnu/xml/libxmlj/dom/GnomeNotation.java | 80 + .../libxmlj/dom/GnomeProcessingInstruction.java | 79 + .../classpath/gnu/xml/libxmlj/dom/GnomeText.java | 132 + .../gnu/xml/libxmlj/dom/GnomeTypeInfo.java | 65 + .../gnu/xml/libxmlj/dom/GnomeXPathExpression.java | 86 + .../gnu/xml/libxmlj/dom/GnomeXPathNSResolver.java | 64 + .../gnu/xml/libxmlj/dom/GnomeXPathNodeList.java | 73 + .../gnu/xml/libxmlj/dom/GnomeXPathResult.java | 134 + .../gnu/xml/libxmlj/sax/GnomeLocator.java | 99 + .../gnu/xml/libxmlj/sax/GnomeSAXParser.java | 105 + .../gnu/xml/libxmlj/sax/GnomeSAXParserFactory.java | 92 + .../gnu/xml/libxmlj/sax/GnomeXMLReader.java | 1065 ++++ .../classpath/gnu/xml/libxmlj/sax/Namespaces.java | 122 + .../gnu/xml/libxmlj/sax/StringArrayAttributes.java | 170 + libjava/classpath/gnu/xml/libxmlj/sax/XMLName.java | 92 + .../transform/ErrorListenerErrorHandler.java | 111 + .../xml/libxmlj/transform/GnomeTransformer.java | 572 ++ .../libxmlj/transform/GnomeTransformerFactory.java | 349 ++ .../transform/URIResolverEntityResolver.java | 87 + .../gnu/xml/libxmlj/transform/package.html | 14 + .../gnu/xml/libxmlj/util/EmptyNodeList.java | 62 + .../gnu/xml/libxmlj/util/NamedInputStream.java | 99 + .../xml/libxmlj/util/StandaloneDocumentType.java | 294 + .../gnu/xml/libxmlj/util/StandaloneLocator.java | 89 + libjava/classpath/gnu/xml/libxmlj/util/XMLJ.java | 280 + libjava/classpath/gnu/xml/pipeline/CallFilter.java | 257 + .../classpath/gnu/xml/pipeline/DomConsumer.java | 967 ++++ .../classpath/gnu/xml/pipeline/EventConsumer.java | 95 + .../classpath/gnu/xml/pipeline/EventFilter.java | 796 +++ libjava/classpath/gnu/xml/pipeline/LinkFilter.java | 242 + libjava/classpath/gnu/xml/pipeline/NSFilter.java | 341 ++ .../gnu/xml/pipeline/PipelineFactory.java | 723 +++ .../classpath/gnu/xml/pipeline/TeeConsumer.java | 417 ++ .../classpath/gnu/xml/pipeline/TextConsumer.java | 117 + .../gnu/xml/pipeline/ValidationConsumer.java | 1928 +++++++ .../gnu/xml/pipeline/WellFormednessFilter.java | 363 ++ .../classpath/gnu/xml/pipeline/XIncludeFilter.java | 579 ++ libjava/classpath/gnu/xml/pipeline/XsltFilter.java | 130 + libjava/classpath/gnu/xml/pipeline/package.html | 255 + .../classpath/gnu/xml/stream/AttributeImpl.java | 123 + .../classpath/gnu/xml/stream/BufferedReader.java | 198 + libjava/classpath/gnu/xml/stream/CRLFReader.java | 180 + .../classpath/gnu/xml/stream/CharactersImpl.java | 119 + libjava/classpath/gnu/xml/stream/CommentImpl.java | 91 + libjava/classpath/gnu/xml/stream/DTDImpl.java | 114 + .../classpath/gnu/xml/stream/EndDocumentImpl.java | 70 + .../classpath/gnu/xml/stream/EndElementImpl.java | 107 + .../gnu/xml/stream/EntityDeclarationImpl.java | 163 + .../gnu/xml/stream/EntityReferenceImpl.java | 101 + .../gnu/xml/stream/FilteredEventReader.java | 114 + .../gnu/xml/stream/FilteredStreamReader.java | 90 + .../classpath/gnu/xml/stream/NamespaceImpl.java | 137 + .../gnu/xml/stream/NotationDeclarationImpl.java | 125 + .../gnu/xml/stream/ProcessingInstructionImpl.java | 104 + libjava/classpath/gnu/xml/stream/SAXParser.java | 1041 ++++ .../classpath/gnu/xml/stream/SAXParserFactory.java | 104 + .../gnu/xml/stream/StartDocumentImpl.java | 143 + .../classpath/gnu/xml/stream/StartElementImpl.java | 152 + .../classpath/gnu/xml/stream/UnicodeReader.java | 205 + .../classpath/gnu/xml/stream/XIncludeFilter.java | 931 ++++ .../gnu/xml/stream/XMLEventAllocatorImpl.java | 204 + .../gnu/xml/stream/XMLEventFactoryImpl.java | 269 + libjava/classpath/gnu/xml/stream/XMLEventImpl.java | 198 + .../gnu/xml/stream/XMLEventReaderImpl.java | 157 + .../gnu/xml/stream/XMLEventWriterImpl.java | 190 + .../gnu/xml/stream/XMLInputFactoryImpl.java | 397 ++ .../gnu/xml/stream/XMLOutputFactoryImpl.java | 187 + libjava/classpath/gnu/xml/stream/XMLParser.java | 5434 ++++++++++++++++++ .../gnu/xml/stream/XMLStreamWriterImpl.java | 1016 ++++ .../gnu/xml/transform/AbstractNumberNode.java | 330 ++ .../gnu/xml/transform/ApplyImportsNode.java | 82 + .../gnu/xml/transform/ApplyTemplatesNode.java | 219 + .../classpath/gnu/xml/transform/AttributeNode.java | 244 + .../classpath/gnu/xml/transform/AttributeSet.java | 66 + libjava/classpath/gnu/xml/transform/Bindings.java | 346 ++ .../gnu/xml/transform/CallTemplateNode.java | 156 + .../classpath/gnu/xml/transform/ChooseNode.java | 88 + .../classpath/gnu/xml/transform/CommentNode.java | 103 + libjava/classpath/gnu/xml/transform/CopyNode.java | 168 + .../classpath/gnu/xml/transform/CopyOfNode.java | 174 + .../gnu/xml/transform/CurrentFunction.java | 103 + .../gnu/xml/transform/DOMSourceLocator.java | 84 + .../gnu/xml/transform/DocumentFunction.java | 244 + .../xml/transform/ElementAvailableFunction.java | 181 + .../classpath/gnu/xml/transform/ElementNode.java | 261 + .../xml/transform/ErrorListenerErrorHandler.java | 101 + .../classpath/gnu/xml/transform/ForEachNode.java | 159 + .../gnu/xml/transform/FormatNumberFunction.java | 145 + .../xml/transform/FunctionAvailableFunction.java | 192 + .../gnu/xml/transform/GenerateIdFunction.java | 139 + libjava/classpath/gnu/xml/transform/IfNode.java | 112 + libjava/classpath/gnu/xml/transform/Key.java | 70 + .../classpath/gnu/xml/transform/KeyFunction.java | 227 + .../classpath/gnu/xml/transform/LiteralNode.java | 202 + .../classpath/gnu/xml/transform/MessageNode.java | 110 + .../gnu/xml/transform/NamespaceProxy.java | 77 + .../gnu/xml/transform/NodeNumberNode.java | 269 + .../classpath/gnu/xml/transform/NumberNode.java | 88 + .../classpath/gnu/xml/transform/OtherwiseNode.java | 83 + .../classpath/gnu/xml/transform/ParameterNode.java | 172 + .../xml/transform/ProcessingInstructionNode.java | 118 + .../classpath/gnu/xml/transform/SAXSerializer.java | 305 + .../gnu/xml/transform/SAXTemplatesHandler.java | 97 + .../gnu/xml/transform/SAXTransformerHandler.java | 111 + libjava/classpath/gnu/xml/transform/SortKey.java | 239 + .../gnu/xml/transform/StreamSerializer.java | 854 +++ .../gnu/xml/transform/StrippingInstruction.java | 73 + .../classpath/gnu/xml/transform/Stylesheet.java | 1772 ++++++ .../gnu/xml/transform/SystemPropertyFunction.java | 140 + libjava/classpath/gnu/xml/transform/Template.java | 263 + .../classpath/gnu/xml/transform/TemplateNode.java | 130 + .../classpath/gnu/xml/transform/TemplatesImpl.java | 95 + libjava/classpath/gnu/xml/transform/TextNode.java | 121 + .../gnu/xml/transform/TransformerFactoryImpl.java | 438 ++ .../gnu/xml/transform/TransformerImpl.java | 805 +++ .../xml/transform/TransformerOutputProperties.java | 186 + .../xml/transform/URIResolverEntityResolver.java | 83 + .../xml/transform/UnparsedEntityUriFunction.java | 132 + .../classpath/gnu/xml/transform/ValueOfNode.java | 141 + libjava/classpath/gnu/xml/transform/WhenNode.java | 115 + libjava/classpath/gnu/xml/transform/WithParam.java | 127 + .../classpath/gnu/xml/transform/XSLComparator.java | 118 + .../gnu/xml/transform/XSLURIResolver.java | 321 ++ libjava/classpath/gnu/xml/transform/package.html | 77 + libjava/classpath/gnu/xml/util/DoParse.java | 302 + libjava/classpath/gnu/xml/util/DomParser.java | 804 +++ libjava/classpath/gnu/xml/util/Resolver.java | 263 + .../gnu/xml/util/SAXNullTransformerFactory.java | 676 +++ libjava/classpath/gnu/xml/util/XCat.java | 1611 ++++++ libjava/classpath/gnu/xml/util/XHTMLWriter.java | 114 + libjava/classpath/gnu/xml/util/XMLWriter.java | 1931 +++++++ libjava/classpath/gnu/xml/util/package.html | 20 + .../gnu/xml/validation/datatype/Annotation.java | 60 + .../gnu/xml/validation/datatype/AnySimpleType.java | 58 + .../gnu/xml/validation/datatype/AnyType.java | 57 + .../gnu/xml/validation/datatype/AnyURIType.java | 93 + .../xml/validation/datatype/AtomicSimpleType.java | 77 + .../xml/validation/datatype/Base64BinaryType.java | 128 + .../gnu/xml/validation/datatype/BooleanType.java | 89 + .../gnu/xml/validation/datatype/ByteType.java | 132 + .../gnu/xml/validation/datatype/DateTimeType.java | 334 ++ .../gnu/xml/validation/datatype/DateType.java | 221 + .../gnu/xml/validation/datatype/DecimalType.java | 118 + .../gnu/xml/validation/datatype/DoubleType.java | 110 + .../gnu/xml/validation/datatype/DurationType.java | 238 + .../gnu/xml/validation/datatype/EntitiesType.java | 108 + .../gnu/xml/validation/datatype/EntityType.java | 87 + .../xml/validation/datatype/EnumerationFacet.java | 68 + .../gnu/xml/validation/datatype/Facet.java | 77 + .../gnu/xml/validation/datatype/FloatType.java | 110 + .../validation/datatype/FractionDigitsFacet.java | 71 + .../gnu/xml/validation/datatype/GDayType.java | 174 + .../gnu/xml/validation/datatype/GMonthDayType.java | 183 + .../gnu/xml/validation/datatype/GMonthType.java | 163 + .../xml/validation/datatype/GYearMonthType.java | 176 + .../gnu/xml/validation/datatype/GYearType.java | 151 + .../gnu/xml/validation/datatype/HexBinaryType.java | 89 + .../gnu/xml/validation/datatype/IDRefType.java | 86 + .../gnu/xml/validation/datatype/IDRefsType.java | 86 + .../gnu/xml/validation/datatype/IDType.java | 86 + .../gnu/xml/validation/datatype/IntType.java | 132 + .../gnu/xml/validation/datatype/IntegerType.java | 109 + .../gnu/xml/validation/datatype/LanguageType.java | 86 + .../gnu/xml/validation/datatype/LengthFacet.java | 71 + .../xml/validation/datatype/ListSimpleType.java | 82 + .../gnu/xml/validation/datatype/LongType.java | 132 + .../xml/validation/datatype/MaxExclusiveFacet.java | 110 + .../xml/validation/datatype/MaxInclusiveFacet.java | 111 + .../xml/validation/datatype/MaxLengthFacet.java | 71 + .../xml/validation/datatype/MinExclusiveFacet.java | 110 + .../xml/validation/datatype/MinInclusiveFacet.java | 111 + .../xml/validation/datatype/MinLengthFacet.java | 71 + .../gnu/xml/validation/datatype/NCNameType.java | 110 + .../gnu/xml/validation/datatype/NMTokenType.java | 101 + .../gnu/xml/validation/datatype/NMTokensType.java | 125 + .../gnu/xml/validation/datatype/NameType.java | 103 + .../validation/datatype/NegativeIntegerType.java | 110 + .../datatype/NonNegativeIntegerType.java | 120 + .../datatype/NonPositiveIntegerType.java | 120 + .../validation/datatype/NormalizedStringType.java | 87 + .../gnu/xml/validation/datatype/NotationType.java | 87 + .../gnu/xml/validation/datatype/PatternFacet.java | 70 + .../validation/datatype/PositiveIntegerType.java | 110 + .../gnu/xml/validation/datatype/QNameType.java | 121 + .../gnu/xml/validation/datatype/ShortType.java | 132 + .../gnu/xml/validation/datatype/SimpleType.java | 255 + .../gnu/xml/validation/datatype/StringType.java | 72 + .../gnu/xml/validation/datatype/TimeType.java | 302 + .../gnu/xml/validation/datatype/TokenType.java | 95 + .../xml/validation/datatype/TotalDigitsFacet.java | 71 + .../gnu/xml/validation/datatype/Type.java | 62 + .../gnu/xml/validation/datatype/TypeBuilder.java | 278 + .../gnu/xml/validation/datatype/TypeLibrary.java | 173 + .../validation/datatype/TypeLibraryFactory.java | 60 + .../xml/validation/datatype/UnionSimpleType.java | 82 + .../xml/validation/datatype/UnsignedByteType.java | 120 + .../xml/validation/datatype/UnsignedIntType.java | 120 + .../xml/validation/datatype/UnsignedLongType.java | 120 + .../xml/validation/datatype/UnsignedShortType.java | 121 + .../xml/validation/datatype/WhiteSpaceFacet.java | 74 + .../xml/validation/relaxng/AnyNameNameClass.java | 57 + .../xml/validation/relaxng/AttributePattern.java | 52 + .../xml/validation/relaxng/ChoiceNameClass.java | 58 + .../gnu/xml/validation/relaxng/ChoicePattern.java | 52 + .../gnu/xml/validation/relaxng/DataPattern.java | 59 + .../gnu/xml/validation/relaxng/Define.java | 51 + .../gnu/xml/validation/relaxng/ElementPattern.java | 52 + .../gnu/xml/validation/relaxng/EmptyPattern.java | 51 + .../xml/validation/relaxng/FullSyntaxBuilder.java | 1650 ++++++ .../gnu/xml/validation/relaxng/Grammar.java | 69 + .../xml/validation/relaxng/GrammarException.java | 56 + .../xml/validation/relaxng/GrammarValidator.java | 97 + .../gnu/xml/validation/relaxng/GroupPattern.java | 52 + .../xml/validation/relaxng/InterleavePattern.java | 52 + .../gnu/xml/validation/relaxng/ListPattern.java | 51 + .../xml/validation/relaxng/NSNameNameClass.java | 60 + .../gnu/xml/validation/relaxng/NameClass.java | 50 + .../gnu/xml/validation/relaxng/NameNameClass.java | 59 + .../xml/validation/relaxng/NotAllowedPattern.java | 51 + .../xml/validation/relaxng/OneOrMorePattern.java | 51 + .../gnu/xml/validation/relaxng/Param.java | 51 + .../gnu/xml/validation/relaxng/Pattern.java | 47 + .../validation/relaxng/RELAXNGSchemaFactory.java | 163 + .../gnu/xml/validation/relaxng/RefPattern.java | 51 + .../gnu/xml/validation/relaxng/TextPattern.java | 51 + .../gnu/xml/validation/relaxng/ValuePattern.java | 57 + .../gnu/xml/validation/xmlschema/AnyAttribute.java | 66 + .../validation/xmlschema/AttributeDeclaration.java | 98 + .../gnu/xml/validation/xmlschema/AttributeUse.java | 78 + .../gnu/xml/validation/xmlschema/ComplexType.java | 101 + .../validation/xmlschema/ElementDeclaration.java | 124 + .../gnu/xml/validation/xmlschema/Particle.java | 60 + .../validation/xmlschema/ValidationException.java | 57 + .../gnu/xml/validation/xmlschema/XMLSchema.java | 133 + .../xmlschema/XMLSchemaAttributeTypeInfo.java | 98 + .../xml/validation/xmlschema/XMLSchemaBuilder.java | 839 +++ .../xmlschema/XMLSchemaElementTypeInfo.java | 91 + .../xmlschema/XMLSchemaSchemaFactory.java | 171 + .../validation/xmlschema/XMLSchemaTypeInfo.java | 76 + .../xmlschema/XMLSchemaTypeInfoProvider.java | 81 + .../validation/xmlschema/XMLSchemaValidator.java | 97 + .../xmlschema/XMLSchemaValidatorHandler.java | 393 ++ libjava/classpath/gnu/xml/xpath/AndExpr.java | 87 + .../classpath/gnu/xml/xpath/ArithmeticExpr.java | 170 + .../classpath/gnu/xml/xpath/BooleanFunction.java | 95 + .../classpath/gnu/xml/xpath/CeilingFunction.java | 89 + .../classpath/gnu/xml/xpath/ConcatFunction.java | 115 + libjava/classpath/gnu/xml/xpath/Constant.java | 98 + .../classpath/gnu/xml/xpath/ContainsFunction.java | 93 + libjava/classpath/gnu/xml/xpath/CountFunction.java | 89 + .../gnu/xml/xpath/DocumentOrderComparator.java | 57 + libjava/classpath/gnu/xml/xpath/EqualityExpr.java | 274 + libjava/classpath/gnu/xml/xpath/Expr.java | 549 ++ libjava/classpath/gnu/xml/xpath/FalseFunction.java | 72 + libjava/classpath/gnu/xml/xpath/FloorFunction.java | 90 + libjava/classpath/gnu/xml/xpath/Function.java | 56 + libjava/classpath/gnu/xml/xpath/FunctionCall.java | 169 + libjava/classpath/gnu/xml/xpath/IdFunction.java | 103 + libjava/classpath/gnu/xml/xpath/LangFunction.java | 123 + libjava/classpath/gnu/xml/xpath/LastFunction.java | 73 + .../classpath/gnu/xml/xpath/LocalNameFunction.java | 98 + libjava/classpath/gnu/xml/xpath/NameFunction.java | 109 + libjava/classpath/gnu/xml/xpath/NameTest.java | 143 + libjava/classpath/gnu/xml/xpath/NamespaceTest.java | 120 + .../gnu/xml/xpath/NamespaceUriFunction.java | 98 + libjava/classpath/gnu/xml/xpath/NegativeExpr.java | 81 + libjava/classpath/gnu/xml/xpath/NodeTypeTest.java | 141 + .../gnu/xml/xpath/NormalizeSpaceFunction.java | 108 + libjava/classpath/gnu/xml/xpath/NotFunction.java | 88 + .../classpath/gnu/xml/xpath/NumberFunction.java | 103 + libjava/classpath/gnu/xml/xpath/OrExpr.java | 87 + .../classpath/gnu/xml/xpath/ParenthesizedExpr.java | 95 + libjava/classpath/gnu/xml/xpath/Path.java | 54 + libjava/classpath/gnu/xml/xpath/Pattern.java | 53 + .../classpath/gnu/xml/xpath/PositionFunction.java | 73 + libjava/classpath/gnu/xml/xpath/Predicate.java | 85 + .../classpath/gnu/xml/xpath/RelationalExpr.java | 107 + libjava/classpath/gnu/xml/xpath/Root.java | 91 + libjava/classpath/gnu/xml/xpath/RoundFunction.java | 97 + libjava/classpath/gnu/xml/xpath/Selector.java | 503 ++ .../gnu/xml/xpath/StartsWithFunction.java | 92 + libjava/classpath/gnu/xml/xpath/Steps.java | 260 + .../classpath/gnu/xml/xpath/StringFunction.java | 119 + .../gnu/xml/xpath/StringLengthFunction.java | 92 + .../gnu/xml/xpath/SubstringAfterFunction.java | 98 + .../gnu/xml/xpath/SubstringBeforeFunction.java | 97 + .../classpath/gnu/xml/xpath/SubstringFunction.java | 119 + libjava/classpath/gnu/xml/xpath/SumFunction.java | 104 + libjava/classpath/gnu/xml/xpath/Test.java | 58 + .../classpath/gnu/xml/xpath/TranslateFunction.java | 135 + libjava/classpath/gnu/xml/xpath/TrueFunction.java | 72 + libjava/classpath/gnu/xml/xpath/UnionExpr.java | 117 + .../classpath/gnu/xml/xpath/VariableReference.java | 102 + .../classpath/gnu/xml/xpath/XPathFactoryImpl.java | 90 + libjava/classpath/gnu/xml/xpath/XPathImpl.java | 164 + libjava/classpath/gnu/xml/xpath/XPathParser.java | 1475 +++++ libjava/classpath/gnu/xml/xpath/XPathParser.y | 794 +++ .../classpath/gnu/xml/xpath/XPathTokenizer.java | 594 ++ 2179 files changed, 456082 insertions(+) create mode 100644 libjava/classpath/gnu/CORBA/Asynchron.java create mode 100644 libjava/classpath/gnu/CORBA/BigDecimalHelper.java create mode 100644 libjava/classpath/gnu/CORBA/ByteArrayComparator.java create mode 100644 libjava/classpath/gnu/CORBA/CDR/AbstractCdrInput.java create mode 100644 libjava/classpath/gnu/CORBA/CDR/AbstractCdrOutput.java create mode 100644 libjava/classpath/gnu/CORBA/CDR/AbstractDataInput.java create mode 100644 libjava/classpath/gnu/CORBA/CDR/AbstractDataOutput.java create mode 100644 libjava/classpath/gnu/CORBA/CDR/AligningInput.java create mode 100644 libjava/classpath/gnu/CORBA/CDR/AligningOutput.java create mode 100644 libjava/classpath/gnu/CORBA/CDR/ArrayValueHelper.java create mode 100644 libjava/classpath/gnu/CORBA/CDR/BigEndianInputStream.java create mode 100644 libjava/classpath/gnu/CORBA/CDR/BigEndianOutputStream.java create mode 100644 libjava/classpath/gnu/CORBA/CDR/BufferedCdrOutput.java create mode 100644 libjava/classpath/gnu/CORBA/CDR/BufferredCdrInput.java create mode 100644 libjava/classpath/gnu/CORBA/CDR/EncapsulationStream.java create mode 100644 libjava/classpath/gnu/CORBA/CDR/HeadlessInput.java create mode 100644 libjava/classpath/gnu/CORBA/CDR/IDLTypeHelper.java create mode 100644 libjava/classpath/gnu/CORBA/CDR/LittleEndianInputStream.java create mode 100644 libjava/classpath/gnu/CORBA/CDR/LittleEndianOutputStream.java create mode 100644 libjava/classpath/gnu/CORBA/CDR/UnknownExceptionCtxHandler.java create mode 100644 libjava/classpath/gnu/CORBA/CDR/VMVio.java create mode 100644 libjava/classpath/gnu/CORBA/CDR/Vio.java create mode 100644 libjava/classpath/gnu/CORBA/CDR/gnuRuntime.java create mode 100644 libjava/classpath/gnu/CORBA/CDR/gnuValueStream.java create mode 100644 libjava/classpath/gnu/CORBA/CdrEncapsCodecImpl.java create mode 100644 libjava/classpath/gnu/CORBA/CollocatedOrbs.java create mode 100644 libjava/classpath/gnu/CORBA/Connected_objects.java create mode 100644 libjava/classpath/gnu/CORBA/CorbaList.java create mode 100644 libjava/classpath/gnu/CORBA/DefaultSocketFactory.java create mode 100644 libjava/classpath/gnu/CORBA/DefinitionKindHolder.java create mode 100644 libjava/classpath/gnu/CORBA/DuplicateNameHolder.java create mode 100644 libjava/classpath/gnu/CORBA/DynAn/AbstractAny.java create mode 100644 libjava/classpath/gnu/CORBA/DynAn/DivideableAny.java create mode 100644 libjava/classpath/gnu/CORBA/DynAn/NameValuePairHolder.java create mode 100644 libjava/classpath/gnu/CORBA/DynAn/RecordAny.java create mode 100644 libjava/classpath/gnu/CORBA/DynAn/UndivideableAny.java create mode 100644 libjava/classpath/gnu/CORBA/DynAn/ValueChangeListener.java create mode 100644 libjava/classpath/gnu/CORBA/DynAn/gnuDynAny.java create mode 100644 libjava/classpath/gnu/CORBA/DynAn/gnuDynAnyFactory.java create mode 100644 libjava/classpath/gnu/CORBA/DynAn/gnuDynArray.java create mode 100644 libjava/classpath/gnu/CORBA/DynAn/gnuDynEnum.java create mode 100644 libjava/classpath/gnu/CORBA/DynAn/gnuDynFixed.java create mode 100644 libjava/classpath/gnu/CORBA/DynAn/gnuDynSequence.java create mode 100644 libjava/classpath/gnu/CORBA/DynAn/gnuDynStruct.java create mode 100644 libjava/classpath/gnu/CORBA/DynAn/gnuDynUnion.java create mode 100644 libjava/classpath/gnu/CORBA/DynAn/gnuDynValue.java create mode 100644 libjava/classpath/gnu/CORBA/DynAn/gnuDynValueBox.java create mode 100644 libjava/classpath/gnu/CORBA/DynAnySeqHolder.java create mode 100644 libjava/classpath/gnu/CORBA/EmptyExceptionHolder.java create mode 100644 libjava/classpath/gnu/CORBA/ForwardRequestHelper.java create mode 100644 libjava/classpath/gnu/CORBA/GIOP/CancelHeader.java create mode 100644 libjava/classpath/gnu/CORBA/GIOP/CharSets_OSF.java create mode 100644 libjava/classpath/gnu/CORBA/GIOP/CloseMessage.java create mode 100644 libjava/classpath/gnu/CORBA/GIOP/CodeSetServiceContext.java create mode 100644 libjava/classpath/gnu/CORBA/GIOP/ContextHandler.java create mode 100644 libjava/classpath/gnu/CORBA/GIOP/ErrorMessage.java create mode 100644 libjava/classpath/gnu/CORBA/GIOP/MessageHeader.java create mode 100644 libjava/classpath/gnu/CORBA/GIOP/ReplyHeader.java create mode 100644 libjava/classpath/gnu/CORBA/GIOP/RequestHeader.java create mode 100644 libjava/classpath/gnu/CORBA/GIOP/ServiceContext.java create mode 100644 libjava/classpath/gnu/CORBA/GIOP/v1_0/CancelHeader.java create mode 100644 libjava/classpath/gnu/CORBA/GIOP/v1_0/ReplyHeader.java create mode 100644 libjava/classpath/gnu/CORBA/GIOP/v1_0/RequestHeader.java create mode 100644 libjava/classpath/gnu/CORBA/GIOP/v1_2/ReplyHeader.java create mode 100644 libjava/classpath/gnu/CORBA/GIOP/v1_2/RequestHeader.java create mode 100644 libjava/classpath/gnu/CORBA/GeneralHolder.java create mode 100644 libjava/classpath/gnu/CORBA/HolderLocator.java create mode 100644 libjava/classpath/gnu/CORBA/IOR.java create mode 100644 libjava/classpath/gnu/CORBA/Interceptor/ClientRequestInterceptors.java create mode 100644 libjava/classpath/gnu/CORBA/Interceptor/ForwardRequestHolder.java create mode 100644 libjava/classpath/gnu/CORBA/Interceptor/IORInterceptors.java create mode 100644 libjava/classpath/gnu/CORBA/Interceptor/Registrator.java create mode 100644 libjava/classpath/gnu/CORBA/Interceptor/ServerRequestInterceptors.java create mode 100644 libjava/classpath/gnu/CORBA/Interceptor/gnuClientRequestInfo.java create mode 100644 libjava/classpath/gnu/CORBA/Interceptor/gnuIcCurrent.java create mode 100644 libjava/classpath/gnu/CORBA/Interceptor/gnuIorInfo.java create mode 100644 libjava/classpath/gnu/CORBA/Interceptor/gnuServerRequestInfo.java create mode 100644 libjava/classpath/gnu/CORBA/IorDelegate.java create mode 100644 libjava/classpath/gnu/CORBA/IorObject.java create mode 100644 libjava/classpath/gnu/CORBA/IorProvider.java create mode 100644 libjava/classpath/gnu/CORBA/Minor.java create mode 100644 libjava/classpath/gnu/CORBA/NameDynAnyPairHolder.java create mode 100644 libjava/classpath/gnu/CORBA/NameDynAnyPairSeqHolder.java create mode 100644 libjava/classpath/gnu/CORBA/NameValuePairHolder.java create mode 100644 libjava/classpath/gnu/CORBA/NameValuePairSeqHolder.java create mode 100644 libjava/classpath/gnu/CORBA/NamingService/Binding_iterator_impl.java create mode 100644 libjava/classpath/gnu/CORBA/NamingService/Ext.java create mode 100644 libjava/classpath/gnu/CORBA/NamingService/NameComponentComparator.java create mode 100644 libjava/classpath/gnu/CORBA/NamingService/NameParser.java create mode 100644 libjava/classpath/gnu/CORBA/NamingService/NameTransformer.java create mode 100644 libjava/classpath/gnu/CORBA/NamingService/NameValidator.java create mode 100644 libjava/classpath/gnu/CORBA/NamingService/NamingMap.java create mode 100644 libjava/classpath/gnu/CORBA/NamingService/NamingServiceTransient.java create mode 100644 libjava/classpath/gnu/CORBA/NamingService/TransientContext.java create mode 100644 libjava/classpath/gnu/CORBA/ObjectCreator.java create mode 100644 libjava/classpath/gnu/CORBA/OctetHolder.java create mode 100644 libjava/classpath/gnu/CORBA/OrbFocused.java create mode 100644 libjava/classpath/gnu/CORBA/OrbFunctional.java create mode 100644 libjava/classpath/gnu/CORBA/OrbRestricted.java create mode 100644 libjava/classpath/gnu/CORBA/Poa/AOM.java create mode 100644 libjava/classpath/gnu/CORBA/Poa/AccessiblePolicy.java create mode 100644 libjava/classpath/gnu/CORBA/Poa/DynamicImpHandler.java create mode 100644 libjava/classpath/gnu/CORBA/Poa/ForwardRequestHolder.java create mode 100644 libjava/classpath/gnu/CORBA/Poa/ForwardedServant.java create mode 100644 libjava/classpath/gnu/CORBA/Poa/InvalidPolicyHolder.java create mode 100644 libjava/classpath/gnu/CORBA/Poa/LocalDelegate.java create mode 100644 libjava/classpath/gnu/CORBA/Poa/LocalRequest.java create mode 100644 libjava/classpath/gnu/CORBA/Poa/LocalServerRequest.java create mode 100644 libjava/classpath/gnu/CORBA/Poa/ORB_1_4.java create mode 100644 libjava/classpath/gnu/CORBA/Poa/ServantDelegateImpl.java create mode 100644 libjava/classpath/gnu/CORBA/Poa/StandardPolicies.java create mode 100644 libjava/classpath/gnu/CORBA/Poa/gnuAdapterActivator.java create mode 100644 libjava/classpath/gnu/CORBA/Poa/gnuForwardRequest.java create mode 100644 libjava/classpath/gnu/CORBA/Poa/gnuIdAssignmentPolicy.java create mode 100644 libjava/classpath/gnu/CORBA/Poa/gnuIdUniquenessPolicy.java create mode 100644 libjava/classpath/gnu/CORBA/Poa/gnuImplicitActivationPolicy.java create mode 100644 libjava/classpath/gnu/CORBA/Poa/gnuLifespanPolicy.java create mode 100644 libjava/classpath/gnu/CORBA/Poa/gnuPOA.java create mode 100644 libjava/classpath/gnu/CORBA/Poa/gnuPOAManager.java create mode 100644 libjava/classpath/gnu/CORBA/Poa/gnuPoaCurrent.java create mode 100644 libjava/classpath/gnu/CORBA/Poa/gnuRequestProcessingPolicy.java create mode 100644 libjava/classpath/gnu/CORBA/Poa/gnuServantObject.java create mode 100644 libjava/classpath/gnu/CORBA/Poa/gnuServantRetentionPolicy.java create mode 100644 libjava/classpath/gnu/CORBA/Poa/gnuThreadPolicy.java create mode 100644 libjava/classpath/gnu/CORBA/RawReply.java create mode 100644 libjava/classpath/gnu/CORBA/ResponseHandlerImpl.java create mode 100644 libjava/classpath/gnu/CORBA/SafeForDirectCalls.java create mode 100644 libjava/classpath/gnu/CORBA/ServiceDetailHolder.java create mode 100644 libjava/classpath/gnu/CORBA/ServiceRequestAdapter.java create mode 100644 libjava/classpath/gnu/CORBA/SetOverrideTypeHolder.java create mode 100644 libjava/classpath/gnu/CORBA/SimpleDelegate.java create mode 100644 libjava/classpath/gnu/CORBA/SocketRepository.java create mode 100644 libjava/classpath/gnu/CORBA/StreamBasedRequest.java create mode 100644 libjava/classpath/gnu/CORBA/StreamHolder.java create mode 100644 libjava/classpath/gnu/CORBA/StubLocator.java create mode 100644 libjava/classpath/gnu/CORBA/TypeCodeHelper.java create mode 100644 libjava/classpath/gnu/CORBA/TypeKindNamer.java create mode 100644 libjava/classpath/gnu/CORBA/Unexpected.java create mode 100644 libjava/classpath/gnu/CORBA/Version.java create mode 100644 libjava/classpath/gnu/CORBA/WCharHolder.java create mode 100644 libjava/classpath/gnu/CORBA/WStringHolder.java create mode 100644 libjava/classpath/gnu/CORBA/_PolicyImplBase.java create mode 100644 libjava/classpath/gnu/CORBA/gnuAny.java create mode 100644 libjava/classpath/gnu/CORBA/gnuCodecFactory.java create mode 100644 libjava/classpath/gnu/CORBA/gnuContext.java create mode 100644 libjava/classpath/gnu/CORBA/gnuContextList.java create mode 100644 libjava/classpath/gnu/CORBA/gnuEnvironment.java create mode 100644 libjava/classpath/gnu/CORBA/gnuExceptionList.java create mode 100644 libjava/classpath/gnu/CORBA/gnuNVList.java create mode 100644 libjava/classpath/gnu/CORBA/gnuNamedValue.java create mode 100644 libjava/classpath/gnu/CORBA/gnuRequest.java create mode 100644 libjava/classpath/gnu/CORBA/gnuValueHolder.java create mode 100644 libjava/classpath/gnu/CORBA/interfaces/SocketFactory.java create mode 100644 libjava/classpath/gnu/CORBA/interfaces/package.html create mode 100644 libjava/classpath/gnu/CORBA/typecodes/AliasTypeCode.java create mode 100644 libjava/classpath/gnu/CORBA/typecodes/ArrayTypeCode.java create mode 100644 libjava/classpath/gnu/CORBA/typecodes/FixedTypeCode.java create mode 100644 libjava/classpath/gnu/CORBA/typecodes/GeneralTypeCode.java create mode 100644 libjava/classpath/gnu/CORBA/typecodes/PrimitiveTypeCode.java create mode 100644 libjava/classpath/gnu/CORBA/typecodes/RecordTypeCode.java create mode 100644 libjava/classpath/gnu/CORBA/typecodes/RecursiveTypeCode.java create mode 100644 libjava/classpath/gnu/CORBA/typecodes/StringTypeCode.java create mode 100644 libjava/classpath/gnu/CORBA/typecodes/package.html create mode 100644 libjava/classpath/gnu/classpath/.cvsignore create mode 100644 libjava/classpath/gnu/classpath/Configuration.java.in create mode 100644 libjava/classpath/gnu/classpath/NotImplementedException.java create mode 100644 libjava/classpath/gnu/classpath/Pair.java create mode 100644 libjava/classpath/gnu/classpath/Pointer.java create mode 100644 libjava/classpath/gnu/classpath/Pointer32.java create mode 100644 libjava/classpath/gnu/classpath/Pointer64.java create mode 100644 libjava/classpath/gnu/classpath/ServiceFactory.java create mode 100644 libjava/classpath/gnu/classpath/ServiceProviderLoadingAction.java create mode 100644 libjava/classpath/gnu/classpath/SystemProperties.java create mode 100644 libjava/classpath/gnu/classpath/debug/Component.java create mode 100644 libjava/classpath/gnu/classpath/debug/PreciseFilter.java create mode 100644 libjava/classpath/gnu/classpath/debug/Simple1LineFormatter.java create mode 100644 libjava/classpath/gnu/classpath/debug/SystemLogger.java create mode 100644 libjava/classpath/gnu/classpath/debug/TeeInputStream.java create mode 100644 libjava/classpath/gnu/classpath/debug/TeeOutputStream.java create mode 100644 libjava/classpath/gnu/classpath/debug/TeeReader.java create mode 100644 libjava/classpath/gnu/classpath/debug/TeeWriter.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/Jdwp.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/JdwpConstants.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/event/BreakpointEvent.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/event/ClassPrepareEvent.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/event/ClassUnloadEvent.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/event/Event.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/event/EventManager.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/event/EventRequest.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/event/ExceptionEvent.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/event/MethodEntryEvent.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/event/MethodExitEvent.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/event/SingleStepEvent.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/event/ThreadEndEvent.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/event/ThreadStartEvent.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/event/VmDeathEvent.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/event/VmInitEvent.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/event/filters/ClassExcludeFilter.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/event/filters/ClassMatchFilter.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/event/filters/ClassOnlyFilter.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/event/filters/ConditionalFilter.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/event/filters/CountFilter.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/event/filters/ExceptionOnlyFilter.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/event/filters/FieldOnlyFilter.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/event/filters/IEventFilter.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/event/filters/InstanceOnlyFilter.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/event/filters/LocationOnlyFilter.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/event/filters/StepFilter.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/event/filters/ThreadOnlyFilter.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/exception/AbsentInformationException.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/exception/InvalidClassException.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/exception/InvalidClassLoaderException.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/exception/InvalidCountException.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/exception/InvalidEventTypeException.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/exception/InvalidFieldException.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/exception/InvalidFrameException.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/exception/InvalidLocationException.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/exception/InvalidMethodException.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/exception/InvalidObjectException.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/exception/InvalidSlotException.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/exception/InvalidStringException.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/exception/InvalidTagException.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/exception/InvalidThreadException.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/exception/InvalidThreadGroupException.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/exception/JdwpException.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/exception/JdwpIllegalArgumentException.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/exception/JdwpInternalErrorException.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/exception/NativeMethodException.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/exception/NotImplementedException.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/exception/TypeMismatchException.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/exception/VmDeadException.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/id/ArrayId.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/id/ArrayReferenceTypeId.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/id/ClassLoaderId.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/id/ClassObjectId.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/id/ClassReferenceTypeId.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/id/InterfaceReferenceTypeId.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/id/JdwpId.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/id/NullObjectId.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/id/ObjectId.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/id/ReferenceTypeId.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/id/StringId.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/id/ThreadGroupId.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/id/ThreadId.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/processor/ArrayReferenceCommandSet.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/processor/ArrayTypeCommandSet.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/processor/ClassLoaderReferenceCommandSet.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/processor/ClassObjectReferenceCommandSet.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/processor/ClassTypeCommandSet.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/processor/CommandSet.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/processor/EventRequestCommandSet.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/processor/FieldCommandSet.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/processor/InterfaceTypeCommandSet.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/processor/MethodCommandSet.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/processor/ObjectReferenceCommandSet.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/processor/PacketProcessor.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/processor/ReferenceTypeCommandSet.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/processor/StackFrameCommandSet.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/processor/StringReferenceCommandSet.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/processor/ThreadGroupReferenceCommandSet.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/processor/ThreadReferenceCommandSet.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/processor/VirtualMachineCommandSet.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/transport/ITransport.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/transport/JdwpCommandPacket.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/transport/JdwpConnection.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/transport/JdwpPacket.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/transport/JdwpReplyPacket.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/transport/SocketTransport.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/transport/TransportException.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/transport/TransportFactory.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/util/JdwpString.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/util/LineTable.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/util/Location.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/util/MethodResult.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/util/MonitorInfo.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/util/NullObject.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/util/Signature.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/util/VariableTable.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/value/ArrayValue.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/value/BooleanValue.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/value/ByteValue.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/value/CharValue.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/value/DoubleValue.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/value/FloatValue.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/value/IntValue.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/value/LongValue.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/value/ObjectValue.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/value/ShortValue.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/value/StringValue.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/value/Value.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/value/ValueFactory.java create mode 100644 libjava/classpath/gnu/classpath/jdwp/value/VoidValue.java create mode 100644 libjava/classpath/gnu/classpath/toolkit/DefaultDaemonThreadFactory.java create mode 100644 libjava/classpath/gnu/java/awt/AWTUtilities.java create mode 100644 libjava/classpath/gnu/java/awt/BitMaskExtent.java create mode 100644 libjava/classpath/gnu/java/awt/BitwiseXORComposite.java create mode 100644 libjava/classpath/gnu/java/awt/Buffers.java create mode 100644 libjava/classpath/gnu/java/awt/ClasspathGraphicsEnvironment.java create mode 100644 libjava/classpath/gnu/java/awt/ClasspathToolkit.java create mode 100644 libjava/classpath/gnu/java/awt/ComponentDataBlitOp.java create mode 100644 libjava/classpath/gnu/java/awt/ComponentReshapeEvent.java create mode 100644 libjava/classpath/gnu/java/awt/EmbeddedWindow.java create mode 100644 libjava/classpath/gnu/java/awt/EventModifier.java create mode 100644 libjava/classpath/gnu/java/awt/GradientPaintContext.java create mode 100644 libjava/classpath/gnu/java/awt/LowPriorityEvent.java create mode 100644 libjava/classpath/gnu/java/awt/color/CieXyzConverter.java create mode 100644 libjava/classpath/gnu/java/awt/color/ClutProfileConverter.java create mode 100644 libjava/classpath/gnu/java/awt/color/ColorLookUpTable.java create mode 100644 libjava/classpath/gnu/java/awt/color/ColorSpaceConverter.java create mode 100644 libjava/classpath/gnu/java/awt/color/GrayProfileConverter.java create mode 100644 libjava/classpath/gnu/java/awt/color/GrayScaleConverter.java create mode 100644 libjava/classpath/gnu/java/awt/color/LinearRGBConverter.java create mode 100644 libjava/classpath/gnu/java/awt/color/ProfileHeader.java create mode 100644 libjava/classpath/gnu/java/awt/color/PyccConverter.java create mode 100644 libjava/classpath/gnu/java/awt/color/RgbProfileConverter.java create mode 100644 libjava/classpath/gnu/java/awt/color/SrgbConverter.java create mode 100644 libjava/classpath/gnu/java/awt/color/TagEntry.java create mode 100644 libjava/classpath/gnu/java/awt/color/ToneReproductionCurve.java create mode 100644 libjava/classpath/gnu/java/awt/color/package.html create mode 100644 libjava/classpath/gnu/java/awt/dnd/GtkMouseDragGestureRecognizer.java create mode 100644 libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDragSourceContextPeer.java create mode 100644 libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDropTargetContextPeer.java create mode 100644 libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDropTargetPeer.java create mode 100644 libjava/classpath/gnu/java/awt/doc-files/BitwiseXORComposite-1.png create mode 100644 libjava/classpath/gnu/java/awt/font/FontDelegate.java create mode 100644 libjava/classpath/gnu/java/awt/font/FontFactory.java create mode 100644 libjava/classpath/gnu/java/awt/font/GNUGlyphVector.java create mode 100644 libjava/classpath/gnu/java/awt/font/OpenTypeFontPeer.java create mode 100644 libjava/classpath/gnu/java/awt/font/autofit/AutoHinter.java create mode 100644 libjava/classpath/gnu/java/awt/font/autofit/AxisHints.java create mode 100644 libjava/classpath/gnu/java/awt/font/autofit/Constants.java create mode 100644 libjava/classpath/gnu/java/awt/font/autofit/Edge.java create mode 100644 libjava/classpath/gnu/java/awt/font/autofit/GlyphHints.java create mode 100644 libjava/classpath/gnu/java/awt/font/autofit/HintScaler.java create mode 100644 libjava/classpath/gnu/java/awt/font/autofit/Latin.java create mode 100644 libjava/classpath/gnu/java/awt/font/autofit/LatinAxis.java create mode 100644 libjava/classpath/gnu/java/awt/font/autofit/LatinBlue.java create mode 100644 libjava/classpath/gnu/java/awt/font/autofit/LatinMetrics.java create mode 100644 libjava/classpath/gnu/java/awt/font/autofit/Script.java create mode 100644 libjava/classpath/gnu/java/awt/font/autofit/ScriptMetrics.java create mode 100644 libjava/classpath/gnu/java/awt/font/autofit/Segment.java create mode 100644 libjava/classpath/gnu/java/awt/font/autofit/Utils.java create mode 100644 libjava/classpath/gnu/java/awt/font/autofit/Width.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/CharGlyphMap.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/GlyphNamer.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/Hinter.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/MacResourceFork.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/NameDecoder.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/OpenTypeFont.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/OpenTypeFontFactory.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/Scaler.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/truetype/Fixed.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphLoader.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphLocator.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphMeasurer.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/truetype/Point.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/truetype/TrueTypeScaler.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/truetype/VirtualMachine.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/truetype/Zone.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/truetype/ZonePathIterator.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/truetype/doc-files/ZonePathIterator-1.dia create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/truetype/doc-files/ZonePathIterator-1.png create mode 100644 libjava/classpath/gnu/java/awt/image/AsyncImage.java create mode 100644 libjava/classpath/gnu/java/awt/image/ImageConverter.java create mode 100644 libjava/classpath/gnu/java/awt/image/ImageDecoder.java create mode 100644 libjava/classpath/gnu/java/awt/image/XBMDecoder.java create mode 100644 libjava/classpath/gnu/java/awt/image/package.html create mode 100644 libjava/classpath/gnu/java/awt/java2d/AbstractGraphics2D.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/ActiveEdges.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/AlphaCompositeContext.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/CubicSegment.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/ImagePaint.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/LineSegment.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/PixelCoverage.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/Pixelizer.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/PolyEdge.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/PolyEdgeComparator.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/QuadSegment.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/RasterGraphics.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/Scanline.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/ScanlineConverter.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/ScanlineCoverage.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/Segment.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/ShapeCache.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/ShapeWrapper.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/TextCacheKey.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/TexturePaintContext.java create mode 100644 libjava/classpath/gnu/java/awt/package.html create mode 100644 libjava/classpath/gnu/java/awt/peer/ClasspathDesktopPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/ClasspathFontPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/EmbeddedWindowPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/GLightweightPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/GnomeDesktopPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/KDEDesktopPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/NativeEventLoopRunningEvent.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/AsyncImage.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/BufferedImageGraphics.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/CairoGraphics2D.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/CairoSurface.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/ComponentGraphics.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/ComponentGraphicsCopy.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GdkFontPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsConfiguration.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GdkRobotPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GdkScreenGraphicsDevice.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkButtonPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkCanvasPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkCheckboxMenuItemPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkCheckboxPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkChoicePeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkClipboard.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkClipboardNotifier.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkComponentPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkContainerPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkCursor.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkDialogPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkEmbeddedWindowPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkFileDialogPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkFramePeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkGenericPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkImage.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkImageConsumer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkLabelPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkListPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkMainThread.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuBarPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuComponentPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuItemPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkMouseInfoPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkPanelPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkPopupMenuPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkScrollPanePeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkScrollbarPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkSelection.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkTextAreaPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkTextFieldPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkToolkit.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkVolatileImage.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkWindowPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/VolatileImageGraphics.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/package.html create mode 100644 libjava/classpath/gnu/java/awt/peer/headless/HeadlessGraphicsEnvironment.java create mode 100644 libjava/classpath/gnu/java/awt/peer/headless/HeadlessToolkit.java create mode 100644 libjava/classpath/gnu/java/awt/peer/package.html create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/MainQtThread.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/NativeWrapper.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QMatrix.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QPainterPath.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QPen.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtAudioClip.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtButtonPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtCanvasPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtCheckboxPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtChoicePeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtComponentGraphics.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtComponentPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtContainerPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtDialogPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtEmbeddedWindowPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtFileDialogPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtFontMetrics.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtFontPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtFramePeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtGraphics.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtGraphicsEnvironment.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtImage.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtImageConsumer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtImageDirectGraphics.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtImageGraphics.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtLabelPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtListPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtMenuBarPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtMenuComponentPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtMenuItemPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtMenuPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtPanelPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtPopupMenuPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtRepaintThread.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtScreenDevice.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtScreenDeviceConfiguration.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtScrollPanePeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtScrollbarPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtTextAreaPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtTextFieldPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtToolkit.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtVolatileImage.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtWindowPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/SwingButtonPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/SwingCanvasPeer.java create mode 100755 libjava/classpath/gnu/java/awt/peer/swing/SwingCheckboxPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/SwingComponent.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/SwingComponentPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/SwingContainerPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/SwingFramePeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/SwingLabelPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/SwingListPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/SwingMenuBarPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/SwingMenuItemPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/SwingMenuPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/SwingPanelPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/SwingTextAreaPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/SwingTextFieldPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/SwingToolkit.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/SwingWindowPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/package.html create mode 100644 libjava/classpath/gnu/java/awt/peer/x/GLGraphics.java create mode 100644 libjava/classpath/gnu/java/awt/peer/x/KeyboardMapping.java create mode 100644 libjava/classpath/gnu/java/awt/peer/x/PixmapVolatileImage.java create mode 100644 libjava/classpath/gnu/java/awt/peer/x/XDialogPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/x/XEventPump.java create mode 100644 libjava/classpath/gnu/java/awt/peer/x/XFontPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/x/XFramePeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/x/XGraphics2D.java create mode 100644 libjava/classpath/gnu/java/awt/peer/x/XGraphicsConfiguration.java create mode 100644 libjava/classpath/gnu/java/awt/peer/x/XGraphicsDevice.java create mode 100644 libjava/classpath/gnu/java/awt/peer/x/XGraphicsEnvironment.java create mode 100644 libjava/classpath/gnu/java/awt/peer/x/XImage.java create mode 100644 libjava/classpath/gnu/java/awt/peer/x/XToolkit.java create mode 100644 libjava/classpath/gnu/java/awt/peer/x/XWindowPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/x/ZPixmapDataBuffer.java create mode 100644 libjava/classpath/gnu/java/awt/print/JavaPrinterGraphics.java create mode 100644 libjava/classpath/gnu/java/awt/print/JavaPrinterJob.java create mode 100644 libjava/classpath/gnu/java/awt/print/PostScriptGraphics2D.java create mode 100644 libjava/classpath/gnu/java/awt/print/SpooledDocument.java create mode 100644 libjava/classpath/gnu/java/beans/BeanInfoEmbryo.java create mode 100644 libjava/classpath/gnu/java/beans/DefaultExceptionListener.java create mode 100644 libjava/classpath/gnu/java/beans/DummyAppletContext.java create mode 100644 libjava/classpath/gnu/java/beans/DummyAppletStub.java create mode 100644 libjava/classpath/gnu/java/beans/ExplicitBeanInfo.java create mode 100644 libjava/classpath/gnu/java/beans/IntrospectionIncubator.java create mode 100644 libjava/classpath/gnu/java/beans/TODO create mode 100644 libjava/classpath/gnu/java/beans/decoder/AbstractContext.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/AbstractCreatableObjectContext.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/AbstractElementHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/AbstractObjectContext.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/ArrayContext.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/ArrayHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/AssemblyException.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/BooleanHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/ByteHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/CharHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/ClassHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/ConstructorContext.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/Context.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/DecoderContext.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/DoubleHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/DummyContext.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/DummyHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/ElementHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/FloatHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/GrowableArrayContext.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/IndexContext.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/IntHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/JavaHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/LongHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/MethodContext.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/MethodFinder.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/NullHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/ObjectContext.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/ObjectHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/PersistenceParser.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/PropertyContext.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/ShortHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/SimpleHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/StaticMethodContext.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/StringHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/VoidHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/package.html create mode 100644 libjava/classpath/gnu/java/beans/editors/ColorEditor.java create mode 100644 libjava/classpath/gnu/java/beans/editors/FontEditor.java create mode 100644 libjava/classpath/gnu/java/beans/editors/NativeBooleanEditor.java create mode 100644 libjava/classpath/gnu/java/beans/editors/NativeByteEditor.java create mode 100644 libjava/classpath/gnu/java/beans/editors/NativeDoubleEditor.java create mode 100644 libjava/classpath/gnu/java/beans/editors/NativeFloatEditor.java create mode 100644 libjava/classpath/gnu/java/beans/editors/NativeIntEditor.java create mode 100644 libjava/classpath/gnu/java/beans/editors/NativeLongEditor.java create mode 100644 libjava/classpath/gnu/java/beans/editors/NativeShortEditor.java create mode 100644 libjava/classpath/gnu/java/beans/editors/StringEditor.java create mode 100644 libjava/classpath/gnu/java/beans/editors/TODO create mode 100644 libjava/classpath/gnu/java/beans/editors/package.html create mode 100644 libjava/classpath/gnu/java/beans/encoder/ArrayPersistenceDelegate.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/ClassPersistenceDelegate.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/CollectionPersistenceDelegate.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/Context.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/GenericScannerState.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/IgnoringScannerState.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/MapPersistenceDelegate.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/ObjectId.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/PrimitivePersistenceDelegate.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/ReportingScannerState.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/Root.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/ScanEngine.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/ScannerState.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/StAXWriter.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/Writer.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/elements/ArrayInstantiation.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/elements/Array_Get.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/elements/Array_Set.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/elements/ClassResolution.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/elements/Element.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/elements/List_Get.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/elements/List_Set.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/elements/MethodInvocation.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/elements/NullObject.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/elements/ObjectInstantiation.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/elements/ObjectReference.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/elements/PrimitiveInstantiation.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/elements/StaticFieldAccess.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/elements/StaticMethodInvocation.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/elements/StringReference.java create mode 100644 libjava/classpath/gnu/java/beans/package.html create mode 100644 libjava/classpath/gnu/java/io/ASN1ParsingException.java create mode 100644 libjava/classpath/gnu/java/io/Base64InputStream.java create mode 100644 libjava/classpath/gnu/java/io/ClassLoaderObjectInputStream.java create mode 100644 libjava/classpath/gnu/java/io/NullOutputStream.java create mode 100644 libjava/classpath/gnu/java/io/ObjectIdentityMap2Int.java create mode 100644 libjava/classpath/gnu/java/io/ObjectIdentityWrapper.java create mode 100644 libjava/classpath/gnu/java/io/PlatformHelper.java create mode 100644 libjava/classpath/gnu/java/io/package.html create mode 100644 libjava/classpath/gnu/java/lang/ArrayHelper.java create mode 100644 libjava/classpath/gnu/java/lang/CPStringBuilder.java create mode 100644 libjava/classpath/gnu/java/lang/CharData.java create mode 100644 libjava/classpath/gnu/java/lang/ClassHelper.java create mode 100644 libjava/classpath/gnu/java/lang/InstrumentationImpl.java create mode 100644 libjava/classpath/gnu/java/lang/MainThread.java create mode 100644 libjava/classpath/gnu/java/lang/management/BeanImpl.java create mode 100644 libjava/classpath/gnu/java/lang/management/ClassLoadingMXBeanImpl.java create mode 100644 libjava/classpath/gnu/java/lang/management/CompilationMXBeanImpl.java create mode 100644 libjava/classpath/gnu/java/lang/management/GarbageCollectorMXBeanImpl.java create mode 100644 libjava/classpath/gnu/java/lang/management/MemoryMXBeanImpl.java create mode 100644 libjava/classpath/gnu/java/lang/management/MemoryManagerMXBeanImpl.java create mode 100644 libjava/classpath/gnu/java/lang/management/MemoryPoolMXBeanImpl.java create mode 100644 libjava/classpath/gnu/java/lang/management/OperatingSystemMXBeanImpl.java create mode 100644 libjava/classpath/gnu/java/lang/management/RuntimeMXBeanImpl.java create mode 100644 libjava/classpath/gnu/java/lang/management/ThreadMXBeanImpl.java create mode 100644 libjava/classpath/gnu/java/lang/management/package.html create mode 100644 libjava/classpath/gnu/java/lang/package.html create mode 100644 libjava/classpath/gnu/java/lang/reflect/ClassSignatureParser.java create mode 100644 libjava/classpath/gnu/java/lang/reflect/FieldSignatureParser.java create mode 100644 libjava/classpath/gnu/java/lang/reflect/GenericSignatureParser.java create mode 100644 libjava/classpath/gnu/java/lang/reflect/MethodSignatureParser.java create mode 100644 libjava/classpath/gnu/java/lang/reflect/TypeImpl.java create mode 100644 libjava/classpath/gnu/java/lang/reflect/TypeSignature.java create mode 100644 libjava/classpath/gnu/java/lang/reflect/package.html create mode 100644 libjava/classpath/gnu/java/locale/.cvsignore create mode 100644 libjava/classpath/gnu/java/locale/LocaleHelper.java create mode 100644 libjava/classpath/gnu/java/locale/package.html create mode 100644 libjava/classpath/gnu/java/math/Fixed.java create mode 100644 libjava/classpath/gnu/java/math/GMP.java create mode 100644 libjava/classpath/gnu/java/math/MPN.java create mode 100644 libjava/classpath/gnu/java/math/package.html create mode 100644 libjava/classpath/gnu/java/net/CRLFInputStream.java create mode 100644 libjava/classpath/gnu/java/net/CRLFOutputStream.java create mode 100644 libjava/classpath/gnu/java/net/DefaultContentHandlerFactory.java create mode 100644 libjava/classpath/gnu/java/net/DefaultProxySelector.java create mode 100644 libjava/classpath/gnu/java/net/EmptyX509TrustManager.java create mode 100644 libjava/classpath/gnu/java/net/GetLocalHostAction.java create mode 100644 libjava/classpath/gnu/java/net/HeaderFieldHelper.java create mode 100644 libjava/classpath/gnu/java/net/IndexListParser.java create mode 100644 libjava/classpath/gnu/java/net/LineInputStream.java create mode 100644 libjava/classpath/gnu/java/net/PlainDatagramSocketImpl.java create mode 100644 libjava/classpath/gnu/java/net/PlainSocketImpl.java create mode 100644 libjava/classpath/gnu/java/net/URLParseError.java create mode 100644 libjava/classpath/gnu/java/net/loader/FileResource.java create mode 100644 libjava/classpath/gnu/java/net/loader/FileURLLoader.java create mode 100644 libjava/classpath/gnu/java/net/loader/JarURLLoader.java create mode 100644 libjava/classpath/gnu/java/net/loader/JarURLResource.java create mode 100644 libjava/classpath/gnu/java/net/loader/RemoteResource.java create mode 100644 libjava/classpath/gnu/java/net/loader/RemoteURLLoader.java create mode 100644 libjava/classpath/gnu/java/net/loader/Resource.java create mode 100644 libjava/classpath/gnu/java/net/loader/URLLoader.java create mode 100644 libjava/classpath/gnu/java/net/loader/URLStreamHandlerCache.java create mode 100644 libjava/classpath/gnu/java/net/local/LocalServerSocket.java create mode 100644 libjava/classpath/gnu/java/net/local/LocalSocket.java create mode 100644 libjava/classpath/gnu/java/net/local/LocalSocketAddress.java create mode 100644 libjava/classpath/gnu/java/net/local/LocalSocketImpl.java create mode 100644 libjava/classpath/gnu/java/net/package.html create mode 100644 libjava/classpath/gnu/java/net/protocol/file/Connection.java create mode 100644 libjava/classpath/gnu/java/net/protocol/file/Handler.java create mode 100644 libjava/classpath/gnu/java/net/protocol/file/package.html create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/ActiveModeDTP.java create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/BlockInputStream.java create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/BlockOutputStream.java create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/CompressedInputStream.java create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/CompressedOutputStream.java create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/DTP.java create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/DTPInputStream.java create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/DTPOutputStream.java create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/FTPConnection.java create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/FTPException.java create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/FTPResponse.java create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/FTPURLConnection.java create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/Handler.java create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/PassiveModeDTP.java create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/StreamInputStream.java create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/StreamOutputStream.java create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/package.html create mode 100644 libjava/classpath/gnu/java/net/protocol/http/Authenticator.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/ByteArrayRequestBodyWriter.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/ChunkedInputStream.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/Cookie.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/CookieManager.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/Credentials.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/HTTPConnection.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/HTTPDateFormat.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/HTTPURLConnection.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/Handler.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/Headers.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/LimitedLengthInputStream.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/Request.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/RequestBodyWriter.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/Response.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/ResponseHeaderHandler.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/SimpleCookieManager.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/package.html create mode 100644 libjava/classpath/gnu/java/net/protocol/https/Handler.java create mode 100644 libjava/classpath/gnu/java/net/protocol/jar/Connection.java create mode 100644 libjava/classpath/gnu/java/net/protocol/jar/Handler.java create mode 100644 libjava/classpath/gnu/java/net/protocol/jar/package.html create mode 100644 libjava/classpath/gnu/java/nio/ChannelInputStream.java create mode 100644 libjava/classpath/gnu/java/nio/ChannelOutputStream.java create mode 100644 libjava/classpath/gnu/java/nio/ChannelReader.java create mode 100644 libjava/classpath/gnu/java/nio/ChannelWriter.java create mode 100644 libjava/classpath/gnu/java/nio/DatagramChannelImpl.java create mode 100644 libjava/classpath/gnu/java/nio/DatagramChannelSelectionKey.java create mode 100644 libjava/classpath/gnu/java/nio/EpollSelectionKeyImpl.java create mode 100644 libjava/classpath/gnu/java/nio/EpollSelectorImpl.java create mode 100644 libjava/classpath/gnu/java/nio/FileChannelImpl.java create mode 100644 libjava/classpath/gnu/java/nio/FileLockImpl.java create mode 100644 libjava/classpath/gnu/java/nio/InputStreamChannel.java create mode 100644 libjava/classpath/gnu/java/nio/KqueueSelectionKeyImpl.java create mode 100644 libjava/classpath/gnu/java/nio/KqueueSelectorImpl.java create mode 100644 libjava/classpath/gnu/java/nio/NIOConstants.java create mode 100644 libjava/classpath/gnu/java/nio/NIODatagramSocket.java create mode 100644 libjava/classpath/gnu/java/nio/NIOServerSocket.java create mode 100644 libjava/classpath/gnu/java/nio/NIOSocket.java create mode 100644 libjava/classpath/gnu/java/nio/NIOSocketImpl.java create mode 100644 libjava/classpath/gnu/java/nio/OutputStreamChannel.java create mode 100644 libjava/classpath/gnu/java/nio/PipeImpl.java create mode 100644 libjava/classpath/gnu/java/nio/SelectionKeyImpl.java create mode 100644 libjava/classpath/gnu/java/nio/SelectorImpl.java create mode 100644 libjava/classpath/gnu/java/nio/SelectorProviderImpl.java create mode 100644 libjava/classpath/gnu/java/nio/ServerSocketChannelImpl.java create mode 100644 libjava/classpath/gnu/java/nio/ServerSocketChannelSelectionKey.java create mode 100644 libjava/classpath/gnu/java/nio/SocketChannelImpl.java create mode 100644 libjava/classpath/gnu/java/nio/SocketChannelSelectionKey.java create mode 100644 libjava/classpath/gnu/java/nio/SocketChannelSelectionKeyImpl.java create mode 100644 libjava/classpath/gnu/java/nio/VMChannelOwner.java create mode 100644 libjava/classpath/gnu/java/nio/channels/package.html create mode 100644 libjava/classpath/gnu/java/nio/charset/ByteCharset.java create mode 100644 libjava/classpath/gnu/java/nio/charset/ByteDecodeLoopHelper.java create mode 100644 libjava/classpath/gnu/java/nio/charset/ByteEncodeLoopHelper.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp424.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp437.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp737.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp775.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp850.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp852.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp855.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp857.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp860.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp861.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp862.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp863.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp864.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp865.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp866.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp869.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp874.java create mode 100644 libjava/classpath/gnu/java/nio/charset/EncodingHelper.java create mode 100644 libjava/classpath/gnu/java/nio/charset/ISO_8859_1.java create mode 100644 libjava/classpath/gnu/java/nio/charset/ISO_8859_13.java create mode 100644 libjava/classpath/gnu/java/nio/charset/ISO_8859_15.java create mode 100644 libjava/classpath/gnu/java/nio/charset/ISO_8859_2.java create mode 100644 libjava/classpath/gnu/java/nio/charset/ISO_8859_3.java create mode 100644 libjava/classpath/gnu/java/nio/charset/ISO_8859_4.java create mode 100644 libjava/classpath/gnu/java/nio/charset/ISO_8859_5.java create mode 100644 libjava/classpath/gnu/java/nio/charset/ISO_8859_6.java create mode 100644 libjava/classpath/gnu/java/nio/charset/ISO_8859_7.java create mode 100644 libjava/classpath/gnu/java/nio/charset/ISO_8859_8.java create mode 100644 libjava/classpath/gnu/java/nio/charset/ISO_8859_9.java create mode 100644 libjava/classpath/gnu/java/nio/charset/KOI_8.java create mode 100644 libjava/classpath/gnu/java/nio/charset/MS874.java create mode 100644 libjava/classpath/gnu/java/nio/charset/MacCentralEurope.java create mode 100644 libjava/classpath/gnu/java/nio/charset/MacCroatian.java create mode 100644 libjava/classpath/gnu/java/nio/charset/MacCyrillic.java create mode 100644 libjava/classpath/gnu/java/nio/charset/MacDingbat.java create mode 100644 libjava/classpath/gnu/java/nio/charset/MacGreek.java create mode 100644 libjava/classpath/gnu/java/nio/charset/MacIceland.java create mode 100644 libjava/classpath/gnu/java/nio/charset/MacRoman.java create mode 100644 libjava/classpath/gnu/java/nio/charset/MacRomania.java create mode 100644 libjava/classpath/gnu/java/nio/charset/MacSymbol.java create mode 100644 libjava/classpath/gnu/java/nio/charset/MacThai.java create mode 100644 libjava/classpath/gnu/java/nio/charset/MacTurkish.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Provider.java create mode 100644 libjava/classpath/gnu/java/nio/charset/US_ASCII.java create mode 100644 libjava/classpath/gnu/java/nio/charset/UTF_16.java create mode 100644 libjava/classpath/gnu/java/nio/charset/UTF_16BE.java create mode 100644 libjava/classpath/gnu/java/nio/charset/UTF_16Decoder.java create mode 100644 libjava/classpath/gnu/java/nio/charset/UTF_16Encoder.java create mode 100644 libjava/classpath/gnu/java/nio/charset/UTF_16LE.java create mode 100644 libjava/classpath/gnu/java/nio/charset/UTF_8.java create mode 100644 libjava/classpath/gnu/java/nio/charset/UnicodeLittle.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Windows1250.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Windows1251.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Windows1252.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Windows1253.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Windows1254.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Windows1255.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Windows1256.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Windows1257.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Windows1258.java create mode 100644 libjava/classpath/gnu/java/nio/charset/iconv/IconvCharset.java create mode 100644 libjava/classpath/gnu/java/nio/charset/iconv/IconvDecoder.java create mode 100644 libjava/classpath/gnu/java/nio/charset/iconv/IconvEncoder.java create mode 100644 libjava/classpath/gnu/java/nio/charset/iconv/IconvMetaData.java create mode 100644 libjava/classpath/gnu/java/nio/charset/iconv/IconvProvider.java create mode 100644 libjava/classpath/gnu/java/nio/charset/package.html create mode 100644 libjava/classpath/gnu/java/nio/package.html create mode 100644 libjava/classpath/gnu/java/rmi/RMIMarshalledObjectInputStream.java create mode 100644 libjava/classpath/gnu/java/rmi/RMIMarshalledObjectOutputStream.java create mode 100644 libjava/classpath/gnu/java/rmi/activation/ActivationSystemTransient.java create mode 100644 libjava/classpath/gnu/java/rmi/activation/BidiTable.java create mode 100644 libjava/classpath/gnu/java/rmi/activation/DefaultActivationGroup.java create mode 100644 libjava/classpath/gnu/java/rmi/activation/DefaultActivationSystem.java create mode 100644 libjava/classpath/gnu/java/rmi/dgc/DGCImpl.java create mode 100644 libjava/classpath/gnu/java/rmi/dgc/DGCImpl_Skel.java create mode 100644 libjava/classpath/gnu/java/rmi/dgc/DGCImpl_Stub.java create mode 100644 libjava/classpath/gnu/java/rmi/dgc/LeaseRenewingTask.java create mode 100644 libjava/classpath/gnu/java/rmi/dgc/package.html create mode 100644 libjava/classpath/gnu/java/rmi/package.html create mode 100644 libjava/classpath/gnu/java/rmi/registry/RegistryImpl.java create mode 100644 libjava/classpath/gnu/java/rmi/registry/RegistryImpl_Skel.java create mode 100644 libjava/classpath/gnu/java/rmi/registry/RegistryImpl_Stub.java create mode 100644 libjava/classpath/gnu/java/rmi/registry/package.html create mode 100644 libjava/classpath/gnu/java/rmi/server/ActivatableRef.java create mode 100644 libjava/classpath/gnu/java/rmi/server/ActivatableServerRef.java create mode 100644 libjava/classpath/gnu/java/rmi/server/CombinedClassLoader.java create mode 100644 libjava/classpath/gnu/java/rmi/server/ConnectionRunnerPool.java create mode 100644 libjava/classpath/gnu/java/rmi/server/ProtocolConstants.java create mode 100644 libjava/classpath/gnu/java/rmi/server/RMIClassLoaderImpl.java create mode 100644 libjava/classpath/gnu/java/rmi/server/RMIDefaultSocketFactory.java create mode 100644 libjava/classpath/gnu/java/rmi/server/RMIHashes.java create mode 100644 libjava/classpath/gnu/java/rmi/server/RMIIncomingThread.java create mode 100644 libjava/classpath/gnu/java/rmi/server/RMIObjectInputStream.java create mode 100644 libjava/classpath/gnu/java/rmi/server/RMIObjectOutputStream.java create mode 100644 libjava/classpath/gnu/java/rmi/server/RMIVoidValue.java create mode 100644 libjava/classpath/gnu/java/rmi/server/UnicastConnection.java create mode 100644 libjava/classpath/gnu/java/rmi/server/UnicastConnectionManager.java create mode 100644 libjava/classpath/gnu/java/rmi/server/UnicastRef.java create mode 100644 libjava/classpath/gnu/java/rmi/server/UnicastRemoteCall.java create mode 100644 libjava/classpath/gnu/java/rmi/server/UnicastRemoteStub.java create mode 100644 libjava/classpath/gnu/java/rmi/server/UnicastServer.java create mode 100644 libjava/classpath/gnu/java/rmi/server/UnicastServerRef.java create mode 100644 libjava/classpath/gnu/java/rmi/server/package.html create mode 100644 libjava/classpath/gnu/java/security/.cvsignore create mode 100644 libjava/classpath/gnu/java/security/Configuration.java.in create mode 100644 libjava/classpath/gnu/java/security/Engine.java create mode 100644 libjava/classpath/gnu/java/security/OID.java create mode 100644 libjava/classpath/gnu/java/security/PolicyFile.java create mode 100644 libjava/classpath/gnu/java/security/Properties.java create mode 100644 libjava/classpath/gnu/java/security/Registry.java create mode 100644 libjava/classpath/gnu/java/security/Requires.java create mode 100644 libjava/classpath/gnu/java/security/action/GetPropertyAction.java create mode 100644 libjava/classpath/gnu/java/security/action/GetSecurityPropertyAction.java create mode 100644 libjava/classpath/gnu/java/security/action/SetAccessibleAction.java create mode 100644 libjava/classpath/gnu/java/security/action/package.html create mode 100644 libjava/classpath/gnu/java/security/ber/BER.java create mode 100644 libjava/classpath/gnu/java/security/ber/BEREncodingException.java create mode 100644 libjava/classpath/gnu/java/security/ber/BERReader.java create mode 100644 libjava/classpath/gnu/java/security/ber/BERValue.java create mode 100644 libjava/classpath/gnu/java/security/ber/package.html create mode 100644 libjava/classpath/gnu/java/security/der/BitString.java create mode 100644 libjava/classpath/gnu/java/security/der/DER.java create mode 100644 libjava/classpath/gnu/java/security/der/DEREncodingException.java create mode 100644 libjava/classpath/gnu/java/security/der/DERReader.java create mode 100644 libjava/classpath/gnu/java/security/der/DERValue.java create mode 100644 libjava/classpath/gnu/java/security/der/DERWriter.java create mode 100644 libjava/classpath/gnu/java/security/der/package.html create mode 100644 libjava/classpath/gnu/java/security/hash/BaseHash.java create mode 100644 libjava/classpath/gnu/java/security/hash/HashFactory.java create mode 100644 libjava/classpath/gnu/java/security/hash/Haval.java create mode 100644 libjava/classpath/gnu/java/security/hash/IMessageDigest.java create mode 100644 libjava/classpath/gnu/java/security/hash/MD2.java create mode 100644 libjava/classpath/gnu/java/security/hash/MD4.java create mode 100644 libjava/classpath/gnu/java/security/hash/MD5.java create mode 100644 libjava/classpath/gnu/java/security/hash/RipeMD128.java create mode 100644 libjava/classpath/gnu/java/security/hash/RipeMD160.java create mode 100644 libjava/classpath/gnu/java/security/hash/Sha160.java create mode 100644 libjava/classpath/gnu/java/security/hash/Sha256.java create mode 100644 libjava/classpath/gnu/java/security/hash/Sha384.java create mode 100644 libjava/classpath/gnu/java/security/hash/Sha512.java create mode 100644 libjava/classpath/gnu/java/security/hash/Tiger.java create mode 100644 libjava/classpath/gnu/java/security/hash/Whirlpool.java create mode 100644 libjava/classpath/gnu/java/security/jce/hash/HavalSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/hash/MD2Spi.java create mode 100644 libjava/classpath/gnu/java/security/jce/hash/MD4Spi.java create mode 100644 libjava/classpath/gnu/java/security/jce/hash/MD5Spi.java create mode 100644 libjava/classpath/gnu/java/security/jce/hash/MessageDigestAdapter.java create mode 100644 libjava/classpath/gnu/java/security/jce/hash/RipeMD128Spi.java create mode 100644 libjava/classpath/gnu/java/security/jce/hash/RipeMD160Spi.java create mode 100644 libjava/classpath/gnu/java/security/jce/hash/Sha160Spi.java create mode 100644 libjava/classpath/gnu/java/security/jce/hash/Sha256Spi.java create mode 100644 libjava/classpath/gnu/java/security/jce/hash/Sha384Spi.java create mode 100644 libjava/classpath/gnu/java/security/jce/hash/Sha512Spi.java create mode 100644 libjava/classpath/gnu/java/security/jce/hash/TigerSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/hash/WhirlpoolSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/prng/HavalRandomSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/prng/MD2RandomSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/prng/MD4RandomSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/prng/MD5RandomSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/prng/RipeMD128RandomSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/prng/RipeMD160RandomSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/prng/SecureRandomAdapter.java create mode 100644 libjava/classpath/gnu/java/security/jce/prng/Sha160RandomSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/prng/Sha256RandomSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/prng/Sha384RandomSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/prng/Sha512RandomSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/prng/TigerRandomSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/prng/WhirlpoolRandomSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/DSSKeyFactory.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/DSSKeyPairGeneratorSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/DSSParameters.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/DSSParametersGenerator.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/DSSRawSignatureSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/EncodedKeyFactory.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/KeyPairGeneratorAdapter.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/MD2withRSA.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/MD5withRSA.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/RSAKeyFactory.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/RSAKeyPairGeneratorSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/RSAPSSRawSignatureSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/SHA160withDSS.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/SHA160withRSA.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/SHA256withRSA.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/SHA384withRSA.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/SHA512withRSA.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/SignatureAdapter.java create mode 100644 libjava/classpath/gnu/java/security/key/IKeyPairCodec.java create mode 100644 libjava/classpath/gnu/java/security/key/IKeyPairGenerator.java create mode 100644 libjava/classpath/gnu/java/security/key/KeyPairCodecFactory.java create mode 100644 libjava/classpath/gnu/java/security/key/KeyPairGeneratorFactory.java create mode 100644 libjava/classpath/gnu/java/security/key/dss/DSSKey.java create mode 100644 libjava/classpath/gnu/java/security/key/dss/DSSKeyPairGenerator.java create mode 100644 libjava/classpath/gnu/java/security/key/dss/DSSKeyPairPKCS8Codec.java create mode 100644 libjava/classpath/gnu/java/security/key/dss/DSSKeyPairRawCodec.java create mode 100644 libjava/classpath/gnu/java/security/key/dss/DSSKeyPairX509Codec.java create mode 100644 libjava/classpath/gnu/java/security/key/dss/DSSPrivateKey.java create mode 100644 libjava/classpath/gnu/java/security/key/dss/DSSPublicKey.java create mode 100644 libjava/classpath/gnu/java/security/key/dss/FIPS186.java create mode 100644 libjava/classpath/gnu/java/security/key/rsa/GnuRSAKey.java create mode 100644 libjava/classpath/gnu/java/security/key/rsa/GnuRSAPrivateKey.java create mode 100644 libjava/classpath/gnu/java/security/key/rsa/GnuRSAPublicKey.java create mode 100644 libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairGenerator.java create mode 100644 libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairPKCS8Codec.java create mode 100644 libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairRawCodec.java create mode 100644 libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairX509Codec.java create mode 100644 libjava/classpath/gnu/java/security/package.html create mode 100644 libjava/classpath/gnu/java/security/pkcs/PKCS7Data.java create mode 100644 libjava/classpath/gnu/java/security/pkcs/PKCS7SignedData.java create mode 100644 libjava/classpath/gnu/java/security/pkcs/SignerInfo.java create mode 100644 libjava/classpath/gnu/java/security/pkcs/package.html create mode 100644 libjava/classpath/gnu/java/security/prng/BasePRNG.java create mode 100644 libjava/classpath/gnu/java/security/prng/EntropySource.java create mode 100644 libjava/classpath/gnu/java/security/prng/IRandom.java create mode 100644 libjava/classpath/gnu/java/security/prng/LimitReachedException.java create mode 100644 libjava/classpath/gnu/java/security/prng/MDGenerator.java create mode 100644 libjava/classpath/gnu/java/security/prng/PRNGFactory.java create mode 100644 libjava/classpath/gnu/java/security/prng/RandomEvent.java create mode 100644 libjava/classpath/gnu/java/security/prng/RandomEventListener.java create mode 100644 libjava/classpath/gnu/java/security/provider/CollectionCertStoreImpl.java create mode 100644 libjava/classpath/gnu/java/security/provider/DefaultPolicy.java create mode 100644 libjava/classpath/gnu/java/security/provider/Gnu.java create mode 100644 libjava/classpath/gnu/java/security/provider/PKIXCertPathValidatorImpl.java create mode 100644 libjava/classpath/gnu/java/security/provider/X509CertificateFactory.java create mode 100644 libjava/classpath/gnu/java/security/provider/package.html create mode 100644 libjava/classpath/gnu/java/security/sig/BaseSignature.java create mode 100644 libjava/classpath/gnu/java/security/sig/ISignature.java create mode 100644 libjava/classpath/gnu/java/security/sig/ISignatureCodec.java create mode 100644 libjava/classpath/gnu/java/security/sig/SignatureCodecFactory.java create mode 100644 libjava/classpath/gnu/java/security/sig/SignatureFactory.java create mode 100644 libjava/classpath/gnu/java/security/sig/dss/DSSSignature.java create mode 100644 libjava/classpath/gnu/java/security/sig/dss/DSSSignatureRawCodec.java create mode 100644 libjava/classpath/gnu/java/security/sig/dss/DSSSignatureX509Codec.java create mode 100644 libjava/classpath/gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java create mode 100644 libjava/classpath/gnu/java/security/sig/rsa/EMSA_PKCS1_V1_5.java create mode 100644 libjava/classpath/gnu/java/security/sig/rsa/EMSA_PSS.java create mode 100644 libjava/classpath/gnu/java/security/sig/rsa/RSA.java create mode 100644 libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5Signature.java create mode 100644 libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureRawCodec.java create mode 100644 libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureX509Codec.java create mode 100644 libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignature.java create mode 100644 libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignatureRawCodec.java create mode 100644 libjava/classpath/gnu/java/security/sig/rsa/RSASignatureFactory.java create mode 100644 libjava/classpath/gnu/java/security/util/ByteArray.java create mode 100644 libjava/classpath/gnu/java/security/util/ByteBufferOutputStream.java create mode 100644 libjava/classpath/gnu/java/security/util/DerUtil.java create mode 100644 libjava/classpath/gnu/java/security/util/ExpirableObject.java create mode 100644 libjava/classpath/gnu/java/security/util/FormatUtil.java create mode 100644 libjava/classpath/gnu/java/security/util/IntegerUtil.java create mode 100644 libjava/classpath/gnu/java/security/util/PRNG.java create mode 100644 libjava/classpath/gnu/java/security/util/Prime.java create mode 100644 libjava/classpath/gnu/java/security/util/Sequence.java create mode 100644 libjava/classpath/gnu/java/security/util/SimpleList.java create mode 100644 libjava/classpath/gnu/java/security/util/Util.java create mode 100644 libjava/classpath/gnu/java/security/util/package.html create mode 100644 libjava/classpath/gnu/java/security/x509/GnuPKIExtension.java create mode 100644 libjava/classpath/gnu/java/security/x509/PolicyNodeImpl.java create mode 100644 libjava/classpath/gnu/java/security/x509/Util.java create mode 100644 libjava/classpath/gnu/java/security/x509/X500DistinguishedName.java create mode 100644 libjava/classpath/gnu/java/security/x509/X509CRL.java create mode 100644 libjava/classpath/gnu/java/security/x509/X509CRLEntry.java create mode 100644 libjava/classpath/gnu/java/security/x509/X509CRLSelectorImpl.java create mode 100644 libjava/classpath/gnu/java/security/x509/X509CertPath.java create mode 100644 libjava/classpath/gnu/java/security/x509/X509CertSelectorImpl.java create mode 100644 libjava/classpath/gnu/java/security/x509/X509Certificate.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/AuthorityKeyIdentifier.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/BasicConstraints.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/CRLNumber.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/CertificatePolicies.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/ExtendedKeyUsage.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/Extension.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/GeneralName.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/GeneralNames.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/GeneralSubtree.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/IssuerAlternativeNames.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/KeyUsage.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/NameConstraints.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/PolicyConstraint.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/PolicyMappings.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/PrivateKeyUsagePeriod.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/ReasonCode.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/SubjectAlternativeNames.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/SubjectKeyIdentifier.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/package.html create mode 100644 libjava/classpath/gnu/java/security/x509/package.html create mode 100644 libjava/classpath/gnu/java/text/AttributedFormatBuffer.java create mode 100644 libjava/classpath/gnu/java/text/BaseBreakIterator.java create mode 100644 libjava/classpath/gnu/java/text/CharacterBreakIterator.java create mode 100644 libjava/classpath/gnu/java/text/FormatBuffer.java create mode 100644 libjava/classpath/gnu/java/text/FormatCharacterIterator.java create mode 100644 libjava/classpath/gnu/java/text/LineBreakIterator.java create mode 100644 libjava/classpath/gnu/java/text/SentenceBreakIterator.java create mode 100644 libjava/classpath/gnu/java/text/StringFormatBuffer.java create mode 100644 libjava/classpath/gnu/java/text/WordBreakIterator.java create mode 100644 libjava/classpath/gnu/java/text/package.html create mode 100644 libjava/classpath/gnu/java/util/Base64.java create mode 100644 libjava/classpath/gnu/java/util/DoubleEnumeration.java create mode 100644 libjava/classpath/gnu/java/util/EmptyEnumeration.java create mode 100644 libjava/classpath/gnu/java/util/LRUCache.java create mode 100644 libjava/classpath/gnu/java/util/WeakIdentityHashMap.java create mode 100644 libjava/classpath/gnu/java/util/ZoneInfo.java create mode 100644 libjava/classpath/gnu/java/util/jar/JarUtils.java create mode 100644 libjava/classpath/gnu/java/util/package.html create mode 100644 libjava/classpath/gnu/java/util/prefs/FileBasedFactory.java create mode 100644 libjava/classpath/gnu/java/util/prefs/FileBasedPreferences.java create mode 100644 libjava/classpath/gnu/java/util/prefs/GConfBasedFactory.java create mode 100644 libjava/classpath/gnu/java/util/prefs/GConfBasedPreferences.java create mode 100644 libjava/classpath/gnu/java/util/prefs/MemoryBasedFactory.java create mode 100644 libjava/classpath/gnu/java/util/prefs/MemoryBasedPreferences.java create mode 100644 libjava/classpath/gnu/java/util/prefs/NodeReader.java create mode 100644 libjava/classpath/gnu/java/util/prefs/NodeWriter.java create mode 100644 libjava/classpath/gnu/java/util/prefs/gconf/GConfNativePeer.java create mode 100644 libjava/classpath/gnu/java/util/prefs/package.html create mode 100644 libjava/classpath/gnu/java/util/regex/BacktrackStack.java create mode 100644 libjava/classpath/gnu/java/util/regex/CharIndexed.java create mode 100644 libjava/classpath/gnu/java/util/regex/CharIndexedCharArray.java create mode 100644 libjava/classpath/gnu/java/util/regex/CharIndexedCharSequence.java create mode 100644 libjava/classpath/gnu/java/util/regex/CharIndexedInputStream.java create mode 100644 libjava/classpath/gnu/java/util/regex/CharIndexedString.java create mode 100644 libjava/classpath/gnu/java/util/regex/CharIndexedStringBuffer.java create mode 100644 libjava/classpath/gnu/java/util/regex/RE.java create mode 100644 libjava/classpath/gnu/java/util/regex/REException.java create mode 100644 libjava/classpath/gnu/java/util/regex/REFilterInputStream.java create mode 100644 libjava/classpath/gnu/java/util/regex/REMatch.java create mode 100644 libjava/classpath/gnu/java/util/regex/REMatchEnumeration.java create mode 100644 libjava/classpath/gnu/java/util/regex/RESyntax.java create mode 100644 libjava/classpath/gnu/java/util/regex/REToken.java create mode 100644 libjava/classpath/gnu/java/util/regex/RETokenAny.java create mode 100644 libjava/classpath/gnu/java/util/regex/RETokenBackRef.java create mode 100644 libjava/classpath/gnu/java/util/regex/RETokenChar.java create mode 100644 libjava/classpath/gnu/java/util/regex/RETokenEnd.java create mode 100644 libjava/classpath/gnu/java/util/regex/RETokenEndOfPreviousMatch.java create mode 100644 libjava/classpath/gnu/java/util/regex/RETokenEndSub.java create mode 100644 libjava/classpath/gnu/java/util/regex/RETokenIndependent.java create mode 100644 libjava/classpath/gnu/java/util/regex/RETokenLookAhead.java create mode 100644 libjava/classpath/gnu/java/util/regex/RETokenLookBehind.java create mode 100644 libjava/classpath/gnu/java/util/regex/RETokenNamedProperty.java create mode 100644 libjava/classpath/gnu/java/util/regex/RETokenOneOf.java create mode 100644 libjava/classpath/gnu/java/util/regex/RETokenPOSIX.java create mode 100644 libjava/classpath/gnu/java/util/regex/RETokenRange.java create mode 100644 libjava/classpath/gnu/java/util/regex/RETokenRepeated.java create mode 100644 libjava/classpath/gnu/java/util/regex/RETokenStart.java create mode 100644 libjava/classpath/gnu/java/util/regex/RETokenWordBoundary.java create mode 100644 libjava/classpath/gnu/java/util/regex/UncheckedRE.java create mode 100644 libjava/classpath/gnu/javax/activation/viewers/ImageViewer.java create mode 100644 libjava/classpath/gnu/javax/activation/viewers/TextEditor.java create mode 100644 libjava/classpath/gnu/javax/activation/viewers/TextViewer.java create mode 100644 libjava/classpath/gnu/javax/crypto/RSACipherImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/assembly/Assembly.java create mode 100644 libjava/classpath/gnu/javax/crypto/assembly/Cascade.java create mode 100644 libjava/classpath/gnu/javax/crypto/assembly/CascadeStage.java create mode 100644 libjava/classpath/gnu/javax/crypto/assembly/CascadeTransformer.java create mode 100644 libjava/classpath/gnu/javax/crypto/assembly/DeflateTransformer.java create mode 100644 libjava/classpath/gnu/javax/crypto/assembly/Direction.java create mode 100644 libjava/classpath/gnu/javax/crypto/assembly/LoopbackTransformer.java create mode 100644 libjava/classpath/gnu/javax/crypto/assembly/ModeStage.java create mode 100644 libjava/classpath/gnu/javax/crypto/assembly/Operation.java create mode 100644 libjava/classpath/gnu/javax/crypto/assembly/PaddingTransformer.java create mode 100644 libjava/classpath/gnu/javax/crypto/assembly/Stage.java create mode 100644 libjava/classpath/gnu/javax/crypto/assembly/Transformer.java create mode 100644 libjava/classpath/gnu/javax/crypto/assembly/TransformerException.java create mode 100644 libjava/classpath/gnu/javax/crypto/cipher/Anubis.java create mode 100644 libjava/classpath/gnu/javax/crypto/cipher/BaseCipher.java create mode 100644 libjava/classpath/gnu/javax/crypto/cipher/Blowfish.java create mode 100644 libjava/classpath/gnu/javax/crypto/cipher/Cast5.java create mode 100644 libjava/classpath/gnu/javax/crypto/cipher/CipherFactory.java create mode 100644 libjava/classpath/gnu/javax/crypto/cipher/DES.java create mode 100644 libjava/classpath/gnu/javax/crypto/cipher/IBlockCipher.java create mode 100644 libjava/classpath/gnu/javax/crypto/cipher/IBlockCipherSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/cipher/Khazad.java create mode 100644 libjava/classpath/gnu/javax/crypto/cipher/NullCipher.java create mode 100644 libjava/classpath/gnu/javax/crypto/cipher/Rijndael.java create mode 100644 libjava/classpath/gnu/javax/crypto/cipher/Serpent.java create mode 100644 libjava/classpath/gnu/javax/crypto/cipher/Square.java create mode 100644 libjava/classpath/gnu/javax/crypto/cipher/TripleDES.java create mode 100644 libjava/classpath/gnu/javax/crypto/cipher/Twofish.java create mode 100644 libjava/classpath/gnu/javax/crypto/cipher/WeakKeyException.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/DiffieHellmanImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/GnuCrypto.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/GnuSasl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/PBKDF2SecretKeyFactory.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/AES128KeyWrapSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/AES192KeyWrapSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/AES256KeyWrapSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/AESKeyWrapSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/AESSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/ARCFourSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/AnubisSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/BlowfishSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/Cast5Spi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/CipherAdapter.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/DESSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/KeyWrappingAlgorithmAdapter.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/KhazadSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/NullCipherSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/PBES2.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/RijndaelSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/SerpentSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/SquareSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/TripleDESKeyWrapSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/TripleDESSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/cipher/TwofishSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/AnubisKeyGeneratorImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/AnubisSecretKeyFactoryImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/BlowfishKeyGeneratorImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/BlowfishSecretKeyFactoryImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/Cast5KeyGeneratorImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/Cast5SecretKeyFactoryImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/DESKeyGeneratorImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/DESSecretKeyFactoryImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/DESedeSecretKeyFactoryImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/KhazadKeyGeneratorImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/KhazadSecretKeyFactoryImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/RijndaelKeyGeneratorImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/RijndaelSecretKeyFactoryImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/SecretKeyFactoryImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/SecretKeyGeneratorImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/SerpentKeyGeneratorImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/SerpentSecretKeyFactoryImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/SquareKeyGeneratorImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/SquareSecretKeyFactoryImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/TripleDESKeyGeneratorImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/TwofishKeyGeneratorImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/key/TwofishSecretKeyFactoryImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/keyring/GnuKeyring.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/HMacHavalSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD2Spi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD4Spi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD5Spi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/HMacRipeMD128Spi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/HMacRipeMD160Spi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA160Spi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA256Spi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA384Spi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA512Spi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/HMacTigerSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/HMacWhirlpoolSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/MacAdapter.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/OMacAnubisImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/OMacBlowfishImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/OMacCast5Impl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/OMacDESImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/OMacImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/OMacKhazadImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/OMacRijndaelImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/OMacSerpentImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/OMacSquareImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/OMacTripleDESImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/OMacTwofishImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/TMMH16Spi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/UHash32Spi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/mac/UMac32Spi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/params/BlockCipherParameters.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/params/DEREncodingException.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/params/DERReader.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/params/DERWriter.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/prng/CSPRNGSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/prng/FortunaImpl.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/prng/ICMRandomSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/prng/UMacRandomSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/sig/DHKeyFactory.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/sig/DHKeyPairGeneratorSpi.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/sig/DHParameters.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/sig/DHParametersGenerator.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/spec/BlockCipherParameterSpec.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/spec/TMMHParameterSpec.java create mode 100644 libjava/classpath/gnu/javax/crypto/jce/spec/UMac32ParameterSpec.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/BaseKeyAgreementParty.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/GnuPBEKey.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/GnuSecretKey.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/IKeyAgreementParty.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/IncomingMessage.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/KeyAgreementException.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/KeyAgreementFactory.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/OutgoingMessage.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairPKCS8Codec.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairRawCodec.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairX509Codec.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanKeyAgreement.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanReceiver.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanSender.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/dh/ElGamalKeyAgreement.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/dh/ElGamalReceiver.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/dh/ElGamalSender.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/dh/GnuDHKey.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/dh/GnuDHPrivateKey.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/dh/GnuDHPublicKey.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/dh/RFC2631.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/srp6/SRP6Host.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/srp6/SRP6KeyAgreement.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/srp6/SRP6SaslClient.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/srp6/SRP6SaslServer.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/srp6/SRP6TLSClient.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/srp6/SRP6TLSServer.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/srp6/SRP6User.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/srp6/SRPAlgorithm.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/srp6/SRPKey.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/srp6/SRPKeyPairGenerator.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/srp6/SRPKeyPairRawCodec.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/srp6/SRPPrivateKey.java create mode 100644 libjava/classpath/gnu/javax/crypto/key/srp6/SRPPublicKey.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/AuthenticatedEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/BaseKeyring.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/BinaryDataEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/CertPathEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/CertificateEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/CompressedEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/EncryptedEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/Entry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/EnvelopeEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/GnuPrivateKeyring.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/GnuPublicKeyring.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/IKeyring.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/IPrivateKeyring.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/IPublicKeyring.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/MalformedKeyringException.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/MeteredInputStream.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/PasswordEncryptedEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/PasswordProtectedEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/PrimitiveEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/PrivateKeyEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/Properties.java create mode 100644 libjava/classpath/gnu/javax/crypto/keyring/PublicKeyEntry.java create mode 100644 libjava/classpath/gnu/javax/crypto/kwa/AESKeyWrap.java create mode 100644 libjava/classpath/gnu/javax/crypto/kwa/BaseKeyWrappingAlgorithm.java create mode 100644 libjava/classpath/gnu/javax/crypto/kwa/IKeyWrappingAlgorithm.java create mode 100644 libjava/classpath/gnu/javax/crypto/kwa/KeyUnwrappingException.java create mode 100644 libjava/classpath/gnu/javax/crypto/kwa/KeyWrappingAlgorithmFactory.java create mode 100644 libjava/classpath/gnu/javax/crypto/kwa/TripleDESKeyWrap.java create mode 100644 libjava/classpath/gnu/javax/crypto/mac/BaseMac.java create mode 100644 libjava/classpath/gnu/javax/crypto/mac/HMac.java create mode 100644 libjava/classpath/gnu/javax/crypto/mac/HMacFactory.java create mode 100644 libjava/classpath/gnu/javax/crypto/mac/IMac.java create mode 100644 libjava/classpath/gnu/javax/crypto/mac/MacFactory.java create mode 100644 libjava/classpath/gnu/javax/crypto/mac/MacInputStream.java create mode 100644 libjava/classpath/gnu/javax/crypto/mac/MacOutputStream.java create mode 100644 libjava/classpath/gnu/javax/crypto/mac/OMAC.java create mode 100644 libjava/classpath/gnu/javax/crypto/mac/TMMH16.java create mode 100644 libjava/classpath/gnu/javax/crypto/mac/UHash32.java create mode 100644 libjava/classpath/gnu/javax/crypto/mac/UMac32.java create mode 100644 libjava/classpath/gnu/javax/crypto/mode/BaseMode.java create mode 100644 libjava/classpath/gnu/javax/crypto/mode/CBC.java create mode 100644 libjava/classpath/gnu/javax/crypto/mode/CFB.java create mode 100644 libjava/classpath/gnu/javax/crypto/mode/CTR.java create mode 100644 libjava/classpath/gnu/javax/crypto/mode/EAX.java create mode 100644 libjava/classpath/gnu/javax/crypto/mode/ECB.java create mode 100644 libjava/classpath/gnu/javax/crypto/mode/IAuthenticatedMode.java create mode 100644 libjava/classpath/gnu/javax/crypto/mode/ICM.java create mode 100644 libjava/classpath/gnu/javax/crypto/mode/IMode.java create mode 100644 libjava/classpath/gnu/javax/crypto/mode/ModeFactory.java create mode 100644 libjava/classpath/gnu/javax/crypto/mode/OFB.java create mode 100644 libjava/classpath/gnu/javax/crypto/pad/BasePad.java create mode 100644 libjava/classpath/gnu/javax/crypto/pad/IPad.java create mode 100644 libjava/classpath/gnu/javax/crypto/pad/ISO10126.java create mode 100644 libjava/classpath/gnu/javax/crypto/pad/PKCS1_V1_5.java create mode 100644 libjava/classpath/gnu/javax/crypto/pad/PKCS7.java create mode 100644 libjava/classpath/gnu/javax/crypto/pad/PadFactory.java create mode 100644 libjava/classpath/gnu/javax/crypto/pad/SSL3.java create mode 100644 libjava/classpath/gnu/javax/crypto/pad/TBC.java create mode 100644 libjava/classpath/gnu/javax/crypto/pad/TLS1.java create mode 100644 libjava/classpath/gnu/javax/crypto/pad/WrongPaddingException.java create mode 100644 libjava/classpath/gnu/javax/crypto/prng/ARCFour.java create mode 100644 libjava/classpath/gnu/javax/crypto/prng/CSPRNG.java create mode 100644 libjava/classpath/gnu/javax/crypto/prng/Fortuna.java create mode 100644 libjava/classpath/gnu/javax/crypto/prng/ICMGenerator.java create mode 100644 libjava/classpath/gnu/javax/crypto/prng/IPBE.java create mode 100644 libjava/classpath/gnu/javax/crypto/prng/PBKDF2.java create mode 100644 libjava/classpath/gnu/javax/crypto/prng/PRNGFactory.java create mode 100644 libjava/classpath/gnu/javax/crypto/prng/UMacGenerator.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/AuthInfo.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/AuthInfoProviderFactory.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/ClientFactory.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/ClientMechanism.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/ConfidentialityException.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/IAuthInfoProvider.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/IAuthInfoProviderFactory.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/IllegalMechanismStateException.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/InputBuffer.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/IntegrityException.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/NoSuchMechanismException.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/NoSuchUserException.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/OutputBuffer.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/SaslEncodingException.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/SaslInputStream.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/SaslOutputStream.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/SaslUtil.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/ServerFactory.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/ServerMechanism.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/UserAlreadyExistsException.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousClient.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousServer.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousUtil.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5AuthInfoProvider.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Client.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Registry.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Server.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Util.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/crammd5/PasswordFile.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/plain/PasswordFile.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/plain/PlainAuthInfoProvider.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/plain/PlainClient.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/plain/PlainRegistry.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/plain/PlainServer.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/srp/CALG.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/srp/ClientStore.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/srp/IALG.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/srp/KDF.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/srp/PasswordFile.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/srp/SRP.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/srp/SRPAuthInfoProvider.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/srp/SRPClient.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/srp/SRPRegistry.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/srp/SRPServer.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/srp/SecurityContext.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/srp/ServerStore.java create mode 100644 libjava/classpath/gnu/javax/crypto/sasl/srp/StoreEntry.java create mode 100644 libjava/classpath/gnu/javax/imageio/IIOInputStream.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/BMPDecoder.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/BMPEncoder.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/BMPException.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/BMPFileHeader.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/BMPImageReader.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/BMPImageReaderSpi.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/BMPImageWriter.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/BMPImageWriterSpi.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/BMPInfoHeader.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/DecodeBF16.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/DecodeBF32.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/DecodeRGB1.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/DecodeRGB24.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/DecodeRGB4.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/DecodeRGB8.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/DecodeRLE4.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/DecodeRLE8.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB1.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB16.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB24.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB32.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB4.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB8.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/EncodeRLE4.java create mode 100644 libjava/classpath/gnu/javax/imageio/bmp/EncodeRLE8.java create mode 100644 libjava/classpath/gnu/javax/imageio/gif/GIFFile.java create mode 100644 libjava/classpath/gnu/javax/imageio/gif/GIFImageReader.java create mode 100644 libjava/classpath/gnu/javax/imageio/gif/GIFImageReaderSpi.java create mode 100644 libjava/classpath/gnu/javax/imageio/jpeg/DCT.java create mode 100644 libjava/classpath/gnu/javax/imageio/jpeg/HuffmanTable.java create mode 100644 libjava/classpath/gnu/javax/imageio/jpeg/JPEGComponent.java create mode 100644 libjava/classpath/gnu/javax/imageio/jpeg/JPEGDecoder.java create mode 100644 libjava/classpath/gnu/javax/imageio/jpeg/JPEGException.java create mode 100644 libjava/classpath/gnu/javax/imageio/jpeg/JPEGFrame.java create mode 100644 libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageInputStream.java create mode 100644 libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageReader.java create mode 100644 libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageReaderSpi.java create mode 100644 libjava/classpath/gnu/javax/imageio/jpeg/JPEGMarker.java create mode 100644 libjava/classpath/gnu/javax/imageio/jpeg/JPEGMarkerFoundException.java create mode 100644 libjava/classpath/gnu/javax/imageio/jpeg/JPEGScan.java create mode 100644 libjava/classpath/gnu/javax/imageio/jpeg/YCbCr_ColorSpace.java create mode 100644 libjava/classpath/gnu/javax/imageio/jpeg/ZigZag.java create mode 100644 libjava/classpath/gnu/javax/imageio/png/PNGChunk.java create mode 100644 libjava/classpath/gnu/javax/imageio/png/PNGData.java create mode 100644 libjava/classpath/gnu/javax/imageio/png/PNGDecoder.java create mode 100644 libjava/classpath/gnu/javax/imageio/png/PNGEncoder.java create mode 100644 libjava/classpath/gnu/javax/imageio/png/PNGException.java create mode 100644 libjava/classpath/gnu/javax/imageio/png/PNGFile.java create mode 100644 libjava/classpath/gnu/javax/imageio/png/PNGFilter.java create mode 100644 libjava/classpath/gnu/javax/imageio/png/PNGGamma.java create mode 100644 libjava/classpath/gnu/javax/imageio/png/PNGHeader.java create mode 100644 libjava/classpath/gnu/javax/imageio/png/PNGICCProfile.java create mode 100644 libjava/classpath/gnu/javax/imageio/png/PNGImageReader.java create mode 100644 libjava/classpath/gnu/javax/imageio/png/PNGImageReaderSpi.java create mode 100644 libjava/classpath/gnu/javax/imageio/png/PNGPalette.java create mode 100644 libjava/classpath/gnu/javax/imageio/png/PNGPhys.java create mode 100644 libjava/classpath/gnu/javax/imageio/png/PNGTime.java create mode 100644 libjava/classpath/gnu/javax/management/ListenerData.java create mode 100644 libjava/classpath/gnu/javax/management/Server.java create mode 100644 libjava/classpath/gnu/javax/management/Translator.java create mode 100644 libjava/classpath/gnu/javax/naming/giop/ContextContinuation.java create mode 100644 libjava/classpath/gnu/javax/naming/giop/CorbalocParser.java create mode 100644 libjava/classpath/gnu/javax/naming/giop/GiopNamingEnumeration.java create mode 100644 libjava/classpath/gnu/javax/naming/giop/GiopNamingServiceFactory.java create mode 100644 libjava/classpath/gnu/javax/naming/giop/GiopNamingServiceURLContext.java create mode 100644 libjava/classpath/gnu/javax/naming/giop/ListBindingsEnumeration.java create mode 100644 libjava/classpath/gnu/javax/naming/giop/ListEnumeration.java create mode 100644 libjava/classpath/gnu/javax/naming/ictxImpl/trans/GnuName.java create mode 100644 libjava/classpath/gnu/javax/naming/jndi/url/corbaname/corbanameURLContextFactory.java create mode 100644 libjava/classpath/gnu/javax/naming/jndi/url/rmi/ContextContinuation.java create mode 100644 libjava/classpath/gnu/javax/naming/jndi/url/rmi/ListBindingsEnumeration.java create mode 100644 libjava/classpath/gnu/javax/naming/jndi/url/rmi/ListEnumeration.java create mode 100644 libjava/classpath/gnu/javax/naming/jndi/url/rmi/RmiContinuation.java create mode 100644 libjava/classpath/gnu/javax/naming/jndi/url/rmi/RmiNamingEnumeration.java create mode 100644 libjava/classpath/gnu/javax/naming/jndi/url/rmi/rmiURLContext.java create mode 100644 libjava/classpath/gnu/javax/naming/jndi/url/rmi/rmiURLContextFactory.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/AbstractSessionContext.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/EntropySource.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/NullManagerParameters.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/PreSharedKeyManager.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/PreSharedKeyManagerParameters.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/PrivateCredentials.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/SRPManagerParameters.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/SRPTrustManager.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/SSLCipherSuite.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/SSLProtocolVersion.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/SSLRecordHandler.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/Session.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/SessionStoreException.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/StaticTrustAnchors.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/AbstractHandshake.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/Alert.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/AlertException.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/Builder.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/Certificate.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/CertificateBuilder.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequest.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequestBuilder.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/CertificateStatusRequest.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/CertificateStatusType.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/CertificateType.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/CertificateURL.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/CertificateVerify.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/CipherAlgorithm.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/CipherSuite.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/CipherSuiteList.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ClientCertificateTypeList.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ClientDiffieHellmanPublic.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ClientHandshake.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ClientHello.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ClientHelloBuilder.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ClientHelloV2.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchange.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchangeBuilder.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ClientPSKParameters.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethod.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethodList.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/Constructed.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ContentType.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/Debug.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/DelegatedTask.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/DiffieHellman.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/EmptyExchangeKeys.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ExchangeKeys.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/Extension.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ExtensionList.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/Finished.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/Handshake.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/HelloRequest.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/InputSecurityParameters.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/Jessie.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/KeyExchangeAlgorithm.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/MacAlgorithm.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/MacException.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/MaxFragmentLength.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/OutputSecurityParameters.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/PreSharedKeyManagerFactoryImpl.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ProtocolVersion.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/Random.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/Record.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/SRPTrustManagerFactory.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/SSLContextImpl.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/SSLEngineImpl.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/SSLHMac.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/SSLRSASignatureImpl.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/SSLRandom.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketFactoryImpl.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketImpl.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketFactoryImpl.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketImpl.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/SSLv3HMacMD5Impl.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/SSLv3HMacSHAImpl.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ServerDHParams.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ServerHandshake.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ServerHello.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ServerHelloBuilder.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ServerHelloDone.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchange.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchangeBuilder.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchangeParams.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ServerNameList.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ServerPSKParameters.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ServerRSAParams.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/ServerRSA_PSKParameters.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/SessionImpl.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/Signature.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/SignatureAlgorithm.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/SimpleSessionContext.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/TLSHMac.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/TLSRandom.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/TruncatedHMAC.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/TrustedAuthorities.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/Util.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/X500PrincipalList.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java create mode 100644 libjava/classpath/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java create mode 100644 libjava/classpath/gnu/javax/print/CupsIppOperation.java create mode 100644 libjava/classpath/gnu/javax/print/CupsMediaMapping.java create mode 100644 libjava/classpath/gnu/javax/print/CupsPrintService.java create mode 100644 libjava/classpath/gnu/javax/print/CupsPrintServiceLookup.java create mode 100644 libjava/classpath/gnu/javax/print/CupsServer.java create mode 100644 libjava/classpath/gnu/javax/print/PrintAttributeException.java create mode 100644 libjava/classpath/gnu/javax/print/PrintFlavorException.java create mode 100644 libjava/classpath/gnu/javax/print/PrintUriException.java create mode 100644 libjava/classpath/gnu/javax/print/PrinterDialog.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/DocPrintJobImpl.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/IppDelimiterTag.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/IppException.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/IppMultiDocPrintService.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/IppPrintService.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/IppRequest.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/IppResponse.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/IppStatusCode.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/IppUtilities.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/IppValueTag.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/MultiDocPrintJobImpl.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/CharsetSyntax.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/DefaultValueAttribute.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/DetailedStatusMessage.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/DocumentAccessError.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/NaturalLanguageSyntax.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/RequestedAttributes.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/StatusMessage.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/UnknownAttribute.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/defaults/CopiesDefault.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/defaults/DocumentFormatDefault.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/defaults/FinishingsDefault.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/defaults/JobHoldUntilDefault.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/defaults/JobPriorityDefault.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/defaults/JobSheetsDefault.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/defaults/MediaDefault.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/defaults/MultipleDocumentHandlingDefault.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/defaults/NumberUpDefault.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/defaults/OrientationRequestedDefault.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/defaults/PrintQualityDefault.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/defaults/PrinterResolutionDefault.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/defaults/SidesDefault.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/job/AttributesCharset.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/job/AttributesNaturalLanguage.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/job/JobDetailedStatusMessages.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/job/JobDocumentAccessErrors.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/job/JobId.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/job/JobMoreInfo.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/job/JobPrinterUri.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/job/JobStateMessage.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/job/JobUri.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/printer/CharsetConfigured.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/printer/DocumentFormat.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/printer/MultipleOperationTimeOut.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/printer/NaturalLanguageConfigured.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterCurrentTime.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterDriverInstaller.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterStateMessage.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterUpTime.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/CharsetSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/CompressionSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/DocumentFormatSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/FinishingsSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/GeneratedNaturalLanguageSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/IppVersionsSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/JobHoldUntilSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/JobSheetsSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/MediaSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/MultipleDocumentHandlingSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/MultipleDocumentJobsSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/OperationsSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/OrientationRequestedSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/PageRangesSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/PrintQualitySupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/PrinterResolutionSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/PrinterUriSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/SidesSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/UriAuthenticationSupported.java create mode 100644 libjava/classpath/gnu/javax/print/ipp/attribute/supported/UriSecuritySupported.java create mode 100644 libjava/classpath/gnu/javax/rmi/CORBA/CorbaInput.java create mode 100644 libjava/classpath/gnu/javax/rmi/CORBA/CorbaOutput.java create mode 100644 libjava/classpath/gnu/javax/rmi/CORBA/DefaultWriteObjectTester.java create mode 100644 libjava/classpath/gnu/javax/rmi/CORBA/DelegateFactory.java create mode 100644 libjava/classpath/gnu/javax/rmi/CORBA/GetDelegateInstanceException.java create mode 100644 libjava/classpath/gnu/javax/rmi/CORBA/PortableRemoteObjectDelegateImpl.java create mode 100644 libjava/classpath/gnu/javax/rmi/CORBA/RmiUtilities.java create mode 100644 libjava/classpath/gnu/javax/rmi/CORBA/StubDelegateImpl.java create mode 100644 libjava/classpath/gnu/javax/rmi/CORBA/TieTargetRecord.java create mode 100644 libjava/classpath/gnu/javax/rmi/CORBA/UtilDelegateImpl.java create mode 100644 libjava/classpath/gnu/javax/rmi/CORBA/ValueHandlerDelegateImpl.java create mode 100644 libjava/classpath/gnu/javax/security/auth/Password.java create mode 100644 libjava/classpath/gnu/javax/security/auth/callback/AWTCallbackHandler.java create mode 100644 libjava/classpath/gnu/javax/security/auth/callback/AbstractCallbackHandler.java create mode 100644 libjava/classpath/gnu/javax/security/auth/callback/CertificateCallback.java create mode 100644 libjava/classpath/gnu/javax/security/auth/callback/ConsoleCallbackHandler.java create mode 100644 libjava/classpath/gnu/javax/security/auth/callback/DefaultCallbackHandler.java create mode 100644 libjava/classpath/gnu/javax/security/auth/callback/GnuCallbacks.java create mode 100644 libjava/classpath/gnu/javax/security/auth/callback/SwingCallbackHandler.java create mode 100644 libjava/classpath/gnu/javax/security/auth/login/ConfigFileParser.java create mode 100644 libjava/classpath/gnu/javax/security/auth/login/ConfigFileTokenizer.java create mode 100644 libjava/classpath/gnu/javax/security/auth/login/GnuConfiguration.java create mode 100644 libjava/classpath/gnu/javax/sound/AudioSecurityManager.java create mode 100644 libjava/classpath/gnu/javax/sound/midi/alsa/AlsaInputPortDevice.java create mode 100644 libjava/classpath/gnu/javax/sound/midi/alsa/AlsaMidiDeviceProvider.java create mode 100644 libjava/classpath/gnu/javax/sound/midi/alsa/AlsaMidiSequencerDevice.java create mode 100644 libjava/classpath/gnu/javax/sound/midi/alsa/AlsaOutputPortDevice.java create mode 100644 libjava/classpath/gnu/javax/sound/midi/alsa/AlsaPortDevice.java create mode 100644 libjava/classpath/gnu/javax/sound/midi/dssi/DSSIMidiDeviceProvider.java create mode 100644 libjava/classpath/gnu/javax/sound/midi/dssi/DSSISynthesizer.java create mode 100644 libjava/classpath/gnu/javax/sound/midi/file/ExtendedMidiFileFormat.java create mode 100644 libjava/classpath/gnu/javax/sound/midi/file/MidiDataInputStream.java create mode 100644 libjava/classpath/gnu/javax/sound/midi/file/MidiDataOutputStream.java create mode 100644 libjava/classpath/gnu/javax/sound/midi/file/MidiFileReader.java create mode 100644 libjava/classpath/gnu/javax/sound/midi/file/MidiFileWriter.java create mode 100644 libjava/classpath/gnu/javax/sound/sampled/AU/AUReader.java create mode 100644 libjava/classpath/gnu/javax/sound/sampled/WAV/WAVReader.java create mode 100644 libjava/classpath/gnu/javax/sound/sampled/gstreamer/GStreamerMixer.java create mode 100644 libjava/classpath/gnu/javax/sound/sampled/gstreamer/GStreamerMixerProvider.java create mode 100644 libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReader.java create mode 100644 libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReaderNativePeer.java create mode 100644 libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileWriter.java create mode 100644 libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstInputStream.java create mode 100644 libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstDataLine.java create mode 100644 libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstNativeDataLine.java create mode 100644 libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstPipeline.java create mode 100644 libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstSourceDataLine.java create mode 100644 libjava/classpath/gnu/javax/swing/plaf/gnu/GNULookAndFeel.java create mode 100644 libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Error.png create mode 100644 libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Inform.png create mode 100644 libjava/classpath/gnu/javax/swing/plaf/gtk/icons/JavaCup.png create mode 100644 libjava/classpath/gnu/javax/swing/plaf/gtk/icons/JavaCupLarge.png create mode 100644 libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Question.png create mode 100644 libjava/classpath/gnu/javax/swing/plaf/gtk/icons/README create mode 100644 libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeClosed.png create mode 100644 libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeLeaf-normal.png create mode 100644 libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeLeaf.png create mode 100644 libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeOpen.png create mode 100644 libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Warn.png create mode 100644 libjava/classpath/gnu/javax/swing/plaf/gtk/icons/file-folders.png create mode 100644 libjava/classpath/gnu/javax/swing/plaf/gtk/icons/slider.png create mode 100644 libjava/classpath/gnu/javax/swing/plaf/metal/CustomizableTheme.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/CharacterAttributeTranslator.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/CombinedAttributes.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/ImageViewIconFactory.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/css/BorderStyle.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/css/BorderWidth.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/css/CSSColor.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/css/CSSLexicalException.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/css/CSSParser.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/css/CSSParserCallback.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/css/CSSParserException.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/css/CSSScanner.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/css/FontSize.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/css/FontStyle.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/css/FontWeight.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/css/Length.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/css/Selector.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/package.html create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/GnuParserDelegator.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/HTML_401F.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/SmallHtmlAttributeSet.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/gnuDTD.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/htmlAttributeSet.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/htmlValidator.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/models/PCDATAonly_model.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/models/TableRowContentModel.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/models/list.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/models/noTagModel.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/models/node.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/models/package.html create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/models/transformer.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/package.html create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/support/Parser.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/support/gnuStringIntMapper.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Buffer.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Constants.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Location.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/support/low/ParseException.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Queue.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/support/low/ReaderTokenizer.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Token.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/support/low/node.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/support/low/package.html create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/support/low/pattern.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/support/package.html create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/support/parameterDefaulter.java create mode 100644 libjava/classpath/gnu/javax/swing/text/html/parser/support/textPreProcessor.java create mode 100644 libjava/classpath/gnu/javax/swing/tree/GnuPath.java create mode 100644 libjava/classpath/gnu/test/.cvsignore create mode 100644 libjava/classpath/gnu/test/Fail.java create mode 100644 libjava/classpath/gnu/test/Makefile.am create mode 100644 libjava/classpath/gnu/test/Pass.java create mode 100644 libjava/classpath/gnu/test/Result.java create mode 100644 libjava/classpath/gnu/test/Test.java create mode 100644 libjava/classpath/gnu/test/Unresolved.java create mode 100644 libjava/classpath/gnu/test/Unsupported.java create mode 100644 libjava/classpath/gnu/test/Untested.java create mode 100644 libjava/classpath/gnu/test/XFail.java create mode 100644 libjava/classpath/gnu/test/XPass.java create mode 100644 libjava/classpath/gnu/xml/aelfred2/JAXPFactory.java create mode 100644 libjava/classpath/gnu/xml/aelfred2/SAXDriver.java create mode 100644 libjava/classpath/gnu/xml/aelfred2/XmlParser.java create mode 100644 libjava/classpath/gnu/xml/aelfred2/XmlReader.java create mode 100644 libjava/classpath/gnu/xml/aelfred2/package.html create mode 100644 libjava/classpath/gnu/xml/dom/Consumer.java create mode 100644 libjava/classpath/gnu/xml/dom/DTDAttributeTypeInfo.java create mode 100644 libjava/classpath/gnu/xml/dom/DTDElementTypeInfo.java create mode 100644 libjava/classpath/gnu/xml/dom/DomAttr.java create mode 100644 libjava/classpath/gnu/xml/dom/DomCDATASection.java create mode 100644 libjava/classpath/gnu/xml/dom/DomCharacterData.java create mode 100644 libjava/classpath/gnu/xml/dom/DomComment.java create mode 100644 libjava/classpath/gnu/xml/dom/DomDOMException.java create mode 100644 libjava/classpath/gnu/xml/dom/DomDoctype.java create mode 100644 libjava/classpath/gnu/xml/dom/DomDocument.java create mode 100644 libjava/classpath/gnu/xml/dom/DomDocumentBuilder.java create mode 100644 libjava/classpath/gnu/xml/dom/DomDocumentBuilderFactory.java create mode 100644 libjava/classpath/gnu/xml/dom/DomDocumentConfiguration.java create mode 100644 libjava/classpath/gnu/xml/dom/DomDocumentFragment.java create mode 100644 libjava/classpath/gnu/xml/dom/DomElement.java create mode 100644 libjava/classpath/gnu/xml/dom/DomEntity.java create mode 100644 libjava/classpath/gnu/xml/dom/DomEntityReference.java create mode 100644 libjava/classpath/gnu/xml/dom/DomEvent.java create mode 100644 libjava/classpath/gnu/xml/dom/DomExtern.java create mode 100644 libjava/classpath/gnu/xml/dom/DomImpl.java create mode 100644 libjava/classpath/gnu/xml/dom/DomIterator.java create mode 100644 libjava/classpath/gnu/xml/dom/DomNSResolverContext.java create mode 100644 libjava/classpath/gnu/xml/dom/DomNamedNodeMap.java create mode 100644 libjava/classpath/gnu/xml/dom/DomNode.java create mode 100644 libjava/classpath/gnu/xml/dom/DomNodeIterator.java create mode 100644 libjava/classpath/gnu/xml/dom/DomNotation.java create mode 100644 libjava/classpath/gnu/xml/dom/DomNsNode.java create mode 100644 libjava/classpath/gnu/xml/dom/DomProcessingInstruction.java create mode 100644 libjava/classpath/gnu/xml/dom/DomText.java create mode 100644 libjava/classpath/gnu/xml/dom/DomXPathExpression.java create mode 100644 libjava/classpath/gnu/xml/dom/DomXPathNSResolver.java create mode 100644 libjava/classpath/gnu/xml/dom/DomXPathResult.java create mode 100644 libjava/classpath/gnu/xml/dom/ImplementationList.java create mode 100644 libjava/classpath/gnu/xml/dom/ImplementationSource.java create mode 100644 libjava/classpath/gnu/xml/dom/JAXPFactory.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLAnchorElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLAppletElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLAreaElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLBRElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLBaseElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLBaseFontElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLBodyElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLButtonElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLCollection.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLDListElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLDirectoryElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLDivElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLDocument.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLEmbedElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLFieldSetElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLFontElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLFormElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLFrameElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLFrameSetElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLHRElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLHeadElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLHeadingElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLHtmlElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLIFrameElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLImageElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLImpl.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLInputElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLIsIndexElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLLIElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLLabelElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLLegendElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLLinkElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLMapElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLMenuElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLMetaElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLModElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLOListElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLObjectElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLOptGroupElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLOptionElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLParagraphElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLParamElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLParser.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLPreElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLQuoteElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLScriptElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLSelectElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLStyleElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLTableCaptionElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLTableCellElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLTableColElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLTableElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLTableRowElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLTableSectionElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLTextAreaElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLTitleElement.java create mode 100644 libjava/classpath/gnu/xml/dom/html2/DomHTMLUListElement.java create mode 100644 libjava/classpath/gnu/xml/dom/ls/DomLSException.java create mode 100644 libjava/classpath/gnu/xml/dom/ls/DomLSInput.java create mode 100644 libjava/classpath/gnu/xml/dom/ls/DomLSOutput.java create mode 100644 libjava/classpath/gnu/xml/dom/ls/DomLSParser.java create mode 100644 libjava/classpath/gnu/xml/dom/ls/DomLSSerializer.java create mode 100644 libjava/classpath/gnu/xml/dom/ls/FilteredSAXEventSink.java create mode 100644 libjava/classpath/gnu/xml/dom/ls/ReaderInputStream.java create mode 100644 libjava/classpath/gnu/xml/dom/ls/SAXEventSink.java create mode 100644 libjava/classpath/gnu/xml/dom/ls/WriterOutputStream.java create mode 100644 libjava/classpath/gnu/xml/dom/package.html create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeAttr.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeCDATASection.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeCharacterData.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeComment.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeDOMException.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeDOMStringList.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocument.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentBuilder.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentBuilderFactory.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentFragment.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentType.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeElement.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeEntity.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeEntityReference.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeNamedNodeMap.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeNode.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeNodeList.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeNotation.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeProcessingInstruction.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeText.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeTypeInfo.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathExpression.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathNSResolver.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathNodeList.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathResult.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/sax/GnomeLocator.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/sax/GnomeSAXParser.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/sax/GnomeSAXParserFactory.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/sax/GnomeXMLReader.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/sax/Namespaces.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/sax/StringArrayAttributes.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/sax/XMLName.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/transform/ErrorListenerErrorHandler.java create mode 100755 libjava/classpath/gnu/xml/libxmlj/transform/GnomeTransformer.java create mode 100755 libjava/classpath/gnu/xml/libxmlj/transform/GnomeTransformerFactory.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/transform/URIResolverEntityResolver.java create mode 100755 libjava/classpath/gnu/xml/libxmlj/transform/package.html create mode 100644 libjava/classpath/gnu/xml/libxmlj/util/EmptyNodeList.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/util/NamedInputStream.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/util/StandaloneDocumentType.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/util/StandaloneLocator.java create mode 100644 libjava/classpath/gnu/xml/libxmlj/util/XMLJ.java create mode 100644 libjava/classpath/gnu/xml/pipeline/CallFilter.java create mode 100644 libjava/classpath/gnu/xml/pipeline/DomConsumer.java create mode 100644 libjava/classpath/gnu/xml/pipeline/EventConsumer.java create mode 100644 libjava/classpath/gnu/xml/pipeline/EventFilter.java create mode 100644 libjava/classpath/gnu/xml/pipeline/LinkFilter.java create mode 100644 libjava/classpath/gnu/xml/pipeline/NSFilter.java create mode 100644 libjava/classpath/gnu/xml/pipeline/PipelineFactory.java create mode 100644 libjava/classpath/gnu/xml/pipeline/TeeConsumer.java create mode 100644 libjava/classpath/gnu/xml/pipeline/TextConsumer.java create mode 100644 libjava/classpath/gnu/xml/pipeline/ValidationConsumer.java create mode 100644 libjava/classpath/gnu/xml/pipeline/WellFormednessFilter.java create mode 100644 libjava/classpath/gnu/xml/pipeline/XIncludeFilter.java create mode 100644 libjava/classpath/gnu/xml/pipeline/XsltFilter.java create mode 100644 libjava/classpath/gnu/xml/pipeline/package.html create mode 100644 libjava/classpath/gnu/xml/stream/AttributeImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/BufferedReader.java create mode 100644 libjava/classpath/gnu/xml/stream/CRLFReader.java create mode 100644 libjava/classpath/gnu/xml/stream/CharactersImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/CommentImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/DTDImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/EndDocumentImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/EndElementImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/EntityDeclarationImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/EntityReferenceImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/FilteredEventReader.java create mode 100644 libjava/classpath/gnu/xml/stream/FilteredStreamReader.java create mode 100644 libjava/classpath/gnu/xml/stream/NamespaceImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/NotationDeclarationImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/ProcessingInstructionImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/SAXParser.java create mode 100644 libjava/classpath/gnu/xml/stream/SAXParserFactory.java create mode 100644 libjava/classpath/gnu/xml/stream/StartDocumentImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/StartElementImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/UnicodeReader.java create mode 100644 libjava/classpath/gnu/xml/stream/XIncludeFilter.java create mode 100644 libjava/classpath/gnu/xml/stream/XMLEventAllocatorImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/XMLEventFactoryImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/XMLEventImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/XMLEventReaderImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/XMLEventWriterImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/XMLInputFactoryImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/XMLOutputFactoryImpl.java create mode 100644 libjava/classpath/gnu/xml/stream/XMLParser.java create mode 100644 libjava/classpath/gnu/xml/stream/XMLStreamWriterImpl.java create mode 100644 libjava/classpath/gnu/xml/transform/AbstractNumberNode.java create mode 100644 libjava/classpath/gnu/xml/transform/ApplyImportsNode.java create mode 100644 libjava/classpath/gnu/xml/transform/ApplyTemplatesNode.java create mode 100644 libjava/classpath/gnu/xml/transform/AttributeNode.java create mode 100644 libjava/classpath/gnu/xml/transform/AttributeSet.java create mode 100644 libjava/classpath/gnu/xml/transform/Bindings.java create mode 100644 libjava/classpath/gnu/xml/transform/CallTemplateNode.java create mode 100644 libjava/classpath/gnu/xml/transform/ChooseNode.java create mode 100644 libjava/classpath/gnu/xml/transform/CommentNode.java create mode 100644 libjava/classpath/gnu/xml/transform/CopyNode.java create mode 100644 libjava/classpath/gnu/xml/transform/CopyOfNode.java create mode 100644 libjava/classpath/gnu/xml/transform/CurrentFunction.java create mode 100644 libjava/classpath/gnu/xml/transform/DOMSourceLocator.java create mode 100644 libjava/classpath/gnu/xml/transform/DocumentFunction.java create mode 100644 libjava/classpath/gnu/xml/transform/ElementAvailableFunction.java create mode 100644 libjava/classpath/gnu/xml/transform/ElementNode.java create mode 100644 libjava/classpath/gnu/xml/transform/ErrorListenerErrorHandler.java create mode 100644 libjava/classpath/gnu/xml/transform/ForEachNode.java create mode 100644 libjava/classpath/gnu/xml/transform/FormatNumberFunction.java create mode 100644 libjava/classpath/gnu/xml/transform/FunctionAvailableFunction.java create mode 100644 libjava/classpath/gnu/xml/transform/GenerateIdFunction.java create mode 100644 libjava/classpath/gnu/xml/transform/IfNode.java create mode 100644 libjava/classpath/gnu/xml/transform/Key.java create mode 100644 libjava/classpath/gnu/xml/transform/KeyFunction.java create mode 100644 libjava/classpath/gnu/xml/transform/LiteralNode.java create mode 100644 libjava/classpath/gnu/xml/transform/MessageNode.java create mode 100644 libjava/classpath/gnu/xml/transform/NamespaceProxy.java create mode 100644 libjava/classpath/gnu/xml/transform/NodeNumberNode.java create mode 100644 libjava/classpath/gnu/xml/transform/NumberNode.java create mode 100644 libjava/classpath/gnu/xml/transform/OtherwiseNode.java create mode 100644 libjava/classpath/gnu/xml/transform/ParameterNode.java create mode 100644 libjava/classpath/gnu/xml/transform/ProcessingInstructionNode.java create mode 100644 libjava/classpath/gnu/xml/transform/SAXSerializer.java create mode 100644 libjava/classpath/gnu/xml/transform/SAXTemplatesHandler.java create mode 100644 libjava/classpath/gnu/xml/transform/SAXTransformerHandler.java create mode 100644 libjava/classpath/gnu/xml/transform/SortKey.java create mode 100644 libjava/classpath/gnu/xml/transform/StreamSerializer.java create mode 100644 libjava/classpath/gnu/xml/transform/StrippingInstruction.java create mode 100644 libjava/classpath/gnu/xml/transform/Stylesheet.java create mode 100644 libjava/classpath/gnu/xml/transform/SystemPropertyFunction.java create mode 100644 libjava/classpath/gnu/xml/transform/Template.java create mode 100644 libjava/classpath/gnu/xml/transform/TemplateNode.java create mode 100644 libjava/classpath/gnu/xml/transform/TemplatesImpl.java create mode 100644 libjava/classpath/gnu/xml/transform/TextNode.java create mode 100644 libjava/classpath/gnu/xml/transform/TransformerFactoryImpl.java create mode 100644 libjava/classpath/gnu/xml/transform/TransformerImpl.java create mode 100644 libjava/classpath/gnu/xml/transform/TransformerOutputProperties.java create mode 100644 libjava/classpath/gnu/xml/transform/URIResolverEntityResolver.java create mode 100644 libjava/classpath/gnu/xml/transform/UnparsedEntityUriFunction.java create mode 100644 libjava/classpath/gnu/xml/transform/ValueOfNode.java create mode 100644 libjava/classpath/gnu/xml/transform/WhenNode.java create mode 100644 libjava/classpath/gnu/xml/transform/WithParam.java create mode 100644 libjava/classpath/gnu/xml/transform/XSLComparator.java create mode 100644 libjava/classpath/gnu/xml/transform/XSLURIResolver.java create mode 100644 libjava/classpath/gnu/xml/transform/package.html create mode 100644 libjava/classpath/gnu/xml/util/DoParse.java create mode 100644 libjava/classpath/gnu/xml/util/DomParser.java create mode 100644 libjava/classpath/gnu/xml/util/Resolver.java create mode 100644 libjava/classpath/gnu/xml/util/SAXNullTransformerFactory.java create mode 100644 libjava/classpath/gnu/xml/util/XCat.java create mode 100644 libjava/classpath/gnu/xml/util/XHTMLWriter.java create mode 100644 libjava/classpath/gnu/xml/util/XMLWriter.java create mode 100644 libjava/classpath/gnu/xml/util/package.html create mode 100644 libjava/classpath/gnu/xml/validation/datatype/Annotation.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/AnySimpleType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/AnyType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/AnyURIType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/AtomicSimpleType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/Base64BinaryType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/BooleanType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/ByteType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/DateTimeType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/DateType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/DecimalType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/DoubleType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/DurationType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/EntitiesType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/EntityType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/EnumerationFacet.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/Facet.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/FloatType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/FractionDigitsFacet.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/GDayType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/GMonthDayType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/GMonthType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/GYearMonthType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/GYearType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/HexBinaryType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/IDRefType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/IDRefsType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/IDType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/IntType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/IntegerType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/LanguageType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/LengthFacet.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/ListSimpleType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/LongType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/MaxExclusiveFacet.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/MaxInclusiveFacet.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/MaxLengthFacet.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/MinExclusiveFacet.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/MinInclusiveFacet.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/MinLengthFacet.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/NCNameType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/NMTokenType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/NMTokensType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/NameType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/NegativeIntegerType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/NonNegativeIntegerType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/NonPositiveIntegerType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/NormalizedStringType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/NotationType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/PatternFacet.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/PositiveIntegerType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/QNameType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/ShortType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/SimpleType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/StringType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/TimeType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/TokenType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/TotalDigitsFacet.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/Type.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/TypeBuilder.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/TypeLibrary.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/TypeLibraryFactory.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/UnionSimpleType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/UnsignedByteType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/UnsignedIntType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/UnsignedLongType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/UnsignedShortType.java create mode 100644 libjava/classpath/gnu/xml/validation/datatype/WhiteSpaceFacet.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/AnyNameNameClass.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/AttributePattern.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/ChoiceNameClass.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/ChoicePattern.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/DataPattern.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/Define.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/ElementPattern.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/EmptyPattern.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/FullSyntaxBuilder.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/Grammar.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/GrammarException.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/GrammarValidator.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/GroupPattern.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/InterleavePattern.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/ListPattern.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/NSNameNameClass.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/NameClass.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/NameNameClass.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/NotAllowedPattern.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/OneOrMorePattern.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/Param.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/Pattern.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/RELAXNGSchemaFactory.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/RefPattern.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/TextPattern.java create mode 100644 libjava/classpath/gnu/xml/validation/relaxng/ValuePattern.java create mode 100644 libjava/classpath/gnu/xml/validation/xmlschema/AnyAttribute.java create mode 100644 libjava/classpath/gnu/xml/validation/xmlschema/AttributeDeclaration.java create mode 100644 libjava/classpath/gnu/xml/validation/xmlschema/AttributeUse.java create mode 100644 libjava/classpath/gnu/xml/validation/xmlschema/ComplexType.java create mode 100644 libjava/classpath/gnu/xml/validation/xmlschema/ElementDeclaration.java create mode 100644 libjava/classpath/gnu/xml/validation/xmlschema/Particle.java create mode 100644 libjava/classpath/gnu/xml/validation/xmlschema/ValidationException.java create mode 100644 libjava/classpath/gnu/xml/validation/xmlschema/XMLSchema.java create mode 100644 libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaAttributeTypeInfo.java create mode 100644 libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaBuilder.java create mode 100644 libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaElementTypeInfo.java create mode 100644 libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaSchemaFactory.java create mode 100644 libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaTypeInfo.java create mode 100644 libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaTypeInfoProvider.java create mode 100644 libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaValidator.java create mode 100644 libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaValidatorHandler.java create mode 100644 libjava/classpath/gnu/xml/xpath/AndExpr.java create mode 100644 libjava/classpath/gnu/xml/xpath/ArithmeticExpr.java create mode 100644 libjava/classpath/gnu/xml/xpath/BooleanFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/CeilingFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/ConcatFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/Constant.java create mode 100644 libjava/classpath/gnu/xml/xpath/ContainsFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/CountFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/DocumentOrderComparator.java create mode 100644 libjava/classpath/gnu/xml/xpath/EqualityExpr.java create mode 100644 libjava/classpath/gnu/xml/xpath/Expr.java create mode 100644 libjava/classpath/gnu/xml/xpath/FalseFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/FloorFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/Function.java create mode 100644 libjava/classpath/gnu/xml/xpath/FunctionCall.java create mode 100644 libjava/classpath/gnu/xml/xpath/IdFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/LangFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/LastFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/LocalNameFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/NameFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/NameTest.java create mode 100644 libjava/classpath/gnu/xml/xpath/NamespaceTest.java create mode 100644 libjava/classpath/gnu/xml/xpath/NamespaceUriFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/NegativeExpr.java create mode 100644 libjava/classpath/gnu/xml/xpath/NodeTypeTest.java create mode 100644 libjava/classpath/gnu/xml/xpath/NormalizeSpaceFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/NotFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/NumberFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/OrExpr.java create mode 100644 libjava/classpath/gnu/xml/xpath/ParenthesizedExpr.java create mode 100644 libjava/classpath/gnu/xml/xpath/Path.java create mode 100644 libjava/classpath/gnu/xml/xpath/Pattern.java create mode 100644 libjava/classpath/gnu/xml/xpath/PositionFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/Predicate.java create mode 100644 libjava/classpath/gnu/xml/xpath/RelationalExpr.java create mode 100644 libjava/classpath/gnu/xml/xpath/Root.java create mode 100644 libjava/classpath/gnu/xml/xpath/RoundFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/Selector.java create mode 100644 libjava/classpath/gnu/xml/xpath/StartsWithFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/Steps.java create mode 100644 libjava/classpath/gnu/xml/xpath/StringFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/StringLengthFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/SubstringAfterFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/SubstringBeforeFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/SubstringFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/SumFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/Test.java create mode 100644 libjava/classpath/gnu/xml/xpath/TranslateFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/TrueFunction.java create mode 100644 libjava/classpath/gnu/xml/xpath/UnionExpr.java create mode 100644 libjava/classpath/gnu/xml/xpath/VariableReference.java create mode 100644 libjava/classpath/gnu/xml/xpath/XPathFactoryImpl.java create mode 100644 libjava/classpath/gnu/xml/xpath/XPathImpl.java create mode 100644 libjava/classpath/gnu/xml/xpath/XPathParser.java create mode 100644 libjava/classpath/gnu/xml/xpath/XPathParser.y create mode 100644 libjava/classpath/gnu/xml/xpath/XPathTokenizer.java (limited to 'libjava/classpath/gnu') diff --git a/libjava/classpath/gnu/CORBA/Asynchron.java b/libjava/classpath/gnu/CORBA/Asynchron.java new file mode 100644 index 000000000..275b57091 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Asynchron.java @@ -0,0 +1,185 @@ +/* Asynchron.java -- + 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.CORBA; + +import org.omg.CORBA.Request; +import org.omg.CORBA.WrongTransaction; + +import java.util.Iterator; +import java.util.LinkedList; + +/** + * Handles the asynchronous dynamic invocations. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class Asynchron +{ + LinkedList sent = new LinkedList(); + + /** + * Send multiple prepared requests one way, do not caring about the answer. + * The messages, containing requests, will be marked, indicating that + * the sender is not expecting to get a reply. + * + * @param requests the prepared array of requests. + * + * @see Request#send_oneway() + */ + public void send_multiple_requests_oneway(Request[] requests) + { + for (int i = 0; i < requests.length; i++) + { + requests [ i ].send_oneway(); + } + } + + /** + * Send multiple prepared requests expecting to get a reply. All requests + * are send in parallel, each in its own separate thread. When the + * reply arrives, it is stored in the agreed fields of the corresponing + * request data structure. If this method is called repeatedly, + * the new requests are added to the set of the currently sent requests, + * but the old set is not discarded. + * + * @param requests the prepared array of requests. + * + * @see #poll_next_response() + * @see #get_next_response() + * @see Request#send_deferred() + */ + public void send_multiple_requests_deferred(Request[] requests) + { + synchronized (sent) + { + for (int i = 0; i < requests.length; i++) + { + sent.add(requests [ i ]); + + // TODO Reuse threads that are instantiated in the method below, + // one thread per call. + requests [ i ].send_deferred(); + } + } + } + + /** + * Find if any of the requests that have been previously sent with + * {@link #send_multiple_requests_deferred}, have a response yet. + * + * @return true if there is at least one response to the previously + * sent request, false otherwise. + */ + public boolean poll_next_response() + { + synchronized (sent) + { + Iterator iter = sent.iterator(); + Request r; + while (iter.hasNext()) + { + r = (Request) iter.next(); + if (r.poll_response()) + return true; + } + } + return false; + } + + /** + * Get the next instance with a response being received. If all currently + * sent responses not yet processed, this method pauses till at least one of + * them is complete. If there are no requests currently sent, the method + * pauses till some request is submitted and the response is received. + * This strategy is identical to the one accepted by Suns 1.4 ORB + * implementation. + * + * The returned response is removed from the list of the currently + * submitted responses and is never returned again. + * + * @return the previously sent request that now contains the received + * response. + * + * @throws WrongTransaction If the method was called from the transaction + * scope different than the one, used to send the request. The exception + * can be raised only if the request is implicitly associated with some + * particular transaction. + */ + public Request get_next_response() + throws WrongTransaction + { + // The hard-coded waiting times for the incremental waiter. + // TODO it is possible to write more tricky system where the + // requests notify the Asynchron when they are complete. + // Wait for 5 ms intially. + int wait = 8; + + // Double the waiting time + int INC = 2; + + // Do not increase if the waiting time is already over 500 ms. + int MAX = 500; + while (true) + { + synchronized (sent) + { + Iterator iter = sent.iterator(); + Request r; + while (iter.hasNext()) + { + r = (Request) iter.next(); + if (r.poll_response()) + { + sent.remove(r); + return r; + } + } + } + try + { + Thread.sleep(wait); + if (wait < MAX) + wait = wait * INC; + } + catch (InterruptedException ex) + { + } + } + } +} diff --git a/libjava/classpath/gnu/CORBA/BigDecimalHelper.java b/libjava/classpath/gnu/CORBA/BigDecimalHelper.java new file mode 100644 index 000000000..c5c8f99ab --- /dev/null +++ b/libjava/classpath/gnu/CORBA/BigDecimalHelper.java @@ -0,0 +1,191 @@ +/* BigDecimalHelper.java -- + 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.CORBA; + +import gnu.java.lang.CPStringBuilder; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import java.math.BigDecimal; +import java.math.BigInteger; + +import org.omg.CORBA.TypeCodePackage.BadKind; + +/** + * Reads and writes BigDecimal as CORBA fixed. + * The format, described in CORBA specification, requires to store + * data in hexadecimal format, two digits per byte (oceted), most + * significant digit first. The last half-byte in the representation + * stores the sign, being 0xD for negative numbers and 0xC for + * zero and positive numbers. To have the even number of half bytes, + * 0x0 is appended to the beginning, if required. The position of the + * decimal point is not stored. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class BigDecimalHelper +{ + { + } + + /** + * @todo remove from the release version. + */ + public static void main(String[] args) + { + try + { + ByteArrayOutputStream b = new ByteArrayOutputStream(); + BigDecimal d = new BigDecimal("12234.54689"); + + write(b, d); + + byte[] a = b.toByteArray(); + + for (int i = 0; i < a.length; i++) + { + int k = a [ i ] & 0xFF; + System.out.print(Integer.toHexString(k) + " "); + } + + System.out.println("Now reading"); + + ByteArrayInputStream bin = new ByteArrayInputStream(a); + + BigDecimal r = read(bin, d.scale()); + + System.out.println(r); + } + catch (Exception ex) + { + ex.printStackTrace(); + } + } + + /** + * Read the CORBA fixed, autodetecting the number of bytes + * and assuming the given scale. + */ + public static BigDecimal read(java.io.InputStream in, int scale) + throws IOException + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + + int f; + + do + { + f = in.read(); + if (f >= 0) + bout.write(f); + } + // The last byte has 0xC or 0xD in the last halfbyte. + while ((f & 0xF) <= 0x9); + + return createFixed(scale, bout.toByteArray()); + } + + /** + * Write the big decimal as CORBA fixed<.code>. + * The scale will not be stored. + * + * @param out a stream to write into. + * @param x a big decimal to write. + * + * @throws IOException if the stream write method throws one. + * @throws BadKind if this BigDecimal has more digits than + * specified. + */ + public static void write(java.io.OutputStream out, BigDecimal x) + throws IOException, BadKind + { + CPStringBuilder v = new CPStringBuilder(x.unscaledValue().toString()); + + boolean negative = v.charAt(0) == '-'; + + if (negative) + v = v.deleteCharAt(0); + + if ( (v.length() & 1) == 0) + v.insert(0, '0'); + + int c; + + for (int i = 0; i < v.length() - 1; i = i + 2) + { + c = ((v.charAt(i) - '0') << 4) | (v.charAt(i + 1) - '0'); + out.write(c); + } + + c = ((v.charAt(v.length() - 1) - '0') << 4) | (negative ? 0xD : 0xC); + + out.write(c); + } + + /** + * Convert the loaded byte array, representing + * CORBA fixed, into an instance of + * the {@link BigDecimal} + */ + private static BigDecimal createFixed(int scale, byte[] d) + { + CPStringBuilder s = new CPStringBuilder(2 * d.length); + + int last = d.length - 1; + + if ((d [ last ] & 0xF) == 0xD) + s.append('-'); + + if (last > 0) + for (int i = 0; i < last; i++) + { + s.append((char) (((d [ i ] >> 4) & 0xF) + '0')); + s.append((char) (((d [ i ]) & 0xF) + '0')); + } + + s.append((char) (((d [ last ] >> 4) & 0xF) + '0')); + + BigInteger b = new BigInteger(s.toString()); + BigDecimal dec = new BigDecimal(b, scale); + + return dec; + } +} diff --git a/libjava/classpath/gnu/CORBA/ByteArrayComparator.java b/libjava/classpath/gnu/CORBA/ByteArrayComparator.java new file mode 100644 index 000000000..e601399df --- /dev/null +++ b/libjava/classpath/gnu/CORBA/ByteArrayComparator.java @@ -0,0 +1,90 @@ +/* ByteArrayComparator.java -- + 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.CORBA; + +import java.util.Comparator; + +/** + * A byte array comparator for mapping with CORBA object keys. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class ByteArrayComparator + implements Comparator +{ + /** + * Compare arrays first by absolute equality, then by length + * and then (byte to byte) by content. + * + * @return 0 if arrays are equal, some comparison value otherwise. + */ + public int compare(Object an_a, Object a_b) + { + if (an_a == a_b) + return 0; + + byte[] a = null; + byte[] b = null; + try + { + a = (byte[]) an_a; + b = (byte[]) a_b; + } + catch (Exception ex) + { + throw new InternalError(an_a.getClass().getName() + "," + + a_b.getClass().getName() + ); + } + + if (a.length != b.length) + return a.length - b.length; + else + { + // The array sizes must be equal. + for (int i = 0; i < b.length; i++) + { + if (a [ i ] != b [ i ]) + return a [ i ] - b [ i ]; + } + } + + return 0; + } +} diff --git a/libjava/classpath/gnu/CORBA/CDR/AbstractCdrInput.java b/libjava/classpath/gnu/CORBA/CDR/AbstractCdrInput.java new file mode 100644 index 000000000..fae16eed9 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/CDR/AbstractCdrInput.java @@ -0,0 +1,1768 @@ +/* AbstractCdrInput.java -- + 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.CORBA.CDR; + +import gnu.CORBA.BigDecimalHelper; +import gnu.CORBA.OrbFunctional; +import gnu.CORBA.GIOP.CharSets_OSF; +import gnu.CORBA.GIOP.CodeSetServiceContext; +import gnu.CORBA.IOR; +import gnu.CORBA.IorDelegate; +import gnu.CORBA.Minor; +import gnu.CORBA.TypeCodeHelper; +import gnu.CORBA.Unexpected; +import gnu.CORBA.Version; +import gnu.CORBA.gnuAny; +import gnu.CORBA.StubLocator; + +import org.omg.CORBA.Any; +import org.omg.CORBA.AnySeqHolder; +import org.omg.CORBA.BAD_OPERATION; +import org.omg.CORBA.BooleanSeqHolder; +import org.omg.CORBA.CharSeqHolder; +import org.omg.CORBA.DoubleSeqHolder; +import org.omg.CORBA.FloatSeqHolder; +import org.omg.CORBA.LongLongSeqHolder; +import org.omg.CORBA.LongSeqHolder; +import org.omg.CORBA.MARSHAL; +import org.omg.CORBA.ORB; +import org.omg.CORBA.OctetSeqHolder; +import org.omg.CORBA.ShortSeqHolder; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.TypeCodePackage.BadKind; +import org.omg.CORBA.TypeCodePackage.Bounds; +import org.omg.CORBA.ULongLongSeqHolder; +import org.omg.CORBA.ULongSeqHolder; +import org.omg.CORBA.UShortSeqHolder; +import org.omg.CORBA.WCharSeqHolder; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.ObjectImpl; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Serializable; + +import java.math.BigDecimal; + +/** + * A simple CORBA CDR (common data representation) input stream, reading data + * from the given {@link java.io.InputStream}. The primitive types are aligned + * on they natural boundaries by implementing the abstract method + * {@link #align(int boundary)}. + * + * The same class also implements {@link org.omg.CORBA.DataInputStream} to read + * the object content in a user defined way. + * + * TODO This class uses 16 bits per Unicode character only, as it was until jdk + * 1.4 inclusive. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public abstract class AbstractCdrInput + extends org.omg.CORBA_2_3.portable.InputStream + implements org.omg.CORBA.DataInputStream +{ + /** + * The runtime, associated with this stream. This field is only used when + * reading and writing value types and filled-in in gnu.CORBA.CDR.Vio. + */ + public transient gnuRuntime runtime; + + /** + * The message, explaining that the exception has been thrown due unexpected + * end of the input stream. This usually happens the server and client + * disagree on communication or data representation rules. + */ + protected static final String UNEXP_EOF = "Unexpected end of stream"; + + /** + * This instance is used to convert primitive data types into the byte + * sequences. + */ + protected AbstractDataInput b; + + /** + * The input stream, from where the data are actually being read. + */ + protected java.io.InputStream actual_stream; + + /** + * The associated orb, if any. + */ + protected ORB orb; + + /** + * The GIOP version. + */ + protected Version giop = new Version(1, 2); + + /** + * The code set information. + */ + protected CodeSetServiceContext codeset = CodeSetServiceContext.STANDARD; + + /** + * The name of the currently used narrow charset, null if the native narrow + * charset is used. + */ + private String narrow_charset = null; + + /** + * The name of the currently used wide charset, null if the native wide + * charset is used. + */ + private String wide_charset = null; + + /** + * True if the native code set is used for narrow characters. If the set is + * native, no the intermediate Reader object is instantiated when writing + * characters. + */ + private boolean narrow_native; + + /** + * True if the native code set is used for wide characters. If the set is + * native, no the intermediate Reader object is instantiated when writing + * characters. + */ + private boolean wide_native; + + /** + * If true, the stream expect the multi-byte data in the form "less + * significant byte first" (Little Endian). This is the opposite to the java + * standard (Big Endian). + */ + private boolean little_endian; + + /** + * Creates the stream. The stream reads Big Endian by default. + * + * @param readFrom a stream to read CORBA input from. + */ + public AbstractCdrInput(java.io.InputStream readFrom) + { + setInputStream(readFrom); + setCodeSet(CodeSetServiceContext.STANDARD); + } + + /** + * Creates the stream, requiring the subsequent call of + * {@link #setInputStream(java.io.InputStream)}. + */ + public AbstractCdrInput() + { + setCodeSet(CodeSetServiceContext.STANDARD); + } + + /** + * Set the Big Endian or Little Endian encoding. The stream reads Big Endian + * by default. + * + * @param use_big_endian if true, the stream expect the multi-byte data in + * the form "most significant byte first" (Big Endian). This is the + * java standard. + */ + public void setBigEndian(boolean use_big_endian) + { + little_endian = !use_big_endian; + setInputStream(actual_stream); + } + + /** + * Get the used encoding. + * + * @return true for Big Endian, false for Little Endian. + */ + public boolean isBigEndian() + { + return !little_endian; + } + + /** + * Clone all important settings to another stream. + */ + public void cloneSettings(AbstractCdrInput stream) + { + stream.setBigEndian(isBigEndian()); + stream.setCodeSet(getCodeSet()); + stream.setVersion(giop); + stream.setOrb(orb); + } + + /** + * Set the input stream that receives the CORBA input. + * + * @param readFrom the stream. + */ + public void setInputStream(java.io.InputStream readFrom) + { + if (little_endian) + b = new LittleEndianInputStream(readFrom); + else + b = new BigEndianInputStream(readFrom); + + actual_stream = readFrom; + } + + /** + * Set the alignment offset, if the index of the first byte in the stream is + * different from 0. + */ + public abstract void setOffset(int offset); + + /** + * Set the orb, associated with this stream. + * + * @param an_orb + */ + public void setOrb(ORB an_orb) + { + orb = an_orb; + } + + /** + * Set the GIOP version. Some data types are written differently for the + * different versions. The default version is 1.0 . + */ + public void setVersion(Version giop_version) + { + giop = giop_version; + } + + /** + * Align the curretn position at the given natural boundary. + */ + public abstract void align(int boundary); + + /** + * Reads the CORBA unsigned long (java int), returning the value in the + * sufficiently large java long. + */ + public long gnu_read_ulong() + { + try + { + long l = b.readInt(); + l &= 0xFFFFFFF; + return l; + } + catch (EOFException ex) + { + MARSHAL t = new MARSHAL(UNEXP_EOF); + t.minor = Minor.EOF; + t.initCause(ex); + throw t; + } + catch (IOException ex) + { + throw new Unexpected(ex); + } + } + + /** + * Read the unsigned short integer value and return it as java int, + * sufficiently large to hold all values. + */ + public int gnu_read_ushort() + { + try + { + align(2); + return b.readUnsignedShort(); + } + catch (EOFException ex) + { + MARSHAL t = new MARSHAL(UNEXP_EOF); + t.minor = Minor.EOF; + t.initCause(ex); + throw t; + } + + catch (IOException ex) + { + throw new Unexpected(ex); + } + } + + /** + * Return the associated {@link ORB}. + * + * @return the associated {@link ORB} or null is no such is set. + */ + public ORB orb() + { + return orb; + } + + /** + * Read a single byte directly from the buffer. + */ + public int read() + throws java.io.IOException + { + try + { + return b.read(); + } + catch (EOFException ex) + { + MARSHAL t = new MARSHAL(UNEXP_EOF); + t.minor = Minor.EOF; + t.initCause(ex); + throw t; + } + } + + /** + * Read bytes directly from the buffer. + */ + public int read(byte[] x, int ofs, int len) + throws java.io.IOException + { + try + { + return b.read(x, ofs, len); + } + catch (EOFException ex) + { + MARSHAL t = new MARSHAL(UNEXP_EOF); + t.minor = Minor.EOF; + t.initCause(ex); + throw t; + } + } + + /** + * Read bytes directly from the buffer. + */ + public int read(byte[] x) + throws java.io.IOException + { + try + { + return b.read(x); + } + catch (EOFException ex) + { + MARSHAL t = new MARSHAL(UNEXP_EOF); + t.minor = Minor.EOF; + t.initCause(ex); + throw t; + } + } + + /** + * Read the CORBA object. The object to read is represented in the form of the + * plain (not a string-encoded) IOR profile without the heading endian + * indicator. The responsible method for reading such data is + * {@link IOR.read_no_endian}. + * + * The returned object is usually casted into the given type using the .narrow + * method of its helper, despite in some cases the direct cast would also + * work. + * + * The null objects are recognised from the empty profile set. For such + * objects, null is returned. + * + * @return the loaded and constructed object. + */ + public org.omg.CORBA.Object read_Object() + { + try + { + IOR ior = new IOR(); + ior._read_no_endian(this); + + if (ior.Id == null) + return null; + + // Check maybe this is a remote reference to the local object. + // This is only possible if we access the repository of the + // connected object. + if (orb instanceof OrbFunctional) + { + OrbFunctional forb = (OrbFunctional) orb; + org.omg.CORBA.Object local = forb.find_local_object(ior); + if (local != null) + return local; + } + + // Search for the available stubs. + ObjectImpl impl = StubLocator.search(orb, ior); + try + { + if (impl._get_delegate() == null) + impl._set_delegate(new IorDelegate(orb, ior)); + } + catch (BAD_OPERATION ex) + { + // Some colaborants may throw this exception + // in response to the attempt to get the unset delegate. + impl._set_delegate(new IorDelegate(orb, ior)); + } + + return impl; + } + catch (IOException ex) + { + MARSHAL bad = new MARSHAL(); + bad.minor = Minor.IOR; + bad.initCause(ex); + throw bad; + } + } + + /** + * Read the type code. The type code format is defined in the CORBA + * documenation. + */ + public TypeCode read_TypeCode() + { + try + { + return TypeCodeHelper.read(this); + } + + catch (Bounds ex) + { + throw new Unexpected(); + } + catch (BadKind ex) + { + throw new Unexpected(); + } + } + + /** + * Read the CORBA {@link Any}. This method first reads the type code, then + * delegates the functionality to {@link Any#read_value}. + */ + public Any read_any() + { + TypeCode ty = read_TypeCode(); + gnuAny any = new gnuAny(); + any.read_value(this, ty); + return any; + } + + /** + * Read the boolean, treating any non zero byte as true, zero byte as false. + */ + public boolean read_boolean() + { + try + { + return b.read() == 0 ? false : true; + } + catch (EOFException ex) + { + MARSHAL t = new MARSHAL(UNEXP_EOF); + t.minor = Minor.EOF; + t.initCause(ex); + throw t; + } + catch (IOException ex) + { + throw new Unexpected(ex); + } + } + + /** + * Read the array of boolean. + */ + public void read_boolean_array(boolean[] x, int offs, int len) + { + try + { + for (int i = offs; i < offs + len; i++) + { + x[i] = b.read() == 0 ? false : true; + } + } + catch (EOFException ex) + { + MARSHAL t = new MARSHAL(UNEXP_EOF); + t.minor = Minor.EOF; + t.initCause(ex); + throw t; + } + + catch (IOException ex) + { + throw new Unexpected(ex); + } + } + + /** + * Read a character using narrow charset encoding. Depending form which + * encoding is set, this still can be Unicode or ever wider. + */ + public char read_char() + { + try + { + if (narrow_native) + return (char) b.read(); + else + return (char) new InputStreamReader((InputStream) b, narrow_charset).read(); + } + catch (EOFException ex) + { + MARSHAL t = new MARSHAL(UNEXP_EOF); + t.minor = Minor.EOF; + t.initCause(ex); + throw t; + } + + catch (IOException ex) + { + throw new Unexpected(ex); + } + } + + /** + * Read a character array, using narrow charset encoding. + */ + public void read_char_array(char[] x, int offset, int length) + { + try + { + if (narrow_native) + { + for (int i = offset; i < offset + length; i++) + x[i] = (char) b.read(); + } + else + { + InputStreamReader reader = new InputStreamReader((InputStream) b, + narrow_charset); + reader.read(x, offset, length); + } + } + catch (EOFException ex) + { + MARSHAL t = new MARSHAL(UNEXP_EOF); + t.minor = Minor.EOF; + t.initCause(ex); + throw t; + } + + catch (IOException ex) + { + throw new Unexpected(ex); + } + } + + /** + * Read the double value, IEEE 754 format. + */ + public double read_double() + { + try + { + align(8); + return b.readDouble(); + } + catch (EOFException ex) + { + MARSHAL t = new MARSHAL(UNEXP_EOF); + t.minor = Minor.EOF; + t.initCause(ex); + throw t; + } + + catch (IOException ex) + { + throw new Unexpected(); + } + } + + /** + * Read the array of double values, IEEE 754 format. + */ + public void read_double_array(double[] x, int offs, int len) + { + try + { + align(8); + for (int i = offs; i < offs + len; i++) + { + x[i] = b.readDouble(); + } + } + catch (EOFException ex) + { + MARSHAL t = new MARSHAL(UNEXP_EOF); + t.minor = Minor.EOF; + t.initCause(ex); + throw t; + } + + catch (IOException ex) + { + throw new Unexpected(ex); + } + } + + /** + * Read the encapsulated stream. If the encapsulated sequence appears to be in + * the Little endian format, the flag of the returned stream is set to read + * Little endian. + */ + public BufferredCdrInput read_encapsulation() + { + try + { + int l = read_long(); + + byte[] r = new byte[l]; + int n = 0; + while (n < r.length) + { + n += read(r, n, r.length - n); + } + + BufferredCdrInput capsule = new BufferredCdrInput(r); + capsule.setOrb(orb); + + int endian = capsule.read_octet(); + + if (endian != 0) + { + capsule.setBigEndian(false); + } + + return capsule; + } + catch (EOFException ex) + { + MARSHAL t = new MARSHAL(UNEXP_EOF); + t.minor = Minor.EOF; + t.initCause(ex); + throw t; + } + + catch (IOException ex) + { + throw new Unexpected(ex); + } + } + + /** + * Read the CORBA fixed (the end of the fixed can be determined + * by its last byte). The scale is always assumed to be zero. + */ + public BigDecimal read_fixed() + { + try + { + return BigDecimalHelper.read(this, 0); + } + catch (EOFException ex) + { + MARSHAL t = new MARSHAL(UNEXP_EOF); + t.minor = Minor.EOF; + t.initCause(ex); + throw t; + } + + catch (IOException ex) + { + throw new Unexpected(ex); + } + } + + /** + * Read the float value, IEEE 754 format. + */ + public float read_float() + { + try + { + align(4); + return b.readFloat(); + } + catch (EOFException ex) + { + MARSHAL t = new MARSHAL(UNEXP_EOF); + t.minor = Minor.EOF; + t.initCause(ex); + throw t; + } + + catch (IOException ex) + { + throw new Unexpected(ex); + } + } + + /** + * Read an array of float values, IEEE 754 format. + */ + public void read_float_array(float[] x, int offs, int len) + { + try + { + align(4); + for (int i = offs; i < offs + len; i++) + { + x[i] = b.readFloat(); + } + } + catch (EOFException ex) + { + MARSHAL t = new MARSHAL(UNEXP_EOF); + t.minor = Minor.EOF; + t.initCause(ex); + throw t; + } + + catch (IOException ex) + { + throw new Unexpected(ex); + } + } + + /** + * Read the CORBA long (java int), high byte first. + */ + public int read_long() + { + try + { + align(4); + return b.readInt(); + } + catch (EOFException ex) + { + MARSHAL t = new MARSHAL(UNEXP_EOF); + t.minor = Minor.EOF; + t.initCause(ex); + throw t; + } + + catch (IOException ex) + { + throw new Unexpected(ex); + } + } + + /** + * Read an array of CORBA longs (java ints). + */ + public void read_long_array(int[] x, int offs, int len) + { + try + { + align(4); + for (int i = offs; i < offs + len; i++) + { + x[i] = b.readInt(); + } + } + catch (EOFException ex) + { + MARSHAL t = new MARSHAL(UNEXP_EOF); + t.minor = Minor.EOF; + t.initCause(ex); + throw t; + } + + catch (IOException ex) + { + throw new Unexpected(ex); + } + } + + /** + * Read the CORBA long long (java long). + */ + public long read_longlong() + { + try + { + align(8); + return b.readLong(); + } + catch (EOFException ex) + { + MARSHAL t = new MARSHAL(UNEXP_EOF); + t.minor = Minor.EOF; + throw t; + } + + catch (IOException ex) + { + throw new Unexpected(ex); + } + } + + /** + * Read an array of CORBA long longs (java longs). + */ + public void read_longlong_array(long[] x, int offs, int len) + { + try + { + align(8); + for (int i = offs; i < offs + len; i++) + { + x[i] = b.readLong(); + } + } + catch (EOFException ex) + { + MARSHAL t = new MARSHAL(UNEXP_EOF); + t.minor = Minor.EOF; + t.initCause(ex); + throw t; + } + + catch (IOException ex) + { + throw new Unexpected(ex); + } + } + + /** + * Read a single byte. + */ + public byte read_octet() + { + try + { + return b.readByte(); + } + catch (EOFException ex) + { + MARSHAL t = new MARSHAL(UNEXP_EOF); + t.minor = Minor.EOF; + t.initCause(ex); + throw t; + } + + catch (IOException ex) + { + throw new Unexpected(ex); + } + } + + /** + * Read the byte array. + */ + public void read_octet_array(byte[] x, int offs, int len) + { + try + { + b.read(x, offs, len); + } + catch (EOFException ex) + { + MARSHAL t = new MARSHAL(UNEXP_EOF); + t.minor = Minor.EOF; + t.initCause(ex); + throw t; + } + + catch (IOException ex) + { + throw new Unexpected(ex); + } + } + + /** + * Read the length of the byte array as CORBA long and then the array itseld. + */ + public byte[] read_sequence() + { + try + { + int l = read_long(); + byte[] buf = new byte[l]; + if (l > 0) + { + b.readFully(buf); + } + return buf; + } + catch (EOFException ex) + { + MARSHAL t = new MARSHAL(UNEXP_EOF); + t.minor = Minor.EOF; + t.initCause(ex); + throw t; + } + + catch (IOException ex) + { + throw new Unexpected(ex); + } + } + + /** + * Read the CORBA short integer. + */ + public short read_short() + { + try + { + align(2); + return b.readShort(); + } + catch (EOFException ex) + { + MARSHAL t = new MARSHAL(UNEXP_EOF); + t.minor = Minor.EOF; + t.initCause(ex); + throw t; + } + + catch (IOException ex) + { + throw new Unexpected(ex); + } + } + + /** + * Read the array of CORBA short integer values. + */ + public void read_short_array(short[] x, int offs, int len) + { + try + { + align(2); + for (int i = offs; i < offs + len; i++) + { + x[i] = b.readShort(); + } + } + catch (EOFException ex) + { + MARSHAL t = new MARSHAL(UNEXP_EOF); + t.minor = Minor.EOF; + t.initCause(ex); + throw t; + } + + catch (IOException ex) + { + throw new Unexpected(ex); + } + } + + /** + * Read a singe byte string. The method firs reads the byte array and then + * calls a constructor to create a string from this array. The character + * encoding, if previously set, is taken into consideration. + * + * @return a loaded string. + */ + public String read_string() + { + int n = 0; + try + { + align(4); + + n = b.readInt(); + byte[] s = new byte[n]; + b.read(s); + + // Discard the null terminator. + if (narrow_charset == null) + return new String(s, 0, n - 1); + else + return new String(s, 0, n - 1, narrow_charset); + } + catch (EOFException ex) + { + MARSHAL t = new MARSHAL(UNEXP_EOF); + t.minor = Minor.EOF; + t.initCause(ex); + throw t; + } + catch (IOException ex) + { + throw new Unexpected(); + } + catch (NegativeArraySizeException nex) + { + MARSHAL m = new MARSHAL("Input stream broken, got " + n + "(0x" + + Integer.toHexString(n) + ") as a string size"); + m.minor = Minor.Negative; + throw m; + } + } + + /** + * Reads the CORBA unsigned long (java int), delegating functionality to + * {@link #read_long}. + */ + public int read_ulong() + { + return read_long(); + } + + /** + * Reads the array of CORBA unsigned long (java integer) values, delegating + * functionality to {@link #real_long_array}. + */ + public void read_ulong_array(int[] x, int offs, int len) + { + read_long_array(x, offs, len); + } + + /** + * Read the CORBA unsigned long long value, delegating functionality to + * {@link #read_longlong}. There is no way to return values over the limit of + * the java signed long in other way than returning the negative value. + */ + public long read_ulonglong() + { + return read_longlong(); + } + + /** + * Reads the array of CORBA long long (java long) values, delegating + * functionality to {@link #real_longlong_array}. + */ + public void read_ulonglong_array(long[] x, int offs, int len) + { + read_longlong_array(x, offs, len); + } + + /** + * Read the unsigned short integer value. Due strange specification, the + * returned value must be the short type as well, so the the best solution + * seems just to delegete functionality to read_short. + */ + public short read_ushort() + { + return read_short(); + } + + /** + * Read an array of unsigned short values, delegating the functionality to + * {@link read_short_array}. + */ + public void read_ushort_array(short[] x, int offs, int len) + { + read_short_array(x, offs, len); + } + + /** + * Reads the wide character using the encoding, specified in the wide_charset. + */ + public char read_wchar() + { + try + { + if (giop.until_inclusive(1, 1)) + { + align(2); + + if (wide_native) + return (char) b.readShort(); + else + return (char) new InputStreamReader((InputStream) b, wide_charset).read(); + } + else + { + int l = b.read(); + if (l == 2 && wide_native) + return b.readChar(); + else if (l <= 0) + { + MARSHAL m = new MARSHAL("wchar size " + l); + m.minor = Minor.Negative; + throw m; + } + else + { + byte[] bytes = new byte[l]; + b.readFully(bytes); + String cs; + + if (bytes.length > 2 && bytes[0] == 0xFE && bytes[1] == 0xFF) + cs = new String(bytes, 2, bytes.length - 2, wide_charset); + else if (bytes.length > 2 && bytes[0] == 0xFF + && bytes[1] == 0xFE) + { + // Litle endian detected - swap bytes. + byte t; + for (int i = 3; i < bytes.length; i = i + 2) + { + t = bytes[i]; + bytes[i - 1] = bytes[i]; + bytes[i] = t; + } + cs = new String(bytes, 2, bytes.length - 2, wide_charset); + } + else + cs = new String(bytes, wide_charset); + + return cs.charAt(0); + } + } + } + catch (EOFException ex) + { + MARSHAL t = new MARSHAL(UNEXP_EOF); + t.minor = Minor.EOF; + t.initCause(ex); + throw t; + } + catch (IOException ex) + { + throw new Unexpected(); + } + } + + /** + * Read an array of "wide chars", each representing a two byte Unicode + * character, high byte first. + */ + public void read_wchar_array(char[] x, int offset, int length) + { + try + { + if (giop.until_inclusive(1, 1)) + align(2); + + if (wide_native) + { + for (int i = offset; i < offset + length; i++) + x[i] = (char) b.readShort(); + } + else + { + InputStreamReader reader = new InputStreamReader((InputStream) b, + wide_charset); + reader.read(x, offset, length); + } + } + catch (EOFException ex) + { + MARSHAL t = new MARSHAL(UNEXP_EOF); + t.minor = Minor.EOF; + t.initCause(ex); + throw t; + } + + catch (IOException ex) + { + throw new Unexpected(ex); + } + } + + /** + * Reads the string in wide character format (ussually UTF-16, Unicode). Takes + * the currently set charset into consideration. + * + * If the native (UTF-16) encoding is used of the GIOP protocol is before 1.2, + * delegates functionality to "plain" {@link #read_wstring_UTF_16}. + */ + public String read_wstring() + { + // Native encoding or word oriented data. + if (wide_native || giop.until_inclusive(1, 1)) + return read_wstring_UTF_16(); + try + { + align(4); + + int n = b.readInt(); + byte[] s = new byte[n]; + b.read(s); + + return new String(s, 0, n, wide_charset); + } + catch (EOFException ex) + { + MARSHAL t = new MARSHAL(UNEXP_EOF); + t.minor = Minor.EOF; + t.initCause(ex); + throw t; + } + + catch (IOException ex) + { + throw new Unexpected(ex); + } + } + + /** + * Reads first length of the string and the all characters as an Unicode + * (UTF-16) characters. Mind that GIOP 1.1 has the extra null character at the + * end that must be discarded. + */ + public String read_wstring_UTF_16() + { + try + { + int p = 0; + int n = read_long(); + + if (n<0) + { + MARSHAL m = new MARSHAL("Negative string size"); + m.minor = Minor.Negative; + throw m; + } + + // The null terminator that is no longer present since 1.2 . + int nt = giop.since_inclusive(1, 2) ? 0 : 1; + + // Convert bytes to shorts. + n = n / 2; + + // Empty string. + if (n == 0) + return ""; + + char[] s = new char[n]; + + for (int i = 0; i < s.length; i++) + s[i] = (char) b.readShort(); + + // Check for the byte order marker here. + if (s[0] == 0xFEFF) + { + // Big endian encoding - do nothing, but move the pointer + // one position forward. + p = 1; + } + else if (s[0] == 0xFFFE) + { + // Little endian encoding, swap the bytes and move one + // position forward. + p = 1; + + for (int i = p; i < s.length; i++) + s[i] = swap(s[i]); + } + + // Discard the null terminator and, if needed, the endian marker. + String r = new String(s, p, n - nt - p); + return r; + } + catch (EOFException ex) + { + MARSHAL t = new MARSHAL(UNEXP_EOF); + t.minor = Minor.EOF; + t.initCause(ex); + throw t; + } + + catch (IOException ex) + { + throw new Unexpected(ex); + } + } + + /** + * Swap bytes in the character. + */ + public static char swap(char x) + { + int hi; + int lo; + + lo = x & 0xFF; + hi = (x >> 8) & 0xFF; + + return (char) ((lo << 8) | hi); + } + + /** + * Set the current code set context. + */ + public void setCodeSet(CodeSetServiceContext a_codeset) + { + this.codeset = a_codeset; + narrow_charset = CharSets_OSF.getName(codeset.char_data); + wide_charset = CharSets_OSF.getName(codeset.wide_char_data); + + narrow_native = CharSets_OSF.NATIVE_CHARACTER == codeset.char_data; + wide_native = CharSets_OSF.NATIVE_WIDE_CHARACTER == codeset.wide_char_data; + } + + /** + * Get the current code set context. + */ + public CodeSetServiceContext getCodeSet() + { + return codeset; + } + + /** + * Read the object that is an instance of the given class. The current + * implementation delegates functionality to the parameterless + * {@link readObject()}. + * + * @param klass a class of that this object the instance is. + * + * @return the returned object. + */ + public org.omg.CORBA.Object read_Object(Class klass) + { + return read_Object(); + } + + /** + * Read a value type structure from the stream. + * + * OMG specification states the writing format is outside the scope of GIOP + * definition. This implementation uses java serialization mechanism, calling + * {@link ObjectInputStream#readObject} + * + * @return an value type structure, unmarshaled from the stream + */ + public Serializable read_Value() + { + return read_value(); + } + + /** + * Read the abstract interface. An abstract interface can be either CORBA + * value type or CORBA object and is returned as an abstract java.lang.Object. + * + * As specified in OMG specification, this reads a single boolean and then + * delegates either to {@link #read_Object()} (for false) or to + * {@link #read_Value()} (for true). + * + * @return an abstract interface, unmarshaled from the stream + */ + public java.lang.Object read_Abstract() + { + return read_abstract_interface(); + } + + /** + * Read an array. In OMG specification is written that if the data does not + * fit into the holder value field, that array must be resized. The + * implementation follows this rule. If the holder value field contains null, + * it is newly instantiated. + */ + public void read_char_array(CharSeqHolder holder, int offset, int length) + { + holder.value = ensureArray(holder.value, offset, length); + read_char_array(holder.value, offset, length); + } + + /** + * Read an array. In OMG specification is written that if the data does not + * fit into the holder value field, that array must be resized. The + * implementation follows this rule. If the holder value field contains null, + * it is newly instantiated. + */ + public void read_wchar_array(WCharSeqHolder holder, int offset, int length) + { + holder.value = ensureArray(holder.value, offset, length); + read_wchar_array(holder.value, offset, length); + } + + /** + * If required, allocate or resize the char array to fit the newly read + * values. + * + * @param holder_value the existing char array, may be null. + * @param offset the required offset to read. + * @param length the length of the new sequence. + * + * @return the allocated or resized array, same array if no such operations + * are required. + */ + private char[] ensureArray(char[] holder_value, int offset, int length) + { + if (holder_value == null) + return new char[offset + length]; + else if (holder_value.length < offset + length) + { + char[] value = new char[offset + length]; + System.arraycopy(holder_value, 0, value, 0, holder_value.length); + return value; + } + else + return holder_value; + } + + /** + * Read an array. In OMG specification is written that if the data does not + * fit into the holder value field, that array must be resized. The + * implementation follows this rule. If the holder value field contains null, + * it is newly instantiated. + */ + public void read_ulong_array(ULongSeqHolder holder, int offset, int length) + { + holder.value = ensureArray(holder.value, offset, length); + read_ulong_array(holder.value, offset, length); + } + + /** + * Read an array. In OMG specification is written that if the data does not + * fit into the holder value field, that array must be resized. The + * implementation follows this rule. If the holder value field contains null, + * it is newly instantiated. + */ + public void read_long_array(LongSeqHolder holder, int offset, int length) + { + holder.value = ensureArray(holder.value, offset, length); + read_ulong_array(holder.value, offset, length); + } + + /** + * If required, allocate or resize the int array to fit the newly read values. + * + * @param holder_value the existing int array, may be null. + * @param offset the required offset to read. + * @param length the length of the new sequence. + * + * @return the allocated or resized array, same array if no such operations + * are required. + */ + private int[] ensureArray(int[] holder_value, int offset, int length) + { + if (holder_value == null) + return new int[offset + length]; + else if (holder_value.length < offset + length) + { + int[] value = new int[offset + length]; + System.arraycopy(holder_value, 0, value, 0, holder_value.length); + return value; + } + else + return holder_value; + } + + /** + * Read an array. In OMG specification is written that if the data does not + * fit into the holder value field, that array must be resized. The + * implementation follows this rule. If the holder value field contains null, + * it is newly instantiated. + */ + public void read_float_array(FloatSeqHolder holder, int offset, int length) + { + holder.value = ensureArray(holder.value, offset, length); + read_float_array(holder.value, offset, length); + } + + /** + * If required, allocate or resize the float array to fit the newly read + * values. + * + * @param holder_value the existing float array, may be null. + * @param offset the required offset to read. + * @param length the length of the new sequence. + * + * @return the allocated or resized array, same array if no such operations + * are required. + */ + private float[] ensureArray(float[] holder_value, int offset, int length) + { + if (holder_value == null) + return new float[offset + length]; + else if (holder_value.length < offset + length) + { + float[] value = new float[offset + length]; + System.arraycopy(holder_value, 0, value, 0, holder_value.length); + return value; + } + else + return holder_value; + } + + /** + * Read an array. In OMG specification is written that if the data does not + * fit into the holder value field, that array must be resized. The + * implementation follows this rule. If the holder value field contains null, + * it is newly instantiated. + */ + public void read_double_array(DoubleSeqHolder holder, int offset, int length) + { + holder.value = ensureArray(holder.value, offset, length); + read_double_array(holder.value, offset, length); + } + + /** + * If required, allocate or resize the double array to fit the newly read + * values. + * + * @param holder_value the existing double array, may be null. + * @param offset the required offset to read. + * @param length the length of the new sequence. + * + * @return the allocated or resized array, same array if no such operations + * are required. + */ + private double[] ensureArray(double[] holder_value, int offset, int length) + { + if (holder_value == null) + return new double[offset + length]; + else if (holder_value.length < offset + length) + { + double[] value = new double[offset + length]; + System.arraycopy(holder_value, 0, value, 0, holder_value.length); + return value; + } + else + return holder_value; + } + + /** + * Read an array. In OMG specification is written that if the data does not + * fit into the holder value field, that array must be resized. The + * implementation follows this rule. If the holder value field contains null, + * it is newly instantiated. + */ + public void read_short_array(ShortSeqHolder holder, int offset, int length) + { + holder.value = ensureArray(holder.value, offset, length); + read_short_array(holder.value, offset, length); + } + + /** {@inheritDoc} */ + public void read_ushort_array(UShortSeqHolder holder, int offset, int length) + { + holder.value = ensureArray(holder.value, offset, length); + read_ushort_array(holder.value, offset, length); + } + + /** + * If required, allocate or resize the short array to fit the newly read + * values. + * + * @param holder_value the existing short array, may be null. + * @param offset the required offset to read. + * @param length the length of the new sequence. + * + * @return the allocated or resized array, same array if no such operations + * are required. + */ + private short[] ensureArray(short[] holder_value, int offset, int length) + { + if (holder_value == null) + return new short[offset + length]; + else if (holder_value.length < offset + length) + { + short[] value = new short[offset + length]; + System.arraycopy(holder_value, 0, value, 0, holder_value.length); + return value; + } + else + return holder_value; + } + + /** + * Read an array. In OMG specification is written that if the data does not + * fit into the holder value field, that array must be resized. The + * implementation follows this rule. If the holder value field contains null, + * it is newly instantiated. + */ + public void read_octet_array(OctetSeqHolder holder, int offset, int length) + { + holder.value = ensureArray(holder.value, offset, length); + read_octet_array(holder.value, offset, length); + } + + /** + * If required, allocate or resize the byte array to fit the newly read + * values. + * + * @param holder_value the existing byte array, may be null. + * @param offset the required offset to read. + * @param length the length of the new sequence. + * + * @return the allocated or resized array, same array if no such operations + * are required. + */ + private byte[] ensureArray(byte[] holder_value, int offset, int length) + { + if (holder_value == null) + return new byte[offset + length]; + else if (holder_value.length < offset + length) + { + byte[] value = new byte[offset + length]; + System.arraycopy(holder_value, 0, value, 0, holder_value.length); + return value; + } + else + return holder_value; + } + + /** + * Read an array. In OMG specification is written that if the data does not + * fit into the holder value field, that array must be resized. The + * implementation follows this rule. If the holder value field contains null, + * it is newly instantiated. + */ + public void read_longlong_array(LongLongSeqHolder holder, int offset, + int length) + { + holder.value = ensureArray(holder.value, offset, length); + read_longlong_array(holder.value, offset, length); + } + + /** + * Read an array. In OMG specification is written that if the data does not + * fit into the holder value field, that array must be resized. The + * implementation follows this rule. If the holder value field contains null, + * it is newly instantiated. + */ + public void read_ulonglong_array(ULongLongSeqHolder holder, int offset, + int length) + { + holder.value = ensureArray(holder.value, offset, length); + read_ulonglong_array(holder.value, offset, length); + } + + /** + * If required, allocate or resize the array of longs to fit the newly read + * values. + * + * @param holder_value the existing array, may be null. + * @param offset the required offset to read. + * @param length the length of the new sequence. + * + * @return the allocated or resized array, same array if no such operations + * are required. + */ + private long[] ensureArray(long[] holder_value, int offset, int length) + { + if (holder_value == null) + return new long[offset + length]; + else if (holder_value.length < offset + length) + { + long[] value = new long[offset + length]; + System.arraycopy(holder_value, 0, value, 0, holder_value.length); + return value; + } + else + return holder_value; + } + + /** + * Read an array. In OMG specification is written that if the data does not + * fit into the holder value field, that array must be resized. The + * implementation follows this rule. If the holder value field contains null, + * it is newly instantiated. + */ + public void read_boolean_array(BooleanSeqHolder holder, int offset, int length) + { + holder.value = ensureArray(holder.value, offset, length); + read_boolean_array(holder.value, offset, length); + } + + /** + * If required, allocate or resize the array of booleans to fit the newly read + * values. + * + * @param holder_value the existing array of booleans, may be null. + * @param offset the required offset to read. + * @param length the length of the new sequence. + * + * @return the allocated or resized array, same array if no such operations + * are required. + */ + private boolean[] ensureArray(boolean[] holder_value, int offset, int length) + { + if (holder_value == null) + return new boolean[offset + length]; + else if (holder_value.length < offset + length) + { + boolean[] value = new boolean[offset + length]; + System.arraycopy(holder_value, 0, value, 0, holder_value.length); + return value; + } + else + return holder_value; + } + + /** + * Read an array. In OMG specification is written that if the data does not + * fit into the holder value field, that array must be resized. The + * implementation follows this rule. If the holder value field contains null, + * it is newly instantiated. + */ + public void read_any_array(AnySeqHolder holder, int offset, int length) + { + holder.value = ensureArray(holder.value, offset, length); + for (int i = offset; i < offset + length; i++) + { + holder.value[i] = read_any(); + } + } + + /** + * If required, allocate or resize the array of Anys to fit the newly read + * values. + * + * @param holder_value the existing array of Anys, may be null. + * @param offset the required offset to read. + * @param length the length of the new sequence. + * + * @return the allocated or resized array, same array if no such operations + * are required. + */ + private Any[] ensureArray(Any[] holder_value, int offset, int length) + { + if (holder_value == null) + return new Any[offset + length]; + else if (holder_value.length < offset + length) + { + Any[] value = new Any[offset + length]; + System.arraycopy(holder_value, 0, value, 0, holder_value.length); + return value; + } + else + return holder_value; + } + + /** + * This method is required to represent the DataInputStream as a value type + * object. + * + * @return a single entity "IDL:omg.org/CORBA/DataInputStream:1.0", always. + */ + public String[] _truncatable_ids() + { + return new String[] { "IDL:omg.org/CORBA/DataInputStream:1.0" }; + } +} diff --git a/libjava/classpath/gnu/CORBA/CDR/AbstractCdrOutput.java b/libjava/classpath/gnu/CORBA/CDR/AbstractCdrOutput.java new file mode 100644 index 000000000..ab0b982ab --- /dev/null +++ b/libjava/classpath/gnu/CORBA/CDR/AbstractCdrOutput.java @@ -0,0 +1,1047 @@ +/* AbstractCdrOutput.java -- + 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.CORBA.CDR; + +import gnu.CORBA.BigDecimalHelper; +import gnu.CORBA.IOR; +import gnu.CORBA.IorProvider; +import gnu.CORBA.Minor; +import gnu.CORBA.TypeCodeHelper; +import gnu.CORBA.Unexpected; +import gnu.CORBA.Version; +import gnu.CORBA.GIOP.CharSets_OSF; +import gnu.CORBA.GIOP.CodeSetServiceContext; +import gnu.CORBA.typecodes.PrimitiveTypeCode; + +import org.omg.CORBA.Any; +import org.omg.CORBA.BAD_OPERATION; +import org.omg.CORBA.Context; +import org.omg.CORBA.ContextList; +import org.omg.CORBA.DataInputStream; +import org.omg.CORBA.MARSHAL; +import org.omg.CORBA.NO_IMPLEMENT; +import org.omg.CORBA.ORB; +import org.omg.CORBA.TCKind; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.UserException; +import org.omg.CORBA.TypeCodePackage.BadKind; +import org.omg.CORBA.portable.Delegate; +import org.omg.CORBA.portable.ObjectImpl; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.Streamable; + +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.Serializable; +import java.math.BigDecimal; + +/** + * A simple CORBA CDR (common data representation) + * output stream, writing data into the + * given {@link java.io.OutputStream}. + * + * The same class also implements the {@link DataInputStream}, + * providing support for writing the value type objects + * in a user defined way. + * + * TODO This class uses 16 bits per Unicode character only, as it was until + * jdk 1.4 inclusive. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public abstract class AbstractCdrOutput + extends org.omg.CORBA_2_3.portable.OutputStream + implements org.omg.CORBA.DataOutputStream +{ + /** + * The runtime, associated with this stream. This field is only used when + * reading and writing value types and filled-in in gnu.CORBA.CDR.Vio. + */ + public transient gnuRuntime runtime; + + /** + * This instance is used to convert primitive data types into the + * byte sequences. + */ + protected AbstractDataOutput b; + + /** + * The associated orb, if any. + */ + protected ORB orb; + + /** + * The GIOP version. + */ + protected Version giop = new Version(1, 2); + + /** + * The code set information. + */ + protected CodeSetServiceContext codeset; + + /** + * The name of the currently used narrow charset. + */ + private String narrow_charset; + + /** + * The name of the currently used wide charset, null if + * the native wide charset is used. + */ + private String wide_charset; + + /** + * True if the native code set is used for narrow characters. + * If the set is native, no the intermediate Reader object + * is instantiated when writing characters. + */ + private boolean narrow_native; + + /** + * True if the native code set is used for wide characters. + * If the set is native, no the intermediate Reader object + * is instantiated when writing characters. + */ + private boolean wide_native; + + /** + * If true, the Little Endian encoding is used to write the + * data. Otherwise, the Big Endian encoding is used. + */ + private boolean little_endian; + + /** + * The stream whre the data are actually written. + */ + private java.io.OutputStream actual_stream; + + /** + * Creates the stream. + * + * @param writeTo a stream to write CORBA output to. + */ + public AbstractCdrOutput(java.io.OutputStream writeTo) + { + setOutputStream(writeTo); + setCodeSet(CodeSetServiceContext.STANDARD); + } + + /** + * Creates the stream, requiring the subsequent call + * of {@link #setOutputStream(java.io.OutputStream)}. + */ + public AbstractCdrOutput() + { + setCodeSet(CodeSetServiceContext.STANDARD); + } + + /** + * Set the alignment offset, if the index of the first byte in the + * stream is different from 0. + */ + public abstract void setOffset(int an_offset); + + /** + * Clone all important settings to another stream. + */ + public void cloneSettings(AbstractCdrOutput stream) + { + stream.setBigEndian(!little_endian); + stream.setCodeSet(getCodeSet()); + stream.setVersion(giop); + stream.setOrb(orb); + } + + /** + * Set the current code set context. + */ + public void setCodeSet(CodeSetServiceContext a_codeset) + { + this.codeset = a_codeset; + narrow_charset = CharSets_OSF.getName(codeset.char_data); + wide_charset = CharSets_OSF.getName(codeset.wide_char_data); + + narrow_native = CharSets_OSF.NATIVE_CHARACTER == codeset.char_data; + wide_native = CharSets_OSF.NATIVE_WIDE_CHARACTER == codeset.wide_char_data; + } + + /** + * Get the current code set context. + */ + public CodeSetServiceContext getCodeSet() + { + return codeset; + } + + /** + * Set the orb, associated with this stream. + * @param an_orb + */ + public void setOrb(ORB an_orb) + { + orb = an_orb; + } + + /** + * Set the output stream that receives the CORBA output. + * + * @param writeTo the stream. + */ + public void setOutputStream(java.io.OutputStream writeTo) + { + if (little_endian) + b = new LittleEndianOutputStream(writeTo); + else + b = new BigEndianOutputStream(writeTo); + + actual_stream = writeTo; + } + + /** + * Set the GIOP version. Some data types are written differently + * for the different versions. The default version is 1.0 . + */ + public void setVersion(Version giop_version) + { + giop = giop_version; + } + + /** + * Specify if the stream should use the Big Endian (usual for java) + * or Little Encoding. The default is Big Endian. + * + * @param use_big_endian if true, use Big Endian, if false, + * use Little Endian. + */ + public void setBigEndian(boolean use_big_endian) + { + little_endian = !use_big_endian; + setOutputStream(actual_stream); + } + + /** + * Align the curretn position at the given natural boundary. + */ + public abstract void align(int boundary); + + /** + * Create the encapsulation stream, associated with the current + * stream. The encapsulated stream must be closed. When being + * closed, the encapsulation stream writes its buffer into + * this stream using the CORBA CDR encapsulation rules. + * + * It is not allowed to write to the current stream directly + * before the encapsulation stream is closed. + * + * The encoding (Big/Little Endian) inside the encapsulated + * sequence is the same as used into the parent stream. + * + * @return the encapsulated stream. + */ + public AbstractCdrOutput createEncapsulation() + { + return new EncapsulationStream(this, !little_endian); + } + + /** + * Return the associated {@link ORB}. + * @return the associated {@link ORB} or null is no such is set. + */ + public ORB orb() + { + return orb; + } + + /** + * Write a single byte. + * @param n byte to write (low 8 bits are written). + */ + public void write(int n) + { + try + { + b.write(n); + } + catch (IOException ex) + { + Unexpected.error(ex); + } + } + + /** + * Write bytes directly into the underlying stream. + */ + public void write(byte[] x) + throws java.io.IOException + { + b.write(x); + } + + /** + * Write bytes directly into the underlying stream. + */ + public void write(byte[] x, int ofs, int len) + throws java.io.IOException + { + b.write(x, ofs, len); + } + + /** + * Following the specification, this is not implemented. + * Override to get the functionality. + */ + public void write_Context(Context context, ContextList contexts) + { + throw new NO_IMPLEMENT(); + } + + /** + * Read the CORBA object. The object is written form of the plain (not a + * string-encoded) IOR profile without the heading endian indicator. The + * responsible method for reading such data is {@link IOR.write_no_endian}. + * + * The null value is written as defined in OMG specification (zero length + * string, followed by an empty set of profiles). + */ + public void write_Object(org.omg.CORBA.Object x) + { + ORB w_orb = orb; + if (x instanceof IorProvider) + { + ((IorProvider) x).getIor()._write_no_endian(this); + return; + } + else if (x == null) + { + IOR.write_null(this); + return; + } + else if (x instanceof ObjectImpl) + { + Delegate d = ((ObjectImpl) x)._get_delegate(); + + if (d instanceof IorProvider) + { + ((IorProvider) d).getIor()._write_no_endian(this); + return; + } + else + { + ORB d_orb = d.orb(x); + if (d_orb != null) + w_orb = d_orb; + } + } + + // Either this is not an ObjectImpl or it has the + // unexpected delegate. Try to convert via ORBs + // object_to_string(). + if (w_orb != null) + { + IOR ior = IOR.parse(w_orb.object_to_string(x)); + ior._write_no_endian(this); + return; + } + else + throw new BAD_OPERATION( + "Please set the ORB for this stream, cannot write " + + x.getClass().getName()); + } + + /** + * Write the TypeCode. This implementation delegates functionality + * to {@link cdrTypeCode}. + * + * @param x a TypeCode to write. + */ + public void write_TypeCode(TypeCode x) + { + try + { + TypeCodeHelper.write(this, x); + } + catch (UserException ex) + { + Unexpected.error(ex); + } + } + + /** + * Writes an instance of the CORBA {@link Any}. + * This method writes the typecode, followed + * by value itself. In Any contains null + * (value not set), the {@link TCKind#tk_null} + * is written. + * + * @param x the {@link Any} to write. + */ + public void write_any(Any x) + { + Streamable value = x.extract_Streamable(); + if (value != null) + { + write_TypeCode(x.type()); + value._write(this); + } + else + { + PrimitiveTypeCode p = new PrimitiveTypeCode(TCKind.tk_null); + write_TypeCode(p); + } + } + + /** + * Writes a single byte, 0 for false, + * 1 for true. + * + * @param x the value to write + */ + public void write_boolean(boolean x) + { + try + { + b.write(x ? 1 : 0); + } + catch (IOException ex) + { + Unexpected.error(ex); + } + } + + /** + * Writes the boolean array. + * + * @param x array + * @param ofs offset + * @param len length. + */ + public void write_boolean_array(boolean[] x, int ofs, int len) + { + try + { + for (int i = ofs; i < ofs + len; i++) + { + b.write(x [ i ] ? 1 : 0); + } + } + catch (IOException ex) + { + Unexpected.error(ex); + } + } + + /** + * Writes the lower byte of the passed parameter. + * @param x the char to write + * + * It is effective to write more characters at once. + */ + public void write_char(char x) + { + try + { + if (narrow_native) + b.write(x); + else + { + OutputStreamWriter ow = + new OutputStreamWriter((OutputStream) b, narrow_charset); + ow.write(x); + ow.flush(); + } + } + catch (IOException ex) + { + Unexpected.error(ex); + } + } + + /** + * Writes the lower bytes of the passed array members. + * + * @param chars an array + * @param offset offset + * @param length length + */ + public void write_char_array(char[] chars, int offset, int length) + { + try + { + if (narrow_native) + { + for (int i = offset; i < offset + length; i++) + { + b.write(chars [ i ]); + } + } + else + { + OutputStreamWriter ow = + new OutputStreamWriter((OutputStream) b, narrow_charset); + ow.write(chars, offset, length); + ow.flush(); + } + } + catch (IOException ex) + { + Unexpected.error(ex); + } + } + + /** + * Writes the double value (IEEE 754 format). + */ + public void write_double(double x) + { + try + { + align(8); + b.writeDouble(x); + } + catch (Exception ex) + { + Unexpected.error(ex); + } + } + + /** + * Writes the array of double values. + */ + public void write_double_array(double[] x, int ofs, int len) + { + try + { + align(8); + for (int i = ofs; i < ofs + len; i++) + { + b.writeDouble(x [ i ]); + } + } + catch (IOException ex) + { + Unexpected.error(ex); + } + } + + /** + * Writes CORBA fixed, storing all digits but not the scale. + * The end of the record on fixed can + * be determined from its last byte. + */ + public void write_fixed(BigDecimal fixed) + { + try + { + BigDecimalHelper.write(this, fixed); + } + catch (IOException ex) + { + Unexpected.error(ex); + } + catch (BadKind ex) + { + Unexpected.error(ex); + } + } + + /** + * Write the float value (IEEE 754 format). + */ + public void write_float(float x) + { + try + { + align(4); + b.writeFloat(x); + } + catch (IOException ex) + { + Unexpected.error(ex); + } + } + + /** + * Writes an array of the float values. + */ + public void write_float_array(float[] x, int ofs, int len) + { + try + { + align(4); + for (int i = ofs; i < ofs + len; i++) + { + b.writeFloat(x [ i ]); + } + } + catch (IOException ex) + { + Unexpected.error(ex); + } + } + + /** + * Writes the integer value (CORBA long, four bytes, high byte first). + * @param x the value to write. + */ + public void write_long(int x) + { + try + { + align(4); + b.writeInt(x); + } + catch (IOException ex) + { + Unexpected.error(ex); + } + } + + /** + * Writes the array of integer (CORBA long) values. + * + * @param x value + * @param ofs offset + * @param len length + */ + public void write_long_array(int[] x, int ofs, int len) + { + try + { + align(4); + for (int i = ofs; i < ofs + len; i++) + { + b.writeInt(x [ i ]); + } + } + catch (IOException ex) + { + Unexpected.error(ex); + } + } + + /** + * Writes the long (CORBA long long) value, 8 bytes, + * high byte first. + * + * @param x the value to write. + */ + public void write_longlong(long x) + { + try + { + align(8); + b.writeLong(x); + } + catch (IOException ex) + { + Unexpected.error(ex); + } + } + + /** + * Writes the array of longs (CORBA long longs) values. + * + * @param x value + * @param ofs offset + * @param len length + */ + public void write_longlong_array(long[] x, int ofs, int len) + { + try + { + align(8); + for (int i = ofs; i < ofs + len; i++) + { + b.writeLong(x [ i ]); + } + } + catch (IOException ex) + { + Unexpected.error(ex); + } + } + + /** + * Writes this byte. + * @param x + */ + public void write_octet(byte x) + { + try + { + b.writeByte(x); + } + catch (IOException ex) + { + Unexpected.error(ex); + } + } + + /** + * Writes the array of bytes (CORBA octets) values. + * + * @param x value + * @param ofs offset + * @param len length + */ + public void write_octet_array(byte[] x, int ofs, int len) + { + try + { + b.write(x, ofs, len); + } + catch (IOException ex) + { + Unexpected.error(ex); + } + } + + /** + * Writes first the size of array, and then the byte array using + * the {@link java.io.OutputStream#write(byte[]) }. The sequence + * being written is preceeded by the int, representing the array + * length. + */ + public void write_sequence(byte[] buf) + { + try + { + write_long(buf.length); + write(buf); + } + catch (IOException ex) + { + MARSHAL t = new MARSHAL(); + t.minor = Minor.CDR; + t.initCause(ex); + throw t; + } + } + + /** + * Writes the contents of the provided stream. + * The sequence being written is preceeded by the int, + * representing the stream buffer length (the number of + * bytes being subsequently written). + */ + public void write_sequence(BufferedCdrOutput from) + { + try + { + write_long(from.buffer.size()); + from.buffer.writeTo(this); + } + catch (IOException ex) + { + MARSHAL t = new MARSHAL(); + t.minor = Minor.CDR; + t.initCause(ex); + throw t; + } + } + + /** + * Writes the two byte integer (short), high byte first. + * + * @param x the integer to write. + */ + public void write_short(short x) + { + try + { + align(2); + b.writeShort(x); + } + catch (IOException ex) + { + Unexpected.error(ex); + } + } + + /** + * Writes the array of short (two byte integer) values. + * + * @param x value + * @param ofs offset + * @param len length + */ + public void write_short_array(short[] x, int ofs, int len) + { + try + { + align(2); + for (int i = ofs; i < ofs + len; i++) + { + b.writeShort(x [ i ]); + } + } + catch (IOException ex) + { + Unexpected.error(ex); + } + } + + /** + * Writes the string. This implementation first calls + * String.getBytes() and then writes the length of the returned + * array (as CORBA ulong) and the returned array itself. + * + * The encoding information, if previously set, is taken + * into consideration. + * + * @param x the string to write. + */ + public void write_string(String x) + { + try + { + byte[] ab = x.getBytes(narrow_charset); + write_long(ab.length + 1); + write(ab); + + // write null terminator. + write(0); + } + catch (IOException ex) + { + Unexpected.error(ex); + } + } + + /** + * Writes the CORBA unsigned long in the same way as CORBA long. + */ + public void write_ulong(int x) + { + write_long(x); + } + + /** + * Writes the array of CORBA unsigned longs in the same way as + * array of ordinary longs. + */ + public void write_ulong_array(int[] x, int ofs, int len) + { + write_long_array(x, ofs, len); + } + + /** + * Write the unsigned long long in the same way as an ordinary long long. + * + * @param x a value to write. + */ + public void write_ulonglong(long x) + { + write_longlong(x); + } + + /** + * Write the array of unsingel long longs in the same way + * an an array of the ordinary long longs. + */ + public void write_ulonglong_array(long[] x, int ofs, int len) + { + write_longlong_array(x, ofs, len); + } + + /** + * Write the unsigned short in the same way as an ordinary short. + */ + public void write_ushort(short x) + { + write_short(x); + } + + /** + * Write an array of unsigned short integersin the same way + * as an array of ordinary short integers. + */ + public void write_ushort_array(short[] x, int ofs, int len) + { + write_short_array(x, ofs, len); + } + + /** + * Writes the character as two byte short integer (Unicode value), high byte + * first. Writes in Big Endian, but never writes the endian indicator. + * + * The character is always written using the native UTF-16BE charset because + * its size under arbitrary encoding is not evident. + */ + public void write_wchar(char x) + { + try + { + if (giop.until_inclusive(1, 1)) + { + align(2); + + if (wide_native) + b.writeShort(x); + else + { + OutputStreamWriter ow = new OutputStreamWriter( + (OutputStream) b, wide_charset); + ow.write(x); + ow.flush(); + } + } + else if (wide_native) + { + b.writeByte(2); + b.writeChar(x); + } + else + { + String encoded = new String(new char[] { x }); + byte[] bytes = encoded.getBytes(wide_charset); + b.write(bytes.length + 2); + b.write(bytes); + } + } + catch (IOException ex) + { + Unexpected.error(ex); + } + } + + /** + * Write the array of wide chars. + * + * @param chars the array of wide chars + * @param offset offset + * @param length length + * + * The char array is always written using the native UTF-16BE charset because + * the character size under arbitrary encoding is not evident. + */ + public void write_wchar_array(char[] chars, int offset, int length) + { + try + { + if (giop.until_inclusive(1, 1)) + align(2); + + if (wide_native) + { + for (int i = offset; i < offset + length; i++) + { + b.writeShort(chars [ i ]); + } + } + else + { + OutputStreamWriter ow = + new OutputStreamWriter((OutputStream) b, wide_charset); + ow.write(chars, offset, length); + ow.flush(); + } + } + catch (IOException ex) + { + Unexpected.error(ex); + } + } + + /** + * Writes the length of the string in bytes (not characters) and + * then all characters as two byte unicode chars. Adds the + * Big Endian indicator, 0xFFFE, at the beginning and null wide char at + * the end. + * + * @param x the string to write. + */ + public void write_wstring(String x) + { + try + { + if (giop.since_inclusive(1, 2)) + { + byte[] bytes = x.getBytes(wide_charset); + write_sequence(bytes); + } + else + { + // Encoding with null terminator always in UTF-16. + // The wide null terminator needs extra two bytes. + write_long(2 * x.length() + 2); + + for (int i = 0; i < x.length(); i++) + { + b.writeShort(x.charAt(i)); + } + + // Write null terminator. + b.writeShort(0); + } + } + catch (IOException ex) + { + Unexpected.error(ex); + } + } + + /** {@inheritDoc} */ + public void write_any_array(Any[] anys, int offset, int length) + { + for (int i = offset; i < offset + length; i++) + { + write_any(anys [ i ]); + } + } + + public String[] _truncatable_ids() + { + /**@todo Implement this org.omg.CORBA.portable.ValueBase abstract method*/ + throw new java.lang.UnsupportedOperationException("Method _truncatable_ids() not yet implemented."); + } + + /** {@inheritDoc} */ + public void write_Abstract(java.lang.Object value) + { + write_abstract_interface(value); + } + + /** {@inheritDoc} */ + public void write_Value(Serializable value) + { + write_value(value); + } +} diff --git a/libjava/classpath/gnu/CORBA/CDR/AbstractDataInput.java b/libjava/classpath/gnu/CORBA/CDR/AbstractDataInput.java new file mode 100644 index 000000000..0ad98bed7 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/CDR/AbstractDataInput.java @@ -0,0 +1,392 @@ +/* AbstractDataInput.java -- + 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.CORBA.CDR; + +import java.io.IOException; + +/** + * Some data input stream that can be either Big or + * Little Endian. + * + * This class reuses code from GNU Classpath DataInputStream. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + * @author Warren Levy (warrenl@cygnus.com) + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface AbstractDataInput +{ + /** + * This method reads bytes from the underlying stream into the specified + * byte array buffer. It will attempt to fill the buffer completely, but + * may return a short count if there is insufficient data remaining to be + * read to fill the buffer. + * + * @param b The buffer into which bytes will be read. + * + * @return The actual number of bytes read, or -1 if end of stream reached + * before reading any bytes. + * + * @exception IOException If an error occurs. + */ + int read(byte[] b) + throws IOException; + + /** + * This method reads bytes from the underlying stream into the specified + * byte array buffer. It will attempt to read len bytes and + * will start storing them at position off into the buffer. + * This method can return a short count if there is insufficient data + * remaining to be read to complete the desired read length. + * + * @param b The buffer into which bytes will be read. + * @param off The offset into the buffer to start storing bytes. + * @param len The requested number of bytes to read. + * + * @return The actual number of bytes read, or -1 if end of stream reached + * before reading any bytes. + * + * @exception IOException If an error occurs. + */ + int read(byte[] b, int off, int len) + throws IOException; + + /** + * This method reads a Java boolean value from an input stream. It does + * so by reading a single byte of data. If that byte is zero, then the + * value returned is false. If the byte is non-zero, then + * the value returned is true. + *

+ * This method can read a boolean written by an object + * implementing the writeBoolean() method in the + * DataOutput interface. + * + * @return The boolean value read + * + * @exception EOFException If end of file is reached before reading + * the boolean + * @exception IOException If any other error occurs + * + * @see DataOutput#writeBoolean + */ + boolean readBoolean() + throws IOException; + + /** + * This method reads a Java byte value from an input stream. The value + * is in the range of -128 to 127. + *

+ * This method can read a byte written by an object + * implementing the writeByte() method in the + * DataOutput interface. + * + * @return The byte value read + * + * @exception EOFException If end of file is reached before reading the byte + * @exception IOException If any other error occurs + * + * @see DataOutput#writeByte + */ + byte readByte() + throws IOException; + + /** + * This method reads a Java char value from an input stream. + * It operates by reading two bytes from the stream and converting them to + * a single 16-bit Java char. The two bytes are stored most + * significant byte first (i.e., "big endian") regardless of the native + * host byte ordering. + *

+ * As an example, if byte1 and byte2 + * represent the first and second byte read from the stream + * respectively, they will be transformed to a char in + * the following manner: + *

+ * (char)(((byte1 & 0xFF) << 8) | (byte2 & 0xFF) + *

+ * This method can read a char written by an object + * implementing the writeChar() method in the + * DataOutput interface. + * + * @return The char value read + * + * @exception EOFException If end of file is reached before reading the char + * @exception IOException If any other error occurs + * + * @see DataOutput#writeChar + */ + char readChar() + throws IOException; + + /** + * This method reads a Java double value from an input stream. It operates + * by first reading a long value from the stream by calling the + * readLong() method in this interface, then converts + * that long to a double using the + * longBitsToDouble method in the class + * java.lang.Double + *

+ * This method can read a double written by an object + * implementing the writeDouble() method in the + * DataOutput interface. + * + * @return The double value read + * + * @exception EOFException If end of file is reached before reading + * the double + * @exception IOException If any other error occurs + * + * @see DataOutput#writeDouble + * @see java.lang.Double#longBitsToDouble + */ + double readDouble() + throws IOException; + + /** + * This method reads a Java float value from an input stream. It + * operates by first reading an int value from the + * stream by calling the readInt() method in this + * interface, then converts that int to a + * float using the intBitsToFloat method + * in the class java.lang.Float + *

+ * This method can read a float written by an object + * implementing the writeFloat() method in the + * DataOutput interface. + * + * @return The float value read + * + * @exception EOFException If end of file is reached before reading the float + * @exception IOException If any other error occurs + * + * @see DataOutput#writeFloat + * @see java.lang.Float#intBitsToFloat + */ + float readFloat() + throws IOException; + + /** + * This method reads raw bytes into the passed array until the array is + * full. Note that this method blocks until the data is available and + * throws an exception if there is not enough data left in the stream to + * fill the buffer. Note also that zero length buffers are permitted. + * In this case, the method will return immediately without reading any + * bytes from the stream. + * + * @param b The buffer into which to read the data + * + * @exception EOFException If end of file is reached before filling the + * buffer + * @exception IOException If any other error occurs + */ + void readFully(byte[] b) + throws IOException; + + /** + * This method reads a Java int value from an input stream + * It operates by reading four bytes from the stream and converting them to + * a single Java int. The bytes are stored most + * significant byte first (i.e., "big endian") regardless of the native + * host byte ordering. + *

+ * As an example, if byte1 through byte4 represent + * the first four bytes read from the stream, they will be + * transformed to an int in the following manner: + *

+ * (int)(((byte1 & 0xFF) << 24) + ((byte2 & 0xFF) << 16) + + * ((byte3 & 0xFF)<< 8) + (byte4 & 0xFF))) + *

+ * The value returned is in the range of -2147483648 to 2147483647. + *

+ * This method can read an int written by an object + * implementing the writeInt() method in the + * DataOutput interface. + * + * @return The int value read + * + * @exception EOFException If end of file is reached before reading the int + * @exception IOException If any other error occurs + * + * @see DataOutput#writeInt + */ + int readInt() + throws IOException; + + /** + * This method reads a Java long value from an input stream + * It operates by reading eight bytes from the stream and converting them to + * a single Java long. The bytes are stored most + * significant byte first (i.e., "big endian") regardless of the native + * host byte ordering. + *

+ * As an example, if byte1 through byte8 represent + * the first eight bytes read from the stream, they will be + * transformed to an long in the following manner: + *

+ * (long)(((byte1 & 0xFF) << 56) + ((byte2 & 0xFF) << 48) + + * ((byte3 & 0xFF) << 40) + ((byte4 & 0xFF) << 32) + + * ((byte5 & 0xFF) << 24) + ((byte6 & 0xFF) << 16) + + * ((byte7 & 0xFF) << 8) + (byte8 & 0xFF))) + * + *

+ * The value returned is in the range of -9223372036854775808 to + * 9223372036854775807. + *

+ * This method can read an long written by an object + * implementing the writeLong() method in the + * DataOutput interface. + * + * @return The long value read + * + * @exception EOFException If end of file is reached before reading the long + * @exception IOException If any other error occurs + * + * @see DataOutput#writeLong + */ + long readLong() + throws IOException; + + /** + * This method reads a signed 16-bit value into a Java in from the + * stream. It operates by reading two bytes from the stream and + * converting them to a single 16-bit Java short. The + * two bytes are stored most significant byte first (i.e., "big + * endian") regardless of the native host byte ordering. + *

+ * As an example, if byte1 and byte2 + * represent the first and second byte read from the stream + * respectively, they will be transformed to a short. in + * the following manner: + *

+ * (short)(((byte1 & 0xFF) << 8) | (byte2 & 0xFF)) + *

+ * The value returned is in the range of -32768 to 32767. + *

+ * This method can read a short written by an object + * implementing the writeShort() method in the + * DataOutput interface. + * + * @return The short value read + * + * @exception EOFException If end of file is reached before reading the value + * @exception IOException If any other error occurs + * + * @see DataOutput#writeShort + */ + short readShort() + throws IOException; + + /** + * This method reads 8 unsigned bits into a Java int + * value from the stream. The value returned is in the range of 0 to + * 255. + *

+ * This method can read an unsigned byte written by an object + * implementing the writeUnsignedByte() method in the + * DataOutput interface. + * + * @return The unsigned bytes value read as a Java int. + * + * @exception EOFException If end of file is reached before reading the value + * @exception IOException If any other error occurs + * + * @see DataOutput#writeByte + */ + int readUnsignedByte() + throws IOException; + + /** + * This method reads 16 unsigned bits into a Java int value from the stream. + * It operates by reading two bytes from the stream and converting them to + * a single Java int The two bytes are stored most + * significant byte first (i.e., "big endian") regardless of the native + * host byte ordering. + *

+ * As an example, if byte1 and byte2 + * represent the first and second byte read from the stream + * respectively, they will be transformed to an int in + * the following manner: + *

+ * (int)(((byte1 & 0xFF) << 8) + (byte2 & 0xFF)) + *

+ * The value returned is in the range of 0 to 65535. + *

+ * This method can read an unsigned short written by an object + * implementing the writeUnsignedShort() method in the + * DataOutput interface. + * + * @return The unsigned short value read as a Java int + * + * @exception EOFException If end of file is reached before reading the value + * @exception IOException If any other error occurs + * + * @see DataOutput#writeShort + */ + int readUnsignedShort() + throws IOException; + + /** + * Read a single byte. + * + * @return a byte, extracted from the stream or -1 if + * EOF has been reached. + * @throws IOException + */ + public int read() + throws IOException; + + /** + * This method attempts to skip and discard the specified number of bytes + * in the input stream. It may actually skip fewer bytes than requested. + * This method will not skip any bytes if passed a negative number of bytes + * to skip. + * + * @param n The requested number of bytes to skip. + * + * @return The requested number of bytes to skip. + * + * @exception IOException If an error occurs. + * @specnote The JDK docs claim that this returns the number of bytes + * actually skipped. The JCL claims that this method can throw an + * EOFException. Neither of these appear to be true in the JDK 1.3's + * implementation. This tries to implement the actual JDK behaviour. + */ + int skipBytes(int n) + throws IOException; +} diff --git a/libjava/classpath/gnu/CORBA/CDR/AbstractDataOutput.java b/libjava/classpath/gnu/CORBA/CDR/AbstractDataOutput.java new file mode 100644 index 000000000..e41ec598a --- /dev/null +++ b/libjava/classpath/gnu/CORBA/CDR/AbstractDataOutput.java @@ -0,0 +1,185 @@ +/* AbstractDataOutput.java -- + 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.CORBA.CDR; + +import java.io.IOException; + +/** + * An abstract data output stream that could write data in either + * Big Endian or Little Endian format. + * + * This class reuses code from GNU Classpath DataOutputStream. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + * @author Warren Levy (warrenl@cygnus.com) + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public interface AbstractDataOutput +{ + /** + * This method flushes any unwritten bytes to the underlying stream. + * + * @exception IOException If an error occurs. + */ + void flush() + throws IOException; + + /** + * This method writes the specified byte (passed as an int) + * to the underlying output stream. + * + * @param value The byte to write, passed as an int. + * + * @exception IOException If an error occurs. + */ + void write(int value) + throws IOException; + + /** + * This method writes len bytes from the specified byte array + * buf starting at position offset into the + * buffer to the underlying output stream. + * + * @param buf The byte array to write from. + * @param offset The index into the byte array to start writing from. + * @param len The number of bytes to write. + * + * @exception IOException If an error occurs. + */ + void write(byte[] buf, int offset, int len) + throws IOException; + + /** + * Write the complete byte array. + * @throws IOException + */ + void write(byte[] buf) + throws IOException; + + /** + * This method writes a Java boolean value to an output stream. If + * value is true, a byte with the value of + * 1 will be written, otherwise a byte with the value of 0 will be + * written. + * + * The value written can be read using the readBoolean + * method in DataInput. + * + * @param value The boolean value to write to the stream + * + * @exception IOException If an error occurs + */ + void writeBoolean(boolean value) + throws IOException; + + /** + * This method writes a Java byte value to an output stream. The + * byte to be written will be in the lowest 8 bits of the + * int value passed. + * + * The value written can be read using the readByte or + * readUnsignedByte methods in DataInput. + * + * @param value The byte to write to the stream, passed as + * the low eight bits of an int. + * + * @exception IOException If an error occurs + */ + void writeByte(int value) + throws IOException; + + /** + * This method writes a Java short value to an output stream. The + * char to be written will be in the lowest 16 bits of the int + * value passed. + * + * @exception IOException If an error occurs + */ + void writeShort(int value) + throws IOException; + + /** + * This method writes a Java char value to an output stream. The + * char to be written will be in the lowest 16 bits of the int + * value passed. + * + * @exception IOException If an error occurs + */ + void writeChar(int value) + throws IOException; + + /** + * This method writes a Java int value to an output stream. + * + * @param value The int value to write to the stream + * + * @exception IOException If an error occurs + */ + void writeInt(int value) + throws IOException; + + /** + * This method writes a Java long value to an output stream. + * + * @param value The long value to write to the stream + * + * @exception IOException If an error occurs + */ + void writeLong(long value) + throws IOException; + + /** + * This method writes a Java float value to the stream. + * @param value The float value to write to the stream + * + * @exception IOException If an error occurs + */ + void writeFloat(float value) + throws IOException; + + /** + * This method writes a Java double value to the stream. + * + * @param value The double value to write to the stream + * + * @exception IOException If an error occurs + */ + void writeDouble(double value) + throws IOException; +} diff --git a/libjava/classpath/gnu/CORBA/CDR/AligningInput.java b/libjava/classpath/gnu/CORBA/CDR/AligningInput.java new file mode 100644 index 000000000..8d438ab06 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/CDR/AligningInput.java @@ -0,0 +1,131 @@ +/* AligningInput.java -- + 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.CORBA.CDR; + +import java.io.ByteArrayInputStream; + +import org.omg.CORBA.BAD_PARAM; + +/** + * The input stream with the possibility to align on the + * word (arbitrary size) boundary. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class AligningInput + extends ByteArrayInputStream +{ + /** + * The alignment offset. + */ + private int offset = 0; + + /** + * Create a stream, reading form the given buffer. + * + * @param a_buffer a buffer to read from. + */ + public AligningInput(byte[] a_buffer) + { + super(a_buffer); + } + + /** + * Set the alignment offset, if the index of the first byte in the + * stream is different from 0. + */ + public void setOffset(int an_offset) + { + offset = an_offset; + } + + /** + * Skip several bytes, aligning the internal pointer on the + * selected boundary. + * + * @throws BAD_PARAM, minor code 0, the alignment is not possible, + * usually due the wrong parameter value. + */ + public void align(int alignment) + { + try + { + int d = (pos + offset) % alignment; + if (d > 0) + { + skip(alignment - d); + } + } + catch (Exception ex) + { + BAD_PARAM p = new BAD_PARAM("Unable to align at " + alignment); + p.initCause(ex); + throw p; + } + } + + /** + * Get the byte buffer, from where the data are read. + */ + public byte[] getBuffer() + { + return buf; + } + + /** + * Get the current position in the buffer. + * + * @return The position in the buffer, taking offset into consideration. + */ + public int getPosition() + { + return pos + offset; + } + + /** + * Jump to the given position, taking offset into consideration. + */ + public void seek(int position) + { + if (position < offset || position > (count+offset)) + throw new ArrayIndexOutOfBoundsException(position + + " is out of valid ["+offset+".." + (count+offset) + "[ range"); + pos = position - offset; + } +} diff --git a/libjava/classpath/gnu/CORBA/CDR/AligningOutput.java b/libjava/classpath/gnu/CORBA/CDR/AligningOutput.java new file mode 100644 index 000000000..b0c569ec8 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/CDR/AligningOutput.java @@ -0,0 +1,148 @@ +/* AligningOutput.java -- + 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.CORBA.CDR; + +import java.io.ByteArrayOutputStream; + +import org.omg.CORBA.BAD_PARAM; + +/** + * The input stream with the possibility to align on the + * word (arbitrary size) boundary. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class AligningOutput + extends ByteArrayOutputStream +{ + /** + * The alignment offset. + */ + private int offset = 0; + + /** + * Create a stream with the default intial buffer size. + */ + public AligningOutput() + { + } + + /** + * Create a stream with the given intial buffer size. + */ + public AligningOutput(int initial_size) + { + super(initial_size); + } + + /** + * Set the alignment offset, if the index of the first byte in the + * stream is different from 0. + */ + public void setOffset(int an_offset) + { + offset = an_offset; + } + + /** + * Skip several bytes, aligning the internal pointer on the + * selected boundary. + * + * @throws BAD_PARAM, minor code 0, the alignment is not possible, + * usually due the wrong parameter value. + */ + public void align(int alignment) + { + try + { + int d = (count + offset) % alignment; + if (d > 0) + { + skip(alignment - d); + } + } + catch (Exception ex) + { + BAD_PARAM p = new BAD_PARAM("Unable to align at " + alignment); + p.initCause(ex); + throw p; + } + } + + /** + * Write the specified number of zero bytes. + * + * @param bytes the number of zero bytes to write. + */ + public void skip(int bytes) + { + for (int i = 0; i < bytes; i++) + { + write(0); + } + } + + /** + * Get the current position in the buffer. + * + * @return The position in the buffer, taking offset into consideration. + */ + public int getPosition() + { + return size()+offset; + } + + /** + * Seek to the given position (not in use). + */ + public void seek(int position) + { + count = position - offset; + } + + /** + * Get the buffer without copying it. Use with care. + */ + public byte[] getBuffer() + { + return buf; + } + + +} diff --git a/libjava/classpath/gnu/CORBA/CDR/ArrayValueHelper.java b/libjava/classpath/gnu/CORBA/CDR/ArrayValueHelper.java new file mode 100644 index 000000000..0578f13b8 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/CDR/ArrayValueHelper.java @@ -0,0 +1,254 @@ +/* ArrayValueHelper.java -- + 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.CORBA.CDR; + +import gnu.CORBA.ObjectCreator; + +import org.omg.CORBA.BooleanSeqHelper; +import org.omg.CORBA.CharSeqHelper; +import org.omg.CORBA.DoubleSeqHelper; +import org.omg.CORBA.FloatSeqHelper; +import org.omg.CORBA.LongLongSeqHelper; +import org.omg.CORBA.LongSeqHelper; +import org.omg.CORBA.OctetSeqHelper; +import org.omg.CORBA.ShortSeqHelper; +import org.omg.CORBA.portable.BoxedValueHelper; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.OutputStream; + +import java.io.Serializable; +import java.lang.reflect.Array; +import java.rmi.Remote; + +import javax.rmi.CORBA.Util; +import javax.rmi.CORBA.ValueHandler; + +/** + * Writes arrays as a boxed value types. A single instance is used to write a + * single array. This class is only used with RMI/IIOP, to handle array boxed + * values. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +class ArrayValueHelper + implements BoxedValueHelper +{ + /** + * The value handler (one for all instances). + */ + static ValueHandler handler = Util.createValueHandler(); + + /** + * A class of the array being written. + */ + Class arrayClass; + + /** + * The array component class. + */ + Class component; + + /** + * The array component repository Id. + */ + String componentId; + + /** + * If true, the array members are written as objects rather than as values. + * True for Remotes and CORBA objects. + */ + boolean written_as_object() + { + return org.omg.CORBA.Object.class.isAssignableFrom(component) + || Remote.class.isAssignableFrom(component); + } + + /** + * Creates the instance of the helper to write this specific array class. + */ + ArrayValueHelper(Class an_arrayClass) + { + arrayClass = an_arrayClass; + } + + /** + * Get the array repository Id that will be the RMI repository id. + */ + public String get_id() + { + return ObjectCreator.getRepositoryId(arrayClass); + } + + /** + * Read the array from the input stream. + */ + public Serializable read_value(InputStream input) + { + if (input instanceof HeadlessInput) + { + ((HeadlessInput) input).subsequentCalls = true; + } + + component = arrayClass.getComponentType(); + + if (component.equals(byte.class)) + return OctetSeqHelper.read(input); + else if (component.equals(String.class)) + { + // String array is optimized because this may be frequent. + String[] s = new String[input.read_long()]; + + for (int i = 0; i < s.length; i++) + s[i] = (String) Vio.read(input, Vio.m_StringValueHelper); + return s; + } + else if (component.equals(int.class)) + return LongSeqHelper.read(input); + else if (component.equals(long.class)) + return LongLongSeqHelper.read(input); + else if (component.equals(double.class)) + return DoubleSeqHelper.read(input); + else if (component.equals(float.class)) + return FloatSeqHelper.read(input); + else if (component.equals(boolean.class)) + return BooleanSeqHelper.read(input); + else if (component.equals(short.class)) + return ShortSeqHelper.read(input); + else if (component.equals(char.class)) + return CharSeqHelper.read(input); + else + { + // Read others, use reflection. + int n = input.read_long(); + + gnuValueStream s = null; + + Serializable array = (Serializable) Array.newInstance(component, n); + if (written_as_object()) + for (int i = 0; i < n; i++) + { + gnuRuntime g; + int position; + if (input instanceof gnuValueStream) + { + s = (gnuValueStream) input; + g = s.getRunTime(); + position = s.getPosition(); + } + else + { + g = null; + position = -1; + } + + if (input instanceof HeadlessInput) + ((HeadlessInput) input).subsequentCalls = true; + + Object o = handler.readValue(input, position, component, null, g); + Array.set(array, i, o); + } + else + for (int i = 0; i < n; i++) + Array.set(array, i, Vio.read(input, component)); + return array; + } + } + + /** + * Write the array to the input stream. + */ + public void write_value(OutputStream output, Serializable value) + { + if (output instanceof gnuValueStream) + { + gnuRuntime r = ((gnuValueStream) output).getRunTime(); + if (r != null) + r.target = null; + } + + if (value instanceof byte[]) + OctetSeqHelper.write(output, (byte[]) value); + else if (value instanceof String[]) + { + String[] s = (String[]) value; + output.write_long(s.length); + for (int i = 0; i < s.length; i++) + Vio.write(output, s[i], Vio.m_StringValueHelper); + } + else if (value instanceof int[]) + LongSeqHelper.write(output, (int[]) value); + else if (value instanceof long[]) + LongLongSeqHelper.write(output, (long[]) value); + else if (value instanceof double[]) + DoubleSeqHelper.write(output, (double[]) value); + else if (value instanceof float[]) + FloatSeqHelper.write(output, (float[]) value); + else if (value instanceof boolean[]) + BooleanSeqHelper.write(output, (boolean[]) value); + else if (value instanceof short[]) + ShortSeqHelper.write(output, (short[]) value); + else if (value instanceof char[]) + CharSeqHelper.write(output, (char[]) value); + else + { + // Write others, use reflection. + component = arrayClass.getComponentType(); + + int n = Array.getLength(value); + output.write_long(n); + if (written_as_object()) + for (int i = 0; i < n; i++) + { + Object o = Array.get(value, i); + if (o == null) + output.write_Object(null); + else + // CORBA objects have another notation. + handler.writeValue(output, (Serializable) o); + } + else + { + for (int i = 0; i < n; i++) + Vio.write(output, (Serializable) Array.get(value, i), + component); + } + + } + } +} diff --git a/libjava/classpath/gnu/CORBA/CDR/BigEndianInputStream.java b/libjava/classpath/gnu/CORBA/CDR/BigEndianInputStream.java new file mode 100644 index 000000000..5579789a5 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/CDR/BigEndianInputStream.java @@ -0,0 +1,61 @@ +/* BigEndianInputStream.java -- + 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.CORBA.CDR; + +import java.io.DataInputStream; +import java.io.InputStream; + +/** + * As java uses Big Endian by default, this class is directly derived + * form DataInputStream. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class BigEndianInputStream + extends DataInputStream + implements AbstractDataInput +{ + /** + * Delegates to the parent constructor. + */ + public BigEndianInputStream(InputStream in) + { + super(in); + } +} diff --git a/libjava/classpath/gnu/CORBA/CDR/BigEndianOutputStream.java b/libjava/classpath/gnu/CORBA/CDR/BigEndianOutputStream.java new file mode 100644 index 000000000..dda14a03a --- /dev/null +++ b/libjava/classpath/gnu/CORBA/CDR/BigEndianOutputStream.java @@ -0,0 +1,62 @@ +/* BigEndianOutputStream.java -- + 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.CORBA.CDR; + +import java.io.DataOutputStream; +import java.io.OutputStream; + +/** + * A stream to read the data in Big Endian format. This class is + * directly derived from DataOutputStream that uses the Big + * Endian. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class BigEndianOutputStream + extends DataOutputStream + implements AbstractDataOutput +{ + /** + * Delegate functionality to the parent constructor. + */ + public BigEndianOutputStream(OutputStream out) + { + super(out); + } +} diff --git a/libjava/classpath/gnu/CORBA/CDR/BufferedCdrOutput.java b/libjava/classpath/gnu/CORBA/CDR/BufferedCdrOutput.java new file mode 100644 index 000000000..ae510b39c --- /dev/null +++ b/libjava/classpath/gnu/CORBA/CDR/BufferedCdrOutput.java @@ -0,0 +1,156 @@ +/* BufferedCdrOutput.java -- + 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.CORBA.CDR; + +import java.io.ByteArrayOutputStream; + +/** + * A CORBA output stream, writing data into the internal buffer ({@link ByteArrayOutputStream}). + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class BufferedCdrOutput + extends AbstractCdrOutput + implements gnuValueStream +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * The byte buffer. + */ + public final AligningOutput buffer; + + /** + * Creates the instance with the given initial buffer size. + * + * @param bufSize the buffer size. + */ + public BufferedCdrOutput(int bufSize) + { + buffer = new AligningOutput(bufSize); + setOutputStream(buffer); + } + + /** + * Creates the instance with the default buffer size. + */ + public BufferedCdrOutput() + { + buffer = new AligningOutput(); + setOutputStream(buffer); + } + + /** + * Set the alignment offset, if the index of the first byte in the stream is + * different from 0. + */ + public void setOffset(int an_offset) + { + buffer.setOffset(an_offset); + } + + /** + * Align the curretn position at the given natural boundary. + */ + public void align(int boundary) + { + buffer.align(boundary); + } + + /** + * Return the input stream that reads the previously written values. + */ + public org.omg.CORBA.portable.InputStream create_input_stream() + { + BufferredCdrInput in = new BufferredCdrInput(buffer.toByteArray()); + in.setOrb(orb); + + in.setVersion(giop); + in.setCodeSet(getCodeSet()); + + return in; + } + + /** + * Resets (clears) the buffer. + */ + public void reset() + { + buffer.reset(); + setOutputStream(buffer); + } + + /** + * Get the current position in the buffer. + * + * @return The position in the buffer, taking offset into consideration. + */ + public int getPosition() + { + return buffer.getPosition(); + } + + /** + * Get the associated RunTime. + */ + public gnuRuntime getRunTime() + { + return runtime; + } + + /** + * Replace the instance of RunTime. + */ + public void setRunTime(gnuRuntime a_runtime) + { + runtime = a_runtime; + } + + /** + * Seek to the given position. + */ + public void seek(int position) + { + buffer.seek(position); + } + +} diff --git a/libjava/classpath/gnu/CORBA/CDR/BufferredCdrInput.java b/libjava/classpath/gnu/CORBA/CDR/BufferredCdrInput.java new file mode 100644 index 000000000..accb65a0d --- /dev/null +++ b/libjava/classpath/gnu/CORBA/CDR/BufferredCdrInput.java @@ -0,0 +1,153 @@ +/* BufferredCdrInput.java -- + 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.CORBA.CDR; + + +/** + * The CDR input stream that reads data from the byte buffer. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class BufferredCdrInput + extends AbstractCdrInput + implements gnuValueStream +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * The byte array input stream to read data from. + */ + public final AligningInput buffer; + + /** + * Creates the CDR input stream that reads from the given buffer + * array. + * + * @param a_buffer an array to read from. + */ + public BufferredCdrInput(byte[] a_buffer) + { + buffer = new AligningInput(a_buffer); + setInputStream(buffer); + } + + /** + * Set the alignment offset, if the index of the first byte in the + * stream is different from 0. + */ + public void setOffset(int offset) + { + buffer.setOffset(offset); + } + + /** + * Skip several bytes, aligning the internal pointer on the + * selected boundary. + */ + public void align(int alignment) + { + buffer.align(alignment); + } + + /** + * Mark the current position. + * @param ahead + */ + public synchronized void mark(int ahead) + { + buffer.mark(ahead); + } + + /** + * Checks if marking is supported. + * @return + */ + public boolean markSupported() + { + return buffer.markSupported(); + } + + /** + * Resets the stream to the previously marked position. + */ + public void reset() + { + buffer.reset(); + setInputStream(buffer); + } + + /** + * Get the current position in the buffer. + * + * @return The position in the buffer, taking offset into consideration. + */ + public int getPosition() + { + return buffer.getPosition(); + } + + /** + * Jump to the given position, taking offset into consideration. + */ + public void seek(int position) + { + buffer.seek(position); + setInputStream(buffer); + } + + /** + * Get the associated RunTime. + */ + public gnuRuntime getRunTime() + { + return runtime; + } + + /** + * Replace the instance of RunTime. + */ + public void setRunTime(gnuRuntime a_runtime) + { + runtime = a_runtime; + } + +} diff --git a/libjava/classpath/gnu/CORBA/CDR/EncapsulationStream.java b/libjava/classpath/gnu/CORBA/CDR/EncapsulationStream.java new file mode 100644 index 000000000..e42991232 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/CDR/EncapsulationStream.java @@ -0,0 +1,147 @@ +/* EncapsulationOutput.java -- + 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.CORBA.CDR; + +import java.io.IOException; + +/** + * The encapsulated data, as they are defined by CORBA specification. + * This includes the extra 0 byte (Big endian) in the beginning. + * When written to the parent steam, the encapsulated data are preceeded + * by the data length in bytes. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class EncapsulationStream + extends AbstractCdrOutput +{ + /** + * The Big Endian (most siginificant byte first flag). + */ + public static final byte BIG_ENDIAN = 0; + + /** + * The Little Endian (least siginificant byte first flag). + */ + public static final byte LITTLE_ENDIAN = 1; + + /** + * The byte buffer. + */ + public final AligningOutput buffer; + + /** + * The stream, where the data are being encapsulated. + */ + public final org.omg.CORBA.portable.OutputStream parent; + + /** + * Create the EncapsulationOutput with the given parent stream + * and the specified encoding. + */ + public EncapsulationStream(org.omg.CORBA.portable.OutputStream _parent, + boolean use_big_endian) + { + super(); + setBigEndian(use_big_endian); + buffer = new AligningOutput(); + setOutputStream(buffer); + parent = _parent; + write(use_big_endian?BIG_ENDIAN:LITTLE_ENDIAN); + } + + /** + * Set the alignment offset, if the index of the first byte in the + * stream is different from 0. + */ + public void setOffset(int an_offset) + { + buffer.setOffset(an_offset); + } + + /** + * Align the curretn position at the given natural boundary. + */ + public void align(int boundary) + { + buffer.align(boundary); + } + + /** + * Writes the content of the encapsulated output into the parent + * buffer. + */ + public void close() + { + try + { + parent.write_long(buffer.size()); + buffer.writeTo(parent); + } + catch (IOException ex) + { + InternalError err = new InternalError(); + err.initCause(ex); + throw err; + } + } + + /** + * Return the input stream that reads the previously written values. + */ + public org.omg.CORBA.portable.InputStream create_input_stream() + { + BufferredCdrInput in = new BufferredCdrInput(buffer.toByteArray()); + in.setOrb(orb); + + in.setVersion(giop); + in.setCodeSet(getCodeSet()); + + return in; + } + + /** + * Resets (clears) the buffer. + */ + public void reset() + { + buffer.reset(); + setOutputStream(buffer); + } +} diff --git a/libjava/classpath/gnu/CORBA/CDR/HeadlessInput.java b/libjava/classpath/gnu/CORBA/CDR/HeadlessInput.java new file mode 100644 index 000000000..5e97c73b8 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/CDR/HeadlessInput.java @@ -0,0 +1,749 @@ +/* HeadlessInput.java -- + 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.CORBA.CDR; + +import gnu.CORBA.Minor; + +import org.omg.CORBA.Any; +import org.omg.CORBA.AnySeqHolder; +import org.omg.CORBA.BooleanSeqHolder; +import org.omg.CORBA.CharSeqHolder; +import org.omg.CORBA.Context; +import org.omg.CORBA.DataInputStream; +import org.omg.CORBA.DoubleSeqHolder; +import org.omg.CORBA.FloatSeqHolder; +import org.omg.CORBA.LongLongSeqHolder; +import org.omg.CORBA.LongSeqHolder; +import org.omg.CORBA.MARSHAL; +import org.omg.CORBA.ORB; +import org.omg.CORBA.OctetSeqHolder; +import org.omg.CORBA.Principal; +import org.omg.CORBA.ShortSeqHolder; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.ULongLongSeqHolder; +import org.omg.CORBA.ULongSeqHolder; +import org.omg.CORBA.UShortSeqHolder; +import org.omg.CORBA.WCharSeqHolder; +import org.omg.CORBA.portable.BoxedValueHelper; +import org.omg.CORBA.portable.InputStream; + +import java.io.IOException; +import java.io.Serializable; +import java.math.BigDecimal; + +/** + * Substitutes the main stream in factories when the header is already behind. + * Overrides methods that may be invoked from the factory, forcing not to read + * the header if called first time on this stream. + * + * This stream reverts to default behavior if one or more call are made (reading + * value types that are nested fields of the value type). + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class HeadlessInput + extends org.omg.CORBA_2_3.portable.InputStream + implements DataInputStream, gnuValueStream +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * Indicates that no positional information is available. + */ + static final int NONE = -1; + + /** + * If true, this is not the first call. + */ + public boolean subsequentCalls; + + /** + * The enclosed stream. + */ + final BufferredCdrInput stream; + + /** + * Create an instance, reading from the given buffer. + * + * @param a_stream a stream from where the data will be read. + * @param inheritSettings a stream from that endian and other settings are + * inherited. + */ + public HeadlessInput(BufferredCdrInput a_stream, InputStream inheritSettings) + { + stream = a_stream; + + if (inheritSettings instanceof AbstractCdrInput) + { + AbstractCdrInput t = (AbstractCdrInput) inheritSettings; + t.cloneSettings(stream); + } + else if (stream.orb() == null) + stream.setOrb(inheritSettings.orb()); + + if (inheritSettings instanceof gnuValueStream + && stream.getRunTime() == null) + { + stream.setRunTime(((gnuValueStream) inheritSettings).getRunTime()); + } + } + + /** + * Tries to read using boxed value helper. + */ + public Serializable read_value(BoxedValueHelper helper) + { + if (subsequentCalls) + return stream.read_value(helper); + else + { + subsequentCalls = true; + return helper.read_value(this); + } + } + + /** + * Tries to locate a factory using repository id. + */ + public Serializable read_value(String repository_id) + { + if (subsequentCalls) + return stream.read_value(repository_id); + else + { + subsequentCalls = true; + Serializable value = Vio.readValue(this, NONE, null, + null, repository_id, null, null); + return value; + } + } + + /** + * Try to read when having an unitialised value. + */ + public Serializable read_value(Serializable value) + { + if (subsequentCalls) + return stream.read_value(value); + else + { + subsequentCalls = true; + value = Vio.readValue(this, NONE, value, null, null, + null, null); + return value; + } + } + + /** + * Try to read when having an unitialised value. + */ + public Serializable read_value(Class clz) + { + if (subsequentCalls) + return stream.read_value(clz); + else + { + try + { + subsequentCalls = true; + Serializable value = (Serializable) Vio.instantiateAnyWay(clz); + value = Vio.readValue(this, NONE, value, null, null, + null, null); + return value; + } + catch (Exception ex) + { + MARSHAL m = new MARSHAL("Can't read an instance of " + + clz.getName()); + m.minor = Minor.Value; + m.initCause(ex); + throw m; + } + } + } + + /** + * Delegates functionality to the underlying stream. + */ + public int available() + throws IOException + { + return stream.available(); + } + + /** + * Delegates functionality to the underlying stream. + */ + public void close() + throws IOException + { + stream.close(); + } + + /** + * Delegates functionality to the underlying stream. + */ + public void mark(int readlimit) + { + stream.mark(readlimit); + } + + /** + * Delegates functionality to the underlying stream. + */ + public boolean markSupported() + { + return stream.markSupported(); + } + + /** + * Delegates functionality to the underlying stream. + */ + public ORB orb() + { + return stream.orb(); + } + + /** + * Delegates functionality to the underlying stream. + */ + public Object read_abstract_interface() + { + return stream.read_abstract_interface(); + } + + /** + * Delegates functionality to the underlying stream. + */ + public Object read_abstract_interface(Class clz) + { + return stream.read_abstract_interface(clz); + } + + /** + * Delegates functionality to the underlying stream. + */ + public Any read_any() + { + return stream.read_any(); + } + + /** + * Delegates functionality to the underlying stream. + */ + public void read_boolean_array(boolean[] value, int offset, int length) + { + stream.read_boolean_array(value, offset, length); + } + + /** + * Delegates functionality to the underlying stream. + */ + public boolean read_boolean() + { + return stream.read_boolean(); + } + + /** + * Delegates functionality to the underlying stream. + */ + public void read_char_array(char[] value, int offset, int length) + { + stream.read_char_array(value, offset, length); + } + + /** + * Delegates functionality to the underlying stream. + */ + public char read_char() + { + return stream.read_char(); + } + + /** + * Delegates functionality to the underlying stream. + */ + public Context read_Context() + { + return stream.read_Context(); + } + + /** + * Delegates functionality to the underlying stream. + */ + public void read_double_array(double[] value, int offset, int length) + { + stream.read_double_array(value, offset, length); + } + + /** + * Delegates functionality to the underlying stream. + */ + public double read_double() + { + return stream.read_double(); + } + + /** + * Delegates functionality to the underlying stream. + */ + public BigDecimal read_fixed() + { + return stream.read_fixed(); + } + + /** + * Delegates functionality to the underlying stream. + */ + public void read_float_array(float[] value, int offset, int length) + { + stream.read_float_array(value, offset, length); + } + + /** + * Delegates functionality to the underlying stream. + */ + public float read_float() + { + return stream.read_float(); + } + + /** + * Delegates functionality to the underlying stream. + */ + public void read_long_array(int[] value, int offset, int length) + { + stream.read_long_array(value, offset, length); + } + + /** + * Delegates functionality to the underlying stream. + */ + public int read_long() + { + return stream.read_long(); + } + + /** + * Delegates functionality to the underlying stream. + */ + public void read_longlong_array(long[] value, int offset, int length) + { + stream.read_longlong_array(value, offset, length); + } + + /** + * Delegates functionality to the underlying stream. + */ + public long read_longlong() + { + return stream.read_longlong(); + } + + /** + * Delegates functionality to the underlying stream. + */ + public org.omg.CORBA.Object read_Object() + { + return stream.read_Object(); + } + + /** + * Delegates functionality to the underlying stream. + */ + public org.omg.CORBA.Object read_Object(Class klass) + { + return stream.read_Object(klass); + } + + /** + * Delegates functionality to the underlying stream. + */ + public void read_octet_array(byte[] value, int offset, int length) + { + stream.read_octet_array(value, offset, length); + } + + /** + * Delegates functionality to the underlying stream. + */ + public byte read_octet() + { + return stream.read_octet(); + } + + /** + * Delegates functionality to the underlying stream. + */ + public Principal read_Principal() + { + return stream.read_Principal(); + } + + /** + * Delegates functionality to the underlying stream. + */ + public void read_short_array(short[] value, int offset, int length) + { + stream.read_short_array(value, offset, length); + } + + /** + * Delegates functionality to the underlying stream. + */ + public short read_short() + { + return stream.read_short(); + } + + /** + * Delegates functionality to the underlying stream. + */ + public String read_string() + { + return stream.read_string(); + } + + /** + * Delegates functionality to the underlying stream. + */ + public TypeCode read_TypeCode() + { + return stream.read_TypeCode(); + } + + /** + * Delegates functionality to the underlying stream. + */ + public void read_ulong_array(int[] value, int offset, int length) + { + stream.read_ulong_array(value, offset, length); + } + + /** + * Delegates functionality to the underlying stream. + */ + public int read_ulong() + { + return stream.read_ulong(); + } + + /** + * Delegates functionality to the underlying stream. + */ + public void read_ulonglong_array(long[] value, int offset, int length) + { + stream.read_ulonglong_array(value, offset, length); + } + + /** + * Delegates functionality to the underlying stream. + */ + public long read_ulonglong() + { + return stream.read_ulonglong(); + } + + /** + * Delegates functionality to the underlying stream. + */ + public void read_ushort_array(short[] value, int offset, int length) + { + stream.read_ushort_array(value, offset, length); + } + + /** + * Delegates functionality to the underlying stream. + */ + public short read_ushort() + { + return stream.read_ushort(); + } + + /** + * Delegates functionality to the underlying stream. + */ + public Serializable read_value() + { + return read_value((Serializable) null); + } + + /** + * Delegates functionality to the underlying stream. + */ + public void read_wchar_array(char[] value, int offset, int length) + { + stream.read_wchar_array(value, offset, length); + } + + /** + * Delegates functionality to the underlying stream. + */ + public char read_wchar() + { + return stream.read_wchar(); + } + + /** + * Delegates functionality to the underlying stream. + */ + public String read_wstring() + { + return stream.read_wstring(); + } + + /** + * Delegates functionality to the underlying stream. + */ + public int read() + throws IOException + { + return stream.read(); + } + + /** + * Delegates functionality to the underlying stream. + */ + public int read(byte[] b, int off, int len) + throws IOException + { + return stream.read(b, off, len); + } + + /** + * Delegates functionality to the underlying stream. + */ + public int read(byte[] b) + throws IOException + { + return stream.read(b); + } + + /** + * Delegates functionality to the underlying stream. + */ + public void reset() + throws IOException + { + stream.reset(); + } + + /** + * Delegates functionality to the underlying stream. + */ + public long skip(long n) + throws IOException + { + return stream.skip(n); + } + + /** + * Get a string representation. + */ + public String toString() + { + return "HeadlessInput+" + stream.toString(); + } + + /** + * Delegates functionality to the underlying stream. + */ + public String[] _truncatable_ids() + { + return stream._truncatable_ids(); + } + + /** + * Delegates functionality to the underlying stream. + */ + public Object read_Abstract() + { + return stream.read_Abstract(); + } + + /** + * Delegates functionality to the underlying stream. + */ + public void read_any_array(AnySeqHolder holder, int offset, int length) + { + stream.read_any_array(holder, offset, length); + } + + /** + * Delegates functionality to the underlying stream. + */ + public void read_boolean_array(BooleanSeqHolder holder, int offset, int length) + { + stream.read_boolean_array(holder, offset, length); + } + + /** + * Delegates functionality to the underlying stream. + */ + public void read_char_array(CharSeqHolder holder, int offset, int length) + { + stream.read_char_array(holder, offset, length); + } + + /** + * Delegates functionality to the underlying stream. + */ + public void read_double_array(DoubleSeqHolder holder, int offset, int length) + { + stream.read_double_array(holder, offset, length); + } + + /** + * Delegates functionality to the underlying stream. + */ + public void read_float_array(FloatSeqHolder holder, int offset, int length) + { + stream.read_float_array(holder, offset, length); + } + + /** + * Delegates functionality to the underlying stream. + */ + public void read_long_array(LongSeqHolder holder, int offset, int length) + { + stream.read_long_array(holder, offset, length); + } + + /** + * Delegates functionality to the underlying stream. + */ + public void read_longlong_array(LongLongSeqHolder holder, int offset, + int length) + { + stream.read_longlong_array(holder, offset, length); + } + + /** + * Delegates functionality to the underlying stream. + */ + public void read_octet_array(OctetSeqHolder holder, int offset, int length) + { + stream.read_octet_array(holder, offset, length); + } + + /** + * Delegates functionality to the underlying stream. + */ + public void read_short_array(ShortSeqHolder holder, int offset, int length) + { + stream.read_short_array(holder, offset, length); + } + + /** + * Delegates functionality to the underlying stream. + */ + public void read_ulong_array(ULongSeqHolder holder, int offset, int length) + { + stream.read_ulong_array(holder, offset, length); + } + + /** + * Delegates functionality to the underlying stream. + */ + public void read_ulonglong_array(ULongLongSeqHolder holder, int offset, + int length) + { + stream.read_ulonglong_array(holder, offset, length); + } + + /** + * Delegates functionality to the underlying stream. + */ + public void read_ushort_array(UShortSeqHolder holder, int offset, int length) + { + stream.read_ushort_array(holder, offset, length); + } + + /** + * Delegates functionality to read_value. + */ + public Serializable read_Value() + { + return read_value(); + } + + /** + * Delegates functionality to the underlying stream. + */ + public void read_wchar_array(WCharSeqHolder holder, int offset, int length) + { + stream.read_wchar_array(holder, offset, length); + } + + /** + * Delegates functionality to the underlying stream. + */ + public int getPosition() + { + return stream.getPosition(); + } + + /** + * Delegates functionality to the underlying stream. + */ + public gnuRuntime getRunTime() + { + return stream.runtime; + } + + /** + * Replace the instance of RunTime. + */ + public void setRunTime(gnuRuntime a_runtime) + { + stream.runtime = a_runtime; + } + + /** + * Delegates functionality to the underlying stream. + */ + public void seek(int position) + { + stream.seek(position); + } + +} diff --git a/libjava/classpath/gnu/CORBA/CDR/IDLTypeHelper.java b/libjava/classpath/gnu/CORBA/CDR/IDLTypeHelper.java new file mode 100644 index 000000000..663e04196 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/CDR/IDLTypeHelper.java @@ -0,0 +1,169 @@ +/* IDLTypeHelper.java -- + 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.CORBA.CDR; + +import gnu.CORBA.Minor; + +import org.omg.CORBA.MARSHAL; +import org.omg.CORBA.portable.BoxedValueHelper; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.OutputStream; + +import java.io.Serializable; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +/** + * Handles case when the CORBA IDL type with the known helper is wrapped into + * Value type. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class IDLTypeHelper + implements BoxedValueHelper +{ + /** + * A helper class. + */ + protected Class helper; + + /** + * Argument values for Helper.id(). + */ + static final Object[] ARGS_ID_V = new Object[0]; + + /** + * Argument types for Helper.id()). + */ + static final Class[] ARGS_ID = new Class[0]; + + /** + * Argument types for Helper.read. + */ + static final Class[] ARGS_READ = new Class[] { org.omg.CORBA.portable.InputStream.class }; + + /** + * Create an IDLTypeHelper that works via given helper class. + */ + public IDLTypeHelper(Class a_helperClass) + { + helper = a_helperClass; + } + + /** + * Get the Id, returned by this helper (use reflection). + */ + public String get_id() + { + try + { + Method m = helper.getMethod("id", ARGS_ID); + return (String) m.invoke(null, ARGS_ID_V); + } + catch (Exception ex) + { + MARSHAL m = new MARSHAL(msg() + " id()"); + m.minor = Minor.Boxed; + m.initCause(ex); + throw m; + } + } + + /** + * Read an instance from the stream. + */ + public Serializable read_value(InputStream input) + { + try + { + Method m = helper.getMethod("read", ARGS_READ); + return (Serializable) m.invoke(null, new Object[] { input }); + } + catch (Exception ex) + { + MARSHAL m = new MARSHAL(msg() + " read(..)"); + m.minor = Minor.Boxed; + m.initCause(ex); + throw m; + } + } + + /** + * Write the instance to the stream. + */ + public void write_value(OutputStream output, Serializable value) + { + try + { + Method[] m = helper.getMethods(); + + for (int i = 0; i < m.length; i++) + { + if (m[i].getName().equals("write") + && ((m[i].getModifiers() & Modifier.STATIC) != 0)) + { + Class[] p = m[i].getParameterTypes(); + + if (p.length == 2 && OutputStream.class.isAssignableFrom(p[0]) + && p[1].isAssignableFrom(value.getClass())) + { + m[i].invoke(null, new Object[] { output, value }); + return; + } + } + } + } + catch (Exception ex) + { + MARSHAL m = new MARSHAL(msg() + " write(..)"); + m.minor = Minor.Boxed; + m.initCause(ex); + throw m; + } + } + + /** + * Create the start of message for exceptions. + */ + String msg() + { + return "Failed calling " + helper.getName() + " method: "; + } + +} diff --git a/libjava/classpath/gnu/CORBA/CDR/LittleEndianInputStream.java b/libjava/classpath/gnu/CORBA/CDR/LittleEndianInputStream.java new file mode 100644 index 000000000..93d18fb11 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/CDR/LittleEndianInputStream.java @@ -0,0 +1,634 @@ +/* LittleEndianInputStream.java -- + Copyright (C) 1998, 1999, 2000, 2001, 2003, 2005 Free Software Foundation + +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.CORBA.CDR; + +import gnu.java.lang.CPStringBuilder; + +import java.io.EOFException; +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PushbackInputStream; + +/** + * This class reads data in the Little Endian format. It reuses + * code from GNU Classpath DataInputStream. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + * @author Warren Levy (warrenl@cygnus.com) + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class LittleEndianInputStream + extends FilterInputStream + implements AbstractDataInput +{ + // Byte buffer, used to make primitive read calls more efficient. + byte[] buf = new byte[ 8 ]; + + /** + * This constructor initializes a new DataInputStream + * to read from the specified subordinate stream. + * + * @param in The subordinate InputStream to read from + */ + public LittleEndianInputStream(InputStream in) + { + super(in); + } + + /** + * This method reads bytes from the underlying stream into the specified + * byte array buffer. It will attempt to fill the buffer completely, but + * may return a short count if there is insufficient data remaining to be + * read to fill the buffer. + * + * @param b The buffer into which bytes will be read. + * + * @return The actual number of bytes read, or -1 if end of stream reached + * before reading any bytes. + * + * @exception IOException If an error occurs. + */ + public int read(byte[] b) + throws IOException + { + return in.read(b, 0, b.length); + } + + /** + * This method reads bytes from the underlying stream into the specified + * byte array buffer. It will attempt to read len bytes and + * will start storing them at position off into the buffer. + * This method can return a short count if there is insufficient data + * remaining to be read to complete the desired read length. + * + * @param b The buffer into which bytes will be read. + * @param off The offset into the buffer to start storing bytes. + * @param len The requested number of bytes to read. + * + * @return The actual number of bytes read, or -1 if end of stream reached + * before reading any bytes. + * + * @exception IOException If an error occurs. + */ + public int read(byte[] b, int off, int len) + throws IOException + { + return in.read(b, off, len); + } + + /** + * This method reads a Java boolean value from an input stream. It does + * so by reading a single byte of data. If that byte is zero, then the + * value returned is false. If the byte is non-zero, then + * the value returned is true. + *

+ * This method can read a boolean written by an object + * implementing the writeBoolean() method in the + * DataOutput interface. + * + * @return The boolean value read + * + * @exception EOFException If end of file is reached before reading + * the boolean + * @exception IOException If any other error occurs + * + * @see DataOutput#writeBoolean + */ + public boolean readBoolean() + throws IOException + { + return convertToBoolean(in.read()); + } + + /** + * This method reads a Java byte value from an input stream. The value + * is in the range of -128 to 127. + *

+ * This method can read a byte written by an object + * implementing the writeByte() method in the + * DataOutput interface. + * + * @return The byte value read + * + * @exception EOFException If end of file is reached before reading the byte + * @exception IOException If any other error occurs + * + * @see DataOutput#writeByte + */ + public byte readByte() + throws IOException + { + return convertToByte(in.read()); + } + + /** + * This method reads a Java char value from an input stream. + * It operates by reading two bytes from the stream and converting them to + * a single 16-bit Java char. The two bytes are stored most + * significant byte first (i.e., "big endian") regardless of the native + * host byte ordering. + *

+ * As an example, if byte1 and byte2 + * represent the first and second byte read from the stream + * respectively, they will be transformed to a char in + * the following manner: + *

+ * (char)(((byte1 & 0xFF) << 8) | (byte2 & 0xFF) + *

+ * This method can read a char written by an object + * implementing the writeChar() method in the + * DataOutput interface. + * + * @return The char value read + * + * @exception EOFException If end of file is reached before reading the char + * @exception IOException If any other error occurs + * + * @see DataOutput#writeChar + */ + public char readChar() + throws IOException + { + readFully(buf, 0, 2); + return convertToChar(buf); + } + + /** + * This method reads a Java double value from an input stream. It operates + * by first reading a long value from the stream by calling the + * readLong() method in this interface, then converts + * that long to a double using the + * longBitsToDouble method in the class + * java.lang.Double + *

+ * This method can read a double written by an object + * implementing the writeDouble() method in the + * DataOutput interface. + * + * @return The double value read + * + * @exception EOFException If end of file is reached before reading + * the double + * @exception IOException If any other error occurs + * + * @see DataOutput#writeDouble + * @see java.lang.Double#longBitsToDouble + */ + public double readDouble() + throws IOException + { + return Double.longBitsToDouble(readLong()); + } + + /** + * This method reads a Java float value from an input stream. It + * operates by first reading an int value from the + * stream by calling the readInt() method in this + * interface, then converts that int to a + * float using the intBitsToFloat method + * in the class java.lang.Float + *

+ * This method can read a float written by an object + * implementing the writeFloat() method in the + * DataOutput interface. + * + * @return The float value read + * + * @exception EOFException If end of file is reached before reading the float + * @exception IOException If any other error occurs + * + * @see DataOutput#writeFloat + * @see java.lang.Float#intBitsToFloat + */ + public float readFloat() + throws IOException + { + return Float.intBitsToFloat(readInt()); + } + + /** + * This method reads raw bytes into the passed array until the array is + * full. Note that this method blocks until the data is available and + * throws an exception if there is not enough data left in the stream to + * fill the buffer. Note also that zero length buffers are permitted. + * In this case, the method will return immediately without reading any + * bytes from the stream. + * + * @param b The buffer into which to read the data + * + * @exception EOFException If end of file is reached before filling the + * buffer + * @exception IOException If any other error occurs + */ + public void readFully(byte[] b) + throws IOException + { + readFully(b, 0, b.length); + } + + /** + * This method reads raw bytes into the passed array buf + * starting + * offset bytes into the buffer. The number of bytes read + * will be + * exactly len. Note that this method blocks until the data is + * available and throws an exception if there is not enough data left in + * the stream to read len bytes. Note also that zero length + * buffers are permitted. In this case, the method will return immediately + * without reading any bytes from the stream. + * + * @param buf The buffer into which to read the data + * @param offset The offset into the buffer to start storing data + * @param len The number of bytes to read into the buffer + * + * @exception EOFException If end of file is reached before filling the + * buffer + * @exception IOException If any other error occurs + */ + public void readFully(byte[] buf, int offset, int len) + throws IOException + { + if (len < 0) + throw new IndexOutOfBoundsException("Negative length: " + len); + + while (len > 0) + { + // in.read will block until some data is available. + int numread = in.read(buf, offset, len); + if (numread < 0) + throw new EOFException(); + len -= numread; + offset += numread; + } + } + + /** + * This method reads a Java int value from an input stream + * It operates by reading four bytes from the stream and converting them to + * a single Java int. The bytes are stored most + * significant byte first (i.e., "big endian") regardless of the native + * host byte ordering. + *

+ * As an example, if byte1 through byte4 represent + * the first four bytes read from the stream, they will be + * transformed to an int in the following manner: + *

+ * (int)(((byte1 & 0xFF) << 24) + ((byte2 & 0xFF) << 16) + + * ((byte3 & 0xFF)<< 8) + (byte4 & 0xFF))) + *

+ * The value returned is in the range of -2147483648 to 2147483647. + *

+ * This method can read an int written by an object + * implementing the writeInt() method in the + * DataOutput interface. + * + * @return The int value read + * + * @exception EOFException If end of file is reached before reading the int + * @exception IOException If any other error occurs + * + * @see DataOutput#writeInt + */ + public int readInt() + throws IOException + { + readFully(buf, 0, 4); + return convertToInt(buf); + } + + /** + * This method reads the next line of text data from an input + * stream. It operates by reading bytes and converting those bytes + * to char values by treating the byte read as the low + * eight bits of the char and using 0 as the high eight + * bits. Because of this, it does not support the full 16-bit + * Unicode character set. + *

+ * The reading of bytes ends when either the end of file or a line + * terminator is encountered. The bytes read are then returned as a + * String A line terminator is a byte sequence + * consisting of either \r, \n or + * \r\n. These termination charaters are discarded and + * are not returned as part of the string. + *

+ * This method can read data that was written by an object implementing the + * writeLine() method in DataOutput. + * + * @return The line read as a String + * + * @exception IOException If an error occurs + * + * @see DataOutput + * + * @deprecated + */ + public String readLine() + throws IOException + { + CPStringBuilder strb = new CPStringBuilder(); + + while (true) + { + int c = in.read(); + if (c == -1) // got an EOF + return strb.length() > 0 ? strb.toString() : null; + if (c == '\r') + { + int next_c = in.read(); + if (next_c != '\n' && next_c != -1) + { + if (!(in instanceof PushbackInputStream)) + in = new PushbackInputStream(in); + ((PushbackInputStream) in).unread(next_c); + } + break; + } + if (c == '\n') + break; + strb.append((char) c); + } + + return strb.length() > 0 ? strb.toString() : ""; + } + + /** + * This method reads a Java long value from an input stream + * It operates by reading eight bytes from the stream and converting them to + * a single Java long. The bytes are stored most + * significant byte first (i.e., "big endian") regardless of the native + * host byte ordering. + *

+ * As an example, if byte1 through byte8 represent + * the first eight bytes read from the stream, they will be + * transformed to an long in the following manner: + *

+ * (long)(((byte1 & 0xFF) << 56) + ((byte2 & 0xFF) << 48) + + * ((byte3 & 0xFF) << 40) + ((byte4 & 0xFF) << 32) + + * ((byte5 & 0xFF) << 24) + ((byte6 & 0xFF) << 16) + + * ((byte7 & 0xFF) << 8) + (byte8 & 0xFF))) + * + *

+ * The value returned is in the range of -9223372036854775808 to + * 9223372036854775807. + *

+ * This method can read an long written by an object + * implementing the writeLong() method in the + * DataOutput interface. + * + * @return The long value read + * + * @exception EOFException If end of file is reached before reading the long + * @exception IOException If any other error occurs + * + * @see DataOutput#writeLong + */ + public long readLong() + throws IOException + { + readFully(buf, 0, 8); + return convertToLong(buf); + } + + /** + * This method reads a signed 16-bit value into a Java in from the + * stream. It operates by reading two bytes from the stream and + * converting them to a single 16-bit Java short. The + * two bytes are stored most significant byte first (i.e., "big + * endian") regardless of the native host byte ordering. + *

+ * As an example, if byte1 and byte2 + * represent the first and second byte read from the stream + * respectively, they will be transformed to a short. in + * the following manner: + *

+ * (short)(((byte1 & 0xFF) << 8) | (byte2 & 0xFF)) + *

+ * The value returned is in the range of -32768 to 32767. + *

+ * This method can read a short written by an object + * implementing the writeShort() method in the + * DataOutput interface. + * + * @return The short value read + * + * @exception EOFException If end of file is reached before reading the value + * @exception IOException If any other error occurs + * + * @see DataOutput#writeShort + */ + public short readShort() + throws IOException + { + readFully(buf, 0, 2); + return convertToShort(buf); + } + + /** + * This method reads 8 unsigned bits into a Java int + * value from the stream. The value returned is in the range of 0 to + * 255. + *

+ * This method can read an unsigned byte written by an object + * implementing the writeUnsignedByte() method in the + * DataOutput interface. + * + * @return The unsigned bytes value read as a Java int. + * + * @exception EOFException If end of file is reached before reading the value + * @exception IOException If any other error occurs + * + * @see DataOutput#writeByte + */ + public int readUnsignedByte() + throws IOException + { + return convertToUnsignedByte(in.read()); + } + + /** + * This method reads 16 unsigned bits into a Java int value from the stream. + * It operates by reading two bytes from the stream and converting them to + * a single Java int The two bytes are stored most + * significant byte first (i.e., "big endian") regardless of the native + * host byte ordering. + *

+ * As an example, if byte1 and byte2 + * represent the first and second byte read from the stream + * respectively, they will be transformed to an int in + * the following manner: + *

+ * (int)(((byte1 & 0xFF) << 8) + (byte2 & 0xFF)) + *

+ * The value returned is in the range of 0 to 65535. + *

+ * This method can read an unsigned short written by an object + * implementing the writeUnsignedShort() method in the + * DataOutput interface. + * + * @return The unsigned short value read as a Java int + * + * @exception EOFException If end of file is reached before reading the value + * @exception IOException If any other error occurs + * + * @see DataOutput#writeShort + */ + public int readUnsignedShort() + throws IOException + { + readFully(buf, 0, 2); + return convertToUnsignedShort(buf); + } + + /** + * This method attempts to skip and discard the specified number of bytes + * in the input stream. It may actually skip fewer bytes than requested. + * This method will not skip any bytes if passed a negative number of bytes + * to skip. + * + * @param n The requested number of bytes to skip. + * + * @return The requested number of bytes to skip. + * + * @exception IOException If an error occurs. + * @specnote The JDK docs claim that this returns the number of bytes + * actually skipped. The JCL claims that this method can throw an + * EOFException. Neither of these appear to be true in the JDK 1.3's + * implementation. This tries to implement the actual JDK behaviour. + */ + public int skipBytes(int n) + throws IOException + { + if (n <= 0) + return 0; + try + { + return (int) in.skip(n); + } + catch (EOFException x) + { + // do nothing. + } + return n; + } + + protected boolean convertToBoolean(int b) + throws EOFException + { + if (b < 0) + throw new EOFException(); + + return (b != 0); + } + + protected byte convertToByte(int i) + throws EOFException + { + if (i < 0) + throw new EOFException(); + + return (byte) i; + } + + protected int convertToUnsignedByte(int i) + throws EOFException + { + if (i < 0) + throw new EOFException(); + + return (i & 0xFF); + } + + /** + * Less significant byte first. + */ + protected char convertToChar(byte[] buf) + { + return (char) ((buf [ 1 ] << 8) | (buf [ 0 ] & 0xff)); + } + + /** + * Less significant byte first. + */ + protected short convertToShort(byte[] buf) + { + return (short) ((buf [ 1 ] << 8) | (buf [ 0 ] & 0xff)); + } + + /** + * Less significant byte first. + */ + protected int convertToUnsignedShort(byte[] buf) + { + return (((buf [ 1 ] & 0xff) << 8) | (buf [ 0 ] & 0xff)); + } + + /** + * Less significant byte first. + */ + protected int convertToInt(byte[] buf) + { + return (((buf [ 3 ] & 0xff) << 24) | ((buf [ 2 ] & 0xff) << 16) | + ((buf [ 1 ] & 0xff) << 8) | (buf [ 0 ] & 0xff)); + } + + /** + * Less significant byte first. + */ + protected long convertToLong(byte[] buf) + { + return (((long) (buf [ 7 ] & 0xff) << 56) | + ((long) (buf [ 6 ] & 0xff) << 48) | + ((long) (buf [ 5 ] & 0xff) << 40) | + ((long) (buf [ 4 ] & 0xff) << 32) | + ((long) (buf [ 3 ] & 0xff) << 24) | + ((long) (buf [ 2 ] & 0xff) << 16) | + ((long) (buf [ 1 ] & 0xff) << 8) | ((long) (buf [ 0 ] & 0xff))); + } + + /** + * This should never be called. + * + * @throws InternalError, always. + */ + public String readUTF() + { + throw new InternalError(); + } +} diff --git a/libjava/classpath/gnu/CORBA/CDR/LittleEndianOutputStream.java b/libjava/classpath/gnu/CORBA/CDR/LittleEndianOutputStream.java new file mode 100644 index 000000000..f1b8e04b3 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/CDR/LittleEndianOutputStream.java @@ -0,0 +1,253 @@ +/* LittleEndianOutputStream.java -- + Copyright (C) 1998, 2001, 2003, 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.CORBA.CDR; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * This stream writes data in the Little Endian format + * (less significant byte first). This is opposite to the + * usual data presentation in java platform. + * + * This class reuses code from DataOutputStream. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + */ +public class LittleEndianOutputStream + extends FilterOutputStream + implements AbstractDataOutput +{ + /** + * This method initializes an instance of DataOutputStream to + * write its data to the specified underlying OutputStream + * + * @param out The subordinate OutputStream to which this + * object will write + */ + public LittleEndianOutputStream(OutputStream out) + { + super(out); + } + + /** + * This method flushes any unwritten bytes to the underlying stream. + * + * @exception IOException If an error occurs. + */ + public void flush() + throws IOException + { + out.flush(); + } + + /** + * This method writes the specified byte (passed as an int) + * to the underlying output stream. + * + * @param value The byte to write, passed as an int. + * + * @exception IOException If an error occurs. + */ + public synchronized void write(int value) + throws IOException + { + out.write(value); + } + + /** + * This method writes len bytes from the specified byte array + * buf starting at position offset into the + * buffer to the underlying output stream. + * + * @param buf The byte array to write from. + * @param offset The index into the byte array to start writing from. + * @param len The number of bytes to write. + * + * @exception IOException If an error occurs. + */ + public synchronized void write(byte[] buf, int offset, int len) + throws IOException + { + out.write(buf, offset, len); + } + + /** + * This method writes a Java boolean value to an output stream. If + * value is true, a byte with the value of + * 1 will be written, otherwise a byte with the value of 0 will be + * written. + * + * The value written can be read using the readBoolean + * method in DataInput. + * + * @param value The boolean value to write to the stream + * + * @exception IOException If an error occurs + * + * @see DataInput#readBoolean + */ + public void writeBoolean(boolean value) + throws IOException + { + write(value ? 1 : 0); + } + + /** + * This method writes a Java byte value to an output stream. The + * byte to be written will be in the lowest 8 bits of the + * int value passed. + * + * The value written can be read using the readByte or + * readUnsignedByte methods in DataInput. + * + * @param value The byte to write to the stream, passed as + * the low eight bits of an int. + * + * @exception IOException If an error occurs + * + * @see DataInput#readByte + * @see DataInput#readUnsignedByte + */ + public void writeByte(int value) + throws IOException + { + write(value & 0xff); + } + + /** + * This method writes a Java short value to an output stream. + * + * @param value The short value to write to the stream, + * passed as an int. + * + * @exception IOException If an error occurs + */ + public synchronized void writeShort(int value) + throws IOException + { + write((byte) (0xff & value)); + write((byte) (0xff & (value >> 8))); + } + + /** + * Writes char in Little Endian. + */ + public synchronized void writeChar(int value) + throws IOException + { + write((byte) (0xff & value)); + write((byte) (0xff & (value >> 8))); + } + + /** + * Writes int in Little Endian. + */ + public synchronized void writeInt(int value) + throws IOException + { + write((byte) (0xff & value)); + write((byte) (0xff & (value >> 8))); + write((byte) (0xff & (value >> 16))); + write((byte) (0xff & (value >> 24))); + } + + /** + * Writes long in Little Endian. + */ + public synchronized void writeLong(long value) + throws IOException + { + write((byte) (0xff & value)); + write((byte) (0xff & (value >> 8))); + write((byte) (0xff & (value >> 16))); + write((byte) (0xff & (value >> 24))); + write((byte) (0xff & (value >> 32))); + write((byte) (0xff & (value >> 40))); + write((byte) (0xff & (value >> 48))); + write((byte) (0xff & (value >> 56))); + } + + /** + * This method writes a Java float value to the stream. This + * value is written by first calling the method + * Float.floatToIntBits + * to retrieve an int representing the floating point number, + * then writing this int value to the stream exactly the same + * as the writeInt() method does. + * + * @param value The float value to write to the stream + * + * @exception IOException If an error occurs + * + * @see writeInt + * @see DataInput#readFloat + * @see Float#floatToIntBits + */ + public void writeFloat(float value) + throws IOException + { + writeInt(Float.floatToIntBits(value)); + } + + /** + * This method writes a Java double value to the stream. This + * value is written by first calling the method + * Double.doubleToLongBits + * to retrieve an long representing the floating point number, + * then writing this long value to the stream exactly the same + * as the writeLong() method does. + * + * @param value The double value to write to the stream + * + * @exception IOException If an error occurs + * + * @see writeLong + * @see DataInput#readDouble + * @see Double#doubleToLongBits + */ + public void writeDouble(double value) + throws IOException + { + writeLong(Double.doubleToLongBits(value)); + } +} diff --git a/libjava/classpath/gnu/CORBA/CDR/UnknownExceptionCtxHandler.java b/libjava/classpath/gnu/CORBA/CDR/UnknownExceptionCtxHandler.java new file mode 100644 index 000000000..cb36f8c42 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/CDR/UnknownExceptionCtxHandler.java @@ -0,0 +1,292 @@ +/* UnknownExceptionCtxHandler.java -- + 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.CORBA.CDR; + +import gnu.CORBA.Minor; +import gnu.CORBA.ObjectCreator; +import gnu.CORBA.GIOP.ServiceContext; + +import org.omg.CORBA.MARSHAL; +import org.omg.CORBA.NO_IMPLEMENT; +import org.omg.CORBA.StringValueHelper; +import org.omg.CORBA.portable.OutputStream; + +import java.lang.reflect.Constructor; +import java.util.StringTokenizer; + +import javax.rmi.CORBA.Util; + +/** + * Reads the data about an unknown exception from the UnknownExceptionInfo. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class UnknownExceptionCtxHandler + extends Vio +{ + /** + * Encode exception and add its recored to the message service contexts. + */ + public static ServiceContext[] addExceptionContext(ServiceContext[] current, + Throwable exception, Object details) + { + try + { + ServiceContext[] c = new ServiceContext[current.length + 1]; + if (current.length > 0) + System.arraycopy(current, 0, c, 0, current.length); + + BufferedCdrOutput output = new BufferedCdrOutput(); + + if (details instanceof OutputStream) + output.setOrb(((OutputStream) output).orb()); + + if (details instanceof AbstractCdrOutput) + ((AbstractCdrOutput) details).cloneSettings(output); + + write(output, exception); + + ServiceContext xc = new ServiceContext(); + xc.context_id = ServiceContext.UnknownExceptionInfo; + xc.context_data = output.buffer.toByteArray(); + c[current.length] = xc; + return c; + } + catch (Exception ex) + { + ex.printStackTrace(); + return current; + } + } + + /** + * Write data about unknown exception. + */ + public static void write(BufferedCdrOutput output, Throwable t) + { + t.fillInStackTrace(); + output.write_Value(t); + } + + /** + * Read the data about an unknown exception from the UnknownExceptionInfo. + * Following the documentation, this must be just value type, but it seems + * that in Sun's implementation is is not, as starts from 0x0. For value type, + * this would be null. + * + * TODO Implement reading and writing in Sun format, making Classpath IIOP + * interoperable with Sun's implementation. Current inmplementation reads and + * reproduces the exception class type only. + * + * @param input the input stream to read the context (orb and other settings + * are inherited from the main stream that received the message). + * + * @param contexts all service contexts that were present in the message. + * + * @return the Throwable, extracted from context, on null, if this has failed. + */ + public static Throwable read(BufferredCdrInput input, ServiceContext[] contexts) + { + input.mark(Integer.MAX_VALUE); + + int h = input.read_long(); + if (h == 0) + { + // This block reads exception info in the Sun specific format. + // (currently we read the exception name only). + try + { + // We may need to jump back if the value is read via value + // factory. + input.mark(512); + + int value_tag = input.read_long(); + checkTag(value_tag); + + String codebase = null; + String[] ids = null; + String id = null; + + // Check for the agreed null value. + if (value_tag == vt_NULL) + return null; + else if (value_tag == vt_INDIRECTION) + return (Throwable) readIndirection(input); + else + { + // Read the value. + if ((value_tag & vf_CODEBASE) != 0) + { + // The codebase is present. The codebase is a space + // separated list of URLs from where the implementing + // code can be downloaded. + codebase = read_string(input); + } + + if ((value_tag & vf_MULTIPLE_IDS) != 0) + { + // Multiple supported repository ids are present. + ids = read_string_array(input); + } + else if ((value_tag & vf_ID) != 0) + { + // Single supported repository id is present. + id = read_string(input); + } + } + + java.lang.Object ox = createInstance(id, ids, codebase); + + return (Throwable) ox; + } + catch (Exception ex) + { + ex.printStackTrace(); + return null; + } + } + else + { + input.reset(); + // Read as defined in OMG documentation. + return (Throwable) input.read_Value(); + } + } + + /** + * Load exception by name and create the instance. The reason why this is + * different from Vio is because some exceptions have no parameterless + * constructor, but have a constructor with the string parameter instead. + */ + static Object createInstance(String id, String[] ids, String codebase) + { + Object o = _createInstance(id, codebase); + + if (ids != null) + for (int i = 0; i < ids.length && o == null; i++) + o = _createInstance(ids[i], codebase); + return o; + } + + static Object _createInstance(String id, String codebase) + { + if (id == null) + return null; + if (id.equals(StringValueHelper.id())) + return ""; + StringTokenizer st = new StringTokenizer(id, ":"); + + String prefix = st.nextToken(); + if (prefix.equalsIgnoreCase("IDL")) + return ObjectCreator.Idl2Object(id); + else if (prefix.equalsIgnoreCase("RMI")) + { + String className = st.nextToken(); + String hashCode = st.nextToken(); + String sid = null; + if (st.hasMoreElements()) + sid = st.nextToken(); + + try + { + Class objectClass = Util.loadClass(className, codebase, + Vio.class.getClassLoader()); + + String rid = ObjectCreator.getRepositoryId(objectClass); + + if (!rid.equals(id)) + { + // If direct string comparison fails, compare by meaning. + StringTokenizer st2 = new StringTokenizer(rid, ":"); + if (!st2.nextToken().equals("RMI")) + throw new InternalError("RMI format expected: '" + rid + "'"); + if (!st2.nextToken().equals(className)) + throwIt("Class name mismatch", id, rid, null); + + try + { + long h1 = Long.parseLong(hashCode, 16); + long h2 = Long.parseLong(st2.nextToken(), 16); + if (h1 != h2) + throwIt("Hashcode mismatch", id, rid, null); + + if (sid != null && st2.hasMoreTokens()) + { + long s1 = Long.parseLong(hashCode, 16); + long s2 = Long.parseLong(st2.nextToken(), 16); + if (s1 != s2) + throwIt("serialVersionUID mismatch", id, rid, null); + } + } + catch (NumberFormatException e) + { + throwIt("Invalid hashcode or svuid format: ", id, rid, e); + } + } + + // Some RemoteExceptions have no public parameterless constructor, + // but they have constructor taking string as parameter. + try + { + return objectClass.newInstance(); + } + catch (Exception ex) + { + // Try instantiate passing string as parameter. + Constructor c = objectClass.getConstructor(new Class[] { String.class }); + return c.newInstance(new Object[] { "" }); + } + } + catch (MARSHAL m) + { + m.minor = Minor.Instantiation; + throw m; + } + catch (Exception ex) + { + MARSHAL m = new MARSHAL("Unable to instantiate " + id); + m.minor = Minor.Instantiation; + m.initCause(ex); + throw m; + } + } + else + throw new NO_IMPLEMENT("Unsupported prefix " + prefix + ":"); + } +} diff --git a/libjava/classpath/gnu/CORBA/CDR/VMVio.java b/libjava/classpath/gnu/CORBA/CDR/VMVio.java new file mode 100644 index 000000000..47a6c0c25 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/CDR/VMVio.java @@ -0,0 +1,101 @@ +/* VMVio.java -- Native operations, required by value IO. + 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. */ + +/** + * This is a temporary replacement for the native call that would allocate + * objects without public constructors. The replacement only allocates + * objects with public parameterless constructor and objects with public + * constructor taking string (like some Throwables). + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + * + * TODO FIXME replace by native call like in VMObjectInputStream. + * Required modification of Classpath the build system. + */ + + +package gnu.CORBA.CDR; + +import java.lang.reflect.Constructor; + +public class VMVio +{ + /** + * Allocates a new Object of type clazz but without running the default + * constructor on it. It then calls the given constructor on it. The given + * constructor method comes from the constr_clazz which is a super class of + * the given clazz. + */ + public static Object allocateObject(Class clazz, Class constr_clazz, + Constructor constructor) + throws InstantiationException + { + try + { + Constructor c = clazz.getConstructor(new Class[0]); + c.setAccessible(true); + return c.newInstance(new Object[0]); + } + catch (Exception ex) + { + try + { + Constructor c = clazz.getConstructor(new Class[] { String.class }); + return c.newInstance(new Object[] { "" }); + } + catch (Exception ex2) + { + Constructor c[] = clazz.getConstructors(); + + for (int i = 0; i < c.length; i++) + { + try + { + c[i].setAccessible(true); + Class[] args = c[i].getParameterTypes(); + return c[i].newInstance(new Object[args.length]); + } + catch (Exception ex3) + { + // Try another one. + } + } + } + throw new InstantiationException(clazz.getName()); + } + } +} diff --git a/libjava/classpath/gnu/CORBA/CDR/Vio.java b/libjava/classpath/gnu/CORBA/CDR/Vio.java new file mode 100644 index 000000000..1eecb651b --- /dev/null +++ b/libjava/classpath/gnu/CORBA/CDR/Vio.java @@ -0,0 +1,1474 @@ +/* Vio.java -- Value type IO operations. + 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.CORBA.CDR; + +import gnu.CORBA.Minor; +import gnu.CORBA.ObjectCreator; + +import gnu.java.lang.CPStringBuilder; + +import org.omg.CORBA.CustomMarshal; +import org.omg.CORBA.DataInputStream; +import org.omg.CORBA.DataOutputStream; +import org.omg.CORBA.MARSHAL; +import org.omg.CORBA.NO_IMPLEMENT; +import org.omg.CORBA.StringSeqHelper; +import org.omg.CORBA.StringValueHelper; +import org.omg.CORBA.SystemException; +import org.omg.CORBA.WStringValueHelper; +import org.omg.CORBA.portable.BoxedValueHelper; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.Streamable; +import org.omg.CORBA.portable.ValueFactory; + +import java.io.IOException; +import java.io.Serializable; +import java.lang.reflect.Constructor; +import java.lang.reflect.Modifier; +import java.util.StringTokenizer; + +import javax.rmi.CORBA.Util; +import javax.rmi.CORBA.ValueHandler; + +/** + * A specialised class for reading and writing the value types. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public abstract class Vio +{ + /** + * If true, wrap value type data into chunks. This decrease the performance, + * and is not required for interoperability with jdk 1.5, but is left in the + * implementation as the optional mode for solving possible interoperability + * problems with non-Sun CORBA implementations. + * + * The current implementation would accept both single chunk or multiple + * chunks, but will always send a single chunk (if true) or unchunked data (if + * false). + */ + public static boolean USE_CHUNKING = false; + + /** + * The first field in the value record. The last octet may contain additional + * flags (vf_CODEBASE, vf_ID and vf_MULTIPLE_IDS). The tag value is different + * for the indirections (vt_INDIRECTION) and nulls (vt_NULL). + */ + public static final int vt_VALUE_TAG = 0x7fffff00; + + /** + * The value tag flag, indicating that the codebase URL is present in the + * value tag record. + */ + public static final int vf_CODEBASE = 0x1; + + /** + * The value tag flag, indicating that a single repository id is present in + * the value tag record. + */ + public static final int vf_ID = 0x2; + + /** + * The value tag flag, indicating, that there are multiple repository ids + * present in the record. If this flag is set, the flag vf_ID must also be + * set, resulting the value of the least significant byte 0x6. + */ + public static final int vf_MULTIPLE_IDS = 0x4; + + /** + * The value tag flag, indicating the presence of chunking. Each chunk is + * preceeded by a positive int, indicating the number of bytes in the chunk. A + * sequence of chunks is terminated by a non positive int. + */ + public static final int vf_CHUNKING = 0x8; + + /** + * The indirection tag value. Such tag must be followed by the CORBA long, + * indicating the offset in the CORBA message, where the indirected + * information is present. This offset is assumed zero at the position where + * the mentioned CORBA long starts and can refer both forward (positive + * values) and backward (negative values). + */ + public static final int vt_INDIRECTION = 0xffffffff; + + /** + * This tag value means that the value object being transferred is equal to + * null. + */ + public static final int vt_NULL = 0x0; + + /** + * The size of CORBA long (java int). + */ + static final int INT_SIZE = 4; + + /** + * The String value helper (one instance is sufficient). + */ + public static final WStringValueHelper m_StringValueHelper = new WStringValueHelper(); + + /** + * An instance of the value handler. + */ + static ValueHandler handler = Util.createValueHandler(); + + /** + * Read the value base from the given input stream. Determines the required + * class from the repository id. This includes operations that are not + * required when an unitialised instance or at least class of the value type + * is known. Hence it may be faster to use the alternative methods, + * read(InputStream, Class) or read(InputStream, Serializable). + * + * @param input a stream to read from. + * + * @return the loaded value. + * + * @throws MARSHAL if the reading has failed due any reason. + */ + public static Serializable read(InputStream input) + { + return read(input, (String) null); + } + + /** + * Read the value base from the given input stream. Determines the required + * class from the repository id. This includes operations that are not + * required when an unitialised instance or at least class of the value type + * is known. Hence it may be faster to use the alternative methods, + * read(InputStream, Class) or read(InputStream, Serializable). + * + * @param input a stream to read from. + * @param repository_id a repository id of the object being read, may be null. + * + * @return the loaded value. + * + * @throws MARSHAL if the reading has failed due any reason. + */ + public static Serializable read(InputStream input, String repository_id) + { + try + { + final int position = getCurrentPosition(input); + // We may need to jump back if the value is read via value factory. + input.mark(512); + + int value_tag = input.read_long(); + checkTag(value_tag); + + String codebase = null; + String[] ids = null; + String id = repository_id; + + // Check for the agreed null value. + if (value_tag == vt_NULL) + return null; + else if (value_tag == vt_INDIRECTION) + return readIndirection(input); + else + { + // Read the value. + if ((value_tag & vf_CODEBASE) != 0) + { + // The codebase is present. The codebase is a space + // separated list of URLs from where the implementing + // code can be downloaded. + codebase = read_string(input); + } + + if ((value_tag & vf_MULTIPLE_IDS) != 0) + { + // Multiple supported repository ids are present. + ids = read_string_array(input); + } + else if ((value_tag & vf_ID) != 0) + { + // Single supported repository id is present. + id = read_string(input); + } + } + + BoxedValueHelper helper = getHelper(null, id); + // The existing implementing object. + java.lang.Object ox = null; + + if (helper != null) + ox = null; // Helper will care about the instantiating. + else if (id.equals(WStringValueHelper.id())) + helper = m_StringValueHelper; + else + ox = createInstance(id, ids, codebase); + return (Serializable) read_instance(input, position, ox, value_tag, + helper, id, ids, codebase); + } + catch (Exception ex) + { + MARSHAL m = new MARSHAL(); + m.minor = Minor.Value; + m.initCause(ex); + throw m; + } + } + + /** + * Read the value base from the given input stream when the value base class + * is available. Hence there is no need to guess it from the repository id. + * + * @param input a stream to read from. + * @param value_class the class of the value being read. + * + * @return the loaded value. + * + * @throws MARSHAL if the reading has failed due any reason. + */ + public static Serializable read(InputStream input, Class value_class) + { + final int position = getCurrentPosition(input); + + String id = null; + String[] ids = null; + String codebase = null; + + try + { + int value_tag = input.read_long(); + checkTag(value_tag); + + // Check for the agreed null value. + if (value_tag == vt_NULL) + return null; + else if (value_tag == vt_INDIRECTION) + return readIndirection(input); + else + { + // Read the value. + if ((value_tag & vf_CODEBASE) != 0) + { + // The codebase is present. + codebase = read_string(input); + } + + if ((value_tag & vf_MULTIPLE_IDS) != 0) + { + // Multiple supported repository ids are present. + ids = read_string_array(input); + } + else if ((value_tag & vf_ID) != 0) + { + // Single supported repository id is present. + id = read_string(input); + } + } + + BoxedValueHelper vHelper = id != null ? getHelper(value_class, id) + : getHelper(value_class, ids); + + java.lang.Object ox; + + if (vHelper == null) + { + try + { + ox = createInstance(id, ids, codebase); + } + catch (Exception e) + { + ox = null; + } + + if (ox != null) + { + if (value_class != null + && !value_class.isAssignableFrom(ox.getClass())) + { + MARSHAL m = new MARSHAL(ox.getClass() + " is not a " + + value_class.getName()); + m.minor = Minor.ClassCast; + throw m; + } + } + } + else + ox = null; + + ox = read_instance(input, position, ox, value_tag, vHelper, id, ids, + codebase); + return (Serializable) ox; + } + catch (MARSHAL m) + { + throw m; + } + catch (SystemException sysEx) + { + // OK. + throw sysEx; + } + catch (Exception ex) + { + MARSHAL m = new MARSHAL("Cant read " + value_class); + m.minor = Minor.Value; + m.initCause(ex); + throw m; + } + } + + /** + * Read the value base from the given input stream when the unitialised + * instance is available. Hence there is no need to guess the class from the + * repository id and then to instantiate an instance. + * + * @param input a stream to read from. + * + * @param value_instance an pre-created instance of the value. If the helper + * is not null, this parameter is ignored an should be null. + * + * @param helper a helper to create an instance and read the object- specific + * part of the record. If the value_instance is used instead, this parameter + * should be null. + * + * @return the loaded value. + * + * @throws MARSHAL if the reading has failed due any reason. + */ + public static Object read(InputStream input, Object value_instance, + BoxedValueHelper helper) + { + final int position = getCurrentPosition(input); + + String id = null; + String[] ids = null; + String codebase = null; + + try + { + int value_tag = input.read_long(); + checkTag(value_tag); + + // Check for the agreed null value. + if (value_tag == vt_NULL) + return null; + else if (value_tag == vt_INDIRECTION) + return readIndirection(input); + else + { + // Read the value. + if ((value_tag & vf_CODEBASE) != 0) + { + // The codebase is present. + codebase = read_string(input); + } + + if ((value_tag & vf_MULTIPLE_IDS) != 0) + { + // Multiple supported repository ids are present. + ids = read_string_array(input); + } + else if ((value_tag & vf_ID) != 0) + { + // Single supported repository id is present. + id = read_string(input); + } + } + + Class value_class = value_instance == null ? null + : value_instance.getClass(); + + if (helper == null) + helper = id != null ? getHelper(value_class, id) : getHelper( + value_class, ids); + + value_instance = read_instance(input, position, value_instance, + value_tag, helper, id, ids, codebase); + return value_instance; + } + catch (Exception ex) + { + MARSHAL m = new MARSHAL(); + m.minor = Minor.Value; + m.initCause(ex); + throw m; + } + } + + /** + * Read using provided boxed value helper. This method expects the full value + * type header, followed by contents, that are delegated to the provided + * helper. It handles null. + * + * @param input the stream to read from. + * @param helper the helper that reads the type-specific part of the content. + * + * @return the value, created by the helper, or null if the header indicates + * that null was previously written. + */ + public static Serializable read(InputStream input, BoxedValueHelper helper) + { + return (Serializable) read(input, null, helper); + } + + /** + * Fill in the instance fields by the data from the input stream. The method + * assumes that the value header, if any, is already behind. The information + * from the stream is stored into the passed ox parameter. + * + * @param input an input stream to read from. + * + * @param value a pre-instantiated value type object, must be either + * Streamable or CustomMarshal. If the helper is used, this parameter is + * ignored and should be null. + * + * @param value_tag the tag that must be read previously. + * @param helper the helper for read object specific part; may be null to read + * in using other methods. + * + * @return the value that was read. + */ + static Object read_instance(InputStream input, final int position, + Object value, int value_tag, BoxedValueHelper helper, String id, + String[] ids, String codebase) + { + if (helper != m_StringValueHelper && id != null) + if (id.equals(StringValueHelper.id())) + { + value = null; + helper = m_StringValueHelper; + } + + try + { + if ((value_tag & vf_CHUNKING) != 0) + { + BufferedCdrOutput output = createBuffer(input, 1024); + // Read the current (not a nested one) value in this spec case. + readNestedValue(value_tag, input, output, -1); + BufferredCdrInput ci = new BufferredCdrInput(output.buffer.getBuffer()); + ci.setRunTime(output.getRunTime()); + + input = new HeadlessInput(ci, input); + } + else + { + if (input instanceof BufferredCdrInput) + { + // Highly probable case. + input = new HeadlessInput((BufferredCdrInput) input, null); + } + else if (input instanceof HeadlessInput) + { + // There is no need to instantiate one more HeadlessInput + // as we can just reset. + ((HeadlessInput) input).subsequentCalls = false; + } + else + { + BufferedCdrOutput bout = new BufferedCdrOutput(); + int c; + while ((c = input.read()) >= 0) + bout.write((byte) c); + input = new HeadlessInput( + (BufferredCdrInput) bout.create_input_stream(), input); + } + } + } + catch (IOException ex) + { + MARSHAL m = new MARSHAL("Unable to read chunks"); + m.minor = Minor.Value; + m.initCause(ex); + throw m; + } + + return readValue(input, position, value, helper, id, ids, codebase); + } + + /** + * Create a buffer, inheriting critical settings from the passed input stream. + */ + private static BufferedCdrOutput createBuffer(InputStream input, int proposed_size) + { + BufferedCdrOutput bout; + bout = new BufferedCdrOutput(2 * proposed_size + 256); + + if (input instanceof BufferredCdrInput) + { + BufferredCdrInput in = (BufferredCdrInput) input; + bout.setBigEndian(in.isBigEndian()); + } + + if (input instanceof gnuValueStream) + bout.setRunTime(((gnuValueStream) input).getRunTime()); + else + bout.setRunTime(new gnuRuntime(null, null)); + return bout; + } + + /** + * Read the chunked nested value from the given input stream, transferring the + * contents to the given output stream. + * + * @param value_tag the value tag of the value being read. + * @param input the input stream from where the remainder of the nested value + * must be read. + * @param output the output stream where the unchunked nested value must be + * copied. + * + * @return the tag that ended the nested value. + */ + public static int readNestedValue(int value_tag, InputStream input, + BufferedCdrOutput output, int level) + throws IOException + { + String id = null; + if (level < -1) + { + // For the first level, this information is already behind. + output.write_long(value_tag - vf_CHUNKING); + + // The nested value should be aways chunked. + if ((value_tag & vf_CHUNKING) == 0) + { + MARSHAL m = new MARSHAL("readNestedValue: must be chunked"); + m.minor = Minor.Chunks; + throw m; + } + else if (value_tag == vt_NULL) + { + MARSHAL m = new MARSHAL("readNestedValue: nul"); + m.minor = Minor.Chunks; + throw m; + } + else if (value_tag == vt_INDIRECTION) + { + MARSHAL m = new MARSHAL("readNestedValue: indirection"); + m.minor = Minor.Chunks; + throw m; + } + else + { + // Read the value. + if ((value_tag & vf_CODEBASE) != 0) + { + String codebase = read_string(input); + write_string(output, codebase); + } + + if ((value_tag & vf_MULTIPLE_IDS) != 0) + { + // Multiple supported repository ids are present. + String[] ids = read_string_array(input); + id = ids[0]; + write_string_array(output, ids); + } + else if ((value_tag & vf_ID) != 0) + { + id = read_string(input); + write_string(output, id); + } + } + } + + int n = -1; + + // Read all chunks. + int chunk_size; + + byte[] r = null; + + while (true) + { + // Read the size of the next chunk or it may also be the + // header of the nested value. + chunk_size = input.read_long(); + + // End of chunk terminator. + if (chunk_size < 0 && chunk_size >= level) + return chunk_size; + else if (chunk_size >= 0x7FFFFF00) + { + int onInput = getCurrentPosition(input) - 4; + int onOutput = output.getPosition(); + output.getRunTime().redirect(onInput, onOutput); + // Value over 0x7FFFFF00 indicates that the nested value + // starts here. Read the nested value, storing it into the output. + // First parameter is actually the value tag. + chunk_size = readNestedValue(chunk_size, input, output, level - 1); + if (chunk_size < 0 && chunk_size >= level) + return chunk_size; + } + else + { + // The chunk follows. + if (r == null || r.length < chunk_size) + r = new byte[chunk_size + 256]; + + n = 0; + while (n < chunk_size) + n += input.read(r, n, chunk_size - n); + output.write(r, 0, n); + } + } + } + + /** + * Read the value (the header must be behind). + */ + public static Serializable readValue(InputStream input, final int position, + Object value, BoxedValueHelper helper, String id, String[] ids, + String codebase) + { + gnuRuntime g; + gnuValueStream c = ((gnuValueStream) input); + if (c.getRunTime() == null) + { + g = new gnuRuntime(codebase, value); + c.setRunTime(g); + } + else + { + g = c.getRunTime(); + g.addCodeBase(codebase); + g.target = (Serializable) value; + } + if (value != null) + g.objectWritten(value, position); + + if (input instanceof HeadlessInput) + ((HeadlessInput) input).subsequentCalls = false; + + boolean ok = true; + + // The user-defined io operations are implemented. + if (value instanceof CustomMarshal) + { + CustomMarshal marsh = (CustomMarshal) value; + marsh.unmarshal((DataInputStream) input); + } + else + // The IDL-generated io operations are implemented. + if (value instanceof Streamable) + { + ((Streamable) value)._read(input); + } + else if (helper != null) + { + // If helper is non-null the value should normally be null. + value = helper.read_value(input); + g.objectWritten(value, position); + } + else + { + ok = false; + ValueFactory factory = null; + org.omg.CORBA_2_3.ORB orb = (org.omg.CORBA_2_3.ORB) input.orb(); + + if (id != null) + factory = orb.lookup_value_factory(id); + + if (factory == null && ids != null) + { + for (int i = 0; i < ids.length && factory == null; i++) + { + factory = orb.lookup_value_factory(ids[i]); + } + } + + if (factory != null) + { + value = factory.read_value((org.omg.CORBA_2_3.portable.InputStream) input); + ok = true; + } + } + + if (!ok && value instanceof Serializable) + // Delegate to ValueHandler + { + if (ids != null && ids.length > 0) + id = ids[0]; + + value = handler.readValue(input, position, value.getClass(), id, g); + ok = true; + } + + if (!ok) + { + if (value != null) + { + MARSHAL m = new MARSHAL(value.getClass().getName() + + " must be Streamable, CustomMarshal or Serializable"); + m.minor = Minor.UnsupportedValue; + throw m; + } + else + { + MARSHAL m = new MARSHAL("Unable to instantiate " + id + ":" + list(ids) + + " helper " + helper); + m.minor = Minor.UnsupportedValue; + throw m; + } + } + else + return (Serializable) value; + } + + /** + * Conveniency method to list ids in exception reports. + */ + static String list(String[] s) + { + if (s == null) + return "null"; + else + { + CPStringBuilder b = new CPStringBuilder("{"); + for (int i = 0; i < s.length; i++) + { + b.append(s[i]); + b.append(" "); + } + b.append("}"); + return b.toString(); + } + } + + /** + * Write the value base into the given stream. + * + * @param output a stream to write to. + * + * @param value a value type object, must be either Streamable or + * CustomMarshal. + * + * @throws MARSHAL if the writing failed due any reason. + */ + public static void write(OutputStream output, Serializable value) + { + // Write null if this is a null value. + if (value == null) + output.write_long(vt_NULL); + else if (value instanceof String) + write(output, value, m_StringValueHelper); + else + write(output, value, value.getClass()); + } + + /** + * Write the value base into the given stream, stating that it is an instance + * of the given class. + * + * @param output a stream to write to. + * + * @param value a value to write. + * + * @throws MARSHAL if the writing failed due any reason. + */ + public static void write(OutputStream output, Serializable value, + Class substitute) + { + // Write null if this is a null value. + if (value == null) + output.write_long(vt_NULL); + else if (value instanceof String || substitute == String.class) + writeString(output, value); + else + { + String vId = ObjectCreator.getRepositoryId(value.getClass()); + if (substitute == null || value.getClass().equals(substitute)) + write_instance(output, value, vId, getHelper(value.getClass(), vId)); + else + { + String vC = ObjectCreator.getRepositoryId(substitute); + String[] ids = new String[] { vId, vC }; + BoxedValueHelper h = getHelper(substitute.getClass(), ids); + // If the helper is available, it is also responsible for + // providing the repository Id. Otherwise, write both + // ids. + if (h == null) + write_instance(output, value, ids, null); + else + write_instance(output, value, h.get_id(), null); + } + } + } + + /** + * Write the value base into the given stream, supplementing it with an array + * of the provided repository ids plus the repository id, derived from the + * passed value. + * + * @param output a stream to write to. + * + * @param value a value to write. + * + * @throws MARSHAL if the writing failed due any reason. + */ + public static void write(OutputStream output, Serializable value, + String[] multiple_ids) + { + // Write null if this is a null value. + if (value == null) + output.write_long(vt_NULL); + else + { + String[] ids = new String[multiple_ids.length + 1]; + ids[0] = ObjectCreator.getRepositoryId(value.getClass()); + System.arraycopy(multiple_ids, 0, ids, 1, multiple_ids.length); + BoxedValueHelper h = getHelper(value.getClass(), ids); + write_instance(output, value, ids, h); + } + } + + /** + * Write value when its repository Id is explicitly given. Only this Id is + * written, the type of value is not taken into consideration. + * + * @param output an output stream to write into. + * @param value a value to write. + * @param id a value repository id. + */ + public static void write(OutputStream output, Serializable value, String id) + { + if (value == null) + output.write_long(vt_NULL); + else + write_instance(output, value, id, getHelper(value.getClass(), id)); + } + + /** + * Write standard value type header, followed by contents, produced by the + * boxed value helper. + * + * @param output the stream to write to. + * @param value the value to write, can be null. + * @param helper the helper that writes the value content if it is not null + * (must be provided for this method). + */ + public static void write(OutputStream output, Serializable value, + BoxedValueHelper helper) + { + if (helper == null) + throw new AssertionError("Helper must be provided"); + if (value == null) + output.write_long(vt_NULL); + else + write_instance(output, value, helper.get_id(), helper); + } + + /** + * Write the parameter that is surely a string and not null. + */ + private static void writeString(OutputStream output, Serializable string) + { + write_instance(output, string, m_StringValueHelper.get_id(), + m_StringValueHelper); + } + + /** + * Write value when its repository Id is explicitly given. Does not handle + * null. + * + * @param output an output stream to write into. + * @param value a value to write. + * @param ids a value repository id (can be either single string or string + * array). + * @param helper a helper, writing object - specifical part. Can be null if + * the value should be written using other methods. + */ + static void write_instance(OutputStream output, Serializable value, + Object ids, BoxedValueHelper helper) + { + gnuValueStream rout = null; + gnuRuntime runtime = null; + + try + { + if (output instanceof gnuValueStream) + { + int position; + rout = (gnuValueStream) output; + runtime = rout.getRunTime(); + + if (runtime == null) + { + runtime = new gnuRuntime(null, value); + rout.setRunTime(runtime); + rout.getRunTime().objectWritten(value, + position = rout.getPosition()); + } + else if (runtime.target == value) + { + if (!writeSelf(output, value)) + throw new InternalError("Recursive helper call for " + + value.getClass().getName()); + return; + } + else + { + position = runtime.isWrittenAt(value); + if (position >= 0) + { + // The object was already written. + output.write_long(vt_INDIRECTION); + output.write_long(position - rout.getPosition()); + // Replacing object write data by indirection reference. + return; + } + else + { + runtime.objectWritten(value, position = rout.getPosition()); + } + } + } + + int value_tag = vt_VALUE_TAG; + + if (ids instanceof String) + value_tag |= vf_ID; + else if (ids instanceof String[]) + // OMG standard requires to set both flags. + value_tag |= vf_MULTIPLE_IDS | vf_ID; + + int chunkSizeLocation; + + OutputStream outObj; + + if (USE_CHUNKING) + { + // Wrap the value being written into one chunk (makes sense only for + // compatibility reasons). + outObj = output; + value_tag |= vf_CHUNKING; + } + else + outObj = output; + + output.write_long(value_tag); + + if ((value_tag & vf_MULTIPLE_IDS) != 0) + write_string_array(output, (String[]) ids); + else if ((value_tag & vf_ID) != 0) + write_string(output, (String) ids); + + if (USE_CHUNKING) + { + // So far, write 0x55555555 instead of the chunk size (alignment may + // take place). + output.write_long(0x55555555); + // If the chunking is involved, the chunk size must be written here. + chunkSizeLocation = rout.getPosition() - INT_SIZE; + } + else + // Not in use for this case. + chunkSizeLocation = -1; + + writeValue(outObj, value, helper); + + if (USE_CHUNKING) + { + // Write the chunk size where the place for it was reserved. + int chunkSize = rout.getPosition() - chunkSizeLocation - INT_SIZE; + int current = rout.getPosition(); + rout.seek(chunkSizeLocation); + output.write_long(chunkSize); + rout.seek(current); + + // The end of record marker. + output.write_long(-1); + } + } + finally + { + if (runtime != null) + runtime.target = null; + } + } + + /** + * Write value (after header). + */ + static void writeValue(OutputStream output, Serializable value, + BoxedValueHelper helper) + { + ((gnuValueStream) output).getRunTime().target = value; + if (helper != null) + helper.write_value(output, value); + else if (!writeSelf(output, value)) + { + // Try to find helper via class loader. + boolean ok = false; + + if (!ok) + { + if (output instanceof BufferedCdrOutput) + { + BufferedCdrOutput b = (BufferedCdrOutput) output; + if (b.runtime == null) + b.runtime = new gnuRuntime(null, value); + } + + handler.writeValue(output, value); + } + } + } + + /** + * Try to write value supposing that it implements self-streamable interfaces. + * Return false if it does not or true on success. + */ + static boolean writeSelf(OutputStream output, Serializable value) + { + // User defined write method is present. + if (value instanceof CustomMarshal) + { + ((CustomMarshal) value).marshal((DataOutputStream) output); + return true; + } + else if (value instanceof Streamable) + { + ((Streamable) value)._write(output); + return true; + } + return false; + } + + /** + * Read the indirection data and return the object that was already written to + * this stream. + * + * @param an_input the input stream, must be BufferredCdrInput. + */ + static Serializable readIndirection(InputStream an_input) + { + if (!(an_input instanceof gnuValueStream)) + throw new NO_IMPLEMENT(gnuValueStream.class.getName() + + " expected as parameter"); + + gnuValueStream in = (gnuValueStream) an_input; + + int current_pos = in.getPosition(); + + int offset = an_input.read_long(); + if (offset > -INT_SIZE) + { + MARSHAL m = new MARSHAL("Indirection tag refers to " + offset + + " (must be less than -" + INT_SIZE + ")"); + m.minor = Minor.Offset; + throw m; + } + + int stored_at = current_pos + offset; + + if (in.getRunTime() == null) + { + MARSHAL m = new MARSHAL(stored_at + " offset " + offset + ": not written"); + m.minor = Minor.Value; + throw m; + } + + return (Serializable) in.getRunTime().isObjectWrittenAt(stored_at, offset); + } + + /** + * Check the passed value tag for correctness. + * + * @param value_tag a tag to check, must be between 0x7fffff00 and 0x7fffffff + * + * @throws MARSHAL if the tag is outside this interval. + */ + static void checkTag(int value_tag) + { + if ((value_tag < 0x7fffff00 || value_tag > 0x7fffffff) + && value_tag != vt_NULL && value_tag != vt_INDIRECTION) + { + MARSHAL m = new MARSHAL("Invalid value record, unsupported header tag: " + + value_tag + " (0x" + Integer.toHexString(value_tag) + ")"); + m.minor = Minor.ValueHeaderTag; + throw m; + } + + if ((value_tag & vf_MULTIPLE_IDS) != 0 && (value_tag & vf_ID) == 0) + { + MARSHAL m = new MARSHAL("Invalid value record header flag combination (0x" + + Integer.toHexString(value_tag) + ")"); + m.minor = Minor.ValueHeaderFlags; + throw m; + } + } + + /** + * Throw MARSHAL. + */ + static void throwIt(String msg, String id1, String id2, Throwable e) + throws MARSHAL + { + MARSHAL m = new MARSHAL(msg + ":'" + id1 + "' versus '" + id2 + "'"); + if (e != null) + m.initCause(e); + m.minor = Minor.Value; + throw m; + } + + /** + * Load class by name and create the instance. + */ + static Object createInstance(String id, String[] ids, String codebase) + { + Object o = null; + + if (id != null) + o = _createInstance(id, codebase); + + if (ids != null) + for (int i = 0; i < ids.length && o == null; i++) + o = _createInstance(ids[i], codebase); + return o; + } + + static Object _createInstance(String id, String codebase) + { + if (id == null) + return null; + if (id.equals(StringValueHelper.id())) + return ""; + StringTokenizer st = new StringTokenizer(id, ":"); + + String prefix = st.nextToken(); + if (prefix.equalsIgnoreCase("IDL")) + return ObjectCreator.Idl2Object(id); + else if (prefix.equalsIgnoreCase("RMI")) + { + String className = st.nextToken(); + String hashCode = st.nextToken(); + String sid = null; + if (st.hasMoreElements()) + sid = st.nextToken(); + + try + { + Class objectClass = Util.loadClass(className, codebase, + Vio.class.getClassLoader()); + + String rid = ObjectCreator.getRepositoryId(objectClass); + + if (!rid.equals(id)) + { + // If direct string comparison fails, compare by meaning. + StringTokenizer st2 = new StringTokenizer(rid, ":"); + if (!st2.nextToken().equals("RMI")) + throw new InternalError("RMI format expected: '" + rid + "'"); + if (!st2.nextToken().equals(className)) + throwIt("Class name mismatch", id, rid, null); + + try + { + long h1 = Long.parseLong(hashCode, 16); + long h2 = Long.parseLong(st2.nextToken(), 16); + if (h1 != h2) + throwIt("Hashcode mismatch", id, rid, null); + + if (sid != null && st2.hasMoreTokens()) + { + long s1 = Long.parseLong(hashCode, 16); + long s2 = Long.parseLong(st2.nextToken(), 16); + if (s1 != s2) + throwIt("serialVersionUID mismatch", id, rid, null); + } + } + catch (NumberFormatException e) + { + throwIt("Invalid hashcode or svuid format: ", id, rid, e); + } + } + + // Low - level instantiation required here. + return instantiateAnyWay(objectClass); + } + catch (Exception ex) + { + MARSHAL m = new MARSHAL("Unable to instantiate " + id); + m.minor = Minor.Instantiation; + m.initCause(ex); + throw m; + } + } + else + throw new NO_IMPLEMENT("Unsupported prefix " + prefix + ":"); + } + + /** + * Read string, expecting the probable indirection. + */ + static String read_string(InputStream input) + { + gnuValueStream g = (gnuValueStream) input; + int previous = g.getPosition(); + int l = input.read_long(); + if (l != vt_INDIRECTION) + { + g.seek(previous); + String s = input.read_string(); + if (g.getRunTime() == null) + g.setRunTime(new gnuRuntime(null, null)); + g.getRunTime().singleIdWritten(s, previous); + return s; + } + else + { + gnuRuntime r = g.getRunTime(); + int base = g.getPosition(); + int delta = input.read_long(); + if (r == null) + { + previous = g.getPosition(); + g.seek(base + delta); + String indir = input.read_string(); + g.seek(previous); + return indir; + } + else + { + return (String) r.isObjectWrittenAt(base + delta, delta); + } + } + } + + /** + * Read string array, expecting the probable indirection. + */ + static String[] read_string_array(InputStream input) + { + gnuValueStream g = (gnuValueStream) input; + int previous = g.getPosition(); + int l = input.read_long(); + if (l != vt_INDIRECTION) + { + g.seek(previous); + String[] s = StringSeqHelper.read(input); + if (g.getRunTime() == null) + g.setRunTime(new gnuRuntime(null, null)); + g.getRunTime().objectWritten(s, previous); + return s; + } + else + { + gnuRuntime r = g.getRunTime(); + int base = g.getPosition(); + int delta = input.read_long(); + if (r == null) + { + previous = g.getPosition(); + g.seek(base + delta); + String[] indir = StringSeqHelper.read(input); + g.seek(previous); + return indir; + } + else + { + return (String[]) r.isObjectWrittenAt(base + delta, delta); + } + } + } + + /** + * Write repository Id, probably shared. + */ + static void write_string(OutputStream output, String id) + { + if (output instanceof gnuValueStream) + { + gnuValueStream b = (gnuValueStream) output; + if (b != null) + { + int written = b.getRunTime().idWrittenAt(id); + if (written >= 0) + { + // Reuse existing id record. + output.write_long(vt_INDIRECTION); + int p = b.getPosition(); + output.write_long(written - p); + } + else + { + b.getRunTime().singleIdWritten(id, b.getPosition()); + output.write_string(id); + } + } + } + else + output.write_string(id); + } + + /** + * Write repository Id, probably shared. + */ + static void write_string_array(OutputStream output, String[] ids) + { + if (output instanceof gnuValueStream) + { + gnuValueStream b = (gnuValueStream) output; + if (b != null) + { + int written = b.getRunTime().idWrittenAt(ids); + if (written >= 0) + { + // Reuse existing id record. + output.write_long(vt_INDIRECTION); + int p = b.getPosition(); + output.write_long(written - p); + } + else + { + b.getRunTime().multipleIdsWritten(ids, b.getPosition()); + StringSeqHelper.write(output, ids); + } + } + } + else + StringSeqHelper.write(output, ids); + } + + /** + * Get the helper that could write the given object, or null if no pre-defined + * helper available for this object. + */ + public static BoxedValueHelper getHelper(Class x, Object ids) + { + if (x != null && x.equals(String.class)) + return m_StringValueHelper; + else if (x != null && x.isArray()) + return new ArrayValueHelper(x); + else if (ids instanceof String) + return locateHelper((String) ids); + else if (ids instanceof String[]) + { + String[] ia = (String[]) ids; + BoxedValueHelper h; + for (int i = 0; i < ia.length; i++) + { + h = locateHelper(ia[i]); + if (h != null) + return h; + } + return null; + } + else + return null; + } + + /** + * Get the helper that could write the given object, or null if no pre-defined + * helper available for this object. + */ + public static BoxedValueHelper getHelper(Class x, String id) + { + if (x != null && x.equals(String.class)) + return m_StringValueHelper; + else if (x != null && x.isArray()) + return new ArrayValueHelper(x); + else + return locateHelper(id); + } + + /** + * Try to locate helper from the repository id. + */ + static BoxedValueHelper locateHelper(String id) + { + if (id != null) + { + if (id.equals(m_StringValueHelper.get_id())) + return m_StringValueHelper; + else + // Try to locate helper for IDL type. + if (id.startsWith("IDL:")) + { + try + { + Class helperClass = ObjectCreator.findHelper(id); + if (BoxedValueHelper.class.isAssignableFrom(helperClass)) + return (BoxedValueHelper) helperClass.newInstance(); + else if (helperClass != null) + return new IDLTypeHelper(helperClass); + else + return null; + } + catch (Exception ex) + { + return null; + } + } + } + return null; + } + + /** + * Get the current position. + */ + static int getCurrentPosition(InputStream x) + { + if (x instanceof gnuValueStream) + return ((gnuValueStream) x).getPosition(); + else + return 0; + } + + /** + * Instantiate an instance of this class anyway; also in the case when it has + * no parameterless or any other constructor. The fields will be assigned + * while reading the class from the stream. + * + * @param clazz a class for that the instance should be instantiated. + */ + public static Object instantiateAnyWay(Class clazz) + throws Exception + { + Class first_nonserial = clazz; + + while (Serializable.class.isAssignableFrom(first_nonserial) + || Modifier.isAbstract(first_nonserial.getModifiers())) + first_nonserial = first_nonserial.getSuperclass(); + + final Class local_constructor_class = first_nonserial; + + Constructor constructor = local_constructor_class.getDeclaredConstructor(new Class[0]); + + return VMVio.allocateObject(clazz, constructor.getDeclaringClass(), + constructor); + } +} diff --git a/libjava/classpath/gnu/CORBA/CDR/gnuRuntime.java b/libjava/classpath/gnu/CORBA/CDR/gnuRuntime.java new file mode 100644 index 000000000..1d07094e9 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/CDR/gnuRuntime.java @@ -0,0 +1,338 @@ +/* gnuRuntime.java -- + 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.CORBA.CDR; + +import gnu.CORBA.Minor; + +import gnu.java.lang.CPStringBuilder; + +import org.omg.CORBA.LocalObject; +import org.omg.CORBA.MARSHAL; + +import java.io.Serializable; +import java.util.Comparator; +import java.util.HashMap; +import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.TreeMap; +import java.util.TreeSet; + +/** + * Our implementation of the sending context runtime. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class gnuRuntime + extends LocalObject + implements org.omg.SendingContext.RunTime +{ + /** + * The data entry about the object that was written. + */ + static class Entry + { + /** + * The stream position, where the object was written. + */ + int at; + + /** + * The object that was written. + */ + Object object; + + public String toString() + { + return object + "[" + at + "] "+object.getClass().getName(); + } + } + + /** + * The instruction that the actual object is stored at different location. + * Used when processing chunked data where positions shifts due removing the + * chunking tags. + */ + static class Redirection + extends Entry + { + public String toString() + { + return "->" + at; + } + } + + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * The history of the written objects, maps object to records. The different + * objects must be treated as different regardless that .equals returns. + */ + private Map sh_objects = new IdentityHashMap(); + + /** + * The written repository Ids that can be shared. + */ + private Map sh_ids = new TreeMap(new Comparator() + { + public int compare(Object a, Object b) + { + if (a instanceof String && b instanceof String) + // Comparing string with string. + return ((String) a).compareTo((String) b); + else if (a instanceof String[] && b instanceof String[]) + { + // Comparing array with array. + String[] sa = (String[]) a; + String[] sb = (String[]) b; + + if (sa.length != sb.length) + return sa.length - sb.length; + else + { + int c; + for (int i = 0; i < sa.length; i++) + { + c = sa[i].compareTo(sb[i]); + if (c != 0) + return c; + } + return 0; + } + } + else + // Comparing string with array. + return a instanceof String ? 1 : -1; + } + }); + + /** + * The history of the written objects, maps positions to records. The + * different objects must be treated as different regardless that .equals + * returns. + */ + private Map positions = new HashMap(); + + /** + * The Codebase. + */ + private String codebase; + + /** + * The pre-created instance of the object being written (avoid + * re-instantiation). + */ + public Serializable target; + + /** + * Create Runtime. + * + * @param a_id a repository Id, if only one Id was specified in the stream. + * @param a_ids a repository Ids, if the multiple Ids were specified in te + * stream. + * @param a_codebase a codebase, if it was specified in the stream. + */ + public gnuRuntime(String a_codebase, Object a_target) + { + if (a_target instanceof Serializable) + target = (Serializable) a_target; + + codebase = a_codebase; + } + + /** + * Mark the given object as written at the given position. + */ + public void objectWritten(Object object, int at) + { + if (object == null || at < 0) + return; // No positional information provided. + if (sh_objects.containsKey(object)) + throw new AssertionError("Repetetive writing of the same object " + + object + " at " + at + dump()); + + Entry e = new Entry(); + e.at = at; + e.object = object; + + sh_objects.put(object, e); + positions.put(new Integer(at), e); + } + + /** + * Check if the object is already written. + * + * @return the position, at that the object is allready written or -1 if it is + * not yet written. + */ + public int isWrittenAt(Object x) + { + Entry e = (Entry) sh_objects.get(x); + return e == null ? -1 : e.at; + } + + /** + * Set redirection, indicating that the object, searched at the p_searched + * position can be actually found at the p_present position. + */ + public void redirect(int p_searched, int p_present) + { + Redirection redirection = new Redirection(); + redirection.at = p_present; + positions.put(new Integer(p_searched), redirection); + } + + /** + * Get the object, written at the given position. This returs both shared + * objects and repository Ids. + * + * @return the position, at that the object is allready written. + * + * @throws MARSHAL if there is no object written at that position. + */ + public Object isObjectWrittenAt(int x, int offset) + { + Entry e = (Entry) positions.get(new Integer(x)); + if (e instanceof Redirection) + return isObjectWrittenAt(e.at, offset); + else if (e != null) + return e.object; + else + { + MARSHAL m = new MARSHAL("No object was written at " + x + + " (offset " + offset + ") r " + this + dump()); + m.minor = Minor.Graph; + throw m; + } + } + + /** + * Mark the given object as written at the given position. + */ + public void singleIdWritten(String id, int at) + { + if (sh_ids.containsKey(id)) + throw new InternalError("Repetetive writing of the same string " + + id + dump()); + + Entry e = new Entry(); + e.at = at; + e.object = id; + + sh_ids.put(id, e); + positions.put(new Integer(at), e); + } + + /** + * Mark the given object as written at the given position. + */ + public void multipleIdsWritten(String[] ids, int at) + { + if (sh_ids.containsKey(ids)) + throw new InternalError("Repetetive writing of the same string " + + ids + dump()); + + Entry e = new Entry(); + e.at = at; + e.object = ids; + + sh_ids.put(ids, e); + positions.put(new Integer(at), e); + } + + /** + * Check if the object is already written. + * + * @return the position, at that the object is allready written or -1 if it is + * not yet written. + */ + public int idWrittenAt(Object x) + { + Entry e = (Entry) sh_ids.get(x); + return e == null ? -1 : e.at; + } + + /** + * Get the codebase. + */ + public String getCodeBase() + { + return codebase; + } + + /** + * Set the codebase, preserving the old value if the passed parameter is null + * and forming the space delimited list if both new and old values are not + * null. + */ + public void addCodeBase(String base) + { + if (base != null) + { + if (codebase == null) + codebase = base; + else + codebase = codebase + " " + base; + } + } + + /** + * Dump all objects that are currently stored. + */ + public String dump() + { + CPStringBuilder b = new CPStringBuilder(" Stream content: \n"); + + // Sort by position. + TreeSet t = new TreeSet(positions.keySet()); + Iterator p = t.iterator(); + + while (p.hasNext()) + { + Object k = p.next(); + b.append(" " + k + ": " + ((Entry) positions.get(k)).toString() + + "\n"); + } + return b.toString(); + } + +} diff --git a/libjava/classpath/gnu/CORBA/CDR/gnuValueStream.java b/libjava/classpath/gnu/CORBA/CDR/gnuValueStream.java new file mode 100644 index 000000000..95d9edb2e --- /dev/null +++ b/libjava/classpath/gnu/CORBA/CDR/gnuValueStream.java @@ -0,0 +1,71 @@ +/* gnuValueStream.java -- + 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.CORBA.CDR; + +/** + * A stream, implementing this interface, provides methods to get/set a position + * and get the RunTime. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public interface gnuValueStream +{ + /** + * Get the current position in the buffer. + * + * @return The position in the buffer, taking offset into consideration. + */ + public int getPosition(); + + /** + * Jump to the given position, taking offset into consideration. + */ + public void seek(int position); + + /** + * Get the RunTime information. + */ + public gnuRuntime getRunTime(); + + /** + * Replace the instance of RunTime. + */ + public void setRunTime(gnuRuntime a_runtime); + +} diff --git a/libjava/classpath/gnu/CORBA/CdrEncapsCodecImpl.java b/libjava/classpath/gnu/CORBA/CdrEncapsCodecImpl.java new file mode 100644 index 000000000..1dc7f9282 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/CdrEncapsCodecImpl.java @@ -0,0 +1,358 @@ +/* CdrEncapsCodecImpl.java -- + 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.CORBA; + +import gnu.CORBA.CDR.BufferredCdrInput; +import gnu.CORBA.CDR.BufferedCdrOutput; +import gnu.CORBA.CDR.AbstractCdrOutput; + +import org.omg.CORBA.Any; +import org.omg.CORBA.LocalObject; +import org.omg.CORBA.MARSHAL; +import org.omg.CORBA.ORB; +import org.omg.CORBA.TCKind; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.UserException; +import org.omg.IOP.Codec; +import org.omg.IOP.CodecPackage.FormatMismatch; +import org.omg.IOP.CodecPackage.InvalidTypeForEncoding; +import org.omg.IOP.CodecPackage.TypeMismatch; + +/** + * The local {@link Codec} implementation for ENCODING_CDR_ENCAPS + * encoding. This is a local implementation; the remote side should + * have its own Codec of this kind. + * + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class CdrEncapsCodecImpl + extends LocalObject + implements Codec +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * If set to true, no wide string or wide character is allowed (GIOP 1.0). + */ + private final boolean noWide; + + /** + * The version of this encoding. + */ + private final Version version; + + /** + * The associated ORB. + */ + protected final ORB orb; + + /** + * If true, this Codec writes the record length (as int) in the beginning + * of the record. This indicator is part of the formal OMG standard, but it is + * missing in Sun's implementation. Both Suns's and this Codec detects + * the indicator, if present, but can also decode data where this information + * is missing. If the length indicator is missing, the first four bytes in + * Suns encoding are equal to 0 (Big Endian marker). + */ + private boolean lengthIndicator = true; + + /** + * Create an instance of this Codec, encoding following the given version. + */ + public CdrEncapsCodecImpl(ORB _orb, Version _version) + { + orb = _orb; + version = _version; + noWide = version.until_inclusive(1, 0); + } + + /** + * Return the array of repository ids for this object. + * + * @return { "IDL:gnu/CORBA/cdrEnapsCodec:1.0" }, always. + */ + public String[] _ids() + { + return new String[] { "IDL:gnu/CORBA/cdrEnapsCodec:1.0" }; + } + + /** + * Decode the contents of the byte array into Any. + * The byte array may have the optional four byte length indicator + * in the beginning. If these four bytes are zero, it is assumed, + * that no length indicator is present. + */ + public Any decode(byte[] them) + throws FormatMismatch + { + BufferredCdrInput input = createInput(them); + BufferredCdrInput encapsulation = createEncapsulation(them, input); + + TypeCode type = encapsulation.read_TypeCode(); + + try + { + checkTypePossibility("", type); + } + catch (InvalidTypeForEncoding ex) + { + throw new FormatMismatch(ex.getMessage()); + } + + return readAny(type, encapsulation); + } + + private BufferredCdrInput createEncapsulation(byte[] them, BufferredCdrInput input) + { + BufferredCdrInput encapsulation; + + if ((them [ 0 ] | them [ 1 ] | them [ 2 ] | them [ 3 ]) == 0) + { + // Skip that appears to be the always present Big Endian marker. + encapsulation = input; + input.read_short(); + } + else + encapsulation = input.read_encapsulation(); + return encapsulation; + } + + /** {@inheritDoc} */ + public byte[] encode(Any that) + throws InvalidTypeForEncoding + { + checkTypePossibility("", that.type()); + + BufferedCdrOutput output = createOutput(that); + + // BufferedCdrOutput has internal support for this encoding. + AbstractCdrOutput encapsulation = output.createEncapsulation(); + + try + { + TypeCodeHelper.write(encapsulation, that.type()); + that.write_value(encapsulation); + + encapsulation.close(); + output.close(); + } + catch (Exception ex) + { + MARSHAL m = new MARSHAL(); + m.minor = Minor.Encapsulation; + m.initCause(ex); + throw m; + } + return output.buffer.toByteArray(); + } + + /** + * Decode the value, stored in the byte array, into Any, assuming, + * that the byte array holds the data structure, defined by the + * given typecode. + * + * The byte array may have the optional four byte length indicator + * in the beginning. If these four bytes are zero, it is assumed, + * that no length indicator is present. + */ + public Any decode_value(byte[] them, TypeCode type) + throws FormatMismatch, TypeMismatch + { + try + { + checkTypePossibility("", type); + } + catch (InvalidTypeForEncoding ex) + { + throw new TypeMismatch(ex.getMessage()); + } + + BufferredCdrInput input = createInput(them); + BufferredCdrInput encapsulation = createEncapsulation(them, input); + return readAny(type, encapsulation); + } + + /** + * Read an Any from the given stream. + * + * @param type a type of the Any to read. + * @param input the encapsulation stream. + */ + private Any readAny(TypeCode type, BufferredCdrInput encapsulation) + throws MARSHAL + { + gnuAny a = new gnuAny(); + a.setOrb(orb); + + // BufferredCdrInput has internal support for this encoding. + a.read_value(encapsulation, type); + return a; + } + + /** {@inheritDoc} */ + public byte[] encode_value(Any that) + throws InvalidTypeForEncoding + { + checkTypePossibility("", that.type()); + + BufferedCdrOutput output = createOutput(that); + + AbstractCdrOutput encapsulation = output.createEncapsulation(); + + try + { + that.write_value(encapsulation); + + encapsulation.close(); + output.close(); + } + catch (Exception ex) + { + MARSHAL m = new MARSHAL(); + m.minor = Minor.Encapsulation; + m.initCause(ex); + throw m; + } + return output.buffer.toByteArray(); + } + + /** + * Create the CDR output stream for writing the given Any. + * The BufferedCdrOutput has internal support for encapsulation encodings. + * + * @param that the Any that will be written. + * + * @return the stream. + * + * @throws InvalidTypeForEncoding if that Any cannot be written under the + * given version. + */ + private BufferedCdrOutput createOutput(Any that) + throws InvalidTypeForEncoding + { + BufferedCdrOutput output = new BufferedCdrOutput(); + output.setOrb(orb); + output.setVersion(version); + return output; + } + + /** + * Checks if the given type can be encoded. Currently only checks for wide + * strings and wide chars for GIOP 1.0. + * + * @param t a typecode to chek. + * + * @throws InvalidTypeForEncoding if the typecode is not valid for the given + * version. + */ + private void checkTypePossibility(String name, TypeCode t) + throws InvalidTypeForEncoding + { + if (noWide) + { + try + { + int kind = t.kind().value(); + + if (kind == TCKind._tk_wchar || kind == TCKind._tk_wstring) + throw new InvalidTypeForEncoding(name + " wide char in " + + version + ); + else if (kind == TCKind._tk_alias || kind == TCKind._tk_array || + kind == TCKind._tk_sequence + ) + checkTypePossibility("Array member", t.content_type()); + + else if (kind == TCKind._tk_struct || kind == TCKind._tk_union) + { + for (int i = 0; i < t.member_count(); i++) + { + checkTypePossibility(t.member_name(i), t.member_type(i)); + } + } + } + catch (UserException ex) + { + InternalError ierr = new InternalError(); + ierr.initCause(ex); + throw ierr; + } + } + } + + /** + * Create the CDR input stream for reading the given byte array. + * + * @param them a byte array to read. + * + * @return the stream. + */ + private BufferredCdrInput createInput(byte[] them) + { + BufferredCdrInput input = new BufferredCdrInput(them); + input.setOrb(orb); + input.setVersion(version); + return input; + } + + /** + * Check if the Codec writes the length indicator. + */ + public boolean hasLengthIndicator() + { + return lengthIndicator; + } + + /** + * Sets if the Codec must write the record length in the beginning of the + * array. Encodings both with and without that indicator are understood + * both by Suns and this codec, but the OMG specification seems requiring + * it. The default behavior is to use the length indicator. + * + * @param use_lengthIndicator + */ + public void setUseLengthIndicator(boolean use_lengthIndicator) + { + lengthIndicator = use_lengthIndicator; + } +} diff --git a/libjava/classpath/gnu/CORBA/CollocatedOrbs.java b/libjava/classpath/gnu/CORBA/CollocatedOrbs.java new file mode 100644 index 000000000..5634ff3cf --- /dev/null +++ b/libjava/classpath/gnu/CORBA/CollocatedOrbs.java @@ -0,0 +1,160 @@ +/* CollocatedOrbs.java -- Handles collocations + 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.CORBA; + +import gnu.CORBA.Poa.gnuServantObject; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.ArrayList; + +/** + * This class provides support for the direct method invocations without + * involving the network in the case when both ORBs run on the same java + * virtual machine. Special attention is only needed when call is made + * between two independent ORBs, instantiated via ORB.init. The call to the + * object, obtained via IOR reference from the ORB where it was locally + * connected is always local anyway. + * + * For security reasons it may be sensible to keep this class and all support + * package private. + * + * @author Audrius Meskauskas + */ +class CollocatedOrbs +{ + /** + * This field is used in automated Classpath specific testing to disable + * the direct calls. + */ + static boolean DIRECT_CALLS_ALLOWED = true; + + /** + * Containts the references of the all running GNU Classpath ORBs in the + * local virtual machine. GNU Classpath ORBs register themselves here when + * created and unregister when either ORB.destroy is called or in the + * finalizer. + */ + private static ArrayList orbs = new ArrayList(); + + /** + * The address of the local host. + */ + static String localHost; + + static + { + try + { + localHost = InetAddress.getLocalHost().getHostAddress(); + } + catch (UnknownHostException ex) + { + throw new InternalError("Local host is not accessible:" + ex); + } + } + + /** + * Register the new ORB + * + * @param orb the orb to register + */ + static void registerOrb(OrbFunctional orb) + { + if (DIRECT_CALLS_ALLOWED) + synchronized (orbs) + { + assert ! orbs.contains(orb); + orbs.add(orb); + } + } + + /** + * Unregister the ORB. The ORB will no longer be reacheable locally but may + * be reacheable via network as if it would be remote. + * + * @param orb the orb to unregister + */ + static void unregisterOrb(OrbFunctional orb) + { + if (DIRECT_CALLS_ALLOWED) + synchronized (orbs) + { + assert orbs.contains(orb); + orbs.remove(orb); + } + } + + /** + * Search the possibly local object. If the IOR is not local or none of the + * found ORBs of this virtual machine knows about it, null is returned. + * + * @param ior the IOR to search + * @return the found local CORBA object or null in not found. + */ + static org.omg.CORBA.Object searchLocalObject(IOR ior) + { + if (! DIRECT_CALLS_ALLOWED && ! ior.Internet.host.equals(localHost)) + return null; + + synchronized (orbs) + { + OrbFunctional orb; + org.omg.CORBA.Object object; + for (int i = 0; i < orbs.size(); i++) + { + orb = (OrbFunctional) orbs.get(i); + object = orb.find_connected_object(ior.key, ior.Internet.port); + if (object != null) + { + if (object instanceof SafeForDirectCalls) + { + return object; + } + else if (object instanceof gnuServantObject) + { + return object; + } + } + } + } + return null; + } + +} diff --git a/libjava/classpath/gnu/CORBA/Connected_objects.java b/libjava/classpath/gnu/CORBA/Connected_objects.java new file mode 100644 index 000000000..62976c71f --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Connected_objects.java @@ -0,0 +1,255 @@ +/* Connected_objects.java -- + 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.CORBA; + +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +/** + * The repository of objects, that have been connected to the + * {@link FunctionalORB} by the method + * {@link ORB.connect(org.omg.CORBA.Object)}. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class Connected_objects +{ + /** + * The reference data about the connected object. + */ + public class cObject + { + /** + * Create an initialised instance. + */ + cObject(org.omg.CORBA.Object _object, int _port, byte[] _key, + java.lang.Object an_identity + ) + { + object = _object; + port = _port; + key = _key; + identity = an_identity; + } + + /** + * The object. + */ + public final org.omg.CORBA.Object object; + + /** + * The port on that the object is connected. + */ + public final int port; + + /** + * The object key. + */ + public final byte[] key; + + /** + * The shared serving identity (usually POA) or null if no such + * applicable. + */ + public final java.lang.Object identity; + } + + /** + * The free number to give for the next instance. + * This field is incremented each time the + * new collection of the connected objects is created. + * Each collection has its own unique instance number. + */ + private static long free_object_number; + + /** + * The map of the all connected objects, maps the object key to the + * object. + */ + private Map objects = new TreeMap(new ByteArrayComparator()); + + /** + * Get the record of the stored object. + * + * @param stored_object the stored object + * + * @return the record about the stored object, null if + * this object is not stored here. + */ + public cObject getKey(org.omg.CORBA.Object stored_object) + { + synchronized (objects) + { + Map.Entry item; + Iterator iter = objects.entrySet().iterator(); + cObject ref; + + while (iter.hasNext()) + { + item = (Map.Entry) iter.next(); + ref = (cObject) item.getValue(); + if (stored_object.equals(ref.object) || + stored_object._is_equivalent(ref.object) + ) + return ref; + } + } + + return null; + } + + /** + * Add the new object to the repository. The object key is + * generated automatically. + * + * @param object the object to add. + * @param port on that the ORB will be listening to the remote + * invocations. + * + * @return the newly created object record. + */ + public cObject add(org.omg.CORBA.Object object, int port) + { + return add(generateObjectKey(object), object, port, null); + } + + /** + * Add the new object to the repository. + * + * @param key the object key. + * @param object the object to add. + * @param port the port, on that the ORB will be listening on the + * remote invocations. + */ + public cObject add(byte[] key, org.omg.CORBA.Object object, int port, + java.lang.Object identity + ) + { + cObject rec = new cObject(object, port, key, identity); + synchronized (objects) + { + objects.put(key, rec); + } + return rec; + } + + /** + * Get the stored object. + * + * @param key the key (in the byte array form). + * + * @return the matching object, null if none is matching. + */ + public cObject get(byte[] key) + { + synchronized (objects) + { + return (cObject) objects.get(key); + } + } + + /** + * Get the map entry set. + */ + public Set entrySet() + { + return objects.entrySet(); + } + + /** + * Remove the given object. + * + * @param object the object to remove. + */ + public void remove(org.omg.CORBA.Object object) + { + synchronized (objects) + { + cObject ref = getKey(object); + if (ref != null) + objects.remove(ref.key); + } + } + + /** + * Remove the given object, indiciating it by the key. + * + * @param object the object to remove. + */ + public void remove(byte[] key) + { + objects.remove(key); + } + + /** + * Generate the object key, unique in the currently + * running java virtual machine. + * + * The generated key includes the object class name + * and the absolute instance number. + * + * @return the generated key. + */ + protected byte[] generateObjectKey(org.omg.CORBA.Object object) + { + return (object.getClass().getName() + ":" + getFreeInstanceNumber()).getBytes(); + } + + /** + * Get next free instance number. + */ + private static synchronized long getFreeInstanceNumber() + { + long instance_number = free_object_number; + free_object_number++; + return instance_number; + } + + /** + * Get the number of the connected objects. + * + * @return the size of the internal map. + */ + public int size() + { + return objects.size(); + } +} diff --git a/libjava/classpath/gnu/CORBA/CorbaList.java b/libjava/classpath/gnu/CORBA/CorbaList.java new file mode 100644 index 000000000..25bea9230 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/CorbaList.java @@ -0,0 +1,115 @@ +/* CorbaList.java -- + 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.CORBA; + +import java.io.Serializable; + +import java.util.ArrayList; + +import org.omg.CORBA.Bounds; + +/** + * This class is used to store array lists. Differently from + * the java.util lists, + * it throws {@link org.omg.CORBA.Bounds} rather than + * {@link IndexOutOfBoundsException}. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class CorbaList + extends ArrayList + implements Serializable +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * Creates the list with the given initial size. + */ + public CorbaList(int initial_size) + { + super(initial_size); + } + + /** + * Creates the list with the default size. + */ + public CorbaList() + { + } + + /** + * Remove the item at the given index. + * @param at the index + * @throws org.omg.CORBA.Bounds if the index is out of bounds. + */ + public void drop(int at) + throws Bounds + { + try + { + super.remove(at); + } + catch (IndexOutOfBoundsException ex) + { + throw new Bounds("[" + at + "], valid [0.." + size() + "]"); + } + } + + /** + * Get the item at the given index. + * @param at the index + * @return the item at the index + * @throws org.omg.CORBA.Bounds if the index is out of bounds. + */ + public Object item(int at) + throws Bounds + { + try + { + return super.get(at); + } + catch (IndexOutOfBoundsException ex) + { + throw new Bounds("[" + at + "], valid [0.." + size() + "]"); + } + } +} diff --git a/libjava/classpath/gnu/CORBA/DefaultSocketFactory.java b/libjava/classpath/gnu/CORBA/DefaultSocketFactory.java new file mode 100644 index 000000000..e540fd0a4 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/DefaultSocketFactory.java @@ -0,0 +1,79 @@ +/* DefaultSocketFactory.java -- + 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.CORBA; + +import gnu.CORBA.interfaces.SocketFactory; + +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; + +/** + * The default socket factory that forges "plain" server and client sockets. The + * class can be replaced by setting the gnu.CORBA.SocketFactory property. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class DefaultSocketFactory + implements SocketFactory +{ + /** + * It is enough to have one instance of this class for all ORBs. + */ + public static final DefaultSocketFactory Singleton = new DefaultSocketFactory(); + + /** + * Create a client socket. + */ + public Socket createClientSocket(String host, int port) + throws IOException + { + return new Socket(host, port); + } + + /** + * Create a server socket. + */ + public ServerSocket createServerSocket(int port) + throws IOException + { + return new ServerSocket(port); + } + +} diff --git a/libjava/classpath/gnu/CORBA/DefinitionKindHolder.java b/libjava/classpath/gnu/CORBA/DefinitionKindHolder.java new file mode 100644 index 000000000..1ef7350dd --- /dev/null +++ b/libjava/classpath/gnu/CORBA/DefinitionKindHolder.java @@ -0,0 +1,91 @@ +/* DefinitionKindHolder.java -- + 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.CORBA; + +import org.omg.CORBA.DefinitionKind; +import org.omg.CORBA.DefinitionKindHelper; + + +/** + * The definition kind holder. This class is not included in the original + * API specification, so we place it outside the org.omg namespace. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class DefinitionKindHolder + implements org.omg.CORBA.portable.Streamable +{ + /** + * The stored value. + */ + public DefinitionKind value; + + /** + * Create the initialised instance. + * @param initialValue + */ + public DefinitionKindHolder(DefinitionKind initialValue) + { + value = initialValue; + } + + /** + * Read from the CDR stream. + */ + public void _read(org.omg.CORBA.portable.InputStream in) + { + value = DefinitionKindHelper.read(in); + } + + /** + * Get the typecode. + */ + public org.omg.CORBA.TypeCode _type() + { + return DefinitionKindHelper.type(); + } + + /** + * Write into the CDR stream. + */ + public void _write(org.omg.CORBA.portable.OutputStream out) + { + DefinitionKindHelper.write(out, value); + } +} diff --git a/libjava/classpath/gnu/CORBA/DuplicateNameHolder.java b/libjava/classpath/gnu/CORBA/DuplicateNameHolder.java new file mode 100644 index 000000000..d98f0ed40 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/DuplicateNameHolder.java @@ -0,0 +1,106 @@ +/* DuplicateNameHolder.java -- + 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.CORBA; + +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.Streamable; +import org.omg.PortableInterceptor.ORBInitInfoPackage.DuplicateName; +import org.omg.PortableInterceptor.ORBInitInfoPackage.DuplicateNameHelper; + +/** +* A holder for the exception {@link DuplicateName}. + +* @author Audrius Meskauskas, Lithiania (AudriusA@Bioinformatics.org) +*/ +public class DuplicateNameHolder + implements Streamable +{ + /** + * The stored DuplicateName value. + */ + public DuplicateName value; + + /** + * Create the unitialised instance, leaving the value field + * with default null value. + */ + public DuplicateNameHolder() + { + } + + /** + * Create the initialised instance. + * @param initialValue the value that will be assigned to + * the value field. + */ + public DuplicateNameHolder(DuplicateName initialValue) + { + value = initialValue; + } + + /** + * Fill in the {@link value} by data from the CDR stream. + * + * @param input the org.omg.CORBA.portable stream to read. + */ + public void _read(InputStream input) + { + value = DuplicateNameHelper.read(input); + } + + /** + * Write the stored value into the CDR stream. + * + * @param output the org.omg.CORBA.portable stream to write. + */ + public void _write(OutputStream output) + { + DuplicateNameHelper.write(output, value); + } + + /** + * Get the typecode of the DuplicateName. + */ + public TypeCode _type() + { + return DuplicateNameHelper.type(); + } +} diff --git a/libjava/classpath/gnu/CORBA/DynAn/AbstractAny.java b/libjava/classpath/gnu/CORBA/DynAn/AbstractAny.java new file mode 100644 index 000000000..0f3b897df --- /dev/null +++ b/libjava/classpath/gnu/CORBA/DynAn/AbstractAny.java @@ -0,0 +1,177 @@ +/* AbstractAny.java -- + 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.CORBA.DynAn; + +import gnu.CORBA.TypeKindNamer; + +import org.omg.CORBA.Any; +import org.omg.CORBA.LocalObject; +import org.omg.CORBA.ORB; +import org.omg.CORBA.TypeCode; +import org.omg.DynamicAny.DynAnyPackage.TypeMismatch; + +import java.io.Serializable; + +/** + * The top of our DynAny implementation, this class provides ORB that is + * required to create anys and factory that is required to initialise DynAnys. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public abstract class AbstractAny + extends LocalObject + implements Serializable +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * The "initial final_type" that can be an alias of the known final_type. + */ + public TypeCode official_type; + + /** + * The "basic" final_type to that the final_type finally evaluates. + */ + public final TypeCode final_type; + + /** + * The DynAny factory, required in initializations. + */ + public final gnuDynAnyFactory factory; + + /** + * The ORB, to that this DynAny belongs. + */ + public final ORB orb; + + /** + * The minor code, indicating the error, related to work with non - GNU + * Classpath DynAny. + */ + short MINOR = 8148; + + /** + * The message about the empty structure or exception. + */ + static final String EMPTY = "Empty structure with no fields."; + + /** + * The message about the structure or exception size mismatch. + */ + static final String SIZE = "Size mismatch."; + + /** + * The message about the content of this DynAny being equal to + * null + */ + static final String ISNULL = "The content is null"; + + /** + * The change value listener. + */ + ValueChangeListener listener; + + /** + * Create the abstract dyn any. + */ + public AbstractAny(TypeCode oType, TypeCode aType, + gnuDynAnyFactory aFactory, ORB anOrb + ) + { + official_type = oType; + final_type = aType; + factory = aFactory; + orb = anOrb; + } + + /** + * Get the typecode. + */ + public TypeCode type() + { + return official_type; + } + + /** + * Create the Any. + */ + public Any createAny() + { + return orb.create_any(); + } + + /** + * The "value changed" listener. + */ + protected void valueChanged() + { + if (listener != null) + listener.changed(); + } + + /** + * Check the type. + */ + void checkType(TypeCode expected, TypeCode actual) + throws TypeMismatch + { + if (!expected.equal(actual)) + throw new TypeMismatch(typeMismatch(expected, actual)); + } + + /** + * Format "Type mismatch" string. + */ + String typeMismatch(TypeCode expected, TypeCode actual) + { + return TypeKindNamer.nameIt(expected) + " expected " + + TypeKindNamer.nameIt(actual); + } + + /** + * Format "size mismatch" string. + */ + String sizeMismatch(int here, int other) + { + return "Size mismatch, " + other + " (expected " + here + ")"; + } +} diff --git a/libjava/classpath/gnu/CORBA/DynAn/DivideableAny.java b/libjava/classpath/gnu/CORBA/DynAn/DivideableAny.java new file mode 100644 index 000000000..ae73cfe6f --- /dev/null +++ b/libjava/classpath/gnu/CORBA/DynAn/DivideableAny.java @@ -0,0 +1,512 @@ +/* DivideableAny.java -- + 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.CORBA.DynAn; + +import org.omg.CORBA.Any; +import org.omg.CORBA.CompletionStatus; +import org.omg.CORBA.ORB; +import org.omg.CORBA.Object; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.UNKNOWN; +import org.omg.DynamicAny.DynAny; +import org.omg.DynamicAny.DynAnyPackage.InvalidValue; +import org.omg.DynamicAny.DynAnyPackage.TypeMismatch; +import org.omg.DynamicAny.DynValueCommon; + +import java.io.Serializable; + +/** + * Provides a base for DynAnys, having multiple components. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public abstract class DivideableAny + extends AbstractAny + implements Serializable +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * The array of the components that in general case may have different + * final_type. + */ + protected DynAny[] array; + + /** + * The internal pointer. + */ + protected int pos = 0; + + public DivideableAny(TypeCode oType, TypeCode aType, + gnuDynAnyFactory aFactory, ORB anOrb + ) + { + super(oType, aType, aFactory, anOrb); + } + + /** + * Advance forward. + */ + public boolean next() + { + pos++; + return array.length > pos; + } + + /** + * Set zero position. + */ + public void rewind() + { + pos = 0; + } + + /** + * Set a position. + */ + public boolean seek(int p) + { + pos = p; + return pos >= 0 && array.length > pos; + } + + /** + * Get the insertion point as DynAny. This method may throw exceptions if the + * current insertion point does not support reading or insertion of the + * primitive types. + * + * @return the focused component, from where the primitve value can be read or + * where it can be inserted. + * @throws InvalidValue if the primitive value cannot be inserted at the given + * point. + */ + protected DynAny focused() + throws InvalidValue, TypeMismatch + { + if (pos >= 0 && pos < array.length) + { + if (array [ pos ].component_count() == 0) + return array [ pos ]; + else + throw new TypeMismatch("Multiple coponents at " + pos); + } + else + throw new InvalidValue("Out of bounds at " + pos + " valid 0.." + + (array.length - 1) + ); + } + + /** {@inheritDoc} */ + public int component_count() + { + return array.length; + } + + /** + * Return the second (enclosed any) that is stored in the wrapped Any. + */ + public Any get_any() + throws TypeMismatch, InvalidValue + { + return focused().get_any(); + } + + /** {@inheritDoc} */ + public boolean get_boolean() + throws TypeMismatch, InvalidValue + { + return focused().get_boolean(); + } + + /** {@inheritDoc} */ + public char get_char() + throws TypeMismatch, InvalidValue + { + return focused().get_char(); + } + + /** {@inheritDoc} */ + public double get_double() + throws TypeMismatch, InvalidValue + { + return focused().get_double(); + } + + /** {@inheritDoc} */ + public float get_float() + throws TypeMismatch, InvalidValue + { + return focused().get_float(); + } + + /** {@inheritDoc} */ + public int get_long() + throws TypeMismatch, InvalidValue + { + return focused().get_long(); + } + + /** {@inheritDoc} */ + public long get_longlong() + throws TypeMismatch, InvalidValue + { + return focused().get_longlong(); + } + + /** {@inheritDoc} */ + public byte get_octet() + throws TypeMismatch, InvalidValue + { + return focused().get_octet(); + } + + /** {@inheritDoc} */ + public Object get_reference() + throws TypeMismatch, InvalidValue + { + return focused().get_reference(); + } + + /** {@inheritDoc} */ + public short get_short() + throws TypeMismatch, InvalidValue + { + return focused().get_short(); + } + + /** {@inheritDoc} */ + public String get_string() + throws TypeMismatch, InvalidValue + { + return focused().get_string(); + } + + /** {@inheritDoc} */ + public TypeCode get_typecode() + throws TypeMismatch, InvalidValue + { + return focused().get_typecode(); + } + + /** {@inheritDoc} */ + public int get_ulong() + throws TypeMismatch, InvalidValue + { + return focused().get_ulong(); + } + + /** {@inheritDoc} */ + public long get_ulonglong() + throws TypeMismatch, InvalidValue + { + return focused().get_ulonglong(); + } + + /** {@inheritDoc} */ + public short get_ushort() + throws TypeMismatch, InvalidValue + { + return focused().get_ushort(); + } + + /** {@inheritDoc} */ + public Serializable get_val() + throws TypeMismatch, InvalidValue + { + if (pos >= 0 && pos < array.length) + { + if (array [ pos ] instanceof DynValueCommon) + return array [ pos ].get_val(); + else + throw new TypeMismatch(); + } + else + throw new InvalidValue("Out of bounds at " + pos + " valid 0.." + + (array.length - 1) + ); + } + + /** {@inheritDoc} */ + public char get_wchar() + throws TypeMismatch, InvalidValue + { + return focused().get_wchar(); + } + + /** {@inheritDoc} */ + public String get_wstring() + throws TypeMismatch, InvalidValue + { + return focused().get_wstring(); + } + + /** {@inheritDoc} */ + public void insert_any(Any a_x) + throws TypeMismatch, InvalidValue + { + focused().insert_any(a_x); + valueChanged(); + } + + /** {@inheritDoc} */ + public void insert_boolean(boolean a_x) + throws InvalidValue, TypeMismatch + { + focused().insert_boolean(a_x); + valueChanged(); + } + + /** {@inheritDoc} */ + public void insert_char(char a_x) + throws InvalidValue, TypeMismatch + { + focused().insert_char(a_x); + valueChanged(); + } + + /** {@inheritDoc} */ + public void insert_double(double a_x) + throws InvalidValue, TypeMismatch + { + focused().insert_double(a_x); + valueChanged(); + } + + /** {@inheritDoc} */ + public void insert_float(float a_x) + throws InvalidValue, TypeMismatch + { + focused().insert_float(a_x); + valueChanged(); + } + + /** {@inheritDoc} */ + public void insert_long(int a_x) + throws InvalidValue, TypeMismatch + { + focused().insert_long(a_x); + valueChanged(); + } + + /** {@inheritDoc} */ + public void insert_longlong(long a_x) + throws InvalidValue, TypeMismatch + { + focused().insert_longlong(a_x); + valueChanged(); + } + + /** {@inheritDoc} */ + public void insert_octet(byte a_x) + throws InvalidValue, TypeMismatch + { + focused().insert_octet(a_x); + valueChanged(); + } + + /** {@inheritDoc} */ + public void insert_reference(Object a_x) + throws InvalidValue, TypeMismatch + { + focused().insert_reference(a_x); + valueChanged(); + } + + /** {@inheritDoc} */ + public void insert_short(short a_x) + throws InvalidValue, TypeMismatch + { + focused().insert_short(a_x); + valueChanged(); + } + + /** {@inheritDoc} */ + public void insert_string(String a_x) + throws InvalidValue, TypeMismatch + { + focused().insert_string(a_x); + valueChanged(); + } + + /** {@inheritDoc} */ + public void insert_typecode(TypeCode a_x) + throws InvalidValue, TypeMismatch + { + focused().insert_typecode(a_x); + valueChanged(); + } + + /** {@inheritDoc} */ + public void insert_ulong(int a_x) + throws InvalidValue, TypeMismatch + { + focused().insert_ulong(a_x); + valueChanged(); + } + + /** {@inheritDoc} */ + public void insert_ulonglong(long a_x) + throws InvalidValue, TypeMismatch + { + focused().insert_ulonglong(a_x); + valueChanged(); + } + + /** {@inheritDoc} */ + public void insert_ushort(short a_x) + throws InvalidValue, TypeMismatch + { + focused().insert_ushort(a_x); + valueChanged(); + } + + /** {@inheritDoc} */ + public void insert_val(Serializable a_x) + throws InvalidValue, TypeMismatch + { + if (pos >= 0 && pos < array.length) + { + if (array [ pos ] instanceof DynValueCommon) + array [ pos ].insert_val(a_x); + else + throw new TypeMismatch(); + } + else + throw new InvalidValue("Out of bounds at " + pos + " valid 0.." + + (array.length - 1) + ); + valueChanged(); + } + + /** {@inheritDoc} */ + public void insert_wchar(char a_x) + throws InvalidValue, TypeMismatch + { + focused().insert_wchar(a_x); + valueChanged(); + } + + /** {@inheritDoc} */ + public void insert_wstring(String a_x) + throws InvalidValue, TypeMismatch + { + focused().insert_wstring(a_x); + valueChanged(); + } + + /** {@inheritDoc} */ + public DynAny get_dyn_any() + throws TypeMismatch, InvalidValue + { + return focused().get_dyn_any(); + } + + /** {@inheritDoc} */ + public void insert_dyn_any(DynAny insert_it) + throws TypeMismatch, InvalidValue + { + focused().insert_dyn_any(insert_it); + } + + /** + * Get current component. + * + * @return current component or null if the pointer is out of + * bounds. + */ + public DynAny current_component() + throws TypeMismatch + { + if (array.length == 0) + throw new TypeMismatch("empty"); + return (pos >= 0 && pos < array.length) ? array [ pos ] : null; + } + + /** + * No action, cleanup is done by garbage collector in java. + */ + public void destroy() + { + } + + /** + * Involved in equal(DynAny). + */ + public abstract Any to_any() + throws TypeMismatch; + + /** + * Compares with other DynAny for equality. The final_type, array size and + * array members must match. + */ + public boolean equal(DynAny other) + { + try + { + if (!official_type.equal(other.type())) + return false; + else if (other instanceof DivideableAny) + { + DivideableAny x = (DivideableAny) other; + if (x.array.length != array.length) + return false; + + for (int i = 0; i < array.length; i++) + { + if (!array [ i ].equal(x.array [ i ])) + return false; + } + return true; + } + else if (other == null || other instanceof AbstractAny) + return false; + else + return other.to_any().equal(to_any()); + } + catch (TypeMismatch e) + { + UNKNOWN u = new UNKNOWN(MINOR, CompletionStatus.COMPLETED_NO); + u.initCause(e); + throw u; + } + } +} diff --git a/libjava/classpath/gnu/CORBA/DynAn/NameValuePairHolder.java b/libjava/classpath/gnu/CORBA/DynAn/NameValuePairHolder.java new file mode 100644 index 000000000..c3214e6ad --- /dev/null +++ b/libjava/classpath/gnu/CORBA/DynAn/NameValuePairHolder.java @@ -0,0 +1,94 @@ +/* NameValuePairHolder.java -- + 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.CORBA.DynAn; + +import org.omg.CORBA.NameValuePair; +import org.omg.CORBA.NameValuePairHelper; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.Streamable; + +/** + * The name-value pair holder. The {@link NameValuePair} has no standard holder + * defined, but it is needed to store the {@link NameValuePair} into {@link Any}. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class NameValuePairHolder + implements Streamable +{ + /** + * The stored value of the name value pair. + */ + public NameValuePair value; + + public NameValuePairHolder() + { + } + + public NameValuePairHolder(NameValuePair a_value) + { + value = a_value; + } + + /** + * Read the name value pair. + */ + public void _read(InputStream input) + { + value = NameValuePairHelper.read(input); + } + + /** + * Return the typecode of the name value pair. + */ + public TypeCode _type() + { + return NameValuePairHelper.type(); + } + + /** + * Write the name value pair. + */ + public void _write(OutputStream output) + { + NameValuePairHelper.write(output, value); + } +} diff --git a/libjava/classpath/gnu/CORBA/DynAn/RecordAny.java b/libjava/classpath/gnu/CORBA/DynAn/RecordAny.java new file mode 100644 index 000000000..8badd2011 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/DynAn/RecordAny.java @@ -0,0 +1,405 @@ +/* RecordAny.java -- + 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.CORBA.DynAn; + +import gnu.CORBA.Unexpected; +import gnu.CORBA.HolderLocator; + +import org.omg.CORBA.Any; +import org.omg.CORBA.ORB; +import org.omg.CORBA.TCKind; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.TypeCodePackage.BadKind; +import org.omg.CORBA.TypeCodePackage.Bounds; +import org.omg.CORBA.portable.Streamable; +import org.omg.DynamicAny.DynAny; +import org.omg.DynamicAny.DynAnyPackage.InvalidValue; +import org.omg.DynamicAny.DynAnyPackage.TypeMismatch; +import org.omg.DynamicAny.DynStruct; +import org.omg.DynamicAny.DynValueCommonOperations; +import org.omg.DynamicAny.NameDynAnyPair; +import org.omg.DynamicAny.NameValuePair; + +import java.io.Serializable; + +import java.lang.reflect.Field; + +/** + * A shared base for both dynamic structure an dynamic value final_type. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public abstract class RecordAny + extends DivideableAny + implements DynAny, Serializable +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + String[] fNames; + + /** + * Creates the structure with the given typecode. + * + * @param fields The DynAny's, representing the fields of the structure. + */ + public RecordAny(TypeCode oType, TypeCode aType, + gnuDynAnyFactory aFactory, ORB anOrb + ) + { + super(oType, aType, aFactory, anOrb); + } + + /** @inheritDoc */ + public TCKind current_member_kind() + throws TypeMismatch, InvalidValue + { + if (array.length == 0) + throw new TypeMismatch(EMPTY); + try + { + return final_type.member_type(pos).kind(); + } + catch (BadKind e) + { + TypeMismatch t = new TypeMismatch(); + t.initCause(e); + throw t; + } + catch (Bounds e) + { + InvalidValue t = new InvalidValue(); + t.initCause(e); + throw t; + } + } + + /** @inheritDoc */ + public String current_member_name() + throws TypeMismatch, InvalidValue + { + if (array.length == 0) + throw new TypeMismatch(EMPTY); + try + { + return final_type.member_name(pos); + } + catch (BadKind e) + { + TypeMismatch t = new TypeMismatch(); + t.initCause(e); + throw t; + } + catch (Bounds e) + { + InvalidValue t = new InvalidValue(); + t.initCause(e); + throw t; + } + } + + /** + * Get content of the structure. This method must be defined on a different + * name because get_members_as_dyn_any() throws exception only in some of the + * supported interfaces. + */ + public NameDynAnyPair[] gnu_get_members_as_dyn_any() + { + NameDynAnyPair[] r = new NameDynAnyPair[ array.length ]; + for (int i = 0; i < r.length; i++) + { + try + { + r [ i ] = new NameDynAnyPair(fNames [ i ], array [ i ]); + } + catch (Exception ex) + { + throw new Unexpected(ex); + } + } + return r; + } + + /** + * Get content of the structure. This method must be defined on a different + * name because get_members_as_dyn_any() throws exception only in some of the + * supported interfaces. + */ + public NameValuePair[] gnu_get_members() + { + NameValuePair[] r = new NameValuePair[ array.length ]; + for (int i = 0; i < r.length; i++) + { + try + { + r [ i ] = new NameValuePair(fNames [ i ], array [ i ].to_any()); + } + catch (Exception ex) + { + throw new Unexpected(ex); + } + } + return r; + } + + /** + * Set members from the provided array. + */ + public void set_members_as_dyn_any(NameDynAnyPair[] value) + throws TypeMismatch, InvalidValue + { + if (value.length != array.length) + throw new InvalidValue(sizeMismatch(array.length, value.length)); + + for (int i = 0; i < value.length; i++) + { + DynAny dynAny = value [ i ].value; + checkType(dynAny.type(), i); + checkName(value [ i ].id, i); + + array [ i ] = dynAny; + } + pos = 0; + } + + /** + * Check the name at the given position ("" matches everything). + */ + private void checkName(String xName, int i) + throws TypeMismatch + { + if (xName.length() > 0 && fNames [ i ].length() > 0) + if (!xName.equals(fNames [ i ])) + throw new TypeMismatch("Field name mismatch " + xName + " expected " + + fNames [ i ] + ); + } + + /** + * Check the type at the given position. + */ + private void checkType(TypeCode t, int i) + throws TypeMismatch + { + if (!array [ i ].type().equal(t)) + throw new TypeMismatch(typeMismatch(array [ i ].type(), t) + " field " + + i + ); + } + + /** + * Set members from the provided array. + */ + public void set_members(NameValuePair[] value) + throws TypeMismatch, InvalidValue + { + if (value.length != array.length) + throw new InvalidValue(sizeMismatch(array.length, value.length)); + + for (int i = 0; i < value.length; i++) + { + Any any = value [ i ].value; + checkType(any.type(), i); + checkName(value [ i ].id, i); + + array [ i ].from_any(any); + } + pos = 0; + } + + /** @inheritDoc */ + public void assign(DynAny from) + throws TypeMismatch + { + checkType(official_type, from.type()); + if (from instanceof DynStruct) + { + try + { + set_members_as_dyn_any(((DynStruct) from).get_members_as_dyn_any()); + } + catch (InvalidValue e) + { + TypeMismatch t = new TypeMismatch("Invalid value"); + t.initCause(e); + throw t; + } + } + else + throw new TypeMismatch("Not a DynStruct"); + } + + /** + * Create a copy. + */ + public DynAny copy() + { + DynAny[] c = new DynAny[ array.length ]; + for (int i = 0; i < c.length; i++) + { + c [ i ] = array [ i ].copy(); + } + + RecordAny d = newInstance(official_type, final_type, factory, orb); + d.array = c; + return d; + } + + /** + * Create a new instance when copying. + */ + protected abstract RecordAny newInstance(TypeCode oType, TypeCode aType, + gnuDynAnyFactory aFactory, + ORB anOrb + ); + + /** + * Done via reflection. + */ + public Any to_any() + { + try + { + Streamable sHolder = HolderLocator.createHolder(official_type); + + Class sHolderClass = sHolder.getClass(); + Field sHolderValue = sHolderClass.getField("value"); + Class sClass = sHolderValue.getType(); + + Object structure = sClass.newInstance(); + Object member; + Any am; + Field vread; + Field vwrite; + Streamable memberHolder; + + for (int i = 0; i < array.length; i++) + { + am = array [ i ].to_any(); + memberHolder = am.extract_Streamable(); + vwrite = structure.getClass().getField(final_type.member_name(i)); + vread = memberHolder.getClass().getField("value"); + member = vread.get(memberHolder); + vwrite.set(structure, member); + } + + Any g = createAny(); + sHolderValue.set(sHolder, structure); + g.insert_Streamable(sHolder); + g.type(official_type); + return g; + } + catch (Exception e) + { + throw new Unexpected(e); + } + } + + /** + * Done via reflection. + */ + public void from_any(Any an_any) + throws TypeMismatch, InvalidValue + { + checkType(official_type, an_any.type()); + try + { + Streamable s = an_any.extract_Streamable(); + if (s == null) + { + if (this instanceof DynValueCommonOperations) + { + ((DynValueCommonOperations) this).set_to_null(); + return; + } + else + throw new InvalidValue(ISNULL); + } + + Object structure = s.getClass().getField("value").get(s); + if (structure == null && (this instanceof DynValueCommonOperations)) + { + ((DynValueCommonOperations) this).set_to_null(); + return; + } + + Any member; + Streamable holder; + Object field; + TypeCode fType; + Field fField; + + for (int i = 0; i < array.length; i++) + { + fField = structure.getClass().getField(fNames [ i ]); + field = fField.get(structure); + fType = array [ i ].type(); + holder = HolderLocator.createHolder(fType); + + member = createAny(); + holder.getClass().getField("value").set(holder, field); + member.insert_Streamable(holder); + member.type(fType); + + array [ i ].from_any(member); + } + + if (this instanceof DynValueCommonOperations) + ((DynValueCommonOperations) this).set_to_value(); + } + catch (InvalidValue v) + { + throw v; + } + catch (NoSuchFieldException ex) + { + TypeMismatch v = + new TypeMismatch("holder value does not match typecode"); + v.initCause(ex); + throw v; + } + catch (Exception ex) + { + TypeMismatch t = new TypeMismatch(); + t.initCause(ex); + throw t; + } + } +} diff --git a/libjava/classpath/gnu/CORBA/DynAn/UndivideableAny.java b/libjava/classpath/gnu/CORBA/DynAn/UndivideableAny.java new file mode 100644 index 000000000..da4e9618e --- /dev/null +++ b/libjava/classpath/gnu/CORBA/DynAn/UndivideableAny.java @@ -0,0 +1,493 @@ +/* Undivideable.java -- + 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.CORBA.DynAn; + +import java.io.Serializable; + +import org.omg.CORBA.Any; +import org.omg.CORBA.ORB; +import org.omg.CORBA.Object; +import org.omg.CORBA.TypeCode; +import org.omg.DynamicAny.DynAny; +import org.omg.DynamicAny.DynAnyPackage.InvalidValue; +import org.omg.DynamicAny.DynAnyPackage.TypeMismatch; + +/** + * Represent DynAny that has no internal components (DynEnum and so on). The + * methods, related to internal components, throw exceptions or return agreed + * values like null. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public abstract class UndivideableAny + extends AbstractAny + implements Serializable +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * Create a new instance with the given typecode. + */ + public UndivideableAny(TypeCode oType, TypeCode aType, + gnuDynAnyFactory aFactory, ORB anOrb) + { + super(oType, aType, aFactory, anOrb); + } + + /** + * There are no components. + * + * @return 0, always. + */ + public int component_count() + { + return 0; + } + + /** + * There is no current component. + * + * @throws TypeMismatch, always. + */ + public DynAny current_component() + throws TypeMismatch + { + throw new TypeMismatch("Not applicable"); + } + + /** + * Returns without action. + */ + public void destroy() + { + } + + /** + * Not in use. + */ + public Any get_any() + throws TypeMismatch, InvalidValue + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public boolean get_boolean() + throws TypeMismatch, InvalidValue + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public char get_char() + throws TypeMismatch, InvalidValue + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public double get_double() + throws TypeMismatch, InvalidValue + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public DynAny get_dyn_any() + throws TypeMismatch, InvalidValue + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public float get_float() + throws TypeMismatch, InvalidValue + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public int get_long() + throws TypeMismatch, InvalidValue + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public long get_longlong() + throws TypeMismatch, InvalidValue + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public byte get_octet() + throws TypeMismatch, InvalidValue + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public Object get_reference() + throws TypeMismatch, InvalidValue + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public short get_short() + throws TypeMismatch, InvalidValue + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public String get_string() + throws TypeMismatch, InvalidValue + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public TypeCode get_typecode() + throws TypeMismatch, InvalidValue + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public int get_ulong() + throws TypeMismatch, InvalidValue + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public long get_ulonglong() + throws TypeMismatch, InvalidValue + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public short get_ushort() + throws TypeMismatch, InvalidValue + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public Serializable get_val() + throws TypeMismatch, InvalidValue + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public char get_wchar() + throws TypeMismatch, InvalidValue + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public String get_wstring() + throws TypeMismatch, InvalidValue + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public void insert_any(Any an_any) + throws TypeMismatch, InvalidValue + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public void insert_boolean(boolean a_x) + throws InvalidValue, TypeMismatch + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public void insert_char(char a_x) + throws InvalidValue, TypeMismatch + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public void insert_double(double a_x) + throws InvalidValue, TypeMismatch + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public void insert_dyn_any(DynAny insert_it) + throws TypeMismatch, InvalidValue + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public void insert_float(float a_x) + throws InvalidValue, TypeMismatch + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public void insert_long(int a_x) + throws InvalidValue, TypeMismatch + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public void insert_longlong(long a_x) + throws InvalidValue, TypeMismatch + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public void insert_octet(byte a_x) + throws InvalidValue, TypeMismatch + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public void insert_reference(Object a_x) + throws InvalidValue, TypeMismatch + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public void insert_short(short a_x) + throws InvalidValue, TypeMismatch + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public void insert_string(String a_x) + throws InvalidValue, TypeMismatch + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public void insert_typecode(TypeCode a_x) + throws InvalidValue, TypeMismatch + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public void insert_ulong(int a_x) + throws InvalidValue, TypeMismatch + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public void insert_ulonglong(long a_x) + throws InvalidValue, TypeMismatch + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public void insert_ushort(short a_x) + throws InvalidValue, TypeMismatch + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public void insert_val(Serializable a_x) + throws InvalidValue, TypeMismatch + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public void insert_wchar(char a_x) + throws InvalidValue, TypeMismatch + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public void insert_wstring(String a_x) + throws InvalidValue, TypeMismatch + { + throw new TypeMismatch(); + } + + /** + * Not in use. + */ + public boolean next() + { + return false; + } + + /** + * Not in use. + */ + public void rewind() + { + } + + /** + * Not in use. + */ + public boolean seek(int p) + { + return false; + } + + /** + * Get the typecode of this enumeration. + */ + public TypeCode type() + { + return official_type; + } + + /** + * Compares with other DynAny for equality. + */ + public boolean equals(java.lang.Object other) + { + if (other instanceof DynAny) + return equal((DynAny) other); + else + return false; + } + + /** + * This depends on an object. + */ + public abstract boolean equal(DynAny other); + +} diff --git a/libjava/classpath/gnu/CORBA/DynAn/ValueChangeListener.java b/libjava/classpath/gnu/CORBA/DynAn/ValueChangeListener.java new file mode 100644 index 000000000..4c3a456d2 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/DynAn/ValueChangeListener.java @@ -0,0 +1,50 @@ +/* ValueChangeListener.java -- + 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.CORBA.DynAn; + +/** + * An interface, able to receive notification about the change of value + * of some DynAny. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public interface ValueChangeListener +{ + void changed(); +} diff --git a/libjava/classpath/gnu/CORBA/DynAn/gnuDynAny.java b/libjava/classpath/gnu/CORBA/DynAn/gnuDynAny.java new file mode 100644 index 000000000..314426c82 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/DynAn/gnuDynAny.java @@ -0,0 +1,945 @@ +/* gnuDynAny.java -- + 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.CORBA.DynAn; + +import gnu.CORBA.CDR.BufferedCdrOutput; +import gnu.CORBA.OctetHolder; +import gnu.CORBA.Unexpected; +import gnu.CORBA.WCharHolder; +import gnu.CORBA.WStringHolder; +import gnu.CORBA.HolderLocator; +import gnu.CORBA.TypeKindNamer; +import gnu.CORBA.GeneralHolder; + +import org.omg.CORBA.Any; +import org.omg.CORBA.AnyHolder; +import org.omg.CORBA.BooleanHolder; +import org.omg.CORBA.CharHolder; +import org.omg.CORBA.DoubleHolder; +import org.omg.CORBA.FloatHolder; +import org.omg.CORBA.IntHolder; +import org.omg.CORBA.LongHolder; +import org.omg.CORBA.MARSHAL; +import org.omg.CORBA.ORB; +import org.omg.CORBA.Object; +import org.omg.CORBA.ObjectHolder; +import org.omg.CORBA.ShortHolder; +import org.omg.CORBA.StringHolder; +import org.omg.CORBA.TCKind; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.TypeCodeHolder; +import org.omg.CORBA.TypeCodePackage.BadKind; +import org.omg.CORBA.ValueBaseHolder; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.Streamable; +import org.omg.DynamicAny.DynAny; +import org.omg.DynamicAny.DynAnyPackage.InvalidValue; +import org.omg.DynamicAny.DynAnyPackage.TypeMismatch; + +import java.io.IOException; +import java.io.Serializable; + +import java.util.Arrays; + +/** + * The primitive dynamic Any holds the value basic final_type that cannot be + * traversed. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class gnuDynAny extends AbstractAny implements DynAny, Serializable +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * The enclosed Streamable, holding the actual value. + */ + protected Streamable holder; + + /** + * Create DynAny providing the holder. + * + * @param a_holder + */ + public gnuDynAny(Streamable aHolder, TypeCode oType, TypeCode aType, + gnuDynAnyFactory aFactory, ORB anOrb + ) + { + super(oType, aType, aFactory, anOrb); + holder = aHolder; + } + + /** + * Assign the contents of the given {@link DynAny} to this DynAny. + * + * @param from the source to assign from. + */ + public void assign(DynAny from) throws TypeMismatch + { + checkType(official_type, from.type()); + + if (from instanceof gnuDynAny) + holder = ((gnuDynAny) from).holder; + else + holder = from.to_any().extract_Streamable(); + valueChanged(); + } + + /** + * Create a copy of this {@link DynAny} via buffer read/write. + */ + public DynAny copy() + { + if (holder != null) + { + BufferedCdrOutput buffer = new BufferedCdrOutput(); + holder._write(buffer); + + gnuDynAny other; + try + { + other = + new gnuDynAny((Streamable) (holder.getClass().newInstance()), + official_type, final_type, factory, orb + ); + } + catch (Exception e) + { + // Holder must have parameterless constructor. + throw new Unexpected(e); + } + other.holder._read(buffer.create_input_stream()); + return other; + } + else + { + return new gnuDynAny(null, official_type, final_type, factory, orb); + } + } + + /** + * Always returns null. + * + * @return null, always. + */ + public DynAny current_component() throws TypeMismatch + { + throw new TypeMismatch("Not applicable for " + + TypeKindNamer.nameIt(final_type) + ); + } + + /** + * Returns without action, leaving all work to the garbage collector. + */ + public void destroy() + { + } + + /** + * Takes the passed parameter as the enclosed {@link Any} reference. + * + * @param an_any the {@link Any} that will be used as an enclosed reference. + * + * @throws TypeMismatch if the final_type of the passed Any is not the same as + * the final_type, currently stored in this Any. + */ + public void from_any(Any an_any) throws TypeMismatch, InvalidValue + { + checkType(official_type, an_any.type()); + + Streamable a_holder = an_any.extract_Streamable(); + if (a_holder == null) + { + throw new InvalidValue(ISNULL); + } + else if (a_holder instanceof GeneralHolder) + { + holder = HolderLocator.createHolder(official_type); + if (holder == null) + holder = HolderLocator.createHolder(final_type); + + if (holder == null) + holder = ((GeneralHolder) a_holder).Clone(); + else + { + InputStream in = an_any.create_input_stream(); + holder._read(in); + try + { + in.close(); + } + catch (IOException ex) + { + throw new Unexpected(ex); + } + } + } + else + { + try + { + InputStream in = an_any.create_input_stream(); + holder = (Streamable) a_holder.getClass().newInstance(); + holder._read(in); + in.close(); + } + catch (Exception ex) + { + TypeMismatch t = new TypeMismatch(); + t.initCause(ex); + throw t; + } + } + valueChanged(); + } + + /** + * Return the second (enclosed any) that is stored in the wrapped Any. + */ + public Any get_any() throws TypeMismatch + { + try + { + return ((AnyHolder) holder).value; + } + catch (ClassCastException cex) + { + TypeMismatch m = new TypeMismatch(); + m.initCause(cex); + throw m; + } + } + + /** {@inheritDoc} */ + public boolean get_boolean() throws TypeMismatch + { + try + { + return ((BooleanHolder) holder).value; + } + catch (ClassCastException cex) + { + TypeMismatch m = new TypeMismatch(); + m.initCause(cex); + throw m; + } + } + + /** {@inheritDoc} */ + public char get_char() throws TypeMismatch + { + try + { + return ((CharHolder) holder).value; + } + catch (ClassCastException cex) + { + TypeMismatch m = new TypeMismatch(); + m.initCause(cex); + throw m; + } + } + + /** {@inheritDoc} */ + public double get_double() throws TypeMismatch + { + try + { + return ((DoubleHolder) holder).value; + } + catch (ClassCastException cex) + { + TypeMismatch m = new TypeMismatch(); + m.initCause(cex); + throw m; + } + } + + /** {@inheritDoc} */ + public float get_float() throws TypeMismatch + { + try + { + return ((FloatHolder) holder).value; + } + catch (ClassCastException cex) + { + TypeMismatch m = new TypeMismatch(); + m.initCause(cex); + throw m; + } + } + + /** {@inheritDoc} */ + public int get_long() throws TypeMismatch + { + try + { + return ((IntHolder) holder).value; + } + catch (ClassCastException cex) + { + TypeMismatch m = new TypeMismatch(); + m.initCause(cex); + throw m; + } + } + + /** {@inheritDoc} */ + public long get_longlong() throws TypeMismatch + { + try + { + return ((LongHolder) holder).value; + } + catch (ClassCastException cex) + { + TypeMismatch m = new TypeMismatch(); + m.initCause(cex); + throw m; + } + } + + /** {@inheritDoc} */ + public byte get_octet() throws TypeMismatch + { + try + { + return ((OctetHolder) holder).value; + } + catch (ClassCastException cex) + { + TypeMismatch m = new TypeMismatch(); + m.initCause(cex); + throw m; + } + } + + /** {@inheritDoc} */ + public Object get_reference() throws TypeMismatch + { + try + { + return ((ObjectHolder) holder).value; + } + catch (ClassCastException cex) + { + TypeMismatch m = new TypeMismatch(); + m.initCause(cex); + throw m; + } + } + + /** {@inheritDoc} */ + public short get_short() throws TypeMismatch + { + try + { + return ((ShortHolder) holder).value; + } + catch (ClassCastException cex) + { + TypeMismatch m = new TypeMismatch(); + m.initCause(cex); + throw m; + } + } + + /** {@inheritDoc} */ + public String get_string() throws TypeMismatch + { + try + { + return ((StringHolder) holder).value; + } + catch (ClassCastException cex) + { + TypeMismatch m = new TypeMismatch(); + m.initCause(cex); + throw m; + } + } + + /** {@inheritDoc} */ + public TypeCode get_typecode() throws TypeMismatch + { + try + { + return ((TypeCodeHolder) holder).value; + } + catch (ClassCastException cex) + { + TypeMismatch m = new TypeMismatch(); + m.initCause(cex); + throw m; + } + } + + /** {@inheritDoc} */ + public int get_ulong() throws TypeMismatch + { + check(TCKind.tk_ulong); + return get_long(); + } + + /** {@inheritDoc} */ + public long get_ulonglong() throws TypeMismatch + { + check(TCKind.tk_ulonglong); + return get_longlong(); + } + + /** {@inheritDoc} */ + public short get_ushort() throws TypeMismatch + { + check(TCKind.tk_ushort); + return get_short(); + } + + /** {@inheritDoc} */ + public Serializable get_val() throws TypeMismatch + { + try + { + return ((ValueBaseHolder) holder).value; + } + catch (ClassCastException cex) + { + TypeMismatch m = new TypeMismatch(); + m.initCause(cex); + throw m; + } + } + + /** {@inheritDoc} */ + public char get_wchar() throws TypeMismatch + { + try + { + return ((WCharHolder) holder).value; + } + catch (ClassCastException cex) + { + TypeMismatch m = new TypeMismatch(); + m.initCause(cex); + throw m; + } + } + + /** {@inheritDoc} */ + public String get_wstring() throws TypeMismatch + { + try + { + return ((WStringHolder) holder).value; + } + catch (ClassCastException cex) + { + TypeMismatch m = new TypeMismatch(); + m.initCause(cex); + throw m; + } + } + + /** {@inheritDoc} */ + public void insert_any(Any a_x) throws TypeMismatch, InvalidValue + { + try + { + if (a_x.type().kind().value() == TCKind._tk_null) + ((AnyHolder) holder).value = a_x; + else + { + OutputStream buf = a_x.create_output_stream(); + buf.write_any(a_x); + holder._read(buf.create_input_stream()); + buf.close(); + } + valueChanged(); + } + catch (ClassCastException cex) + { + TypeMismatch t = new TypeMismatch(); + t.initCause(cex); + throw t; + } + catch (MARSHAL m) + { + InvalidValue v = new InvalidValue(); + v.initCause(m); + throw v; + } + catch (IOException ex) + { + throw new Unexpected(ex); + } + } + + /** {@inheritDoc} */ + public void insert_boolean(boolean a_x) throws InvalidValue, TypeMismatch + { + try + { + ((BooleanHolder) holder).value = a_x; + valueChanged(); + } + catch (ClassCastException cex) + { + TypeMismatch t = new TypeMismatch(); + t.initCause(cex); + throw t; + } + } + + /** {@inheritDoc} */ + public void insert_char(char a_x) throws InvalidValue, TypeMismatch + { + try + { + ((CharHolder) holder).value = a_x; + valueChanged(); + } + catch (ClassCastException cex) + { + TypeMismatch t = new TypeMismatch(); + t.initCause(cex); + throw t; + } + } + + /** {@inheritDoc} */ + public void insert_double(double a_x) throws InvalidValue, TypeMismatch + { + try + { + ((DoubleHolder) holder).value = a_x; + valueChanged(); + } + catch (ClassCastException cex) + { + TypeMismatch t = new TypeMismatch(); + t.initCause(cex); + throw t; + } + } + + /** {@inheritDoc} */ + public void insert_float(float a_x) throws InvalidValue, TypeMismatch + { + try + { + ((FloatHolder) holder).value = a_x; + valueChanged(); + } + catch (ClassCastException cex) + { + TypeMismatch t = new TypeMismatch(); + t.initCause(cex); + throw t; + } + } + + /** {@inheritDoc} */ + public void insert_long(int a_x) throws InvalidValue, TypeMismatch + { + try + { + ((IntHolder) holder).value = a_x; + valueChanged(); + } + catch (ClassCastException cex) + { + TypeMismatch t = new TypeMismatch(); + t.initCause(cex); + throw t; + } + } + + /** {@inheritDoc} */ + public void insert_longlong(long a_x) throws InvalidValue, TypeMismatch + { + try + { + ((LongHolder) holder).value = a_x; + valueChanged(); + } + catch (ClassCastException cex) + { + TypeMismatch t = new TypeMismatch(); + t.initCause(cex); + throw t; + } + } + + /** {@inheritDoc} */ + public void insert_octet(byte a_x) throws InvalidValue, TypeMismatch + { + try + { + ((OctetHolder) holder).value = a_x; + valueChanged(); + } + catch (ClassCastException cex) + { + TypeMismatch t = new TypeMismatch(); + t.initCause(cex); + throw t; + } + } + + /** {@inheritDoc} */ + public void insert_reference(Object a_x) throws InvalidValue, TypeMismatch + { + try + { + ((ObjectHolder) holder).value = a_x; + valueChanged(); + } + catch (ClassCastException cex) + { + TypeMismatch t = new TypeMismatch(); + t.initCause(cex); + throw t; + } + } + + /** {@inheritDoc} */ + public void insert_short(short a_x) throws InvalidValue, TypeMismatch + { + try + { + ((ShortHolder) holder).value = a_x; + valueChanged(); + } + catch (ClassCastException cex) + { + TypeMismatch t = new TypeMismatch(); + t.initCause(cex); + throw t; + } + } + + /** {@inheritDoc} */ + public void insert_string(String a_x) throws InvalidValue, TypeMismatch + { + try + { + if (a_x != null && + final_type.length() > 0 && + a_x.length() > final_type.length() + ) + throw new InvalidValue(a_x.length() + " exceeds bound, " + + final_type.length() + ); + ((StringHolder) holder).value = a_x; + valueChanged(); + } + catch (ClassCastException cex) + { + TypeMismatch t = new TypeMismatch(); + t.initCause(cex); + throw t; + } + catch (BadKind e) + { + TypeMismatch t = new TypeMismatch(); + t.initCause(e); + throw t; + } + } + + /** {@inheritDoc} */ + public void insert_typecode(TypeCode a_x) throws InvalidValue, TypeMismatch + { + try + { + ((TypeCodeHolder) holder).value = a_x; + valueChanged(); + } + catch (ClassCastException cex) + { + TypeMismatch t = new TypeMismatch(); + t.initCause(cex); + throw t; + } + } + + /** {@inheritDoc} */ + public void insert_ulong(int a_x) throws InvalidValue, TypeMismatch + { + try + { + ((IntHolder) holder).value = a_x; + valueChanged(); + } + catch (ClassCastException cex) + { + TypeMismatch t = new TypeMismatch(); + t.initCause(cex); + throw t; + } + } + + /** {@inheritDoc} */ + public void insert_ulonglong(long a_x) throws InvalidValue, TypeMismatch + { + try + { + ((LongHolder) holder).value = a_x; + valueChanged(); + } + catch (ClassCastException cex) + { + TypeMismatch t = new TypeMismatch(); + t.initCause(cex); + throw t; + } + } + + /** {@inheritDoc} */ + public void insert_ushort(short a_x) throws InvalidValue, TypeMismatch + { + try + { + ((ShortHolder) holder).value = a_x; + valueChanged(); + } + catch (ClassCastException cex) + { + TypeMismatch t = new TypeMismatch(); + t.initCause(cex); + throw t; + } + } + + /** {@inheritDoc} */ + public void insert_val(Serializable a_x) throws InvalidValue, TypeMismatch + { + try + { + ((ValueBaseHolder) holder).value = a_x; + valueChanged(); + } + catch (ClassCastException cex) + { + TypeMismatch t = new TypeMismatch(); + t.initCause(cex); + throw t; + } + } + + /** {@inheritDoc} */ + public void insert_wchar(char a_x) throws InvalidValue, TypeMismatch + { + try + { + ((WCharHolder) holder).value = a_x; + valueChanged(); + } + catch (ClassCastException cex) + { + TypeMismatch t = new TypeMismatch(); + t.initCause(cex); + throw t; + } + } + + /** {@inheritDoc} */ + public void insert_wstring(String a_x) throws InvalidValue, TypeMismatch + { + try + { + if (a_x != null && + final_type.length() > 0 && + a_x.length() > type().length() + ) + throw new InvalidValue(a_x.length() + " exceeds bound, " + + final_type.length() + ); + ((WStringHolder) holder).value = a_x; + valueChanged(); + } + catch (ClassCastException cex) + { + TypeMismatch t = new TypeMismatch(); + t.initCause(cex); + throw t; + } + catch (BadKind e) + { + TypeMismatch t = new TypeMismatch(); + t.initCause(e); + throw t; + } + } + + /** + * The objects, enclosed inside this class, have only one component (self). + * + * @return false, always (no other action). + */ + public boolean next() + { + return false; + } + + /** + * Returns without action. + */ + public void rewind() + { + } + + /** + * This objects, stored in this wrapper, never have multiple internal + * components to seek. + * + * @return false, always (no other action). + */ + public boolean seek(int p) + { + return false; + } + + /** + * Returns the enclosed {@link Any}. + * + * @return the enclosed {@link Any}. + */ + public Any to_any() + { + Any a = createAny(); + a.insert_Streamable(holder); + a.type(official_type); + return a; + } + + /** {@inheritDoc} */ + public TypeCode type() + { + return official_type; + } + + /** + * Compute hashcode in a trivial way. + */ + protected int getHashCodeSimple(int maximum) + { + int h = super.hashCode() / 2; + if (h < 0) + h = -h; + return h % maximum; + } + + /** + * Inserts Any, contained in the parameter, into Any, contained in this + * DynAny. + */ + public void insert_dyn_any(DynAny d) throws TypeMismatch, InvalidValue + { + check(d.type().kind()); + + Any a = d.to_any(); + holder = a.extract_Streamable(); + valueChanged(); + } + + /** + * Checks for equality. The DynAnys are equal if the stored Anys are equal. + */ + public boolean equal(DynAny other) + { + if (other instanceof AbstractAny) + { + if (other instanceof gnuDynAny) + { + gnuDynAny x = (gnuDynAny) other; + + if (!x.holder.getClass().equals(holder.getClass())) + return false; + + BufferedCdrOutput b1 = new BufferedCdrOutput(); + x.holder._write(b1); + + BufferedCdrOutput b2 = new BufferedCdrOutput(b1.buffer.size() + 10); + holder._write(b2); + + return Arrays.equals(b1.buffer.toByteArray(), + b2.buffer.toByteArray() + ); + } + else + return false; + } + if (other == null) + return false; + else if (other.component_count() != component_count() || + !official_type.equal(other.type()) + ) + return false; + else + return other.to_any().equal(to_any()); + } + + /** + * This final_type has no components. + * + * @return 0, always. + */ + public int component_count() + { + return 0; + } + + public DynAny get_dyn_any() throws TypeMismatch, InvalidValue + { + return new gnuDynAny(holder, official_type, final_type, factory, orb); + } + + private void check(TCKind t) throws TypeMismatch + { + if (t.value() != final_type.kind().value()) + throw new TypeMismatch(t.value() + "!=" + final_type.kind().value()); + } +} diff --git a/libjava/classpath/gnu/CORBA/DynAn/gnuDynAnyFactory.java b/libjava/classpath/gnu/CORBA/DynAn/gnuDynAnyFactory.java new file mode 100644 index 000000000..b42e63213 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/DynAn/gnuDynAnyFactory.java @@ -0,0 +1,356 @@ +/* gnuDynAnyFactory.java -- + 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.CORBA.DynAn; + +import gnu.CORBA.Poa.ORB_1_4; +import gnu.CORBA.Unexpected; +import gnu.CORBA.HolderLocator; +import gnu.CORBA.TypeKindNamer; + +import org.omg.CORBA.Any; +import org.omg.CORBA.LocalObject; +import org.omg.CORBA.TCKind; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.TypeCodePackage.BadKind; +import org.omg.CORBA.UserException; +import org.omg.CORBA.portable.Streamable; +import org.omg.DynamicAny.DynAny; +import org.omg.DynamicAny.DynAnyFactory; +import org.omg.DynamicAny.DynAnyFactoryPackage.InconsistentTypeCode; +import org.omg.DynamicAny.DynArray; +import org.omg.DynamicAny.DynEnum; +import org.omg.DynamicAny.DynFixed; +import org.omg.DynamicAny.DynSequence; +import org.omg.DynamicAny.DynStruct; +import org.omg.DynamicAny.DynUnion; +import org.omg.DynamicAny.DynValue; +import org.omg.DynamicAny.DynValueBox; + +/** + * This class is returned by ORB when resolving + * initial reference "DynAnyFactory". + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class gnuDynAnyFactory + extends LocalObject + implements DynAnyFactory +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * The ORB, to that the factory belongs. + */ + final ORB_1_4 orb; + + /** + * Create a new factory, specifying the ORB to that the factory belongs. + * + * @param anOrb + */ + public gnuDynAnyFactory(ORB_1_4 anOrb) + { + orb = anOrb; + } + + /** + * Get the orb. + */ + public ORB_1_4 getOrb() + { + return orb; + } + + /** + * Create an initialised array. + */ + public DynArray create_array(TypeCode official, TypeCode type) + { + return new gnuDynArray(official, type, this, orb, true); + } + + /** + * Create an empty sequence. + */ + public DynSequence create_sequence(TypeCode official, TypeCode type) + { + return new gnuDynSequence(official, type, this, orb); + } + + /** + * Create structure. + * + * @param official the type that was originally passed as a parameter by user. + * May be alias of some other type. + * @param type the type into that the "official type" evaluates during alias + * resolving. Initially equal to "official type". + */ + public DynStruct create_structure(TypeCode official, TypeCode type) + { + return new gnuDynStruct(official, type, this, orb); + } + + /** + * Create union. + * + * @param official the type that was originally passed as a parameter by user. + * May be alias of some other type. + * @param type the type into that the "official type" evaluates during alias + * resolving. Initially equal to "official type". + */ + public DynUnion create_union(TypeCode official, TypeCode type) + { + try + { + return new gnuDynUnion(official, type, this, orb); + } + catch (Exception ex) + { + throw new Unexpected(ex); + } + } + + /** + * Create value. + * + * @param official the type that was originally passed as a parameter by user. + * May be alias of some other type. + * @param type the type into that the "official type" evaluates during alias + * resolving. Initially equal to "official type". + */ + public DynValue create_value(TypeCode official, TypeCode type) + { + return new gnuDynValue(official, type, this, orb); + } + + /** + * Create value box. + * + * @param official the type that was originally passed as a parameter by user. + * May be alias of some other type. + * @param type the type into that the "official type" evaluates during alias + * resolving. Initially equal to "official type". + */ + public DynValueBox create_value_box(TypeCode official, TypeCode type) + { + return new gnuDynValueBox(official, type, this, orb); + } + + /** + * Create enumeration. + * + * @param official the type that was originally passed as a parameter by user. + * May be alias of some other type. + * @param type the type into that the "official type" evaluates during alias + * resolving. Initially equal to "official type". + */ + public DynEnum create_enumeration(TypeCode official, TypeCode type) + { + return new gnuDynEnum(official, type, this, orb); + } + + /** + * Create fixed. + * + * @param official the type that was originally passed as a parameter by user. + * May be alias of some other type. + * @param type the type into that the "official type" evaluates during alias + * resolving. Initially equal to "official type". + */ + public DynFixed create_fixed(TypeCode official, TypeCode type) + { + return new gnuDynFixed(official, type, this, orb); + } + + /** + * Create alias. + * + * @param official the type that was originally passed as a parameter by user. + * May be alias of some other type. + * @param type the type into that the "official type" evaluates during alias + * resolving. Initially equal to "official type". + */ + public DynAny create_alias(TypeCode official, TypeCode type) + throws InconsistentTypeCode + { + try + { + return create_dyn_any_from_type_code(official, type.content_type()); + } + catch (BadKind e) + { + throw new Unexpected(e); + } + } + + /** + * Create the undivideable DynAny. + */ + public DynAny create_simple(TypeCode official, TypeCode type) + { + Streamable holder = HolderLocator.createHolder(type); + return new gnuDynAny(holder, official, type, this, orb); + } + + /** + * Create the DynAny from typecode. + */ + public DynAny create_dyn_any_from_type_code(TypeCode type) + throws InconsistentTypeCode + { + return create_dyn_any_from_type_code(type, type); + } + + /** + * Create the DynAny from typecode. + * + * @param official the type that was originally passed as a parameter by user. + * May be alias of some other type. + * @param type the type into that the "official type" evaluates during alias + * resolving. Initially equal to "official type". + */ + public DynAny create_dyn_any_from_type_code(TypeCode official, TypeCode type) + throws InconsistentTypeCode + { + DynAny d; + try + { + switch (type.kind().value()) + { + case TCKind._tk_array : + return create_array(official, type); + + case TCKind._tk_sequence : + return create_sequence(official, type); + + case TCKind._tk_struct : + case TCKind._tk_except : + return create_structure(official, type); + + case TCKind._tk_union : + return create_union(official, type); + + case TCKind._tk_value : + return create_value(official, type); + + case TCKind._tk_value_box : + return create_value_box(official, type); + + case TCKind._tk_enum : + return create_enumeration(official, type); + + case TCKind._tk_fixed : + return create_fixed(official, type); + + case TCKind._tk_alias : + return create_alias(official, type); + + case TCKind._tk_null : + return new gnuDynAny(null, official, type, this, orb); + + case TCKind._tk_TypeCode : + d = create_simple(official, type); + d.insert_typecode(orb.get_primitive_tc(TCKind.tk_null)); + return d; + + case TCKind._tk_any : + d = create_simple(official, type); + + Any empty_any = orb.create_any(); + empty_any.type(orb.get_primitive_tc(TCKind.tk_null)); + d.insert_any(empty_any); + return d; + + case TCKind._tk_wstring : + d = create_simple(official, type); + d.insert_wstring(""); + return d; + + case TCKind._tk_string : + d = create_simple(official, type); + d.insert_string(""); + return d; + + case TCKind._tk_native : + case TCKind._tk_Principal : + case TCKind._tk_abstract_interface : + throw new InconsistentTypeCode("Following API, the " + + TypeKindNamer.nameIt(type) + + " must not be supported." + ); + + default : + return create_simple(official, type); + } + } + catch (UserException uex) + { + InconsistentTypeCode it = new InconsistentTypeCode(); + it.initCause(uex); + throw it; + } + } + + /** + * Create the DynAny using the passed value as template and assign this value. + */ + public DynAny create_dyn_any(Any value) + throws InconsistentTypeCode + { + DynAny created = create_dyn_any_from_type_code(value.type()); + try + { + created.from_any(value); + } + catch (UserException uex) + { + InconsistentTypeCode t = new InconsistentTypeCode("Inconsistent Any"); + t.initCause(uex); + throw t; + } + catch (Exception e) + { + throw new Unexpected(e); + } + return created; + } +} diff --git a/libjava/classpath/gnu/CORBA/DynAn/gnuDynArray.java b/libjava/classpath/gnu/CORBA/DynAn/gnuDynArray.java new file mode 100644 index 000000000..5676c3d39 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/DynAn/gnuDynArray.java @@ -0,0 +1,337 @@ +/* gnuDynArray.java -- + 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.CORBA.DynAn; + +import gnu.CORBA.Unexpected; +import gnu.CORBA.HolderLocator; + +import org.omg.CORBA.Any; +import org.omg.CORBA.BAD_PARAM; +import org.omg.CORBA.ORB; +import org.omg.CORBA.TCKind; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.portable.Streamable; +import org.omg.DynamicAny.DynAny; +import org.omg.DynamicAny.DynAnyFactoryPackage.InconsistentTypeCode; +import org.omg.DynamicAny.DynAnyPackage.InvalidValue; +import org.omg.DynamicAny.DynAnyPackage.TypeMismatch; +import org.omg.DynamicAny.DynArray; + +import java.io.Serializable; + +import java.lang.reflect.Array; +import java.lang.reflect.Field; + +/** + * Provides support for dynamic array or sequence, where all members have the + * same final_type. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class gnuDynArray + extends DivideableAny + implements DynArray, Serializable +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * The component "official" type (may be alias). + */ + final TypeCode official_components; + + /** + * The component "final" type, after resolving any aliases. + */ + final TypeCode final_components; + + /** + * Creates new array. + * + * @param aType the final_type of array. + * @param aFactory the factory, used to initialise default values. + * @param orb the ORB to that this DynAny belongs. + * @param initialise_array if false, the array is not initialised in + * constructor. + * + * + * @throws BAD_PARAM if the passed typecode does not provide the length(). + */ + public gnuDynArray(TypeCode oType, TypeCode aType, gnuDynAnyFactory aFactory, + ORB anOrb, boolean initialise_array + ) + throws BAD_PARAM + { + super(oType, aType, aFactory, anOrb); + + try + { + official_components = final_type.content_type(); + + TypeCode component = official_components; + while (component.kind().value() == TCKind._tk_alias) + component = component.content_type(); + final_components = component; + + if (initialise_array) + { + array = new DynAny[ aType.length() ]; + for (int i = 0; i < array.length; i++) + { + array [ i ] = + factory.create_dyn_any_from_type_code(official_components); + } + } + } + catch (Exception e) + { + BAD_PARAM bad = new BAD_PARAM("Unable to initialise array"); + bad.initCause(e); + throw bad; + } + } + + /** + * Copy one DynAny into another. + */ + public void assign(DynAny from) + throws TypeMismatch + { + checkType(official_type, from.type()); + if (from instanceof DynArray && from.component_count() == array.length) + { + DynArray dyn = (DynArray) from; + array = dyn.get_elements_as_dyn_any(); + } + else + throw new TypeMismatch(); + } + + /** + * Create a copy. + */ + public DynAny copy() + { + DynAny[] c = new DynAny[ array.length ]; + for (int i = 0; i < c.length; i++) + { + c [ i ] = array [ i ].copy(); + } + + gnuDynArray d = + new gnuDynArray(official_type, final_type, factory, orb, false); + d.array = c; + return d; + } + + /** + * Get elements as array of anys. + */ + public Any[] get_elements() + { + Any[] r = new Any[ array.length ]; + for (int i = 0; i < r.length; i++) + r [ i ] = array [ i ].to_any(); + return r; + } + + /** {@inheritDoc} */ + public DynAny[] get_elements_as_dyn_any() + { + DynAny[] a = new DynAny[ array.length ]; + for (int i = 0; i < a.length; i++) + { + a [ i ] = array [ i ].copy(); + } + return a; + } + + /** + * Set elements when array of dyn anys is provided. This method can set nested + * data structures as an array components. + */ + public void set_elements_as_dyn_any(DynAny[] value) + throws InvalidValue, TypeMismatch + { + if (value.length != array.length) + throw new InvalidValue(sizeMismatch(array.length, value.length)); + for (int i = 0; i < value.length; i++) + { + checkType(official_components, value [ i ].type()); + array [ i ].assign(value [ i ]); + } + pos = 0; + valueChanged(); + } + + /** + * Set elements when array of ordinary anys is provided. + */ + public void set_elements(Any[] value) + throws InvalidValue, TypeMismatch + { + if (value.length != array.length) + throw new InvalidValue(sizeMismatch(array.length, value.length)); + + for (int i = 0; i < value.length; i++) + { + checkType(official_components, value [ i ].type()); + try + { + array [ i ] = factory.create_dyn_any(value [ i ]); + } + catch (InconsistentTypeCode e) + { + TypeMismatch t = new TypeMismatch(); + t.initCause(e); + throw t; + } + } + pos = 0; + valueChanged(); + } + + /** + * Done via reflection. + */ + public Any to_any() + { + try + { + Streamable memberHolder = + HolderLocator.createHolder(official_components); + + if (memberHolder == null) + memberHolder = HolderLocator.createHolder(final_components); + + Class memberHolderClass = memberHolder.getClass(); + Class memberClass = memberHolderClass.getField("value").getType(); + + Object members = Array.newInstance(memberClass, array.length); + Object member; + Any am; + Field value = memberHolder.getClass().getField("value"); + + for (int i = 0; i < array.length; i++) + { + // Recursive call should support multidimensional arrays. + am = array [ i ].to_any(); + memberHolder = am.extract_Streamable(); + member = value.get(memberHolder); + Array.set(members, i, member); + } + + Streamable arrayHolder = HolderLocator.createHolder(official_type); + arrayHolder.getClass().getField("value").set(arrayHolder, members); + + Any g = createAny(); + g.insert_Streamable(arrayHolder); + g.type(official_type); + return g; + } + catch (Exception e) + { + throw new Unexpected(e); + } + } + + /** + * Done via reflection. + */ + public void from_any(Any an_any) + throws TypeMismatch, InvalidValue + { + checkType(official_type, an_any.type()); + try + { + Streamable s = an_any.extract_Streamable(); + Object members = s.getClass().getField("value").get(s); + + checkArrayValid(members); + + Any member; + Streamable holder; + Class holderClass = null; + + for (int i = 0; i < array.length; i++) + { + if (holderClass == null) + { + holder = HolderLocator.createHolder(official_components); + if (holder == null) + holder = HolderLocator.createHolder(final_components); + holderClass = holder.getClass(); + } + else + holder = (Streamable) holderClass.newInstance(); + + member = createAny(); + holder.getClass().getField("value").set(holder, + Array.get(members, i) + ); + member.insert_Streamable(holder); + member.type(official_components); + + // This may lead to recursion, supporting multidimensional + // arrays. + array [ i ].from_any(member); + } + } + catch (Exception ex) + { + TypeMismatch t = new TypeMismatch(); + t.initCause(ex); + throw t; + } + valueChanged(); + } + + /** + * Check if array size is valid and (for sequences) resized + * if required. Called from from_any. + */ + protected void checkArrayValid(Object members) + throws TypeMismatch, InvalidValue + { + if (array.length != Array.getLength(members)) + throw new InvalidValue(sizeMismatch(array.length, Array.getLength(members))); + } +} diff --git a/libjava/classpath/gnu/CORBA/DynAn/gnuDynEnum.java b/libjava/classpath/gnu/CORBA/DynAn/gnuDynEnum.java new file mode 100644 index 000000000..76b0a9527 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/DynAn/gnuDynEnum.java @@ -0,0 +1,244 @@ +/* gnuDynEnum.java -- + 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.CORBA.DynAn; + +import gnu.CORBA.Unexpected; + +import org.omg.CORBA.Any; +import org.omg.CORBA.BAD_PARAM; +import org.omg.CORBA.MARSHAL; +import org.omg.CORBA.ORB; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.portable.InputStream; +import org.omg.DynamicAny.DynAny; +import org.omg.DynamicAny.DynAnyPackage.InvalidValue; +import org.omg.DynamicAny.DynAnyPackage.TypeMismatch; +import org.omg.DynamicAny.DynEnum; + +import java.io.IOException; + +import java.util.Arrays; + +/** + * Our implementation of dynamic enumeration. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class gnuDynEnum extends UndivideableAny implements DynEnum +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * The valid string values of the enumeration. Most of enumerations are short, + * counting 2-5 memebers. With so small number of memebers, it seems not + * reasonable to use hashtables. + */ + final String[] values; + + /** + * The current value of enum. + */ + int current; + + /** + * Create a new dyn enum from the given typecode. + */ + public gnuDynEnum(TypeCode oType, TypeCode aType, gnuDynAnyFactory aFactory, + ORB anOrb + ) + { + super(oType, aType, aFactory, anOrb); + try + { + values = new String[ final_type.member_count() ]; + + for (int i = 0; i < values.length; i++) + { + values [ i ] = final_type.member_name(i); + } + } + catch (Exception e) + { + throw new BAD_PARAM("Not enum"); + } + } + + /** + * Create a clone of the given enum, sharing values and final_type. + */ + public gnuDynEnum(gnuDynEnum from) + { + super(from.official_type, from.final_type, from.factory, from.orb); + values = from.values; + } + + /** + * Assign the Enum from the passed value. The passed DynAny must hold the + * enumeration of exactly the same final_type. + */ + public void assign(DynAny from) throws TypeMismatch + { + checkType(official_type, from.type()); + if (!(from instanceof DynEnum)) + throw new TypeMismatch("Not a DynEnum"); + try + { + set_as_ulong(((DynEnum) from).get_as_ulong()); + } + catch (InvalidValue e) + { + TypeMismatch t = new TypeMismatch(); + t.initCause(e); + throw t; + } + } + + /** + * Copy this DynEnum. + */ + public DynAny copy() + { + gnuDynEnum other = new gnuDynEnum(this); + other.current = current; + return other; + } + + /** + * Compares for equality. + */ + public boolean equal(DynAny other) + { + if (other instanceof gnuDynEnum) + { + gnuDynEnum oe = (gnuDynEnum) other; + return current == oe.current && + (oe.values == values || Arrays.equals(values, oe.values)); + } + else if (other instanceof DynEnum) + { + DynEnum oe = (DynEnum) other; + return current == oe.get_as_ulong() && official_type.equal(oe.type()); + } + else + return false; + } + + /** + * Set value from any that must contain enumeration. + */ + public void from_any(Any an_any) throws TypeMismatch, InvalidValue + { + checkType(official_type, an_any.type()); + try + { + InputStream in = an_any.create_input_stream(); + set_as_ulong(in.read_long()); + in.close(); + } + catch (MARSHAL eof) + { + throw new InvalidValue(); + } + catch (IOException ex) + { + throw new Unexpected(ex); + } + } + + /** + * Get the value of this enumeration as string. + */ + public String get_as_string() + { + return values [ current ]; + } + + /** + * Get the value of this enumeration as int. + */ + public int get_as_ulong() + { + return current; + } + + /** + * Set the value of this enumeration as string. + */ + public void set_as_string(String value) throws InvalidValue + { + for (int i = 0; i < values.length; i++) + { + if (values [ i ].equals(value)) + { + current = i; + valueChanged(); + return; + } + } + throw new InvalidValue(value); + } + + /** + * Set the value of this enumeration as int. + */ + public void set_as_ulong(int value) throws InvalidValue + { + if (value < 0 || value >= values.length) + throw new InvalidValue(value + " not in [0.." + values.length); + else + { + current = value; + valueChanged(); + } + } + + /** + * Wrap the enumeration value into any. + */ + public Any to_any() + { + Any a = createAny(); + a.insert_long(current); + a.type(official_type); + return a; + } +} diff --git a/libjava/classpath/gnu/CORBA/DynAn/gnuDynFixed.java b/libjava/classpath/gnu/CORBA/DynAn/gnuDynFixed.java new file mode 100644 index 000000000..9c7ea8252 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/DynAn/gnuDynFixed.java @@ -0,0 +1,252 @@ +/* gnuDynFixed.java -- + 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.CORBA.DynAn; + +import org.omg.CORBA.Any; +import org.omg.CORBA.BAD_OPERATION; +import org.omg.CORBA.BAD_PARAM; +import org.omg.CORBA.ORB; +import org.omg.CORBA.TypeCode; +import org.omg.DynamicAny.DynAny; +import org.omg.DynamicAny.DynAnyPackage.InvalidValue; +import org.omg.DynamicAny.DynAnyPackage.TypeMismatch; +import org.omg.DynamicAny.DynFixed; +import org.omg.DynamicAny.DynFixedOperations; + +import java.math.BigDecimal; + +/** + * Implements DynAny, holding CORBA fixed. This class is derived + * from gnuDynEnm to avoid repetetive inclusion of unused DynAny methods. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class gnuDynFixed extends UndivideableAny implements DynFixed +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * The default value, assigned in the new instance. + */ + static final BigDecimal ZERO = new BigDecimal("0.0"); + + /** + * The content of the dyn fixed, wrapped in this DynAny. + */ + BigDecimal value; + + /** + * The number of digits after the decimal point. + */ + final int scale; + + /** + * The number of digits. + */ + final int digits; + + /** + * Create a new instance of the dyn fixed. + */ + public gnuDynFixed(TypeCode oType, TypeCode aType, + gnuDynAnyFactory aFactory, ORB anOrb + ) + { + super(oType, aType, aFactory, anOrb); + try + { + digits = final_type.fixed_digits(); + scale = final_type.fixed_scale(); + } + catch (Exception e) + { + throw new BAD_PARAM("Not a fixed"); + } + value = ZERO; + } + + /** + * Clone the current instance. + */ + public gnuDynFixed(gnuDynFixed from) + { + super(from.official_type, from.final_type, from.factory, from.orb); + digits = from.digits; + scale = from.scale; + value = from.value; + } + + /** + * Get the value of the wrapped dyn fixed, as string. + */ + public String get_value() + { + return value.toString(); + } + + /** + * Set the value. + */ + public boolean set_value(String fixed_value) + throws TypeMismatch, InvalidValue + { + // Count the digits till decimal point. + int digs = 0; + char c; + boolean leading0 = true; + Digs: + for (int i = 0; i < fixed_value.length(); i++) + { + c = fixed_value.charAt(i); + if (Character.isDigit(c)) + { + if (!(c == '0' && leading0)) + digs++; + if (c != '0') + leading0 = false; + } + else if (c == '.') + break Digs; + } + if (digs > (digits - scale)) + throw new InvalidValue("Too many digits: " + digs + " for " + digits + + "." + scale + ); + + try + { + value = new BigDecimal(fixed_value); + } + catch (NumberFormatException ex) + { + if (fixed_value.trim().length() == 0) + throw new InvalidValue("Empty string passed"); + + TypeMismatch inva = + new TypeMismatch("Not a number: '" + fixed_value + "'"); + inva.initCause(ex); + throw inva; + } + + valueChanged(); + return value.scale() <= scale; + } + + /** + * Assign the value from another BigDecimal. + */ + public void assign(DynAny from) throws TypeMismatch + { + checkType(official_type, from.type()); + + if (from instanceof gnuDynFixed) + { + gnuDynFixed other = (gnuDynFixed) from; + value = other.value; + } + else if (from instanceof DynFixedOperations) + { + value = new BigDecimal(((DynFixedOperations) from).get_value()); + } + else + throw new TypeMismatch("Not a DynFixed"); + valueChanged(); + } + + /** + * Create a copy. + */ + public DynAny copy() + { + return new gnuDynFixed(this); + } + + /** + * Compare for equality. + */ + public boolean equal(DynAny other) + { + if (other instanceof gnuDynFixed) + { + // Normally, this code would be executed. + return value.equals(((gnuDynFixed) other).value); + } + if (other instanceof DynFixedOperations) + { + // This may be involved when mixing implementations. + return ((DynFixedOperations) other).get_value().equals(get_value()); + } + else + return false; + } + + /** + * Set the value from Any (must hold fixed with the matching + * typecode.). + */ + public void from_any(Any an_any) throws TypeMismatch, InvalidValue + { + try + { + checkType(official_type, an_any.type()); + + value = an_any.extract_fixed(); + valueChanged(); + } + catch (BAD_OPERATION e) + { + InvalidValue t = new InvalidValue(); + t.initCause(e); + throw t; + } + } + + /** + * Create and return Any, holding this DynFixed value. + */ + public Any to_any() + { + Any g = createAny(); + g.insert_fixed(value, official_type); + return g; + } +} diff --git a/libjava/classpath/gnu/CORBA/DynAn/gnuDynSequence.java b/libjava/classpath/gnu/CORBA/DynAn/gnuDynSequence.java new file mode 100644 index 000000000..d006c24a5 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/DynAn/gnuDynSequence.java @@ -0,0 +1,254 @@ +/* gnuDynSequence.java -- + 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.CORBA.DynAn; + +import gnu.CORBA.Unexpected; + +import org.omg.CORBA.Any; +import org.omg.CORBA.BAD_PARAM; +import org.omg.CORBA.ORB; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.TypeCodePackage.BadKind; +import org.omg.DynamicAny.DynAny; +import org.omg.DynamicAny.DynAnyFactoryPackage.InconsistentTypeCode; +import org.omg.DynamicAny.DynAnyPackage.InvalidValue; +import org.omg.DynamicAny.DynAnyPackage.TypeMismatch; +import org.omg.DynamicAny.DynSequence; + +import java.io.Serializable; + +import java.lang.reflect.*; + +public class gnuDynSequence + extends gnuDynArray + implements DynSequence, Serializable +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * The bound of the sequence, as defined in typecode. + */ + final int bound; + + /** + * Create a new gnuDynSequence with the given typecode. + * + * @throws BAD_PARAM if the passed typecode is probably not a sequence + * typecode. + */ + public gnuDynSequence(TypeCode oType, TypeCode aType, + gnuDynAnyFactory aFactory, ORB anOrb + ) + throws BAD_PARAM + { + super(oType, aType, aFactory, anOrb, false); + array = new DynAny[ 0 ]; + try + { + bound = final_type.length(); + } + catch (BadKind ex) + { + throw new Unexpected(ex); + } + } + + /** + * Get the length of the sequence. + */ + public int get_length() + { + return array.length; + } + + /** + * Resize the sequence, preserving components. + */ + public void set_length(int length) + throws InvalidValue + { + checkBound(length); + if (length == array.length) + return; // Nothing to do. + else if (length < array.length) + { + // Truncate. + DynAny[] d = new DynAny[ length ]; + for (int i = 0; i < d.length; i++) + d [ i ] = array [ i ]; + array = d; + } + else + { + // Expand. + DynAny[] d = new DynAny[ length ]; + for (int i = 0; i < array.length; i++) + d [ i ] = array [ i ]; + + for (int i = array.length; i < d.length; i++) + { + try + { + d [ i ] = + factory.create_dyn_any_from_type_code(official_components); + } + catch (InconsistentTypeCode e) + { + throw new Unexpected(e); + } + } + array = d; + } + valueChanged(); + } + + /** + * Copy one DynAny into another. + */ + public void assign(DynAny from) + throws TypeMismatch + { + checkType(official_type, from.type()); + if (from instanceof DynSequence) + { + DynSequence dyn = (DynSequence) from; + array = dyn.get_elements_as_dyn_any(); + } + else + throw new TypeMismatch(); + } + + /* + * Set the contenst of the sequence, resizing if required. + */ + public void set_elements_as_dyn_any(DynAny[] value) + throws InvalidValue, TypeMismatch + { + checkBound(value.length); + if (array.length != value.length) + set_length(value.length); + + for (int i = 0; i < value.length; i++) + { + checkType(official_components, value [ i ].type()); + array [ i ].assign(value [ i ]); + } + valueChanged(); + } + + /** + * Set the elements from array of Any's. + */ + public void set_elements(Any[] value) + throws InvalidValue, TypeMismatch + { + checkBound(value.length); + + DynAny[] prev = array; + + array = new DynAny[ value.length ]; + try + { + super.set_elements(value); + + // valueChanged() is called in super.set_elements(value). + } + + // On the problem, value does not change. + catch (TypeMismatch ex) + { + array = prev; + throw ex; + } + catch (InvalidValue ex) + { + array = prev; + throw ex; + } + catch (RuntimeException rex) + { + array = prev; + throw rex; + } + } + + /** + * Create a copy. + */ + public DynAny copy() + { + DynAny[] c = new DynAny[ array.length ]; + for (int i = 0; i < c.length; i++) + { + c [ i ] = array [ i ].copy(); + } + + gnuDynSequence d = + new gnuDynSequence(official_type, final_type, factory, orb); + d.array = c; + return d; + } + + /** + * Check the bound. + * + * @param x the value to check. + */ + void checkBound(int x) + throws InvalidValue + { + if (bound != 0) + if (x < 0 || x > bound) + throw new InvalidValue(x + " out of bounds, valid [0.." + bound + "]"); + } + + /** + * Check if array size is valid. Called from from_any. + */ + protected void checkArrayValid(Object members) + throws TypeMismatch, InvalidValue + { + checkBound(Array.getLength(members)); + if (get_length() != Array.getLength(members)) + set_length(Array.getLength(members)); + } +} diff --git a/libjava/classpath/gnu/CORBA/DynAn/gnuDynStruct.java b/libjava/classpath/gnu/CORBA/DynAn/gnuDynStruct.java new file mode 100644 index 000000000..b15aff3e1 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/DynAn/gnuDynStruct.java @@ -0,0 +1,109 @@ +/* gnuDynStruct.java -- + 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.CORBA.DynAn; + +import java.io.Serializable; + +import org.omg.CORBA.ORB; +import org.omg.CORBA.TypeCode; +import org.omg.DynamicAny.DynStruct; +import org.omg.DynamicAny.NameDynAnyPair; +import org.omg.DynamicAny.NameValuePair; +import gnu.CORBA.Unexpected; +import org.omg.DynamicAny.DynAny; + +/** + * Implementation of the DynStruct. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class gnuDynStruct + extends RecordAny + implements DynStruct, Serializable +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * Create an instance. + */ + public gnuDynStruct(TypeCode oType, TypeCode aType, + gnuDynAnyFactory aFactory, ORB anOrb) + { + super(oType, aType, aFactory, anOrb); + + // Initialise fields. + try + { + array = new DynAny[ final_type.member_count() ]; + fNames = new String[ array.length ]; + for (int i = 0; i < array.length; i++) + { + array [ i ] = + factory.create_dyn_any_from_type_code(final_type.member_type(i)); + fNames [ i ] = final_type.member_name(i); + } + } + catch (Exception e) + { + throw new Unexpected(e); + } + } + + /** @inheritDoc */ + protected RecordAny newInstance(TypeCode oType, TypeCode aType, + gnuDynAnyFactory aFactory, ORB anOrb) + { + return new gnuDynStruct(oType, aType, aFactory, anOrb); + } + + /** @inheritDoc */ + public NameDynAnyPair[] get_members_as_dyn_any() + { + return super.gnu_get_members_as_dyn_any(); + } + + /** @inheritDoc */ + public NameValuePair[] get_members() + { + return super.gnu_get_members(); + } +} diff --git a/libjava/classpath/gnu/CORBA/DynAn/gnuDynUnion.java b/libjava/classpath/gnu/CORBA/DynAn/gnuDynUnion.java new file mode 100644 index 000000000..adbc5731d --- /dev/null +++ b/libjava/classpath/gnu/CORBA/DynAn/gnuDynUnion.java @@ -0,0 +1,437 @@ +/* gnuDynUnion.java -- + 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.CORBA.DynAn; + +import gnu.CORBA.Unexpected; + +import org.omg.CORBA.Any; +import org.omg.CORBA.MARSHAL; +import org.omg.CORBA.ORB; +import org.omg.CORBA.TCKind; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.TypeCodePackage.BadKind; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.OutputStream; +import org.omg.DynamicAny.DynAny; +import org.omg.DynamicAny.DynAnyFactoryPackage.InconsistentTypeCode; +import org.omg.DynamicAny.DynAnyPackage.InvalidValue; +import org.omg.DynamicAny.DynAnyPackage.TypeMismatch; +import org.omg.DynamicAny.DynUnion; + +import java.io.Serializable; + +/** + * Implementation of DynUnion. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class gnuDynUnion + extends DivideableAny + implements DynUnion, Serializable, ValueChangeListener +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * The discrimintor of this union. + */ + DynAny discriminator; + + /** + * The message string that occurs several times throwing exception. + */ + static String NOAM = "No active member"; + + /** + * Create a new instance with the given typecode. + * + * @param aType the final_type, must be final_type of the union. + */ + public gnuDynUnion(TypeCode oType, TypeCode aType, gnuDynAnyFactory aFactory, + ORB anOrb + ) + throws InconsistentTypeCode + { + super(oType, aType, aFactory, anOrb); + try + { + discriminator = + factory.create_dyn_any_from_type_code(final_type.discriminator_type()); + + ((AbstractAny) discriminator).listener = this; + + if (final_type.default_index() >= 0) + set_to_default_member(); + else + set_to_no_active_member(); + } + catch (Exception ex) + { + InconsistentTypeCode inc = new InconsistentTypeCode("discriminator"); + inc.initCause(ex); + throw inc; + } + } + + /* + * (non-Javadoc) + * + * @see gnu.CORBA.DynAn.DivideableAny#to_any() + */ + public Any to_any() + { + Any a = createAny(); + OutputStream ou = a.create_output_stream(); + discriminator.to_any().write_value(ou); + if (array.length == 2) + array [ 1 ].to_any().write_value(ou); + a.read_value(ou.create_input_stream(), final_type); + return a; + } + + /** + * Assign from another identical structure. + */ + public void assign(DynAny from) + throws TypeMismatch + { + checkType(official_type, from.type()); + if (!(from instanceof DynUnion)) + throw new TypeMismatch("DynUnion required"); + else + { + try + { + DynUnion u = (DynUnion) from; + discriminator.assign(u.get_discriminator()); + if (u.has_no_active_member()) + { + if (array.length != 1) + array = new DynAny[] { discriminator }; + } + else + { + if (array.length != 2) + array = new DynAny[] { discriminator, u.member().copy() }; + else + array [ 1 ] = u.member().copy(); + } + } + catch (InvalidValue e) + { + throw new Unexpected(e); + } + } + valueChanged(); + } + + /** @inheritDoc */ + public DynAny copy() + { + try + { + gnuDynUnion other = + new gnuDynUnion(official_type, final_type, factory, orb); + other.discriminator = discriminator.copy(); + ((AbstractAny) other.discriminator).listener = other; + if (array.length == 1) + { + other.array = new DynAny[] { other.discriminator }; + } + else + { + other.array = + new DynAny[] { other.discriminator, array [ 1 ].copy() }; + } + return other; + } + catch (InconsistentTypeCode ex) + { + throw new Unexpected(ex); + } + } + + /** + * Done via reading from stream. + */ + public void from_any(Any an_any) + throws TypeMismatch, InvalidValue + { + checkType(official_type, an_any.type()); + + Any adis = createAny(); + try + { + InputStream stream = an_any.create_input_stream(); + adis.read_value(stream, final_type.discriminator_type()); + + DynAny nd = factory.create_dyn_any(adis); + + set_discriminator(nd); + if (array.length == 2) + { + // Reusing the same Any adis. + adis.read_value(stream, array [ 1 ].type()); + array [ 1 ].from_any(adis); + } + } + catch (InconsistentTypeCode it) + { + TypeMismatch t = new TypeMismatch(); + t.initCause(it); + throw t; + } + catch (MARSHAL m) + { + InvalidValue t = new InvalidValue(); + t.initCause(m); + throw t; + } + catch (BadKind b) + { + throw new Unexpected(b); + } + valueChanged(); + } + + /** @inheritDoc */ + public TCKind discriminator_kind() + { + return discriminator.type().kind(); + } + + /** @inheritDoc */ + public DynAny get_discriminator() + { + return discriminator; + } + + /** @inheritDoc */ + public boolean has_no_active_member() + { + return array.length == 1; + } + + /** @inheritDoc */ + public TCKind member_kind() + throws InvalidValue + { + return member().type().kind(); + } + + /** + * Get the name of the current variant of the union. + */ + public String member_name() + throws InvalidValue + { + if (array.length == 1) + throw new InvalidValue(NOAM); + try + { + Any da = discriminator.to_any(); + + + // Get the discriminator variant. + for (int i = 0; i < final_type.member_count(); i++) + { + if (final_type.member_label(i).equal(da)) + return final_type.member_name(i); + } + throw new InvalidValue(NOAM); + } + catch (Exception e) + { + InvalidValue t = new InvalidValue("Err"); + t.initCause(e); + throw t; + } + } + + /** @inheritDoc */ + public DynAny member() + throws InvalidValue + { + if (array.length < 2) + throw new InvalidValue(NOAM); + else + return array [ 1 ]; + } + + /** + * Set the union discriminator. + */ + public void set_discriminator(DynAny aDiscriminator) + throws TypeMismatch + { + try + { + if (!aDiscriminator.type().equal(final_type.discriminator_type())) + throw new TypeMismatch("Wrong discriminator final_type for " + + final_type.name() + ); + + // Seting the same discriminator value again should not change + // the fields of the current member. + if (!discriminator.equal(aDiscriminator)) + { + discriminator.assign(aDiscriminator); + updateMember(); + } + else + { + pos = array.length == 2 ? 1 : 0; + } + } + catch (Exception e) + { + TypeMismatch t = new TypeMismatch(); + t.initCause(e); + throw t; + } + } + + /** + * Set to default member, if one exists. + */ + public void set_to_default_member() + throws TypeMismatch + { + try + { + int di = final_type.default_index(); + if (di < 0) + throw new TypeMismatch("Union " + final_type.name() + + "has no default index" + ); + + Any da = final_type.member_label(di); + discriminator.from_any(da); + updateMember(); + } + catch (TypeMismatch m) + { + // This one OK. + throw m; + } + catch (Exception e) + { + TypeMismatch t = new TypeMismatch(); + t.initCause(e); + throw t; + } + } + + /** @inheritDoc */ + public void set_to_no_active_member() + throws TypeMismatch + { + try + { + if (final_type.default_index() >= 0) + { + throw new TypeMismatch("Explicit default case defined."); + } + } + catch (BadKind ex) + { + // The default index is not set. + } + array = new DynAny[] { discriminator }; + valueChanged(); + } + + /** + * Update member, in accordance with discriminator value. + */ + public void updateMember() + throws TypeMismatch + { + try + { + Any da = discriminator.to_any(); + + + // Get the discriminator variant. + for (int i = 0; i < final_type.member_count(); i++) + { + if (final_type.member_label(i).equal(da)) + { + array = + new DynAny[] + { + discriminator, + factory.create_dyn_any_from_type_code(final_type.member_type(i)) + }; + pos = 1; + valueChanged(); + return; + } + } + } + catch (Exception e) + { + TypeMismatch t = new TypeMismatch(); + t.initCause(e); + throw t; + } + + // Discrimintator does not point to valid member. + array = new DynAny[] { discriminator }; + pos = 0; + valueChanged(); + } + + /** + * Called when the discriminator is changed. + */ + public void changed() + { + try + { + updateMember(); + } + catch (TypeMismatch ex) + { + throw new Unexpected(ex); + } + } +} diff --git a/libjava/classpath/gnu/CORBA/DynAn/gnuDynValue.java b/libjava/classpath/gnu/CORBA/DynAn/gnuDynValue.java new file mode 100644 index 000000000..32b2f0d1a --- /dev/null +++ b/libjava/classpath/gnu/CORBA/DynAn/gnuDynValue.java @@ -0,0 +1,380 @@ +/* gnuDynValue.java -- + 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.CORBA.DynAn; + +import gnu.CORBA.Minor; +import gnu.CORBA.Unexpected; + +import org.omg.CORBA.Any; +import org.omg.CORBA.BAD_PARAM; +import org.omg.CORBA.MARSHAL; +import org.omg.CORBA.ORB; +import org.omg.CORBA.TCKind; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.VM_TRUNCATABLE; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.ValueFactory; +import org.omg.DynamicAny.DynAny; +import org.omg.DynamicAny.DynAnyPackage.InvalidValue; +import org.omg.DynamicAny.DynAnyPackage.TypeMismatch; +import org.omg.DynamicAny.DynStruct; +import org.omg.DynamicAny.DynValue; +import org.omg.DynamicAny.DynValueCommon; +import org.omg.DynamicAny.DynValueOperations; +import org.omg.DynamicAny.NameDynAnyPair; +import org.omg.DynamicAny.NameValuePair; + +import java.io.Serializable; + +/** + * Implementation of DynValue. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class gnuDynValue extends RecordAny implements DynValue, + Serializable +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * If true, the value of this ValueType is set to null. + */ + boolean isNull; + + /** + * Create an instance. + */ + public gnuDynValue(TypeCode oType, TypeCode aType, + gnuDynAnyFactory aFactory, ORB anOrb + ) + { + super(oType, aType, aFactory, anOrb); + + // Initialise fields. The array of fields also includes all inherited + // fields. + try + { + array = new DynAny[ final_type.member_count() ]; + fNames = new String[ array.length ]; + for (int i = 0; i < array.length; i++) + { + array [ i ] = + factory.create_dyn_any_from_type_code(final_type.member_type(i)); + fNames [ i ] = final_type.member_name(i); + } + + // Search of inherited members. + if (final_type.type_modifier() == VM_TRUNCATABLE.value) + { + TypeCode parent = final_type.concrete_base_type(); + DynAny ancestor = factory.create_dyn_any_from_type_code(parent); + + if (ancestor instanceof DynValue) + { + // Add members of ancestor in front of the curren members. + DynValue anc = (DynValue) ancestor; + anc.set_to_value(); + + NameDynAnyPair[] aar = anc.get_members_as_dyn_any(); + inheritFields(aar); + } + else if (ancestor instanceof DynStruct) + { + // Add members of ancestor in front of the curren members. + DynStruct anc = (DynStruct) ancestor; + NameDynAnyPair[] aar = anc.get_members_as_dyn_any(); + inheritFields(aar); + } + else + throw new BAD_PARAM("The parent of " + final_type.id() + ", " + + parent.id() + ", is not structure nor value." + ); + } + } + catch (Exception e) + { + throw new Unexpected(e); + } + + set_to_null(); + } + + /** + * Inherit the provided fields. + */ + private void inheritFields(NameDynAnyPair[] aar) + { + DynAny[] nArray = new DynAny[ array.length + aar.length ]; + String[] nNames = new String[ array.length + aar.length ]; + int p = 0; + for (int i = 0; i < aar.length; i++) + { + nArray [ p ] = aar [ i ].value; + nNames [ p ] = aar [ i ].id; + p++; + } + + for (int i = 0; i < array.length; i++) + { + nArray [ p ] = array [ i ]; + nNames [ p ] = fNames [ i ]; + p++; + } + + array = nArray; + fNames = nNames; + } + + /** @inheritDoc */ + public TCKind current_member_kind() throws TypeMismatch, InvalidValue + { + if (isNull) + throw new TypeMismatch(ISNULL); + else + return super.current_member_kind(); + } + + /** @inheritDoc */ + public String current_member_name() throws TypeMismatch, InvalidValue + { + if (isNull) + throw new TypeMismatch(ISNULL); + else + return super.current_member_name(); + } + + /** @inheritDoc */ + public NameDynAnyPair[] get_members_as_dyn_any() throws InvalidValue + { + if (isNull) + throw new InvalidValue(ISNULL); + return super.gnu_get_members_as_dyn_any(); + } + + /** @inheritDoc */ + public NameValuePair[] get_members() throws InvalidValue + { + if (isNull) + throw new InvalidValue(ISNULL); + else + return super.gnu_get_members(); + } + + /** @inheritDoc */ + public void set_members_as_dyn_any(NameDynAnyPair[] value) + throws TypeMismatch, InvalidValue + { + super.set_members_as_dyn_any(value); + isNull = false; + } + + /** @inheritDoc */ + public void set_members(NameValuePair[] value) + throws TypeMismatch, InvalidValue + { + super.set_members(value); + isNull = false; + } + + /** @inheritDoc */ + public boolean is_null() + { + return isNull; + } + + /** @inheritDoc */ + public void set_to_null() + { + isNull = true; + valueChanged(); + } + + /** @inheritDoc */ + public void set_to_value() + { + isNull = false; + valueChanged(); + } + + /** + * Create a new instance. + */ + protected RecordAny newInstance(TypeCode oType, TypeCode aType, + gnuDynAnyFactory aFactory, ORB anOrb + ) + { + gnuDynValue v = new gnuDynValue(oType, aType, aFactory, anOrb); + if (isNull) + v.set_to_null(); + else + v.set_to_value(); + return v; + } + + /** + * Compare for equality, minding null values. + */ + public boolean equal(DynAny other) + { + if (other instanceof DynValueOperations) + { + DynValueCommon o = (DynValueCommon) other; + if (isNull) + return o.is_null() && o.type().equal(official_type); + else + return !o.is_null() && super.equal(other); + } + else + return false; + } + + /** + * Get the focused component, throwing exception if the current value is null. + */ + protected DynAny focused() throws InvalidValue, TypeMismatch + { + if (isNull) + throw new TypeMismatch(ISNULL); + else + return super.focused(); + } + + /** + * Convert into Any. + */ + public Any to_any() + { + if (isNull) + { + Any a0 = createAny(); + a0.type(orb.get_primitive_tc(TCKind.tk_null)); + return a0; + } + else + { + try + { + ValueFactory factory = + ((org.omg.CORBA_2_3.ORB) orb).lookup_value_factory(official_type.id()); + if (factory == null) + { + MARSHAL m = new MARSHAL("Factory for " + official_type.id() + + " not registered."); + m.minor = Minor.Factory; + throw m; + } + + OutputStream out = orb.create_output_stream(); + + for (int i = 0; i < array.length; i++) + array [ i ].to_any().write_value(out); + + org.omg.CORBA_2_3.portable.InputStream in = + (org.omg.CORBA_2_3.portable.InputStream) out.create_input_stream(); + Serializable v = factory.read_value(in); + + Any g = createAny(); + g.type(official_type); + g.insert_Value(v, official_type); + + return g; + } + catch (Exception e) + { + throw new Unexpected(e); + } + } + } + + /** @inheritDoc */ + public void assign(DynAny from) throws TypeMismatch + { + checkType(official_type, from.type()); + + if (from instanceof DynValue) + { + DynValue other = (DynValue) from; + if (other.is_null()) + set_to_null(); + else + { + set_to_value(); + try + { + DynValueOperations src = (DynValueOperations) from; + set_members_as_dyn_any(src.get_members_as_dyn_any()); + } + catch (InvalidValue e) + { + TypeMismatch t = new TypeMismatch("Invalid value"); + t.initCause(e); + throw t; + } + } + } + else + throw new TypeMismatch("Not a DynValue"); + } + + /** + * Get the number of components. + */ + public int component_count() + { + return isNull ? 0 : super.component_count(); + } + + /** {@inheritDoc} */ + public Serializable get_val() throws TypeMismatch, InvalidValue + { + return to_any().extract_Value(); + } + + /** {@inheritDoc} */ + public void insert_val(Serializable a_x) throws InvalidValue, TypeMismatch + { + Any a = to_any(); + a.insert_Value(a_x); + from_any(a); + valueChanged(); + } +} diff --git a/libjava/classpath/gnu/CORBA/DynAn/gnuDynValueBox.java b/libjava/classpath/gnu/CORBA/DynAn/gnuDynValueBox.java new file mode 100644 index 000000000..9c50534ed --- /dev/null +++ b/libjava/classpath/gnu/CORBA/DynAn/gnuDynValueBox.java @@ -0,0 +1,389 @@ +/* gnuDynValueBox.java -- + 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.CORBA.DynAn; + +import gnu.CORBA.Unexpected; +import gnu.CORBA.HolderLocator; + +import org.omg.CORBA.Any; +import org.omg.CORBA.ORB; +import org.omg.CORBA.TCKind; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.TypeCodePackage.BadKind; +import org.omg.CORBA.portable.Streamable; +import org.omg.DynamicAny.DynAny; +import org.omg.DynamicAny.DynAnyFactoryPackage.InconsistentTypeCode; +import org.omg.DynamicAny.DynAnyPackage.InvalidValue; +import org.omg.DynamicAny.DynAnyPackage.TypeMismatch; +import org.omg.DynamicAny.DynValueBox; +import org.omg.DynamicAny.DynValueBoxOperations; +import org.omg.DynamicAny.DynValueCommon; + +import java.io.Serializable; + +import java.lang.reflect.Field; + +/** + * Implementation of the DynValueBox. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class gnuDynValueBox + extends DivideableAny + implements DynValueBox, Serializable +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * The final_type of contents of this value box. + */ + final TypeCode content; + + /** + * The string for some TypeMismatch exceptions. + */ + String CONTENT = "Box content final_type mismatch"; + + /** + * Create a new instance of gnuDynValueBox. + */ + public gnuDynValueBox(TypeCode oType, TypeCode aType, + gnuDynAnyFactory aFactory, ORB anOrb + ) + { + super(oType, aType, aFactory, anOrb); + try + { + content = final_type.content_type(); + array = new DynAny[] { factory.create_dyn_any_from_type_code(content) }; + set_to_null(); + } + catch (Exception e) + { + throw new Unexpected(e); + } + } + + /** @inheritDoc */ + public void assign(DynAny from) + throws TypeMismatch + { + checkType(official_type, from.type()); + if (from instanceof DynValueBoxOperations) + { + DynValueBoxOperations other = (DynValueBoxOperations) from; + if (other.is_null()) + set_to_null(); + else + { + DynAny inBox; + try + { + inBox = other.get_boxed_value_as_dyn_any(); + } + catch (InvalidValue e) + { + TypeMismatch t = new TypeMismatch("Invalid value"); + t.initCause(e); + throw t; + } + if (!content.equal(inBox.type())) + throw new TypeMismatch(CONTENT); + array = new DynAny[] { inBox.copy() }; + } + } + valueChanged(); + } + + /** @inheritDoc */ + public DynAny copy() + { + gnuDynValueBox other = + new gnuDynValueBox(official_type, final_type, factory, orb); + if (is_null()) + other.set_to_null(); + else + { + try + { + other.array = new DynAny[] { array [ 0 ].copy() }; + } + catch (Exception e) + { + throw new Unexpected(e); + } + } + return other; + } + + /** + * Returns null for null value, delegates to super. otherwise. + */ + public DynAny current_component() + throws TypeMismatch + { + if (is_null()) + return null; + else + return super.current_component(); + } + + /** + * Compare for equality, minding null values. + */ + public boolean equal(DynAny other) + { + if (other instanceof DynValueCommon) + { + DynValueCommon o = (DynValueCommon) other; + if (is_null()) + return o.is_null() && o.type().equal(official_type); + else + return !o.is_null() && super.equal(other); + } + else + return false; + } + + /** @inheritDoc */ + public void from_any(Any an_any) + throws TypeMismatch, InvalidValue + { + checkType(official_type, an_any.type()); + try + { + if (!an_any.type().content_type().equal(content)) + throw new InvalidValue(CONTENT); + } + catch (BadKind e) + { + TypeMismatch t = new TypeMismatch("Not a box"); + t.initCause(e); + throw t; + } + + Serializable s = an_any.extract_Value(); + if (s == null) + set_to_null(); + else + { + try + { + Streamable holder = HolderLocator.createHolder(content); + Field v = holder.getClass().getField("value"); + v.set(holder, s); + + Any cont = createAny(); + cont.insert_Streamable(holder); + + array = new DynAny[] { factory.create_dyn_any(cont) }; + } + catch (Exception ex) + { + throw new Unexpected(ex); + } + } + valueChanged(); + } + + /** @inheritDoc */ + public Any get_boxed_value() + throws InvalidValue + { + try + { + if (is_null()) + throw new InvalidValue(ISNULL); + else + return array [ 0 ].to_any(); + } + catch (Exception e) + { + InvalidValue t = new InvalidValue(); + t.initCause(e); + throw t; + } + } + + /** @inheritDoc */ + public DynAny get_boxed_value_as_dyn_any() + throws InvalidValue + { + if (is_null()) + throw new InvalidValue(ISNULL); + else + return array [ 0 ].copy(); + } + + /** {@inheritDoc} */ + public Serializable get_val() + throws TypeMismatch, InvalidValue + { + return to_any().extract_Value(); + } + + /** {@inheritDoc} */ + public void insert_val(Serializable a_x) + throws InvalidValue, TypeMismatch + { + Any a = to_any(); + a.insert_Value(a_x); + from_any(a); + valueChanged(); + } + + /** @inheritDoc */ + public boolean is_null() + { + return array.length == 0; + } + + /** @inheritDoc */ + public void set_boxed_value(Any boxIt) + throws TypeMismatch + { + if (!content.equal(boxIt.type())) + throw new TypeMismatch(CONTENT); + try + { + if (is_null()) + { + array = new DynAny[] { factory.create_dyn_any(boxIt) }; + } + else + { + array [ 0 ].from_any(boxIt); + } + } + catch (Exception e) + { + TypeMismatch t = new TypeMismatch(); + t.initCause(e); + throw t; + } + valueChanged(); + } + + /** @inheritDoc */ + public void set_boxed_value_as_dyn_any(DynAny boxIt) + throws TypeMismatch + { + if (!content.equal(boxIt.type())) + throw new TypeMismatch(CONTENT); + try + { + if (is_null()) + { + array = new DynAny[] { boxIt.copy() }; + } + else + { + array [ 0 ].assign(boxIt); + } + } + catch (Exception e) + { + TypeMismatch t = new TypeMismatch(); + t.initCause(e); + throw t; + } + valueChanged(); + } + + /** @inheritDoc */ + public void set_to_null() + { + array = new DynAny[ 0 ]; + valueChanged(); + } + + /** @inheritDoc */ + public void set_to_value() + { + try + { + if (array.length == 0) + { + array = + new DynAny[] { factory.create_dyn_any_from_type_code(content) }; + } + } + catch (InconsistentTypeCode e) + { + throw new Unexpected(e); + } + valueChanged(); + } + + /** @inheritDoc */ + public Any to_any() + { + Any a = createAny(); + + if (!is_null()) + { + try + { + Streamable holder; + if (array [ 0 ] instanceof gnuDynAny) + holder = ((gnuDynAny) array [ 0 ]).holder; + else + { + Any uan = array [ 0 ].to_any(); + holder = uan.extract_Streamable(); + } + + Field v = holder.getClass().getField("value"); + Serializable value = (Serializable) v.get(holder); + a.type(official_type); + a.insert_Value(value, content); + } + catch (Exception ex) + { + throw new Unexpected(ex); + } + } + else + a.type(orb.get_primitive_tc(TCKind.tk_null)); + return a; + } +} diff --git a/libjava/classpath/gnu/CORBA/DynAnySeqHolder.java b/libjava/classpath/gnu/CORBA/DynAnySeqHolder.java new file mode 100644 index 000000000..4447aa685 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/DynAnySeqHolder.java @@ -0,0 +1,116 @@ +/* DynAnySeqHolder.java -- + 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.CORBA; + +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.Streamable; +import org.omg.DynamicAny.DynAny; +import org.omg.DynamicAny.DynAnySeqHelper; + +/** + * A holder for the sequence of {@link DynAny} + * ({@link DynAnySeq}). + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class DynAnySeqHolder + implements Streamable +{ + /** + * The stored array of DynAny. + */ + public DynAny[] value; + + /** + * Create the unitialised instance, leaving the value array + * with default null value. + */ + public DynAnySeqHolder() + { + } + + /** + * Create the initialised instance. + * @param initialValue the array that will be assigned to + * the value array. + */ + public DynAnySeqHolder(DynAny[] initialValue) + { + value = initialValue; + } + + /** + * The method should read this object from the CDR input stream, but + * (following the JDK 1.5 API) it does not. + * + * @param input a org.omg.CORBA.portable stream to read from. + * + * @specenote Sun throws the same exception. + * + * @throws MARSHAL always. + */ + public void _read(InputStream input) + { + value = DynAnySeqHelper.read(input); + } + + /** + * The method should write this object to the CDR input stream, but + * (following the JDK 1.5 API) it does not. + * + * @param input a org.omg.CORBA.portable stream to read from. + * + * @specenote Sun throws the same exception. + * + * @throws MARSHAL always. + */ + public void _write(OutputStream output) + { + DynAnySeqHelper.write(output, value); + } + + /** + * Get the typecode of the DynAny. + */ + public org.omg.CORBA.TypeCode _type() + { + return DynAnySeqHelper.type(); + } +} diff --git a/libjava/classpath/gnu/CORBA/EmptyExceptionHolder.java b/libjava/classpath/gnu/CORBA/EmptyExceptionHolder.java new file mode 100644 index 000000000..a48b60562 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/EmptyExceptionHolder.java @@ -0,0 +1,131 @@ +/* EmptyStructHolder.java -- + 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.CORBA; + +import org.omg.CORBA.BAD_OPERATION; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.UNKNOWN; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.Streamable; + +/** + * This holder can store any CORBA exception that has no user defined fields. + * Only the repository ID is written when the method {@link #_write} is called. + * The _read method is not supported for this holder. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class EmptyExceptionHolder + implements Streamable +{ + /** + * The wrapped exception. + */ + public Throwable value; + + /** + * The typecode of the wrapped exception. + */ + public TypeCode typecode; + + /** + * Create the exception holder, initialised to the given values. + * + * @param an_exception the wrapped exception. + * @param an_id the exception repository id. + */ + public EmptyExceptionHolder(Throwable an_exception, TypeCode a_typecode) + { + value = an_exception; + typecode = a_typecode; + } + + /** + * Reads the exception from the input stream. + * + * The value field obtains the value of either the read exception or + * the UNKNOWN if the repository ID does not match + * the exception from the reachable code. + */ + public void _read(InputStream input) + { + String id = input.read_string(); + Object ex = ObjectCreator.Idl2Object(id); + if (ex == null) + value = new UNKNOWN(id); + else + value = (Throwable) ex; + } + + /** + * Return the typecode of the stored exception. + * + * @return the value, passed as a_typecode in constructor. + */ + public TypeCode _type() + { + return typecode; + } + + /** + * Write the exception into the give output stream. Writes the + * repository id that is taken from the typecode. This method also + * works when no helper class is available. + * + * @param output a stream to write into. + * + * @throws BAD_OPERATION if the value for the holder is not set or + * the typecode cannot provide repository id. + */ + public void _write(OutputStream output) + { + try + { + output.write_string(typecode.id()); + } + catch (Exception ex) + { + BAD_OPERATION bad = new BAD_OPERATION(); + bad.minor = Minor.CDR; + bad.initCause(ex); + throw bad; + } + } +} diff --git a/libjava/classpath/gnu/CORBA/ForwardRequestHelper.java b/libjava/classpath/gnu/CORBA/ForwardRequestHelper.java new file mode 100644 index 000000000..320b6d232 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/ForwardRequestHelper.java @@ -0,0 +1,152 @@ +/* ForwardRequestHelper.java -- + 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.CORBA; + +import gnu.CORBA.Poa.ForwardRequestHolder; + +import org.omg.CORBA.Any; +import org.omg.CORBA.BAD_OPERATION; +import org.omg.CORBA.ORB; +import org.omg.CORBA.ObjectHelper; +import org.omg.CORBA.StructMember; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.OutputStream; +import org.omg.PortableServer.ForwardRequest; + +/** + * The helper operations for the exception {@link ForwardRequest}. + * + * @specnote The helper must be here and not in POA subpackage as it must + * be discovered by the {@link ObjectCreator} when reading this remote + * exception. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public abstract class ForwardRequestHelper +{ + /** + * Extract the ForwardRequest from given Any. + * This method uses the ForwardRequestHolder. + * + * @throws BAD_OPERATION if the passed Any does not contain ForwardRequest. + */ + public static ForwardRequest extract(Any any) + { + try + { + return ((ForwardRequestHolder) any.extract_Streamable()).value; + } + catch (ClassCastException cex) + { + BAD_OPERATION bad = new BAD_OPERATION("ForwardRequest expected"); + bad.minor = Minor.Any; + bad.initCause(cex); + throw bad; + } + } + + /** + * Get the ForwardRequest repository id. + * + * @return "ForwardRequest", always. + */ + public static String id() + { + return "ForwardRequest"; + } + + /** + * Insert the ForwardRequest into the given Any. + * This method uses the ForwardRequestHolder. + * + * @param any the Any to insert into. + * @param that the ForwardRequest to insert. + */ + public static void insert(Any any, ForwardRequest that) + { + any.insert_Streamable(new ForwardRequestHolder(that)); + } + + /** + * Read the exception from the CDR intput stream. + * + * @param input a org.omg.CORBA.portable stream to read from. + */ + public static ForwardRequest read(InputStream input) + { + // Read the exception repository id. + String id = input.read_string(); + ForwardRequest value = new ForwardRequest(); + + value.forward_reference = input.read_Object(); + return value; + } + + /** + * Create the ForwardRequest typecode (structure, + * named "ForwardRequest"). + * The typecode states that the structure contains the + * following fields: forward_reference. + */ + public static TypeCode type() + { + ORB orb = OrbRestricted.Singleton; + StructMember[] members = new StructMember[ 1 ]; + + TypeCode field; + + field = ObjectHelper.type(); + members [ 0 ] = new StructMember("forward_reference", field, null); + return orb.create_exception_tc(id(), "ForwardRequest", members); + } + + /** + * Write the exception to the CDR output stream. + * + * @param output a org.omg.CORBA.portable stream stream to write into. + * @param value a value to write. + */ + public static void write(OutputStream output, ForwardRequest value) + { + // Write the exception repository id. + output.write_string(id()); + output.write_Object(value.forward_reference); + } +} diff --git a/libjava/classpath/gnu/CORBA/GIOP/CancelHeader.java b/libjava/classpath/gnu/CORBA/GIOP/CancelHeader.java new file mode 100644 index 000000000..40f373721 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/GIOP/CancelHeader.java @@ -0,0 +1,70 @@ +/* CancelHeader.java -- + 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.CORBA.GIOP; + +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.OutputStream; + +/** + * The message header for cancelling the request. + * + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public abstract class CancelHeader +{ + /** + * The Id of request being cancelled. + */ + public int request_id; + + /** + * Read the header. + * + * @param input a stream to read from. + */ + public abstract void read(InputStream input); + + /** + * Write the header. + * + * @param output a stream to write to. + */ + public abstract void write(OutputStream output); +} diff --git a/libjava/classpath/gnu/CORBA/GIOP/CharSets_OSF.java b/libjava/classpath/gnu/CORBA/GIOP/CharSets_OSF.java new file mode 100644 index 000000000..6cefe995f --- /dev/null +++ b/libjava/classpath/gnu/CORBA/GIOP/CharSets_OSF.java @@ -0,0 +1,238 @@ +/* CharSets_OSF.java -- + 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.CORBA.GIOP; + +import java.nio.charset.Charset; + +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Set; + +/** + * This class contains the codes, used to identify character sets + * in CORBA. These codes are defined in Open Software Foundation (OSF) + * code set registry. + * + * The name of this class specially sets "OSF" apart if somebody would start + * searching Open Software Foundation abbreviation. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class CharSets_OSF +{ + public static final int ASCII = 0x00010020; + public static final int ISO8859_1 = 0x00010001; + public static final int ISO8859_2 = 0x00010002; + public static final int ISO8859_3 = 0x00010003; + public static final int ISO8859_4 = 0x00010004; + public static final int ISO8859_5 = 0x00010005; + public static final int ISO8859_6 = 0x00010006; + public static final int ISO8859_7 = 0x00010007; + public static final int ISO8859_8 = 0x00010008; + public static final int ISO8859_9 = 0x00010009; + public static final int ISO8859_15_FDIS = 0x0001000F; + public static final int UTF8 = 0x05010001; + public static final int UTF16 = 0x00010109; + public static final int UCS2 = 0x00010100; + public static final int Cp1047 = 0x10020417; + public static final int Cp1250 = 0x100204E2; + public static final int Cp1251 = 0x100204E3; + public static final int Cp1252 = 0x100204E4; + public static final int Cp1253 = 0x100204E5; + public static final int Cp1254 = 0x100204E6; + public static final int Cp1255 = 0x100204E7; + public static final int Cp1256 = 0x100204E8; + public static final int Cp1257 = 0x100204E9; + public static final int Cp1363 = 0x10020553; + public static final int Cp1363C = 0x10020553; + public static final int Cp1381 = 0x10020565; + public static final int Cp1383 = 0x10020567; + public static final int Cp1386 = 0x1002056A; + public static final int Cp33722 = 0x100283BA; + public static final int Cp33722C = 0x100283BA; + public static final int Cp930 = 0x100203A2; + public static final int Cp943 = 0x100203AF; + public static final int Cp943C = 0x100203AF; + public static final int Cp949 = 0x100203B5; + public static final int Cp949C = 0x100203B5; + public static final int Cp950 = 0x100203B6; + public static final int Cp964 = 0x100203C4; + public static final int Cp970 = 0x100203CA; + public static final int EUC_JP = 0x00030010; + public static final int EUC_KR = 0x0004000A; + public static final int EUC_TW = 0x00050010; + + /** + * The native character set for the narrow character. + */ + public static final int NATIVE_CHARACTER = ISO8859_1; + + /** + * The native character set for the wide character. + */ + public static final int NATIVE_WIDE_CHARACTER = UTF16; + + /** + * Table to convert from the code to string name. + */ + private static Hashtable code_to_string; + + /** + * Table to convert from the string name to code. + */ + private static Hashtable string_to_code; + + /** + * Get the charset code from its name. + * + * @return the charset code of 0 if not defined. + */ + public static int getCode(String name) + { + if (string_to_code == null) + makeMap(); + + Integer code = (Integer) string_to_code.get(name); + return code == null ? 0 : code.intValue(); + } + + /** + * Get the charset name from its code. + * + * @return the code set name or nullfor the unknown code set. + */ + public static String getName(int code) + { + if (code_to_string == null) + makeMap(); + return (String) code_to_string.get(new Integer(code)); + } + + /** + * Get the list of supported char sets for that the CORBA codes are + * also known. + */ + public static int[] getSupportedCharSets() + { + Set supported_sets = Charset.availableCharsets().keySet(); + int[] supported = new int[ supported_sets.size() ]; + Iterator iter = supported_sets.iterator(); + + int i = 0; + int code; + while (iter.hasNext()) + { + code = getCode(iter.next().toString()); + if (code > 0) + supported [ i++ ] = code; + } + + // Truncate the unused part. + int[] f = new int[ i ]; + System.arraycopy(supported, 0, f, 0, f.length); + + return f; + } + + /** + * Create a convertion map. + */ + private static void makeMap() + { + code_to_string = new Hashtable(); + string_to_code = new Hashtable(); + + // Put standard char sets. + put(ASCII, "US-ASCII"); + put(ISO8859_1, "ISO-8859-1"); + put(UTF16, "UTF-16"); + + // Put other known char sets. + put(ISO8859_2, "ISO-8859-2"); + put(ISO8859_3, "ISO-8859-3"); + put(ISO8859_4, "ISO-8859-4"); + put(ISO8859_5, "ISO-8859-5"); + put(ISO8859_6, "ISO-8859-6"); + put(ISO8859_7, "ISO-8859-7"); + put(ISO8859_8, "ISO-8859-8"); + put(ISO8859_9, "ISO-8859-9"); + + put(UTF8, "UTF-8"); + put(UCS2, "UCS-2"); + + put(ISO8859_15_FDIS, "ISO8859-15-FDIS"); + + put(Cp1047, "Cp1047"); + put(Cp1250, "Cp1250"); + put(Cp1251, "Cp1251"); + put(Cp1252, "Cp1252"); + put(Cp1253, "Cp1253"); + put(Cp1254, "Cp1254"); + put(Cp1255, "Cp1255"); + put(Cp1256, "Cp1256"); + put(Cp1257, "Cp1257"); + put(Cp1363, "Cp1363"); + put(Cp1363C, "Cp1363C"); + put(Cp1381, "Cp1381"); + put(Cp1383, "Cp1383"); + put(Cp1386, "Cp1386"); + put(Cp33722, "Cp33722"); + put(Cp33722C, "Cp33722C"); + put(Cp930, "Cp930"); + put(Cp943, "Cp943"); + put(Cp943C, "Cp943C"); + put(Cp949, "Cp949"); + put(Cp949C, "Cp949C"); + put(Cp950, "Cp950"); + put(Cp964, "Cp964"); + put(Cp970, "Cp970"); + + put(EUC_JP, "EUC-JP"); + put(EUC_KR, "EUC-KR"); + put(EUC_TW, "EUC-TW"); + } + + private static void put(int code, String name) + { + Integer ic = new Integer(code); + + code_to_string.put(ic, name); + string_to_code.put(name, ic); + } +} diff --git a/libjava/classpath/gnu/CORBA/GIOP/CloseMessage.java b/libjava/classpath/gnu/CORBA/GIOP/CloseMessage.java new file mode 100644 index 000000000..c555f2b94 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/GIOP/CloseMessage.java @@ -0,0 +1,106 @@ +/* CloseMessage.java -- + 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.CORBA.GIOP; + +import gnu.CORBA.Minor; + +import org.omg.CORBA.MARSHAL; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * The explicit command to close the connection. + * + * + * The close message consists from the message header only and + * is the same for GIOP 1.0, 1.1, 1.2 and 1.3. The CloseMessage + * uses the default value from the {@link MessageHeader}. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class CloseMessage + extends MessageHeader +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * The singleton close message is typically enough, despite new + * instances may be instantiated if the specific version field + * value is mandatory. + */ + private static final CloseMessage Singleton = new CloseMessage(); + + /** + * Create a new error message, setting the message field + * to the {@link MESSAGE_CLOSE} and the version number to + * the given major and minor values. + */ + public CloseMessage() + { + message_type = CLOSE_CONNECTION; + } + + /** + * Send the close message to the given output stream. The method, + * however, does not close the socket itself, this must be done + * explicitly in the calling code. + * + * @param socketStream a stream, where the close message is + * written. + */ + public static void close(OutputStream socketStream) + { + try + { + Singleton.write(socketStream); + socketStream.flush(); + } + catch (IOException ex) + { + MARSHAL m = new MARSHAL("Unable to flush the stream"); + m.minor = Minor.Header; + m.initCause(ex); + throw m; + } + } +} diff --git a/libjava/classpath/gnu/CORBA/GIOP/CodeSetServiceContext.java b/libjava/classpath/gnu/CORBA/GIOP/CodeSetServiceContext.java new file mode 100644 index 000000000..81412e029 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/GIOP/CodeSetServiceContext.java @@ -0,0 +1,222 @@ +/* CodeSet_sctx.java -- + 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.CORBA.GIOP; + +import gnu.CORBA.CDR.AbstractCdrInput; +import gnu.CORBA.CDR.AbstractCdrOutput; +import gnu.CORBA.IOR; +import java.io.IOException; + +/** + * The code set service context. This context must be included in all + * messages that use wide characters. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class CodeSetServiceContext + extends ServiceContext +{ + /** + * The context code sets id. + */ + public static final int ID = 1; + + /** + * The standard component to include in the messages. + */ + public static final CodeSetServiceContext STANDARD = new CodeSetServiceContext(); + + /** + * The encoding, used to transfer the narrow (1 byte) character data. + * The default value is taken from {@link CharSets_OSF#NATIVE_CHARACTER}. + */ + public int char_data = CharSets_OSF.NATIVE_CHARACTER; + + /** + * The encoding, used to transfer the wide character data. + * The default value is taken from + * {@link CharSets_OSF#NATIVE_WIDE_CHARACTER}. + */ + public int wide_char_data = CharSets_OSF.NATIVE_WIDE_CHARACTER; + + /** + * Find and return the code set service context in the give + * contexts array. Returns {@link #STANDARD} if no code set + * context is present. + * + * @param contexts the array of contexts, can be null. + */ + public static CodeSetServiceContext find(ServiceContext[] contexts) + { + if (contexts != null) + for (int i = 0; i < contexts.length; i++) + { + if (contexts [ i ] instanceof CodeSetServiceContext) + return (CodeSetServiceContext) contexts [ i ]; + } + return STANDARD; + } + + /** + * Select the suitable encoding that is defined in the provided profile. + * + * TODO character encoding. Now the encoding can be set, but it is ignored. + * If you take this task, scan 'TODO character encoding' for + * relevant places. + */ + public static CodeSetServiceContext negotiate(IOR.CodeSets_profile profile) + { + if (profile.negotiated != null) + return profile.negotiated; + + CodeSetServiceContext use = new CodeSetServiceContext(); + + use.char_data = + negotiate(profile.narrow, STANDARD.char_data, CharSets_OSF.ISO8859_1); + + use.wide_char_data = + negotiate(profile.wide, STANDARD.wide_char_data, CharSets_OSF.UTF16); + + profile.negotiated = use; + + return use; + } + + /** + * Read the context from the given stream. Does not read the + * code sets id. + */ + public void readContext(AbstractCdrInput input) + { + AbstractCdrInput encap = input.read_encapsulation(); + + char_data = encap.read_ulong(); + wide_char_data = encap.read_ulong(); + } + + /** + * Return a string representation. + */ + public String toString() + { + return " Encoding: narrow " + name(char_data) + ", wide " + + name(wide_char_data) + ". "; + } + + /** + * Write the context to the given stream, including the code + * sets id. + */ + public void write(AbstractCdrOutput output) + { + output.write_ulong(ID); + + AbstractCdrOutput enout = output.createEncapsulation(); + + enout.write_long(char_data); + enout.write_ulong(wide_char_data); + + try + { + enout.close(); + } + catch (IOException ex) + { + InternalError t = new InternalError(); + t.initCause(ex); + throw t; + } + } + + /** + * Negotiate about the character encoding. Prefer our native encoding, + * if no, prefer IORs native encoding, if no, find any encoding, + * supported by both sides, if no, return the specified final decission. + * + * @param profile the component profile in IOR. + * @param our_native our native encoding + * @param final_decission the encoding that must be returned if no + * compromise is found. + * + * @return the resulted encoding. + */ + protected static int negotiate(IOR.CodeSets_profile.CodeSet_component profile, + int our_native, int final_decission + ) + { + // If our and IORs native sets match, use the native set. + if (profile.native_set == our_native) + return our_native; + + // If the native sets do not match, but the IOR says it + // supports our native set, use our native set. + if (profile.conversion != null) + for (int i = 0; i < profile.conversion.length; i++) + { + if (our_native == profile.conversion [ i ]) + return our_native; + } + + // At this point, we suggest to use the IORs native set. + int[] allSupported = CharSets_OSF.getSupportedCharSets(); + + for (int s = 0; s < allSupported.length; s++) + if (allSupported [ s ] == profile.native_set) + return profile.native_set; + + // Any compromise left? + if (profile.conversion != null) + for (int s = 0; s < allSupported.length; s++) + for (int i = 0; i < profile.conversion.length; i++) + if (allSupported [ s ] == profile.conversion [ i ]) + return allSupported [ s ]; + + // Return the CORBA default char encoding. + return final_decission; + } + + /** + * Conveniency method, used in toString() + */ + private String name(int set) + { + return "0x" + Integer.toHexString(set) + " (" + CharSets_OSF.getName(set) + + ") "; + } +} diff --git a/libjava/classpath/gnu/CORBA/GIOP/ContextHandler.java b/libjava/classpath/gnu/CORBA/GIOP/ContextHandler.java new file mode 100644 index 000000000..77ea20e38 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/GIOP/ContextHandler.java @@ -0,0 +1,76 @@ +/* ContextHandler.java -- + 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.CORBA.GIOP; + +import org.omg.CORBA.BAD_INV_ORDER; + +/** + * A header, supporting the service contexts. Such header has a context field + * and methods for adding the new contexts. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public abstract class ContextHandler +{ + + /** + * Empty array, indicating that no service context is available. + */ + protected static final ServiceContext[] NO_CONTEXT = new ServiceContext[0]; + + /** + * The context data. + */ + public ServiceContext[] service_context = NO_CONTEXT; + + /** + * Add service context to this header. + * + * @param context_to_add context to add. + * @param replace if true, the existing context with this ID is replaced. + * Otherwise, BAD_INV_ORDER is throwsn. + */ + public void addContext(org.omg.IOP.ServiceContext context_to_add, + boolean replace) + throws BAD_INV_ORDER + { + service_context = ServiceContext.add(service_context, context_to_add, + replace); + } +} diff --git a/libjava/classpath/gnu/CORBA/GIOP/ErrorMessage.java b/libjava/classpath/gnu/CORBA/GIOP/ErrorMessage.java new file mode 100644 index 000000000..0bd48dea8 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/GIOP/ErrorMessage.java @@ -0,0 +1,114 @@ +/* ErrorMessage.java -- + 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.CORBA.GIOP; + +import gnu.CORBA.OrbFunctional; +import gnu.CORBA.IOR; +import gnu.CORBA.Minor; + +import java.io.IOException; +import java.io.OutputStream; + +import java.net.Socket; + +import org.omg.CORBA.MARSHAL; +import org.omg.CORBA.ORB; + +/** + * The error message is sent in response to the message, encoded + * in the unsupported version of the format or otherwise invalid. + * + * The error message consists from the message header only and + * is the same for GIOP 1.0, 1.1, 1.2 and 1.3. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class ErrorMessage + extends MessageHeader +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * Create a new error message, setting the message field + * to the {@link MESSAGE_ERROR} and the version number to + * the given major and minor values. + */ + public ErrorMessage(gnu.CORBA.Version msg_version) + { + version = msg_version; + message_type = MESSAGE_ERROR; + } + + /** + * Send the error message to the given IOR address. + * + * @param ior the IOR address (host and port, other fields + * are not used). + * + * @param orb the ORB, sending the error message. + */ + public void send(IOR ior, ORB orb) + { + try + { + Socket socket; + + if (orb instanceof OrbFunctional) + socket = ((OrbFunctional) orb).socketFactory.createClientSocket( + ior.Internet.host, ior.Internet.port); + else + socket = new Socket(ior.Internet.host, ior.Internet.port); + + OutputStream socketOutput = socket.getOutputStream(); + write(socketOutput); + socketOutput.close(); + socket.close(); + } + catch (IOException ex) + { + MARSHAL t = new MARSHAL(); + t.minor = Minor.Header; + t.initCause(ex); + throw t; + } + } +} diff --git a/libjava/classpath/gnu/CORBA/GIOP/MessageHeader.java b/libjava/classpath/gnu/CORBA/GIOP/MessageHeader.java new file mode 100644 index 000000000..3137343ed --- /dev/null +++ b/libjava/classpath/gnu/CORBA/GIOP/MessageHeader.java @@ -0,0 +1,465 @@ +/* MessageHeader.java -- GIOP message header. + 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.CORBA.GIOP; + +import gnu.CORBA.Minor; +import gnu.CORBA.Version; +import gnu.CORBA.CDR.BigEndianInputStream; +import gnu.CORBA.CDR.BigEndianOutputStream; +import gnu.CORBA.CDR.LittleEndianInputStream; +import gnu.CORBA.CDR.LittleEndianOutputStream; +import gnu.CORBA.CDR.AbstractDataInput; +import gnu.CORBA.CDR.AbstractDataOutput; + +import gnu.java.lang.CPStringBuilder; + +import org.omg.CORBA.MARSHAL; +import org.omg.CORBA.portable.IDLEntity; + +import java.io.ByteArrayOutputStream; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; +import java.util.Arrays; + +/** + * The GIOP message header. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class MessageHeader + implements IDLEntity +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * Request message. + */ + public static final byte REQUEST = 0; + + /** + * Reply message + */ + public static final byte REPLY = 1; + + /** + * Cancel request message. + */ + public static final byte CANCEL_REQUEST = 2; + + /** + * Locate request message, used to check the server ability to process + * requests for the object reference. This message is also used to get the + * address where the object reference should be sent. + */ + public static final byte LOCATE_REQUEST = 3; + + /** + * Locate reply message, sent in response to the {@link #LocateRequest} + * message. + */ + public static final byte LOCATE_REPLY = 4; + + /** + * Instruction to close the connection. + */ + public static final byte CLOSE_CONNECTION = 5; + + /** + * Error report. + */ + public static final byte MESSAGE_ERROR = 6; + + /** + * The fragment messge, following the previous message that has more fragments + * flag set. Added in GIOP 1.1 + */ + public static final byte FRAGMENT = 7; + + /** + * This must always be "GIOP". + */ + public static final byte[] MAGIC = new byte[] { 'G', 'I', 'O', 'P' }; + + /** + * The message type names. + */ + protected static String[] types = new String[] { "Request", "Reply", + "Cancel", "Locate request", "Locate reply", "Close connection", "Error", + "Fragment" }; + + /** + * The GIOP version. Initialised to 1.0 . + */ + public Version version; + + /** + * The flags field, introduced since GIOP 1.1. + */ + public byte flags = 0; + + /** + * The message type. + */ + public byte message_type = REQUEST; + + /** + * The message size, excluding the message header. + */ + public int message_size = 0; + + /** + * Create an empty message header, corresponding version 1.0. + */ + public MessageHeader() + { + version = new Version(1, 0); + } + + /** + * Create an empty message header, corresponding the given version. + * + * @param major the major message header version. + * @param minor the minot message header version. + */ + public MessageHeader(int major, int minor) + { + version = new Version(major, minor); + } + + /** + * Checks if the message is encoded in the Big Endian, most significant byte + * first. + */ + public boolean isBigEndian() + { + return (flags & 0x1) == 0; + } + + /** + * Checks if the message is partial, and more subsequent fragments follow. + */ + public boolean moreFragmentsFollow() + { + return (flags & 0x2) != 0; + } + + /** + * Set the encoding to use. + * + * @param use_big_endian if true (default), the Big Endian encoding is used. + * If false, the Little Endian encoding is used. + */ + public void setBigEndian(boolean use_big_endian) + { + if (use_big_endian) + flags = (byte) (flags & ~1); + else + flags = (byte) (flags | 1); + } + + /** + * Get the size of the message header itself. So far, it is always 12 bytes. + */ + public int getHeaderSize() + { + return 12; + } + + /** + * Get the message type as string. + * + * @param type the message type as int (the field {@link message_type}). + * + * @return the message type as string. + */ + public String getTypeString(int type) + { + try + { + return types[type]; + } + catch (ArrayIndexOutOfBoundsException ex) + { + return "unknown type (" + type + ")"; + } + } + + /** + * Creates reply header, matching the message header version number. + * + * @return one of {@link gnu.CORBA.GIOP.v1_0.ReplyHeader}, + * {@link gnu.CORBA.GIOP.v1_2.ReplyHeader}, etc - depending on the version + * number in this header. + */ + public ReplyHeader create_reply_header() + { + if (version.since_inclusive(1, 2)) + return new gnu.CORBA.GIOP.v1_2.ReplyHeader(); + else + return new gnu.CORBA.GIOP.v1_0.ReplyHeader(); + } + + /** + * Creates request header, matching the message header version number. + * + * @return one of {@link gnu.CORBA.GIOP.v1_0.RequestHeader}, + * {@link gnu.CORBA.GIOP.v1_2.RequestHeader}, etc - depending on the version + * number in this header. + */ + public RequestHeader create_request_header() + { + if (version.since_inclusive(1, 2)) + return new gnu.CORBA.GIOP.v1_2.RequestHeader(); + else + return new gnu.CORBA.GIOP.v1_0.RequestHeader(); + } + + /** + * Create the cancel header, matching the message header version number. + */ + public CancelHeader create_cancel_header() + { + return new gnu.CORBA.GIOP.v1_0.CancelHeader(); + } + + /** + * Create the error message. + */ + public ErrorMessage create_error_message() + { + return new ErrorMessage(version); + } + + /** + * Read the header from the stream. + * + * @param istream a stream to read from. + * @throws MARSHAL if this is not a GIOP 1.0 header. + */ + public void read(java.io.InputStream istream) + throws MARSHAL, EOFException + { + try + { + byte[] xMagic = new byte[MAGIC.length]; + int r = istream.read(xMagic); + int minor; + if (! Arrays.equals(xMagic, MAGIC)) + { + CPStringBuilder b = new CPStringBuilder(); + if (r == - 1) + { + b.append("Immediate EOF"); + minor = Minor.EOF; + } + else + { + minor = Minor.Giop; + b.append(r + " bytes: "); + for (int i = 0; i < xMagic.length; i++) + { + b.append(Integer.toHexString(xMagic[i] & 0xFF)); + b.append(' '); + } + } + MARSHAL m = new MARSHAL("Not a GIOP message: " + b); + m.minor = minor; + throw m; + } + + version = Version.read_version(istream); + + AbstractDataInput din; + + flags = (byte) istream.read(); + + // This checks the bit in the byte we have just received. + if (isBigEndian()) + din = new BigEndianInputStream(istream); + else + din = new LittleEndianInputStream(istream); + + message_type = (byte) din.read(); + + message_size = din.readInt(); + } + catch (IOException ex) + { + MARSHAL t = new MARSHAL(); + t.minor = Minor.Header; + t.initCause(ex); + throw t; + } + } + + /** + * Get the short string summary of the message. + * + * @return a short message summary. + */ + public String toString() + { + return "GIOP " + version + ", " + (isBigEndian() ? "Big" : "Little") + + " endian, " + getTypeString(message_type) + ", " + message_size + + " bytes. "; + } + + /** + * Write the header to stream. + * + * @param out a stream to write into. + */ + public void write(java.io.OutputStream out) + { + try + { + AbstractDataOutput dout; + + if (isBigEndian()) + dout = new BigEndianOutputStream(out); + else + dout = new LittleEndianOutputStream(out); + + // Write magic sequence. + dout.write(MAGIC); + + // Write version number. + version.write((OutputStream) dout); + dout.write(flags); + dout.write(message_type); + dout.writeInt(message_size); + } + catch (IOException ex) + { + MARSHAL t = new MARSHAL(ex.getMessage()); + t.minor = Minor.Header; + t.initCause(ex); + throw t; + } + } + + /** + * Read data, followed by the message header. Handle fragmented messages. + * + * @param source the data source to read from. + * @param service the socket on that the time outs are set. Can be null (no + * timeouts are set). + * @param to_read the timeout while reading the message. + * @param to_pause the timeout for pauses between the message parts. + */ + public byte[] readMessage(InputStream source, Socket service, int to_read, + int to_pause) + { + try + { + byte[] r = new byte[message_size]; + + int n = 0; + if (service != null) + service.setSoTimeout(to_read); + + while (n < r.length) + { + n += source.read(r, n, r.length - n); + } + if (service != null) + service.setSoTimeout(to_pause); + + // Read the message remainder if the message is fragmented. + if (moreFragmentsFollow()) + { + ByteArrayOutputStream buffer = new ByteArrayOutputStream( + 2 * r.length); + buffer.write(r); + + if (r.length < 10) + // Increase the buffer size if the default value (size of the + // previous message) is really too small. + r = new byte[1024]; + + MessageHeader h2 = new MessageHeader(); + + do + { + h2.read(source); + + int dn; + + n = 0; + while (n < h2.message_size) + { + dn = source.read(r, 0, h2.message_size - n); + + if (n == 0 && service != null) + service.setSoTimeout(to_read); + + if (n == 0 && version.since_inclusive(1, 2)) + { + // Skip the four byte request id. + buffer.write(r, 4, dn - 4); + } + else + buffer.write(r, 0, dn); + n = +dn; + } + + if (service != null) + service.setSoTimeout(to_pause); + } + while (h2.moreFragmentsFollow()); + return buffer.toByteArray(); + } + else + return r; + } + catch (IOException ioex) + { + MARSHAL m = new MARSHAL("Unable to read the message continuation."); + m.minor = Minor.Header; + m.initCause(ioex); + throw m; + } + } +} diff --git a/libjava/classpath/gnu/CORBA/GIOP/ReplyHeader.java b/libjava/classpath/gnu/CORBA/GIOP/ReplyHeader.java new file mode 100644 index 000000000..d14482903 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/GIOP/ReplyHeader.java @@ -0,0 +1,145 @@ +/* ReplyHeader.java -- + 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.CORBA.GIOP; + +import gnu.CORBA.CDR.AbstractCdrInput; +import gnu.CORBA.CDR.AbstractCdrOutput; + +/** + * The header of the standard reply. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public abstract class ReplyHeader + extends ContextHandler +{ + /** + * Reply status, if no exception occured. + */ + public static final int NO_EXCEPTION = 0; + + /** + * Reply status, user exception. + */ + public static final int USER_EXCEPTION = 1; + + /** + * Reply status, system exception. + */ + public static final int SYSTEM_EXCEPTION = 2; + + /** + * Reply status, if the client ORB must re - send the request to another + * destination. The body contains IOR. + */ + public static final int LOCATION_FORWARD = 3; + + /** + * Reply status, indicating that the target has permanently changed the + * address to the supplied IOR. + */ + public static final int LOCATION_FORWARD_PERM = 4; + + /** + * Reply status, indicating, that the ORB requires to resend the object + * address in the required addressing mode, contained as the reply body. + */ + public static final int NEEDS_ADDRESSING_MODE = 5; + + /** + * The status of this reply, holds one of the reply status constants. + */ + public int reply_status; + + /** + * The Id of request into response of which this reply has been sent. + */ + public int request_id; + + /** + * Return the message status as a string. + */ + public String getStatusString() + { + switch (reply_status) + { + case NO_EXCEPTION: + return "ok"; + + case USER_EXCEPTION: + return "user exception"; + + case SYSTEM_EXCEPTION: + return "system exception"; + + case LOCATION_FORWARD: + return "moved"; + + default: + return null; + } + } + + /** + * Reads the header from the stream. + * + * @param in a stream to read from. + */ + public abstract void read(AbstractCdrInput in); + + /** + * Returns a short string representation. + * + * @return a string representation. + */ + public String toString() + { + String status = getStatusString(); + if (status == null) + status = "status " + reply_status; + return request_id + ", " + status; + } + + /** + * Writes the header to the stream. + * + * @param out a stream to write into. + */ + public abstract void write(AbstractCdrOutput out); +} diff --git a/libjava/classpath/gnu/CORBA/GIOP/RequestHeader.java b/libjava/classpath/gnu/CORBA/GIOP/RequestHeader.java new file mode 100644 index 000000000..45997ab3d --- /dev/null +++ b/libjava/classpath/gnu/CORBA/GIOP/RequestHeader.java @@ -0,0 +1,156 @@ +/* RequestHeader.java -- The GIOP 1.0 request message. + 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.CORBA.GIOP; + +import gnu.CORBA.CDR.AbstractCdrInput; +import gnu.CORBA.CDR.AbstractCdrOutput; + +import gnu.java.lang.CPStringBuilder; + +import org.omg.CORBA.portable.IDLEntity; + +/** + * The GIOP request message. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public abstract class RequestHeader + extends ContextHandler + implements IDLEntity +{ + /** + * The currently free request id. This field is incremented each time the new + * request header is constructed. To facilitate error detection, the first + * free id is equal to 0x01234567 (19088743). + */ + private static int freeId = 0x01234567; + + /** + * The operation being invoked (IDL scope name). + */ + public String operation; + + /** + * Identifies the object that is the target of the invocation. + */ + public byte[] object_key; + + /** + * A value identifying the requesting principal. Initialised into a single + * zero byte. + * + * @deprecated by CORBA 2.2. + */ + public byte[] requesting_principal; + + /** + * This is used to associate the reply message with the previous request + * message. Initialised each time by the different value, increasing form 1 to + * Integer.MAX_VALUE. + */ + public int request_id = getNextId(); + + /** + * If true, the response from the server is expected. + */ + protected boolean response_expected = true; + + /** + * Get next free request id. The value of the free request id starts from + * 0x02345678, it is incremented each time this function is called and is + * reset to 1 after reaching Integer.MAX_VALUE. + * + * @return the next free request id. + */ + public static synchronized int getNextId() + { + int f = freeId; + if (freeId == Integer.MAX_VALUE) + freeId = 1; + else + freeId++; + + return f; + } + + /** + * Set if the sender expects any response to this message. + */ + public abstract void setResponseExpected(boolean expected); + + /** + * Return true if response is expected. + */ + public abstract boolean isResponseExpected(); + + /** + * Converts an byte array into hexadecimal string values. Used in various + * toString() methods. + */ + public String bytes(byte[] array) + { + CPStringBuilder b = new CPStringBuilder(); + for (int i = 0; i < array.length; i++) + { + b.append(Integer.toHexString(array[i] & 0xFF)); + b.append(" "); + } + return b.toString(); + } + + /** + * Reads the header from the stream. + * + * @param in a stream to read from. + */ + public abstract void read(AbstractCdrInput in); + + /** + * Return a string representation. + */ + public abstract String toString(); + + /** + * Writes the header to the stream. + * + * @param out a stream to write into. + */ + public abstract void write(AbstractCdrOutput out); + +} diff --git a/libjava/classpath/gnu/CORBA/GIOP/ServiceContext.java b/libjava/classpath/gnu/CORBA/GIOP/ServiceContext.java new file mode 100644 index 000000000..673ae0ba9 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/GIOP/ServiceContext.java @@ -0,0 +1,301 @@ +/* ServiceContext.java -- + 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.CORBA.GIOP; + +import gnu.CORBA.CDR.AbstractCdrInput; +import gnu.CORBA.CDR.AbstractCdrOutput; + +import org.omg.CORBA.BAD_INV_ORDER; +import org.omg.CORBA.BAD_PARAM; +import org.omg.CORBA.CompletionStatus; +import org.omg.CORBA.portable.IDLEntity; + +/** + * Contains the ORB service data being passed. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class ServiceContext + implements IDLEntity +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /* Standard values for the context_id. */ + public static final int TransactionService = 0; + + /** + * Defines code sets, used to encode wide and narrow characters. Required for + * messages with data structures, involving wide characters. + */ + public static final int CodeSets = 1; + + public static final int ChainBypassCheck = 2; + + public static final int ChainBypassInfo = 3; + + public static final int LogicalThreadId = 4; + + public static final int BI_DIR_IIOP = 5; + + public static final int SendingContextRunTime = 6; + + public static final int INVOCATION_POLICIES = 7; + + public static final int FORWARDED_IDENTITY = 8; + + /** + * Contains exception details if exception being transferred is other than + * System or User exception. javax.rmi uses this context to transfer arbitrary + * java exceptions as CORBA value types. + */ + public static final int UnknownExceptionInfo = 9; + + public static final int RTCorbaPriority = 10; + + public static final int RTCorbaPriorityRange = 11; + + public static final int FT_GROUP_VERSION = 12; + + public static final int FT_REQUEST = 13; + + public static final int ExceptionDetailMessage = 14; + + public static final int SecurityAttributeService = 15; + + public static final int ActivityService = 16; + + /** + * The context id (for instance, 0x1 for code sets context). At the moment of + * writing, the OMG defines 16 standard values and provides rules to register + * the vendor specific context ids. The range 0-4095 is reserved for the + * future standard OMG contexts. + */ + public int context_id; + + /** + * The context_data. + */ + public byte[] context_data; + + /** + * Crete unitialised instance. + */ + public ServiceContext() + { + } + + /** + * Create from omg context. + */ + public ServiceContext(org.omg.IOP.ServiceContext from) + { + context_id = from.context_id; + context_data = from.context_data; + } + + /** + * Read the context values from the stream. + * + * @param istream a stream to read from. + */ + public static ServiceContext read(AbstractCdrInput istream) + { + int id = istream.read_ulong(); + + switch (id) + { + case CodeSetServiceContext.ID: + + CodeSetServiceContext codeset = new CodeSetServiceContext(); + codeset.readContext(istream); + return codeset; + + default: + + ServiceContext ctx = new ServiceContext(); + ctx.context_id = id; + ctx.context_data = istream.read_sequence(); + return ctx; + } + } + + /** + * Read a sequence of contexts from the input stream. + */ + public static ServiceContext[] readSequence(AbstractCdrInput istream) + { + int size = istream.read_long(); + ServiceContext[] value = new gnu.CORBA.GIOP.ServiceContext[size]; + for (int i = 0; i < value.length; i++) + value[i] = read(istream); + return value; + } + + /** + * Write the context values into the stream. + * + * @param ostream a stream to write the data to. + */ + public void write(AbstractCdrOutput ostream) + { + ostream.write_ulong(context_id); + ostream.write_sequence(context_data); + } + + /** + * Write the sequence of contexts into the input stream. + */ + public static void writeSequence(AbstractCdrOutput ostream, ServiceContext[] value) + { + ostream.write_long(value.length); + for (int i = 0; i < value.length; i++) + value[i].write(ostream); + } + + /** + * Add context to the given array of contexts. + */ + public static void add(org.omg.IOP.ServiceContext[] cx, + org.omg.IOP.ServiceContext service_context, boolean replace) + { + int exists = -1; + + for (int i = 0; i < cx.length; i++) + if (cx[i].context_id == service_context.context_id) + exists = i; + + if (exists < 0) + { + // Add context. + org.omg.IOP.ServiceContext[] n = new org.omg.IOP.ServiceContext[cx.length + 1]; + for (int i = 0; i < cx.length; i++) + n[i] = cx[i]; + n[cx.length] = service_context; + } + else + { + // Replace context. + if (!replace) + throw new BAD_INV_ORDER("Repetetive setting of the context " + + service_context.context_id, 15, CompletionStatus.COMPLETED_NO); + else + cx[exists] = service_context; + } + } + + /** + * Add context to the given array of contexts. + */ + public static ServiceContext[] add(ServiceContext[] cx, + org.omg.IOP.ServiceContext service_context, boolean replace) + { + int exists = -1; + + for (int i = 0; i < cx.length; i++) + if (cx[i].context_id == service_context.context_id) + exists = i; + + if (exists < 0) + { + // Add context. + ServiceContext[] n = new ServiceContext[cx.length + 1]; + for (int i = 0; i < cx.length; i++) + n[i] = cx[i]; + n[cx.length] = new ServiceContext(service_context); + return n; + } + else + { + // Replace context. + if (!replace) + throw new BAD_INV_ORDER("Repetetive setting of the context " + + service_context.context_id, 15, CompletionStatus.COMPLETED_NO); + else + cx[exists] = new ServiceContext(service_context); + return cx; + } + } + + /** + * Find context with the given name in the context array. + */ + public static org.omg.IOP.ServiceContext findContext(int ctx_name, + org.omg.IOP.ServiceContext[] cx) + { + for (int i = 0; i < cx.length; i++) + if (cx[i].context_id == ctx_name) + return cx[i]; + throw new BAD_PARAM("No context with id " + ctx_name); + } + + /** + * Find context with the given name in the context array, converting into + * org.omg.IOP.ServiceContext. + */ + public static org.omg.IOP.ServiceContext findContext(int ctx_name, + ServiceContext[] cx) + { + for (int i = 0; i < cx.length; i++) + if (cx[i].context_id == ctx_name) + return new org.omg.IOP.ServiceContext(ctx_name, cx[i].context_data); + throw new BAD_PARAM("No context with id " + ctx_name); + } + + /** + * Find context with the given name in the context array without conversions. + */ + public static ServiceContext find(int ctx_name, ServiceContext[] cx) + { + for (int i = 0; i < cx.length; i++) + if (cx[i].context_id == ctx_name) + return cx[i]; + return null; + } + + /** + * Return a string representation. + */ + public String toString() + { + return "ctx " + context_id + ", size " + context_data.length; + } +} diff --git a/libjava/classpath/gnu/CORBA/GIOP/v1_0/CancelHeader.java b/libjava/classpath/gnu/CORBA/GIOP/v1_0/CancelHeader.java new file mode 100644 index 000000000..115849223 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/GIOP/v1_0/CancelHeader.java @@ -0,0 +1,72 @@ +/* CancelHeader.java -- + 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.CORBA.GIOP.v1_0; + +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.OutputStream; + +/** + * The message header for cancelling the request. + * + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class CancelHeader + extends gnu.CORBA.GIOP.CancelHeader +{ + /** + * Read the header. + * + * @param input a stream to read from. + */ + public void read(InputStream input) + { + request_id = input.read_ulong(); + } + + /** + * Write the header. + * + * @param output a stream to write to. + */ + public void write(OutputStream output) + { + output.write_ulong(request_id); + } +} diff --git a/libjava/classpath/gnu/CORBA/GIOP/v1_0/ReplyHeader.java b/libjava/classpath/gnu/CORBA/GIOP/v1_0/ReplyHeader.java new file mode 100644 index 000000000..dcb00c0eb --- /dev/null +++ b/libjava/classpath/gnu/CORBA/GIOP/v1_0/ReplyHeader.java @@ -0,0 +1,141 @@ +/* ReplyHeader.java -- + 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.CORBA.GIOP.v1_0; + +import gnu.CORBA.CDR.AbstractCdrInput; +import gnu.CORBA.CDR.AbstractCdrOutput; +import gnu.CORBA.GIOP.ServiceContext; +import gnu.CORBA.GIOP.CodeSetServiceContext; + +import gnu.java.lang.CPStringBuilder; + +/** + * The header of the standard reply. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class ReplyHeader + extends gnu.CORBA.GIOP.ReplyHeader +{ + /** + * Return the message status as a string. + */ + public String getStatusString() + { + switch (reply_status) + { + case NO_EXCEPTION : + return "ok"; + + case USER_EXCEPTION : + return "user exception"; + + case SYSTEM_EXCEPTION : + return "system exception"; + + case LOCATION_FORWARD : + return "moved"; + + default : + return null; + } + } + + /** + * Get the string representation of all included contexts. + */ + public String contexts() + { + CPStringBuilder b = new CPStringBuilder(); + for (int i = 0; i < service_context.length; i++) + { + b.append(service_context [ i ].toString()); + b.append(' '); + } + return b.toString(); + } + + /** + * Reads the header from the stream. + * + * Sets the code set of this stream to + * the code set, specfied in the header. + * + * @param in a stream to read from. + */ + + public void read(AbstractCdrInput in) + { + service_context = ServiceContext.readSequence(in); + request_id = in.read_ulong(); + reply_status = in.read_ulong(); + + in.setCodeSet(CodeSetServiceContext.find(service_context)); + } + + /** + * Returns a short string representation. + * + * @return a string representation. + */ + public String toString() + { + String status = getStatusString(); + if (status == null) + status = "status " + reply_status; + return request_id + ", " + status + " " + contexts(); + } + + /** + * Writes the header to the stream. + * + * Sets the code set of this stream to + * the code set, specfied in the header. + * + * @param out a stream to write into. + */ + public void write(AbstractCdrOutput out) + { + ServiceContext.writeSequence(out, service_context); + out.write_ulong(request_id); + out.write_ulong(reply_status); + + out.setCodeSet(CodeSetServiceContext.find(service_context)); + } +} diff --git a/libjava/classpath/gnu/CORBA/GIOP/v1_0/RequestHeader.java b/libjava/classpath/gnu/CORBA/GIOP/v1_0/RequestHeader.java new file mode 100644 index 000000000..d2bea9d88 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/GIOP/v1_0/RequestHeader.java @@ -0,0 +1,159 @@ +/* RequestHeader.java -- The GIOP 1.0 request message. + 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.CORBA.GIOP.v1_0; + +import gnu.CORBA.CDR.AbstractCdrInput; +import gnu.CORBA.CDR.AbstractCdrOutput; +import gnu.CORBA.GIOP.ServiceContext; +import gnu.CORBA.GIOP.CodeSetServiceContext; + +import gnu.java.lang.CPStringBuilder; + +import org.omg.CORBA.portable.IDLEntity; + +/** + * The GIOP 1.0 request message. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class RequestHeader + extends gnu.CORBA.GIOP.RequestHeader + implements IDLEntity +{ + /** + * Creates an empty request header, setting requesting principal + * to byte[] { 'P' }. + */ + public RequestHeader() + { + requesting_principal = new byte[] { 'P' }; + } + + /** + * Set if the sender expects any response to this message. + */ + public void setResponseExpected(boolean expected) + { + response_expected = expected; + } + + /** + * Return true if response is expected. + */ + public boolean isResponseExpected() + { + return response_expected; + } + + public String bytes(byte[] array) + { + CPStringBuilder b = new CPStringBuilder(); + for (int i = 0; i < array.length; i++) + { + b.append(Integer.toHexString(array [ i ] & 0xFF)); + b.append(" "); + } + return b.toString(); + } + + /** + * Get the string representation of all included contexts. + */ + public String contexts() + { + CPStringBuilder b = new CPStringBuilder(); + for (int i = 0; i < service_context.length; i++) + { + b.append(service_context [ i ].toString()); + b.append(' '); + } + return b.toString(); + } + + /** + * Reads the header from the stream. + * + * Sets the code set of this stream to + * the code set, specfied in the header. + * + * @param in a stream to read from. + */ + public void read(AbstractCdrInput in) + { + service_context = ServiceContext.readSequence(in); + request_id = in.read_ulong(); + response_expected = in.read_boolean(); + object_key = in.read_sequence(); + operation = in.read_string(); + requesting_principal = in.read_sequence(); + + in.setCodeSet(CodeSetServiceContext.find(service_context)); + } + + /** + * Return a string representation. + */ + public String toString() + { + return "Request " + request_id + ", call '" + operation + "' on " + + bytes(object_key) + ", " + + (response_expected ? "wait response" : "one way") + ", from " + + bytes(requesting_principal) + contexts(); + } + + /** + * Writes the header to the stream. + * + * Sets the code set of this stream to + * the code set, specfied in the header. + * + * @param out a stream to write into. + */ + public void write(AbstractCdrOutput out) + { + ServiceContext.writeSequence(out, service_context); + out.write_ulong(request_id); + out.write_boolean(response_expected); + out.write_sequence(object_key); + out.write_string(operation); + out.write_sequence(requesting_principal); + + out.setCodeSet(CodeSetServiceContext.find(service_context)); + } +} diff --git a/libjava/classpath/gnu/CORBA/GIOP/v1_2/ReplyHeader.java b/libjava/classpath/gnu/CORBA/GIOP/v1_2/ReplyHeader.java new file mode 100644 index 000000000..3fc1541d9 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/GIOP/v1_2/ReplyHeader.java @@ -0,0 +1,118 @@ +/* ReplyHeader.java -- + 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.CORBA.GIOP.v1_2; + +import gnu.CORBA.CDR.AbstractCdrInput; +import gnu.CORBA.CDR.AbstractCdrOutput; +import gnu.CORBA.GIOP.ServiceContext; +import gnu.CORBA.GIOP.CodeSetServiceContext; + +/** + * GIOP 1.2 reply header. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class ReplyHeader + extends gnu.CORBA.GIOP.v1_0.ReplyHeader +{ + /** + * Adds the standard encoding context. + */ + public ReplyHeader() + { + service_context = new ServiceContext[] { CodeSetServiceContext.STANDARD }; + } + + /** + * Return the message status as a string. + */ + public String getStatusString() + { + String s = super.getStatusString(); + if (s != null) + return s; + switch (reply_status) + { + case LOCATION_FORWARD_PERM : + return "moved permanently"; + + case NEEDS_ADDRESSING_MODE : + return "the alternative addressing mode required"; + + default : + return null; + } + } + + /** + * Reads the header from the stream. + * The fields go in different order than in the previous GIOP versions. + * + * Sets the code set of this stream to + * the code set, specfied in the header. + * + * @param in a stream to read from. + */ + public void read(AbstractCdrInput in) + { + request_id = in.read_ulong(); + reply_status = in.read_ulong(); + service_context = gnu.CORBA.GIOP.ServiceContext.readSequence(in); + + in.setCodeSet(CodeSetServiceContext.find(service_context)); + } + + /** + * Writes the header to the stream. + * The fields go in different order than in the previous GIOP versions. + * + * Sets the code set of this stream to + * the code set, specfied in the header. + * + * @param out a stream to write into. + */ + public void write(AbstractCdrOutput out) + { + out.write_ulong(request_id); + out.write_ulong(reply_status); + gnu.CORBA.GIOP.ServiceContext.writeSequence(out, service_context); + + out.setCodeSet(CodeSetServiceContext.find(service_context)); + } +} diff --git a/libjava/classpath/gnu/CORBA/GIOP/v1_2/RequestHeader.java b/libjava/classpath/gnu/CORBA/GIOP/v1_2/RequestHeader.java new file mode 100644 index 000000000..d083536a7 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/GIOP/v1_2/RequestHeader.java @@ -0,0 +1,222 @@ +/* RequestHeader.java -- + 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.CORBA.GIOP.v1_2; + +import gnu.CORBA.Minor; +import gnu.CORBA.CDR.AbstractCdrInput; +import gnu.CORBA.CDR.AbstractCdrOutput; +import gnu.CORBA.GIOP.ServiceContext; +import gnu.CORBA.GIOP.CodeSetServiceContext; + +import java.io.IOException; + +import org.omg.CORBA.MARSHAL; +import org.omg.CORBA.NO_IMPLEMENT; + +/** + * The GIOP 1.2 request header. The GIOP 1.1 request header + * is the same as GIOP 1.0 request header, if taking the + * alignment into consideration. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class RequestHeader + extends gnu.CORBA.GIOP.v1_0.RequestHeader +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * Indicates that the object is addressed by the object key. + */ + public static final short KeyAddr = 0; + + /** + * Indicates that the object is addressed by the IOP tagged profile. + */ + public static final short ProfileAddr = 1; + + /** + * Indicates that the objec is addressed by IOR addressing info. + */ + public static final short ReferenceAddr = 2; + + /** + * The response flags of the header. By default, the flags are initialised + * by value 0x3 (response expected). + */ + public byte response_flags = 3; + + /** + * The used addressing method. + */ + public short AddressingDisposition; + + /** + * Adds the standard encoding context. + */ + public RequestHeader() + { + service_context = new ServiceContext[] { CodeSetServiceContext.STANDARD }; + } + + /** + * Set if the sender expects any response to this message. + * Clears or sets the 2 lower bits of flags + * (0 - not expected, 0x3 - expected). + */ + public void setResponseExpected(boolean expected) + { + response_expected = expected; + + if (expected) + response_flags = (byte) (response_flags | 0x3); + else + response_flags = (byte) (response_flags & (~0x3)); + } + + /** + * Return true if response is expected. + * + * @return true if the two lowest bits of the flags are set or + * the response expected is explicitly set to true. + */ + public boolean isResponseExpected() + { + return response_expected || ((response_flags & 0x3) == 0x3); + } + + /** + * Read the header from the given stream. + * + * @param in a stream to read from. + */ + public void read(AbstractCdrInput in) + { + try + { + request_id = in.read_ulong(); + response_flags = (byte) in.read(); + + // Skip 3 reserved octets: + in.skip(3); + + // Read target address. + AddressingDisposition = in.read_ushort(); + + switch (AddressingDisposition) + { + case KeyAddr : + object_key = in.read_sequence(); + break; + + // TODO FIXME add other addressing methods. + case ProfileAddr : + throw new NO_IMPLEMENT("Object addressing by IOP tagged profile"); + + case ReferenceAddr : + throw new NO_IMPLEMENT("Object addressing by IOR addressing info"); + + default : + MARSHAL m = new MARSHAL("Unknow addressing method in request, " + + AddressingDisposition + ); + m.minor = Minor.UnsupportedAddressing; + throw m; + } + + operation = in.read_string(); + service_context = gnu.CORBA.GIOP.ServiceContext.readSequence(in); + + // No requesting principal in this new format. + in.setCodeSet(CodeSetServiceContext.find(service_context)); + } + catch (IOException ex) + { + MARSHAL t = new MARSHAL(); + t.minor = Minor.Header; + t.initCause(ex); + throw t; + } + } + + /** + * Return a string representation. + */ + public String toString() + { + return "Request " + request_id + ", call '" + operation + "' on " + + bytes(object_key) + ", " + + (response_expected ? "wait response" : "one way") + + " addressed by " + " method " + AddressingDisposition + "." + + contexts(); + } + + /** + * Write the header to the given stream. + * + * @param out a stream to write into. + */ + public void write(AbstractCdrOutput out) + { + out.write_ulong(request_id); + + out.write(response_flags); + + // Skip 3 reserved octets: + out.write(0); + out.write(0); + out.write(0); + + // Write addressing disposition from IOR. + // TODO FIXME add other addressing methods. + out.write_ushort(KeyAddr); + + out.write_sequence(object_key); + + out.write_string(operation); + + ServiceContext.writeSequence(out, service_context); + + // No requesting principal in this new format. + out.setCodeSet(CodeSetServiceContext.find(service_context)); + } +} diff --git a/libjava/classpath/gnu/CORBA/GeneralHolder.java b/libjava/classpath/gnu/CORBA/GeneralHolder.java new file mode 100644 index 000000000..d4550bf68 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/GeneralHolder.java @@ -0,0 +1,178 @@ +/* universalStreamable.java -- + 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.CORBA; + +import gnu.CORBA.CDR.BufferredCdrInput; +import gnu.CORBA.CDR.BufferedCdrOutput; + +import org.omg.CORBA.BAD_OPERATION; +import org.omg.CORBA.MARSHAL; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.Streamable; + +import java.io.IOException; + +/** + * This class holds the abstract binary data array of the Streamable + * being stored. It is used to insert and extract into {@link Any} objects + * that have no holder, but have the helper classes. + * Encoding/decoding then must be performed by the helper. This class is + * defined as package private because it is not idiot proof and + * must be used with care. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class GeneralHolder + implements Streamable +{ + /** + * The binary data, stored inside this holder. + */ + private BufferedCdrOutput value = new BufferedCdrOutput(); + + /** + * Create the universal holder that uses the given buffer to store the data. + */ + public GeneralHolder(BufferedCdrOutput buffer) + { + value = buffer; + } + + /** + * Reads into the internal buffer till the end of stream is + * reached. No alignment operations are performed. This operation + * normally reads from the stream, where the single value, + * stored using {@link #_write}, is written. + * + * @throws MARSHALL, if the IOException is thrown during the + * stream operation. + */ + public void _read(InputStream input) + { + try + { + if (input instanceof BufferredCdrInput) + { + BufferredCdrInput b = (BufferredCdrInput) input; + value.write(b.buffer.getBuffer()); + } + else + { + int c; + + do + { + c = input.read(); + if (c >= 0) + value.write(c); + } + while (c >= 0); + } + } + catch (IOException ex) + { + MARSHAL t = new MARSHAL(); + t.minor = Minor.Any; + t.initCause(ex); + throw t; + } + } + + /** + * The type is not known and cannot be returned. + * + * @throws BAD_OPERATION, always. + */ + public TypeCode _type() + { + BAD_OPERATION bad = new BAD_OPERATION(); + bad.minor = Minor.Inappropriate; + throw bad; + } + + /** + * Writes the binary data being stored into the given output + * stream. This operation supposes that the current stream + * position is 0 or satisfies the required alignments anyway. + * + * @throws MARSHAL if the IOExeption is thrown when writing the + * byte array. + */ + public void _write(OutputStream output) + { + try + { + value.buffer.writeTo(output); + } + catch (IOException ex) + { + MARSHAL t = new MARSHAL(); + t.minor = Minor.Any; + t.initCause(ex); + throw t; + } + } + + /** + * Get the input stream that reads the fields of the stored value. + */ + InputStream getInputStream() + { + return value.create_input_stream(); + } + + /** + * Clone. + */ + public GeneralHolder Clone() + { + try + { + BufferedCdrOutput nb = new BufferedCdrOutput(value.buffer.size()); + value.buffer.writeTo(nb); + return new GeneralHolder(nb); + } + catch (IOException ex) + { + throw new Unexpected(ex); + } + } +} diff --git a/libjava/classpath/gnu/CORBA/HolderLocator.java b/libjava/classpath/gnu/CORBA/HolderLocator.java new file mode 100644 index 000000000..edd4d2cf7 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/HolderLocator.java @@ -0,0 +1,184 @@ +/* HolderLocator.java -- + 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.CORBA; + +import org.omg.CORBA.AnyHolder; +import org.omg.CORBA.AnySeqHolder; +import org.omg.CORBA.BooleanHolder; +import org.omg.CORBA.BooleanSeqHolder; +import org.omg.CORBA.CharHolder; +import org.omg.CORBA.CharSeqHolder; +import org.omg.CORBA.DoubleHolder; +import org.omg.CORBA.DoubleSeqHolder; +import org.omg.CORBA.FixedHolder; +import org.omg.CORBA.FloatHolder; +import org.omg.CORBA.FloatSeqHolder; +import org.omg.CORBA.IntHolder; +import org.omg.CORBA.LongHolder; +import org.omg.CORBA.LongLongSeqHolder; +import org.omg.CORBA.LongSeqHolder; +import org.omg.CORBA.OctetSeqHolder; +import org.omg.CORBA.PrincipalHolder; +import org.omg.CORBA.ShortHolder; +import org.omg.CORBA.ShortSeqHolder; +import org.omg.CORBA.StringHolder; +import org.omg.CORBA.StringSeqHolder; +import org.omg.CORBA.TCKind; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.TypeCodeHolder; +import org.omg.CORBA.ULongLongSeqHolder; +import org.omg.CORBA.ULongSeqHolder; +import org.omg.CORBA.UShortSeqHolder; +import org.omg.CORBA.WCharSeqHolder; +import org.omg.CORBA.WStringSeqHolder; +import org.omg.CORBA.portable.Streamable; +import org.omg.CORBA.ObjectHolder; + +/** + * Creates the suitable holder for storing the value of the given final_type. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class HolderLocator +{ + /** + * The array, sufficiently large to use any {@link TCKind}._tk* constant as + * an index. + */ + private static final Class[] holders; + + private static final Class[] seqHolders; + + static + { + holders = new Class[32]; + holders[TCKind._tk_Principal] = PrincipalHolder.class; + holders[TCKind._tk_TypeCode] = TypeCodeHolder.class; + holders[TCKind._tk_any] = AnyHolder.class; + holders[TCKind._tk_boolean] = BooleanHolder.class; + holders[TCKind._tk_char] = CharHolder.class; + holders[TCKind._tk_double] = DoubleHolder.class; + holders[TCKind._tk_float] = FloatHolder.class; + holders[TCKind._tk_fixed] = FixedHolder.class; + holders[TCKind._tk_long] = IntHolder.class; + holders[TCKind._tk_longdouble] = DoubleHolder.class; + holders[TCKind._tk_longlong] = LongHolder.class; + holders[TCKind._tk_octet] = OctetHolder.class; + holders[TCKind._tk_short] = ShortHolder.class; + holders[TCKind._tk_string] = StringHolder.class; + holders[TCKind._tk_ulong] = IntHolder.class; + holders[TCKind._tk_ulonglong] = LongHolder.class; + holders[TCKind._tk_ushort] = ShortHolder.class; + holders[TCKind._tk_wchar] = WCharHolder.class; + holders[TCKind._tk_wstring] = WStringHolder.class; + holders[TCKind._tk_objref] = ObjectHolder.class; + + seqHolders = new Class[32]; + + seqHolders[TCKind._tk_ulonglong] = ULongLongSeqHolder.class; + seqHolders[TCKind._tk_short] = ShortSeqHolder.class; + seqHolders[TCKind._tk_octet] = OctetSeqHolder.class; + seqHolders[TCKind._tk_any] = AnySeqHolder.class; + seqHolders[TCKind._tk_long] = LongSeqHolder.class; + seqHolders[TCKind._tk_longlong] = LongLongSeqHolder.class; + seqHolders[TCKind._tk_float] = FloatSeqHolder.class; + seqHolders[TCKind._tk_double] = DoubleSeqHolder.class; + seqHolders[TCKind._tk_char] = CharSeqHolder.class; + seqHolders[TCKind._tk_boolean] = BooleanSeqHolder.class; + seqHolders[TCKind._tk_wchar] = WCharSeqHolder.class; + seqHolders[TCKind._tk_ushort] = UShortSeqHolder.class; + seqHolders[TCKind._tk_ulong] = ULongSeqHolder.class; + seqHolders[TCKind._tk_string] = StringSeqHolder.class; + seqHolders[TCKind._tk_wstring] = WStringSeqHolder.class; + } + + /** + * Create a holder for storing the value of the given built-in final_type. This + * function returns the defined holders for the built-in primitive types and + * they sequences. + * + * @param t the typecode + * + * @return an instance of the corresponding built-in holder of null if no such + * is defined for this final_type. The holder is created with a parameterless + * constructor. + */ + public static Streamable createHolder(TypeCode t) + { + try + { + int kind = t.kind().value(); + int componentKind; + + Streamable holder = null; + + if (kind < holders.length && holders[kind] != null) + holder = (Streamable) holders[kind].newInstance(); + + if (holder != null) + return holder; + + switch (kind) + { + case TCKind._tk_sequence: + componentKind = t.content_type().kind().value(); + if (componentKind < seqHolders.length) + return (Streamable) seqHolders[componentKind].newInstance(); + break; + + default: + break; + } + } + catch (Exception ex) + { + throw new Unexpected(ex); + } + + try + { + Object ox = ObjectCreator.createObject(t.id(), "Holder"); + return (Streamable) ox; + } + catch (Exception ex) + { + return null; + } + } +} diff --git a/libjava/classpath/gnu/CORBA/IOR.java b/libjava/classpath/gnu/CORBA/IOR.java new file mode 100644 index 000000000..1a476b094 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/IOR.java @@ -0,0 +1,824 @@ +/* IOR.java -- + 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.CORBA; + +import gnu.CORBA.CDR.BufferredCdrInput; +import gnu.CORBA.CDR.BufferedCdrOutput; +import gnu.CORBA.CDR.AbstractCdrInput; +import gnu.CORBA.CDR.AbstractCdrOutput; +import gnu.CORBA.GIOP.CharSets_OSF; +import gnu.CORBA.GIOP.CodeSetServiceContext; + +import gnu.java.lang.CPStringBuilder; + +import org.omg.CORBA.BAD_PARAM; +import org.omg.CORBA.CompletionStatus; +import org.omg.CORBA.MARSHAL; +import org.omg.CORBA.ULongSeqHelper; +import org.omg.IOP.TAG_INTERNET_IOP; +import org.omg.IOP.TAG_MULTIPLE_COMPONENTS; +import org.omg.IOP.TaggedComponent; +import org.omg.IOP.TaggedComponentHelper; +import org.omg.IOP.TaggedProfile; +import org.omg.IOP.TaggedProfileHelper; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.zip.Adler32; + +/** + * The implementaton of the Interoperable Object Reference (IOR). IOR can be + * compared with the Internet address for a web page, it provides means to + * locate the CORBA service on the web. IOR contains the host address, port + * number, the object identifier (key) inside the server, the communication + * protocol version, supported charsets and so on. + * + * Ths class provides method for encoding and decoding the IOR information + * from/to the stringified references, usually returned by + * {@link org.omg.CORBA.ORB#String object_to_string()}. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + * + * @see org.mog.CORBA.Object.object_to_string(Object forObject) + * @see string_to_object(String IOR) + */ +public class IOR +{ + /** + * The code sets tagged component, normally part of the Internet profile. This + * compone consists of the two componenets itself. + */ + public static class CodeSets_profile + { + public CodeSets_profile() + { + int[] supported = CharSets_OSF.getSupportedCharSets(); + + narrow.native_set = CharSets_OSF.NATIVE_CHARACTER; + narrow.conversion = supported; + + wide.native_set = CharSets_OSF.NATIVE_WIDE_CHARACTER; + wide.conversion = supported; + } + + /** + * The code set component. + */ + public static class CodeSet_component + { + /** + * The conversion code sets. + */ + public int[] conversion; + + /** + * The native code set. + */ + public int native_set; + + /** + * Read from the CDR stream. + */ + public void read(org.omg.CORBA.portable.InputStream in) + { + native_set = in.read_ulong(); + conversion = ULongSeqHelper.read(in); + } + + /** + * Get a string representation. + */ + public String toString() + { + CPStringBuilder b = new CPStringBuilder(); + b.append("native " + name(native_set)); + if (conversion != null && conversion.length > 0) + { + b.append(" conversion "); + for (int i = 0; i < conversion.length; i++) + { + b.append(name(conversion[i])); + b.append(' '); + } + } + b.append(' '); + return b.toString(); + } + + /** + * Get a better formatted multiline string representation. + */ + public String toStringFormatted() + { + CPStringBuilder b = new CPStringBuilder(); + 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. + */ + public void write(org.omg.CORBA.portable.OutputStream out) + { + out.write_long(native_set); + ULongSeqHelper.write(out, conversion); + } + + private String name(int set) + { + return "0x" + Integer.toHexString(set) + " (" + + CharSets_OSF.getName(set) + ") "; + } + } + + /** + * The agreed tag for the Codesets profile. + */ + public static final int TAG_CODE_SETS = 1; + + /** + * Information about narrow character encoding (TCS-C). + */ + public CodeSet_component narrow = new CodeSet_component(); + + /** + * About wide character encoding (TCS-W). + */ + public CodeSet_component wide = new CodeSet_component(); + + /** + * The negotiated coding result for this IOR. Saves time, requred for + * negotiation computations. + */ + public CodeSetServiceContext negotiated; + + /** + * Read the code set profile information from the given input stream. + * + * @param profile a stream to read from. + */ + public void read(AbstractCdrInput profile) + { + BufferredCdrInput encapsulation = profile.read_encapsulation(); + narrow.read(encapsulation); + wide.read(encapsulation); + } + + /** + * Returns a string representation. + */ + public String toString() + { + return "Narrow char: " + narrow + ", Wide char: " + wide; + } + + /** + * Write the code set profile information into the given input stream. + * + * @param profile a stream to write into. + */ + public void write(AbstractCdrOutput profile) + { + AbstractCdrOutput encapsulation = profile.createEncapsulation(); + narrow.write(encapsulation); + wide.write(encapsulation); + try + { + encapsulation.close(); + } + catch (IOException ex) + { + throw new InternalError(); + } + } + } + + /** + * The internet profile. + */ + public class Internet_profile + { + /** + * The agreed tag for the Internet profile. + */ + public static final int TAG_INTERNET_IOP = 0; + + /** + * The host. + */ + public String host; + + /** + * The IIOP version (initialised to 1.2 by default). + */ + public Version version = new Version(1, 2); + + /** + * The port. + */ + public int port; + + /** + * The code sets component in the internet profile of this IOR. This is not + * a separate profile. + */ + public CodeSets_profile CodeSets = new CodeSets_profile(); + + /** + * Reserved for all components of this profile, this array holds the + * components other than code set components. + */ + ArrayList components = new ArrayList(); + + /** + * Return the human readable representation. + */ + public String toString() + { + CPStringBuilder b = new CPStringBuilder(); + b.append(host); + b.append(":"); + b.append(port); + b.append(" (v"); + b.append(version); + b.append(")"); + if (components.size() > 0) + b.append(" " + components.size() + " extra components."); + return b.toString(); + } + + /** + * Write the internet profile (except the heading tag. + */ + public void write(AbstractCdrOutput out) + { + try + { + // Need to write the Internet profile into the separate + // stream as we must know the size in advance. + AbstractCdrOutput b = out.createEncapsulation(); + + version.write(b); + b.write_string(host); + + b.write_ushort((short) (port & 0xFFFF)); + + // Write the object key. + b.write_long(key.length); + b.write(key); + + // Number of the tagged components. + b.write_long(1 + components.size()); + + b.write_long(CodeSets_profile.TAG_CODE_SETS); + CodeSets.write(b); + + TaggedComponent t; + + for (int i = 0; i < components.size(); i++) + { + t = (TaggedComponent) components.get(i); + TaggedComponentHelper.write(b, t); + } + + b.close(); + } + catch (Exception e) + { + MARSHAL m = new MARSHAL("Unable to write Internet profile."); + m.minor = Minor.IOR; + m.initCause(e); + throw m; + } + } + } + + /** + * The standard minor code, indicating that the string to object converstio + * has failed due non specific reasons. + */ + public static final int FAILED = 10; + + /** + * The internet profile of this IOR. + */ + public Internet_profile Internet = new Internet_profile(); + + /** + * The object repository Id. + */ + public String Id; + + /** + * The object key. + */ + public byte[] key; + + /** + * All tagged profiles of this IOR, except the separately defined Internet + * profile. + */ + ArrayList profiles = new ArrayList(); + + /** + * True if the profile was encoded using the Big Endian or the encoding is not + * known. + * + * false if it was encoded using the Little Endian. + */ + public boolean Big_Endian = true; + + /** + * Create an empty instance, initialising the code sets to default values. + */ + public IOR() + { + } + + /** + * Parse the provided stringifed reference. + * + * @param stringified_reference in the form of IOR:nnnnnn..... + * + * @return the parsed IOR + * + * @throws BAD_PARAM, minor code 10, if the IOR cannot be parsed. + * + * TODO corballoc and other alternative formats. + */ + public static IOR parse(String stringified_reference) + throws BAD_PARAM + { + try + { + if (!stringified_reference.startsWith("IOR:")) + throw new BAD_PARAM("The string refernce must start with IOR:", + FAILED, CompletionStatus.COMPLETED_NO); + + IOR r = new IOR(); + + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + String x = stringified_reference; + x = x.substring(x.indexOf(":") + 1); + + char cx; + + for (int i = 0; i < x.length(); i = i + 2) + { + cx = (char) Integer.parseInt(x.substring(i, i + 2), 16); + buf.write(cx); + } + + BufferredCdrInput cdr = new BufferredCdrInput(buf.toByteArray()); + + r._read(cdr); + return r; + } + catch (Exception ex) + { + ex.printStackTrace(); + throw new BAD_PARAM(ex + " while parsing " + stringified_reference, + FAILED, CompletionStatus.COMPLETED_NO); + } + } + + /** + * Read the IOR from the provided input stream. + * + * @param c a stream to read from. + * @throws IOException if the stream throws it. + */ + public void _read(AbstractCdrInput c) + throws IOException, BAD_PARAM + { + int endian; + + endian = c.read_long(); + if (endian != 0) + { + Big_Endian = false; + c.setBigEndian(false); + } + _read_no_endian(c); + } + + /** + * Read the IOR from the provided input stream, not reading the endian data at + * the beginning of the stream. The IOR is thansferred in this form in + * {@link write_Object(org.omg.CORBA.Object)}. + * + * If the stream contains a null value, the Id and Internet fields become + * equal to null. Otherwise Id contains some string (possibly empty). + * + * Id is checked for null in AbstractCdrInput that then returns null instead of + * object. + * + * @param c a stream to read from. + * @throws IOException if the stream throws it. + */ + public void _read_no_endian(AbstractCdrInput c) + throws IOException, BAD_PARAM + { + Id = c.read_string(); + + int n_profiles = c.read_long(); + + if (n_profiles == 0) + { + Id = null; + Internet = null; + return; + } + + for (int i = 0; i < n_profiles; i++) + { + int tag = c.read_long(); + BufferredCdrInput profile = c.read_encapsulation(); + + if (tag == Internet_profile.TAG_INTERNET_IOP) + { + Internet = new Internet_profile(); + Internet.version = Version.read_version(profile); + Internet.host = profile.read_string(); + Internet.port = profile.gnu_read_ushort(); + + key = profile.read_sequence(); + + // Read tagged components. + int n_components = 0; + + try + { + if (Internet.version.since_inclusive(1, 1)) + n_components = profile.read_long(); + + for (int t = 0; t < n_components; t++) + { + int ctag = profile.read_long(); + + if (ctag == CodeSets_profile.TAG_CODE_SETS) + { + Internet.CodeSets.read(profile); + } + else + { + // Construct a generic component for codesets + // profile. + TaggedComponent pc = new TaggedComponent(); + pc.tag = ctag; + pc.component_data = profile.read_sequence(); + Internet.components.add(pc); + } + } + } + catch (Unexpected ex) + { + ex.printStackTrace(); + } + } + else + { + // Construct a generic profile. + TaggedProfile p = new TaggedProfile(); + p.tag = tag; + p.profile_data = profile.buffer.getBuffer(); + + profiles.add(p); + } + } + } + + /** + * Write this IOR record to the provided CDR stream. This procedure writes the + * zero (Big Endian) marker first. + */ + public void _write(AbstractCdrOutput out) + { + // Always use Big Endian. + out.write(0); + _write_no_endian(out); + } + + /** + * Write a null value to the CDR output stream. + * + * The null value is written as defined in OMG specification (zero length + * string, followed by an empty set of profiles). + */ + public static void write_null(AbstractCdrOutput out) + { + // Empty Id string. + out.write_string(""); + + // Empty set of profiles. + out.write_long(0); + } + + /** + * Write this IOR record to the provided CDR stream. The procedure writed data + * in Big Endian, but does NOT add any endian marker to the beginning. + */ + public void _write_no_endian(AbstractCdrOutput out) + { + // Write repository id. + out.write_string(Id); + + out.write_long(1 + profiles.size()); + + // Write the Internet profile. + out.write_long(Internet_profile.TAG_INTERNET_IOP); + Internet.write(out); + + // Write other profiles. + TaggedProfile tp; + + for (int i = 0; i < profiles.size(); i++) + { + tp = (TaggedProfile) profiles.get(i); + TaggedProfileHelper.write(out, tp); + } + } + + /** + * Returns a human readable string representation of this IOR object. + */ + public String toString() + { + CPStringBuilder b = new CPStringBuilder(); + b.append(Id); + b.append(" at "); + b.append(Internet); + + if (!Big_Endian) + b.append(" (Little endian) "); + + b.append(" Key "); + + for (int i = 0; i < key.length; i++) + { + b.append(Integer.toHexString(key[i] & 0xFF)); + } + + b.append(" "); + b.append(Internet.CodeSets); + + return b.toString(); + } + + /** + * Returns a multiline formatted human readable string representation of + * this IOR object. + */ + public String toStringFormatted() + { + CPStringBuilder b = new CPStringBuilder(); + 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. + * + * @return a newly constructed stringified reference. + */ + public String toStringifiedReference() + { + BufferedCdrOutput out = new BufferedCdrOutput(); + + _write(out); + + CPStringBuilder b = new CPStringBuilder("IOR:"); + + byte[] binary = out.buffer.toByteArray(); + String s; + + for (int i = 0; i < binary.length; i++) + { + s = Integer.toHexString(binary[i] & 0xFF); + if (s.length() == 1) + b.append('0'); + b.append(s); + } + + return b.toString(); + } + + /** + * Adds a service-specific component to the IOR profile. The specified + * component will be included in all profiles, present in the IOR. + * + * @param tagged_component a tagged component being added. + */ + public void add_ior_component(TaggedComponent tagged_component) + { + // Add to the Internet profile. + Internet.components.add(tagged_component); + + // Add to others. + for (int i = 0; i < profiles.size(); i++) + { + TaggedProfile profile = (TaggedProfile) profiles.get(i); + addComponentTo(profile, tagged_component); + } + } + + /** + * Adds a service-specific component to the IOR profile. + * + * @param tagged_component a tagged component being added. + * + * @param profile_id the IOR profile to that the component must be added. The + * 0 value ({@link org.omg.IOP.TAG_INTERNET_IOP#value}) adds to the Internet + * profile where host and port are stored by default. + */ + public void add_ior_component_to_profile(TaggedComponent tagged_component, + int profile_id) + { + if (profile_id == TAG_INTERNET_IOP.value) + // Add to the Internet profile + Internet.components.add(tagged_component); + else + { + // Add to others. + for (int i = 0; i < profiles.size(); i++) + { + TaggedProfile profile = (TaggedProfile) profiles.get(i); + if (profile.tag == profile_id) + addComponentTo(profile, tagged_component); + } + } + } + + /** + * Add given component to the given profile that is NOT an Internet profile. + * + * @param profile the profile, where the component should be added. + * @param component the component to add. + */ + private static void addComponentTo(TaggedProfile profile, + TaggedComponent component) + { + if (profile.tag == TAG_MULTIPLE_COMPONENTS.value) + { + TaggedComponent[] present; + if (profile.profile_data.length > 0) + { + BufferredCdrInput in = new BufferredCdrInput(profile.profile_data); + + present = new TaggedComponent[in.read_long()]; + + for (int i = 0; i < present.length; i++) + { + present[i] = TaggedComponentHelper.read(in); + } + } + else + present = new TaggedComponent[0]; + + BufferedCdrOutput out = new BufferedCdrOutput(profile.profile_data.length + + component.component_data.length + + 8); + + // Write new amount of components. + out.write_long(present.length + 1); + + // Write other components. + for (int i = 0; i < present.length; i++) + TaggedComponentHelper.write(out, present[i]); + + // Write the passed component. + TaggedComponentHelper.write(out, component); + + try + { + out.close(); + } + catch (IOException e) + { + throw new Unexpected(e); + } + profile.profile_data = out.buffer.toByteArray(); + } + else + // The future supported tagged profiles should be added here. + throw new BAD_PARAM("Unsupported profile type " + profile.tag); + } + + /** + * Checks for equality. + */ + public boolean equals(Object x) + { + if (x instanceof IOR) + { + boolean keys; + boolean hosts = true; + + IOR other = (IOR) x; + + if (Internet==null || other.Internet==null) + return Internet == other.Internet; + + if (key != null && other.key != null) + keys = Arrays.equals(key, other.key); + else + keys = key == other.key; + + if (Internet != null && Internet.host != null) + if (other.Internet != null && other.Internet.host != null) + hosts = other.Internet.host.equals(Internet.host); + + return keys & hosts && Internet.port==other.Internet.port; + } + else + return false; + } + + /** + * Get the hashcode of this IOR. + */ + public int hashCode() + { + Adler32 adler = new Adler32(); + if (key != null) + adler.update(key); + if (Internet != null) + { + if (Internet.host != null) + adler.update(Internet.host.getBytes()); + adler.update(Internet.port); + } + return (int) adler.getValue(); + } +} diff --git a/libjava/classpath/gnu/CORBA/Interceptor/ClientRequestInterceptors.java b/libjava/classpath/gnu/CORBA/Interceptor/ClientRequestInterceptors.java new file mode 100644 index 000000000..783e321d7 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Interceptor/ClientRequestInterceptors.java @@ -0,0 +1,139 @@ +/* ClientRequestInterceptors.java -- + 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.CORBA.Interceptor; + +import org.omg.PortableInterceptor.ClientRequestInfo; +import org.omg.PortableInterceptor.ClientRequestInterceptor; +import org.omg.PortableInterceptor.ClientRequestInterceptorOperations; +import org.omg.PortableInterceptor.ForwardRequest; + +/** + * A block of the all registered ClientRequest interceptors. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class ClientRequestInterceptors + implements ClientRequestInterceptorOperations +{ + /** + * The array of all registered ClientRequest interceptors. + */ + private final ClientRequestInterceptor[] interceptors; + + /** + * Create the interceptor pack with the registerend interceptor array, + * obtained from the registrator. + */ + public ClientRequestInterceptors(Registrator registrator) + { + interceptors = registrator.getClientRequestInterceptors(); + } + + /** @inheritDoc */ + public void receive_exception(ClientRequestInfo info) + throws ForwardRequest + { + for (int i = 0; i < interceptors.length; i++) + { + interceptors [ i ].receive_exception(info); + } + } + + /** @inheritDoc */ + public void receive_other(ClientRequestInfo info) throws ForwardRequest + { + for (int i = 0; i < interceptors.length; i++) + { + interceptors [ i ].receive_other(info); + } + } + + /** @inheritDoc */ + public void receive_reply(ClientRequestInfo info) + { + for (int i = 0; i < interceptors.length; i++) + { + interceptors [ i ].receive_reply(info); + } + } + + /** @inheritDoc */ + public void send_poll(ClientRequestInfo info) + { + for (int i = 0; i < interceptors.length; i++) + { + interceptors [ i ].send_poll(info); + } + } + + /** @inheritDoc */ + public void send_request(ClientRequestInfo info) throws ForwardRequest + { + for (int i = 0; i < interceptors.length; i++) + { + interceptors [ i ].send_request(info); + } + } + + /** + * Call destroy on all registered interceptors. + */ + public void destroy() + { + for (int i = 0; i < interceptors.length; i++) + { + try + { + interceptors [ i ].destroy(); + } + catch (Exception exc) + { + // OMG states we should ignore. + } + } + } + + /** + * Get the class name. + */ + public String name() + { + return getClass().getName(); + } +} diff --git a/libjava/classpath/gnu/CORBA/Interceptor/ForwardRequestHolder.java b/libjava/classpath/gnu/CORBA/Interceptor/ForwardRequestHolder.java new file mode 100644 index 000000000..a250ceaa1 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Interceptor/ForwardRequestHolder.java @@ -0,0 +1,106 @@ +/* ForwardRequestHolder.java -- + 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.CORBA.Interceptor; + +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.Streamable; +import org.omg.PortableInterceptor.ForwardRequest; +import org.omg.PortableInterceptor.ForwardRequestHelper; + +/** + * A holder for the exception {@link ForwardRequest}. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class ForwardRequestHolder implements Streamable +{ + /** + * The stored ForwardRequest value. + */ + public ForwardRequest value; + + /** + * Create the unitialised instance, leaving the value field with default + * null value. + */ + public ForwardRequestHolder() + { + } + + /** + * Create the initialised instance. + * + * @param initialValue the value that will be assigned to the + * value field. + */ + public ForwardRequestHolder(ForwardRequest initialValue) + { + value = initialValue; + } + + /** + * Fill in the {@link value} by data from the CDR stream. + * + * @param input the org.omg.CORBA.portable stream to read. + */ + public void _read(InputStream input) + { + value = ForwardRequestHelper.read(input); + } + + /** + * Write the stored value into the CDR stream. + * + * @param output the org.omg.CORBA.portable stream to write. + */ + public void _write(OutputStream output) + { + ForwardRequestHelper.write(output, value); + } + + /** + * Get the typecode of the ForwardRequest. + */ + public TypeCode _type() + { + return ForwardRequestHelper.type(); + } +} diff --git a/libjava/classpath/gnu/CORBA/Interceptor/IORInterceptors.java b/libjava/classpath/gnu/CORBA/Interceptor/IORInterceptors.java new file mode 100644 index 000000000..67474c173 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Interceptor/IORInterceptors.java @@ -0,0 +1,189 @@ +/* IORInterceptors.java -- + 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.CORBA.Interceptor; + +import org.omg.CORBA.OBJ_ADAPTER; +import org.omg.CORBA.OMGVMCID; +import org.omg.PortableInterceptor.IORInfo; +import org.omg.PortableInterceptor.IORInterceptor; +import org.omg.PortableInterceptor.IORInterceptor_3_0Operations; +import org.omg.PortableInterceptor.ObjectReferenceTemplate; + +/** + * A block of the all registered IOR interceptors. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class IORInterceptors implements IORInterceptor_3_0Operations +{ + /** + * The array of all registered IOR interceptors. + */ + private final IORInterceptor[] interceptors; + + /** + * Create the interceptor pack with the registerend interceptor array, + * obtained from the registrator. + */ + public IORInterceptors(Registrator registrator) + { + interceptors = registrator.getIORInterceptors(); + } + + /** + * Call this method for all registered interceptors. + */ + public void establish_components(IORInfo info) + { + for (int i = 0; i < interceptors.length; i++) + { + try + { + interceptors [ i ].establish_components(info); + } + catch (Exception exc) + { + // OMG states we should ignore. + } + } + } + + /** + * Call destroy on all registered interceptors. + */ + public void destroy() + { + for (int i = 0; i < interceptors.length; i++) + { + try + { + interceptors [ i ].destroy(); + } + catch (Exception exc) + { + // OMG states we should ignore. + } + } + } + + /** + * Get the class name. + */ + public String name() + { + return getClass().getName(); + } + + /** + * Call this method for all registered CORBA 3.0 interceptors. + */ + public void adapter_manager_state_changed(int adapterManagerId, short adapterState) + { + for (int i = 0; i < interceptors.length; i++) + { + try + { + if (interceptors[i] instanceof IORInterceptor_3_0Operations) + { + ((IORInterceptor_3_0Operations) interceptors[i]). + adapter_manager_state_changed(adapterManagerId, adapterState); + } + } + catch (Exception exc) + { + OBJ_ADAPTER oa = new OBJ_ADAPTER("components_established failed"); + oa.initCause(exc); + oa.minor = 6 | OMGVMCID.value; + throw oa; + } + } + } + + /** + * Call this method for all registered CORBA 3.0 interceptors. + */ + public void adapter_state_changed(ObjectReferenceTemplate[] adapters, short adaptersState) + { + for (int i = 0; i < interceptors.length; i++) + { + try + { + if (interceptors[i] instanceof IORInterceptor_3_0Operations) + { + ((IORInterceptor_3_0Operations) interceptors[i]). + adapter_state_changed(adapters, adaptersState); + } + } + catch (Exception exc) + { + OBJ_ADAPTER oa = new OBJ_ADAPTER("components_established failed"); + oa.initCause(exc); + oa.minor = 6 | OMGVMCID.value; + throw oa; + } + } + } + + /** + * Call this method for all registered CORBA 3.0 interceptors. + * + * @throws OBJ_ADAPTER minor 6 on any failure (as defined by OMG specs). + */ + public void components_established(IORInfo info) + { + for (int i = 0; i < interceptors.length; i++) + { + try + { + if (interceptors[i] instanceof IORInterceptor_3_0Operations) + { + ((IORInterceptor_3_0Operations) interceptors[i]). + components_established(info); + } + } + catch (Exception exc) + { + OBJ_ADAPTER oa = new OBJ_ADAPTER("components_established failed"); + oa.initCause(exc); + oa.minor = 6 | OMGVMCID.value; + throw oa; + } + } + } +} diff --git a/libjava/classpath/gnu/CORBA/Interceptor/Registrator.java b/libjava/classpath/gnu/CORBA/Interceptor/Registrator.java new file mode 100644 index 000000000..23ae54a10 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Interceptor/Registrator.java @@ -0,0 +1,472 @@ +/* Registrator.java -- + 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.CORBA.Interceptor; + +import gnu.CORBA.Poa.ORB_1_4; +import gnu.CORBA.ObjectCreator; +import gnu.CORBA.gnuCodecFactory; + +import org.omg.CORBA.BAD_INV_ORDER; +import org.omg.CORBA.CompletionStatus; +import org.omg.CORBA.LocalObject; +import org.omg.CORBA.Object; +import org.omg.IOP.CodecFactory; +import org.omg.PortableInterceptor.ClientRequestInterceptor; +import org.omg.PortableInterceptor.IORInterceptor; +import org.omg.PortableInterceptor.Interceptor; +import org.omg.PortableInterceptor.ORBInitInfo; +import org.omg.PortableInterceptor.ORBInitInfoPackage.DuplicateName; +import org.omg.PortableInterceptor.ORBInitInfoPackage.InvalidName; +import org.omg.PortableInterceptor.ORBInitializer; +import org.omg.PortableInterceptor.ORBInitializerOperations; +import org.omg.PortableInterceptor.PolicyFactory; +import org.omg.PortableInterceptor.ServerRequestInterceptor; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; + +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; +import java.util.TreeMap; + +/** + * Collects interceptors, references and factories into arrays during + * registration. As the class is security sensitive, the most of the fields are + * private. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class Registrator extends LocalObject implements ORBInitInfo +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * The agreed properties prefix. + */ + public static final String m_prefix = + "org.omg.PortableInterceptor.ORBInitializerClass."; + + /** + * The initialization - time server request interceptors. + */ + private ArrayList m_server = new ArrayList(); + + /** + * The initialization - time client request interceptors. + */ + private ArrayList m_client = new ArrayList(); + + /** + * The initialization - time ior interceptors. + */ + private ArrayList m_ior = new ArrayList(); + + /** + * The policy factories. + */ + public Hashtable m_policyFactories = new Hashtable(); + + /** + * The registered references. To avoid exposing the ORB's references map, the + * are added by ORB from inside the ORB code. The ORB is responsible for + * taking them from this field between pre_init and post_init. + */ + public TreeMap m_references = new TreeMap(); + + /** + * The initializers. + */ + public ArrayList m_initializers = new ArrayList(); + + /** + * The ORB being intialised. + */ + final ORB_1_4 orb; + + /** + * The argument string array, passed to ORB.init. + */ + final String[] m_args; + + /** + * The codec factory. + */ + final gnuCodecFactory m_codecFactory; + + /** + * Create the interceptor collection from the given properties, using the + * agreed naming convention. + * + * @param an_orb the ORB being initialised. + * @param props the cumulated set of properties where the orb initializer + * pattern is searched. + * @param an_args the argument string array, passed to ORB.init. + */ + public Registrator(ORB_1_4 an_orb, Properties props, String[] an_args) + { + orb = an_orb; + m_args = an_args; + m_codecFactory = new gnuCodecFactory(orb); + checkProperties(props); + checkProperties(System.getProperties()); + checkFile("user.home", null); + checkFile("java.home", "lib"); + } + + /** + * Scan the given properties for the possible interceptors. + */ + private void checkProperties(Properties props) + { + if (props == null) + { + return; + } + + Enumeration names = props.propertyNames(); + java.lang.Object key; + String sk; + + while (names.hasMoreElements()) + { + key = names.nextElement(); + if (key != null) + { + sk = key.toString(); + if (sk.startsWith(m_prefix)) + { + try + { + String cn = sk.substring(m_prefix.length()); + Class iClass = ObjectCreator.forName(cn); + + ORBInitializer initializer = + (ORBInitializer) iClass.newInstance(); + m_initializers.add(initializer); + } + catch (Exception exc) + { + // OMG states we should not throw an exception, but + // this will help the user to detect his error + // in initialiser properties. Should never print during + // normal run. + System.err.println(sk + " failed"); + } + } + } + } + } + + /** + * Check if the property is defined in the existsting file orb.properties. + */ + private void checkFile(String dir, String subdir) + { + try + { + File f = new File(dir); + if (!f.exists()) + { + return; + } + + if (subdir != null) + { + f = new File(f, subdir); + } + f = new File(f, "orb.properties"); + + if (!f.exists()) + { + return; + } + + Properties p = new Properties(); + p.load(new BufferedInputStream(new FileInputStream(f))); + + checkProperties(p); + } + catch (IOException ex) + { + } + } + + /** + * Called by ORB as a pre_init for all initializers. + */ + public void pre_init() + { + Iterator iter = m_initializers.iterator(); + while (iter.hasNext()) + { + ORBInitializerOperations initializer = + (ORBInitializerOperations) iter.next(); + initializer.pre_init(this); + } + } + + /** + * Get the map of the registered references. The ORB calls this method to + * import the references into its references map. + */ + public Map getRegisteredReferences() + { + return m_references; + } + + /** + * Called by ORB as a post-init for all initializers. After this call, the + * interceptor sets are fixed and redundant information is discarded. + */ + public void post_init() + { + Iterator iter = m_initializers.iterator(); + while (iter.hasNext()) + { + ORBInitializerOperations initializer = + (ORBInitializerOperations) iter.next(); + initializer.post_init(this); + } + } + + public ServerRequestInterceptor[] getServerRequestInterceptors() + { + ServerRequestInterceptor[] iServer = + new ServerRequestInterceptor[ m_server.size() ]; + for (int i = 0; i < iServer.length; i++) + { + iServer [ i ] = (ServerRequestInterceptor) m_server.get(i); + } + return iServer; + } + + public ClientRequestInterceptor[] getClientRequestInterceptors() + { + ClientRequestInterceptor[] iClient = + new ClientRequestInterceptor[ m_client.size() ]; + for (int i = 0; i < iClient.length; i++) + { + iClient [ i ] = (ClientRequestInterceptor) m_client.get(i); + } + return iClient; + } + + public IORInterceptor[] getIORInterceptors() + { + IORInterceptor[] iIor = new IORInterceptor[ m_ior.size() ]; + for (int i = 0; i < iIor.length; i++) + { + iIor [ i ] = (IORInterceptor) m_ior.get(i); + } + return iIor; + } + + public void add_client_request_interceptor( + ClientRequestInterceptor interceptor + ) throws DuplicateName + { + add(m_client, interceptor); + } + + public void add_ior_interceptor(IORInterceptor interceptor) + throws DuplicateName + { + add(m_ior, interceptor); + } + + public void add_server_request_interceptor( + ServerRequestInterceptor interceptor + ) throws DuplicateName + { + add(m_server, interceptor); + } + + /** + * Allocate a new slot for request - specific records. + */ + public int allocate_slot_id() + { + return orb.icSlotSize++; + } + + /** + * Add the interceptor to the given collection. + * + * @param list the collection to add. + * @param interceptor the interceptor to add. + */ + private void add(ArrayList list, Interceptor interceptor) + throws DuplicateName + { + if (interceptor.name().length() > 0) + { + Iterator iter = list.iterator(); + Interceptor ic; + + while (iter.hasNext()) + { + ic = (Interceptor) iter.next(); + if (ic.name().equals(interceptor.name())) + { + throw new DuplicateName(interceptor.name()); + } + } + } + list.add(interceptor); + } + + /** + * Get string array, passed to ORB.init. + */ + public String[] arguments() + { + return m_args; + } + + /** + * Get the codec factory. + */ + public CodecFactory codec_factory() + { + return m_codecFactory; + } + + /** + * Get the ORB's id, currently using .toString. + */ + public String orb_id() + { + return "orb_" + orb; + } + + /** + * Register reference. + */ + public void register_initial_reference(String object_name, Object object) + throws InvalidName + { + if (object_name == null) + { + throw new InvalidName("null"); + } + else if (object_name.length() == 0) + { + throw new InvalidName("Empty string"); + } + else if (m_references.containsKey(object_name)) + { + throw new InvalidName(object_name); + } + else + { + m_references.put(object_name, object); + } + } + + /** + * Accumulates the policy factory map. + */ + public void register_policy_factory(int policy_type, + PolicyFactory policy_factory + ) + { + Integer it = new Integer(policy_type); + if (m_policyFactories.containsKey(it)) + { + throw new BAD_INV_ORDER( + "Repetetive registration of the policy factory for type " + + policy_type, + 16, + CompletionStatus.COMPLETED_NO + ); + } + m_policyFactories.put(it, policy_factory); + } + + /** + * Delegates to ORB. + */ + public org.omg.CORBA.Object resolve_initial_references(String object_name) + throws InvalidName + { + try + { + return orb.resolve_initial_references(object_name); + } + catch (org.omg.CORBA.ORBPackage.InvalidName e) + { + InvalidName in = new InvalidName(e.getMessage()); + in.initCause(e); + throw in; + } + } + + /** + * Check if any interceptors of this type were registered. + */ + public boolean hasClientRequestInterceptors() + { + return m_client.size() > 0; + } + + /** + * Check if any interceptors of this type were registered. + */ + public boolean hasServerRequestInterceptors() + { + return m_server.size() > 0; + } + + /** + * Check if any interceptors of this type were registered. + */ + public boolean hasIorInterceptors() + { + return m_ior.size() > 0; + } +} diff --git a/libjava/classpath/gnu/CORBA/Interceptor/ServerRequestInterceptors.java b/libjava/classpath/gnu/CORBA/Interceptor/ServerRequestInterceptors.java new file mode 100644 index 000000000..5cb5b1ab4 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Interceptor/ServerRequestInterceptors.java @@ -0,0 +1,139 @@ +/* ServerRequestInterceptors.java -- + 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.CORBA.Interceptor; + +import org.omg.PortableInterceptor.ForwardRequest; +import org.omg.PortableInterceptor.ServerRequestInfo; +import org.omg.PortableInterceptor.ServerRequestInterceptor; +import org.omg.PortableInterceptor.ServerRequestInterceptorOperations; + +/** + * A block of the all registered ServerRequest interceptors. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class ServerRequestInterceptors + implements ServerRequestInterceptorOperations +{ + /** + * The array of all registered ServerRequest interceptors. + */ + private final ServerRequestInterceptor[] interceptors; + + /** + * Create the interceptor pack with the registerend interceptor array, + * obtained from the registrator. + */ + public ServerRequestInterceptors(Registrator registrator) + { + interceptors = registrator.getServerRequestInterceptors(); + } + + /** @inheritDoc */ + public void receive_request_service_contexts(ServerRequestInfo info) + throws ForwardRequest + { + for (int i = 0; i < interceptors.length; i++) + { + interceptors [ i ].receive_request_service_contexts(info); + } + } + + /** @inheritDoc */ + public void receive_request(ServerRequestInfo info) throws ForwardRequest + { + for (int i = 0; i < interceptors.length; i++) + { + interceptors [ i ].receive_request(info); + } + } + + /** @inheritDoc */ + public void send_exception(ServerRequestInfo info) throws ForwardRequest + { + for (int i = 0; i < interceptors.length; i++) + { + interceptors [ i ].send_exception(info); + } + } + + /** @inheritDoc */ + public void send_other(ServerRequestInfo info) throws ForwardRequest + { + for (int i = 0; i < interceptors.length; i++) + { + interceptors [ i ].send_other(info); + } + } + + /** @inheritDoc */ + public void send_reply(ServerRequestInfo info) + { + for (int i = 0; i < interceptors.length; i++) + { + interceptors [ i ].send_reply(info); + } + } + + /** + * Call destroy on all registered interceptors. + */ + public void destroy() + { + for (int i = 0; i < interceptors.length; i++) + { + try + { + interceptors [ i ].destroy(); + } + catch (Exception exc) + { + // OMG states we should ignore. + } + } + } + + /** + * Get the class name. + */ + public String name() + { + return getClass().getName(); + } +} diff --git a/libjava/classpath/gnu/CORBA/Interceptor/gnuClientRequestInfo.java b/libjava/classpath/gnu/CORBA/Interceptor/gnuClientRequestInfo.java new file mode 100644 index 000000000..226e7f316 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Interceptor/gnuClientRequestInfo.java @@ -0,0 +1,337 @@ +/* gnuClientRequestInfo.java -- + 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.CORBA.Interceptor; + +import gnu.CORBA.Unexpected; +import gnu.CORBA.gnuRequest; + +import org.omg.CORBA.ARG_IN; +import org.omg.CORBA.ARG_INOUT; +import org.omg.CORBA.ARG_OUT; +import org.omg.CORBA.Any; +import org.omg.CORBA.BAD_PARAM; +import org.omg.CORBA.Bounds; +import org.omg.CORBA.ExceptionList; +import org.omg.CORBA.INV_POLICY; +import org.omg.CORBA.LocalObject; +import org.omg.CORBA.NVList; +import org.omg.CORBA.ORB; +import org.omg.CORBA.ParameterMode; +import org.omg.CORBA.Policy; +import org.omg.CORBA.TCKind; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.TypeCodePackage.BadKind; +import org.omg.Dynamic.Parameter; +import org.omg.IOP.ServiceContext; +import org.omg.IOP.TaggedComponent; +import org.omg.IOP.TaggedProfile; +import org.omg.PortableInterceptor.ClientRequestInfo; +import org.omg.PortableInterceptor.InvalidSlot; + +/** + * Client request info. All requests on the client side in Classpath + * implementations are handled via gnuRequest class. This class holds the + * instance of the gnuRequest, accessing the request info this way. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class gnuClientRequestInfo extends LocalObject + implements ClientRequestInfo +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * The request structure, from that some methods take the needed information + * directly. The same request structure cannot be reused in parallel threads, + * the submission methods are synchronized. + */ + private final gnuRequest request; + + /** + * Provides possibility to set the wrapped thrown exception explicitly, where + * applicable. + */ + public Any m_wrapped_exception; + + /** + * Create the info on the given request. + */ + public gnuClientRequestInfo(gnuRequest a_request) + { + request = a_request; + } + + /** @inheritDoc */ + public void add_request_service_context(ServiceContext service_context, + boolean replace + ) + { + request.add_request_service_context(service_context, replace); + } + + /** @inheritDoc */ + public TaggedProfile effective_profile() + { + return request.effective_profile(); + } + + /** @inheritDoc */ + public org.omg.CORBA.Object effective_target() + { + return request.effective_target(); + } + + /** @inheritDoc */ + public TaggedComponent get_effective_component(int id) + throws BAD_PARAM + { + return request.get_effective_component(id); + } + + /** @inheritDoc */ + public TaggedComponent[] get_effective_components(int id) + throws BAD_PARAM + { + return request.get_effective_components(id); + } + + /** @inheritDoc */ + public Policy get_request_policy(int type) throws INV_POLICY + { + return request.get_request_policy(type); + } + + /** @inheritDoc */ + public String received_exception_id() + { + try + { + if (m_wrapped_exception != null) + { + return m_wrapped_exception.type().id(); + } + else + { + return request.received_exception_id(); + } + } + catch (BadKind e) + { + throw new Unexpected(e); + } + } + + /** @inheritDoc */ + public Any received_exception() + { + if (m_wrapped_exception != null) + { + return m_wrapped_exception; + } + else + { + return request.received_exception(); + } + } + + /** @inheritDoc */ + public org.omg.CORBA.Object target() + { + return request.target(); + } + + /** @inheritDoc */ + public Parameter[] arguments() + { + request.checkDii(); + + NVList args = request.arguments(); + Parameter[] p = new Parameter[ args.count() ]; + try + { + for (int i = 0; i < p.length; i++) + { + ParameterMode mode; + + switch (args.item(i).flags()) + { + case ARG_IN.value : + mode = ParameterMode.PARAM_IN; + break; + + case ARG_OUT.value : + mode = ParameterMode.PARAM_OUT; + break; + + case ARG_INOUT.value : + mode = ParameterMode.PARAM_INOUT; + break; + + default : + throw new Unexpected(); + } + + p [ i ] = new Parameter(args.item(i).value(), mode); + } + } + catch (Bounds e) + { + throw new Unexpected(e); + } + return p; + } + + /** @inheritDoc */ + public Any result() + { + request.checkDii(); + + Any rt = request.return_value(); + + if (rt == null) + { + ORB orb = request.orb(); + rt = orb.create_any(); + rt.type(orb.get_primitive_tc(TCKind.tk_void)); + return rt; + } + + return request.return_value(); + } + + /** @inheritDoc */ + public String[] contexts() + { + return request.ice_contexts(); + } + + /** @inheritDoc */ + public TypeCode[] exceptions() + { + request.checkDii(); + + ExceptionList ex = request.exceptions(); + TypeCode[] et = new TypeCode[ ex.count() ]; + try + { + for (int i = 0; i < et.length; i++) + { + et [ i ] = ex.item(i); + } + } + catch (Bounds e) + { + throw new Unexpected(e); + } + return et; + } + + /** @inheritDoc */ + public org.omg.CORBA.Object forward_reference() + { + return request.forward_reference(); + } + + /** @inheritDoc */ + public String[] operation_context() + { + return request.operation_context(); + } + + /** @inheritDoc */ + public Any get_slot(int id) throws InvalidSlot + { + return request.get_slot(id); + } + + /** @inheritDoc */ + public String operation() + { + return request.operation(); + } + + /** @inheritDoc */ + public short reply_status() + { + return request.reply_status(); + } + + /** @inheritDoc */ + public int request_id() + { + return request.request_id(); + } + + /** @inheritDoc */ + public boolean response_expected() + { + return request.response_expected(); + } + + /** + * Determines how far the request shall progress before control is returned to + * the client. However up till JDK 1.5 inclusive this method always returns + * SYNC_WITH_TRANSPORT. + * + * @return {@link org.omg.Messaging.SYNC_WITH_TRANSPORT.value (1), always. + * + * @specnote as defined in the Suns 1.5 JDK API. + */ + public short sync_scope() + { + return request.sync_scope(); + } + + /** @inheritDoc */ + public ServiceContext get_reply_service_context(int ctx_name) + throws BAD_PARAM + { + return request.get_reply_service_context(ctx_name); + } + + /** @inheritDoc */ + public ServiceContext get_request_service_context(int ctx_name) + throws BAD_PARAM + { + return request.get_request_service_context(ctx_name); + } +} diff --git a/libjava/classpath/gnu/CORBA/Interceptor/gnuIcCurrent.java b/libjava/classpath/gnu/CORBA/Interceptor/gnuIcCurrent.java new file mode 100644 index 000000000..caed69aeb --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Interceptor/gnuIcCurrent.java @@ -0,0 +1,255 @@ +/* gnuIcCurrent.java -- + 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.CORBA.Interceptor; + +import gnu.CORBA.CDR.BufferedCdrOutput; +import gnu.CORBA.Poa.ORB_1_4; + +import org.omg.CORBA.Any; +import org.omg.CORBA.BAD_INV_ORDER; +import org.omg.CORBA.TCKind; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.ObjectImpl; +import org.omg.PortableInterceptor.Current; +import org.omg.PortableInterceptor.CurrentHelper; +import org.omg.PortableInterceptor.InvalidSlot; + +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; + +/** + * Supports the "Interceptor current" concept, providing the slot value + * information for the current thread. When making the invocation, this + * information is copied to the Current, returned by ClientRequestInfo. + * + * There is only one instance of this class per ORB. It maintains a thread to + * information map. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class gnuIcCurrent extends ObjectImpl implements Current +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * The ORB, controllin this Current. It provides data about the required size + * of the slot array. + */ + final ORB_1_4 orb; + + /** + * The table, mapping threads to records. + */ + private Hashtable threads = new Hashtable(); + + /** + * An empty array when no slots are defined, computed once. + */ + static final Any[] NO_SLOTS = new Any[ 0 ]; + + /** + * Create the IC current. + */ + public gnuIcCurrent(ORB_1_4 an_orb) + { + orb = an_orb; + } + + /** + * Get the array of POA current repository ids. + * + * @return a single member array, containing value, returned by the + * {@link CurrentHelper#id}, normally + * "IDL:omg.org/PortableInterceptor/Current:1.0". + */ + public String[] _ids() + { + return new String[] { CurrentHelper.id() }; + } + + /** + * Add the entry to the map. + */ + public void put(Thread t, Any[] record) + { + synchronized (threads) + { + threads.put(t, record); + + // Remove non-running threads, avoiding memory leak. + if (threads.size() > 12) + { + Iterator it = threads.entrySet().iterator(); + while (it.hasNext()) + { + Map.Entry e = (Map.Entry) it.next(); + Thread tx = (Thread) e.getKey(); + if (!tx.isAlive()) + { + it.remove(); + } + } + } + } + } + + /** + * Check if this thread is registered. + */ + public boolean has(Thread t) + { + synchronized (threads) + { + return threads.containsKey(t); + } + } + + /** + * Remove the entry from the map. + */ + public void remove(Thread t) + { + synchronized (threads) + { + threads.remove(t); + } + } + + /** + * Get array of all slots, as it is applicable for the current thread. If the + * slots were not previously allocated, they are allocated during this call. + */ + Any[] get_slots() + { + Any[] r; + synchronized (threads) + { + r = (Any[]) threads.get(Thread.currentThread()); + if (r == null) + { + r = new Any[ orb.icSlotSize ]; + + for (int i = 0; i < r.length; i++) + { + Any a = orb.create_any(); + a.type(orb.get_primitive_tc(TCKind.tk_null)); + r [ i ] = a; + } + + put(Thread.currentThread(), r); + } + return r; + } + } + + /** + * Get copu array of all slots, as it is applicable for the current thread. If + * the slots were not previously allocated, they are allocated during this + * call. + */ + public Any[] clone_slots() + { + if (orb.icSlotSize == 0) + { + return NO_SLOTS; + } + else + { + Any[] r = get_slots(); + Any[] copy = new Any[ r.length ]; + + BufferedCdrOutput buf = new BufferedCdrOutput(); + buf.setOrb(orb); + + for (int i = 0; i < copy.length; i++) + { + r [ i ].write_value(buf); + } + + InputStream input = buf.create_input_stream(); + + for (int i = 0; i < copy.length; i++) + { + copy [ i ] = orb.create_any(); + copy [ i ].read_value(input, r [ i ].type()); + } + + return copy; + } + } + + /** + * Get value for the slot with the given id. If the array of Currents has not + * been yet allocated for the current thread, it is allocated during the + * invocation of this method. + */ + public Any get_slot(int slot_id) throws InvalidSlot, BAD_INV_ORDER + { + try + { + return get_slots() [ slot_id ]; + } + catch (ArrayIndexOutOfBoundsException e) + { + throw new InvalidSlot("Slot " + slot_id); + } + } + + /** + * Set value for the slot with the given id. If the array of Currents has not + * been yet allocated for the current thread, it is allocated during the + * invocation of this method. + */ + public void set_slot(int slot_id, Any data) + throws InvalidSlot, BAD_INV_ORDER + { + try + { + get_slots() [ slot_id ] = data; + } + catch (ArrayIndexOutOfBoundsException e) + { + throw new InvalidSlot("Slot " + slot_id); + } + } +} diff --git a/libjava/classpath/gnu/CORBA/Interceptor/gnuIorInfo.java b/libjava/classpath/gnu/CORBA/Interceptor/gnuIorInfo.java new file mode 100644 index 000000000..257c49728 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Interceptor/gnuIorInfo.java @@ -0,0 +1,156 @@ +/* gnuIorInfo.java -- + 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.CORBA.Interceptor; + +import gnu.CORBA.IOR; +import gnu.CORBA.Poa.ORB_1_4; +import gnu.CORBA.Poa.gnuPOA; + +import org.omg.CORBA.LocalObject; +import org.omg.CORBA.Policy; +import org.omg.IOP.TaggedComponent; +import org.omg.PortableInterceptor.IORInfo; +import org.omg.PortableInterceptor.ObjectReferenceFactory; +import org.omg.PortableInterceptor.ObjectReferenceTemplate; + +/** + * Implements IORInfo. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class gnuIorInfo extends LocalObject implements IORInfo +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * The ORB, to that the IOR is related. + */ + public final ORB_1_4 orb; + + /** + * The POA, to that IOR is related. + */ + public final gnuPOA poa; + + /** + * The IOR itself. + */ + private final IOR ior; + + /** + * Create an instance. + */ + public gnuIorInfo(ORB_1_4 an_orb, gnuPOA a_poa, IOR an_ior) + { + orb = an_orb; + poa = a_poa; + ior = an_ior; + } + + /** + * Add component to tje specified profile of this IOR. + */ + public void add_ior_component_to_profile(TaggedComponent tagged_component, + int profile_id + ) + { + ior.add_ior_component_to_profile(tagged_component, profile_id); + } + + /** + * Add component to all found profiles in this IOR. + */ + public void add_ior_component(TaggedComponent tagged_component) + { + ior.add_ior_component(tagged_component); + } + + /** + * Get the POA policy. + */ + public Policy get_effective_policy(int policy_type) + { + return poa._get_policy(policy_type); + } + + /** + * Return the state of the object POA. + */ + public short state() + { + return (short) poa.the_POAManager().get_state().value(); + } + + /** + * Get the adapter template, associated with this poa. + */ + public ObjectReferenceTemplate adapter_template() + { + return poa.getReferenceTemplate(); + } + + /** + * Get the object factory of the current POA. + */ + public ObjectReferenceFactory current_factory() + { + return poa.getReferenceFactory(); + } + + /** + * Set the object factory of the current POA. + */ + public void current_factory(ObjectReferenceFactory factory) + { + poa.setReferenceFactory(factory); + } + + /** + * The method currently uses system identity hashcode that should be + * different for each object. + */ + public int manager_id() + { + // The System.identityHashCode is also called in gnuPoaManager. + return System.identityHashCode(poa.the_POAManager()); + } +} diff --git a/libjava/classpath/gnu/CORBA/Interceptor/gnuServerRequestInfo.java b/libjava/classpath/gnu/CORBA/Interceptor/gnuServerRequestInfo.java new file mode 100644 index 000000000..03ad773d9 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Interceptor/gnuServerRequestInfo.java @@ -0,0 +1,476 @@ +/* gnuServerRequestInfo.java -- + 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.CORBA.Interceptor; + +import gnu.CORBA.GIOP.ReplyHeader; +import gnu.CORBA.GIOP.RequestHeader; +import gnu.CORBA.ObjectCreator; +import gnu.CORBA.Poa.gnuServantObject; +import gnu.CORBA.OrbFunctional; +import gnu.CORBA.Unexpected; +import gnu.CORBA.gnuRequest; + +import org.omg.CORBA.ARG_IN; +import org.omg.CORBA.ARG_INOUT; +import org.omg.CORBA.ARG_OUT; +import org.omg.CORBA.Any; +import org.omg.CORBA.BAD_PARAM; +import org.omg.CORBA.Bounds; +import org.omg.CORBA.CompletionStatus; +import org.omg.CORBA.ExceptionList; +import org.omg.CORBA.INV_POLICY; +import org.omg.CORBA.LocalObject; +import org.omg.CORBA.NO_RESOURCES; +import org.omg.CORBA.NVList; +import org.omg.CORBA.Object; +import org.omg.CORBA.ParameterMode; +import org.omg.CORBA.Policy; +import org.omg.CORBA.TCKind; +import org.omg.CORBA.TypeCode; +import org.omg.Dynamic.Parameter; +import org.omg.IOP.ServiceContext; +import org.omg.Messaging.SYNC_WITH_TRANSPORT; +import org.omg.PortableInterceptor.InvalidSlot; +import org.omg.PortableInterceptor.ServerRequestInfo; + +/** + * Implementation of the ServerRequestInfo, associacted with gnuServantObject. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class gnuServerRequestInfo extends LocalObject + implements ServerRequestInfo +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * A local object that will serve the invocation. + */ + final gnuServantObject m_object; + + /** + * A message that the given resource is not available using this metod of + * invocation. + */ + static final String not_available = + "The used invocation method provides" + "no access to this resource."; + + /** + * An array of slots. + */ + Any[] m_slots; + + /** + * The request header. + */ + public final RequestHeader m_request_header; + + /** + * The reply header. + */ + public final ReplyHeader m_reply_header; + + /** + * The forward reference, if applicable. + */ + public Object m_forward_reference; + + /** + * The thrown systen exception. + */ + public Exception m_sys_exception; + + /** + * The Any, containing the thrown user exception. + */ + public Any m_usr_exception; + + /** + * The associated request, if any. + */ + public gnuRequest m_request; + + /** + * Create a new instance at the time when it is known which object will serve + * the invocation. + * + * @param an_object a local object, connected to the local servant that will + * serve the invocation. + */ + public gnuServerRequestInfo(gnuServantObject an_object, + RequestHeader a_request_header, ReplyHeader a_reply_header + ) + { + m_object = an_object; + m_request_header = a_request_header; + m_reply_header = a_reply_header; + m_slots = new Any[ m_object.orb.icSlotSize ]; + reset(); + } + + /** + * Set the give slot. + */ + public void set_slot(int id, Any data) throws InvalidSlot + { + try + { + m_slots [ id ] = data; + } + catch (Exception e) + { + InvalidSlot ex = new InvalidSlot("Cannot set slot " + id); + ex.initCause(e); + throw ex; + } + } + + /** + * Get the given slot. + */ + public Any get_slot(int id) throws InvalidSlot + { + try + { + return m_slots [ id ]; + } + catch (Exception e) + { + InvalidSlot ex = new InvalidSlot("Cannot get slot " + id); + ex.initCause(e); + throw ex; + } + } + + /** + * Reset slot data. + */ + public void reset() + { + TypeCode tkNull = m_object.orb.get_primitive_tc(TCKind.tk_null); + for (int i = 0; i < m_slots.length; i++) + { + Any a = m_object.orb.create_any(); + a.type(tkNull); + m_slots [ i ] = a; + } + m_sys_exception = null; + m_usr_exception = null; + } + + /** + * Get the object id (not the object IOR key). + */ + public byte[] object_id() + { + return m_object.Id; + } + + /** + * Check if the target is an instance of the type, represented by the given + * repository Id. + */ + public boolean target_is_a(String id) + { + return m_object._is_a(id); + } + + /** + * Get the POA id. + */ + public byte[] adapter_id() + { + return m_object.poa.id(); + } + + /** + * Get the POA policy of the given type that applies to the object being + * served (request being handled). + */ + public Policy get_server_policy(int type) throws INV_POLICY + { + return m_object.poa._get_policy(type); + } + + /** + * Get the first member of the object repository id array. + */ + public String target_most_derived_interface() + { + return m_object._ids() [ 0 ]; + } + + /** + * Get the name of the operation being performed. + */ + public String operation() + { + if (m_request != null) + { + return m_request.operation(); + } + else + { + return m_request_header.operation; + } + } + + /** + * Not available. + */ + public TypeCode[] exceptions() + { + if (m_request == null) + { + throw new NO_RESOURCES(not_available, 1, + CompletionStatus.COMPLETED_MAYBE + ); + } + + m_request.checkDii(); + + ExceptionList ex = m_request.exceptions(); + TypeCode[] et = new TypeCode[ ex.count() ]; + try + { + for (int i = 0; i < et.length; i++) + { + et [ i ] = ex.item(i); + } + } + catch (Bounds e) + { + throw new Unexpected(e); + } + return et; + } + + /** + * Get reply status. + */ + public short reply_status() + { + return (short) m_reply_header.reply_status; + } + + /** + * Get request id. All local requests have request id = -1. + */ + public int request_id() + { + return m_request_header.request_id; + } + + /** + * Check if the client expected any response. + */ + public boolean response_expected() + { + return m_request_header.isResponseExpected(); + } + + /** @inheritDoc */ + public void add_reply_service_context(ServiceContext service_context, + boolean replace + ) + { + m_reply_header.addContext(service_context, replace); + } + + /** + * Get an exception, wrapped into Any. + */ + public Any sending_exception() + { + if (m_usr_exception != null) + { + return m_usr_exception; + } + else if (m_sys_exception != null) + { + Any a = m_object.orb.create_any(); + ObjectCreator.insertException(a, m_sys_exception); + return a; + } + else + { + return null; + } + } + + public org.omg.CORBA.Object forward_reference() + { + return m_forward_reference; + } + + /** @inheritDoc */ + public ServiceContext get_reply_service_context(int ctx_name) + throws BAD_PARAM + { + return gnu.CORBA.GIOP.ServiceContext.findContext(ctx_name, + m_reply_header.service_context + ); + } + + /** @inheritDoc */ + public ServiceContext get_request_service_context(int ctx_name) + throws BAD_PARAM + { + return gnu.CORBA.GIOP.ServiceContext.findContext(ctx_name, + m_request_header.service_context + ); + } + + /** + * Not available + */ + public String[] operation_context() + { + if (m_request == null) + { + throw new NO_RESOURCES(not_available); + } + else + { + return m_request.operation_context(); + } + } + + /** @inheritDoc */ + public Any result() + { + if (m_request == null) + { + throw new NO_RESOURCES(not_available); + } + else + { + return m_request.return_value(); + } + } + + /** @inheritDoc */ + public String[] contexts() + { + if (m_request == null) + { + throw new NO_RESOURCES(not_available); + } + else + { + return m_request.ice_contexts(); + } + } + + /** + * Always returns "with transport". + */ + public short sync_scope() + { + return SYNC_WITH_TRANSPORT.value; + } + + /** @inheritDoc */ + public Parameter[] arguments() + { + if (m_request == null) + { + throw new NO_RESOURCES(not_available); + } + + m_request.checkDii(); + + NVList args = m_request.arguments(); + Parameter[] p = new Parameter[ args.count() ]; + try + { + for (int i = 0; i < p.length; i++) + { + ParameterMode mode; + + switch (args.item(i).flags()) + { + case ARG_IN.value : + mode = ParameterMode.PARAM_IN; + break; + + case ARG_OUT.value : + mode = ParameterMode.PARAM_OUT; + break; + + case ARG_INOUT.value : + mode = ParameterMode.PARAM_INOUT; + break; + + default : + throw new Unexpected(); + } + + p [ i ] = new Parameter(args.item(i).value(), mode); + } + } + catch (Bounds e) + { + throw new Unexpected(e); + } + return p; + } + + /** @inheritDoc */ + public String[] adapter_name() + { + return m_object.poa.getReferenceTemplate().adapter_name(); + } + + /** @inheritDoc */ + public String orb_id() + { + return m_object.orb.orb_id; + } + + /** @inheritDoc */ + public String server_id() + { + return OrbFunctional.server_id; + } + +} diff --git a/libjava/classpath/gnu/CORBA/IorDelegate.java b/libjava/classpath/gnu/CORBA/IorDelegate.java new file mode 100644 index 000000000..5f0a59df4 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/IorDelegate.java @@ -0,0 +1,425 @@ +/* gnuDelegate.java -- + 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.CORBA; + +import gnu.CORBA.CDR.BufferredCdrInput; +import gnu.CORBA.GIOP.ReplyHeader; + +import org.omg.CORBA.CompletionStatus; +import org.omg.CORBA.Context; +import org.omg.CORBA.ContextList; +import org.omg.CORBA.ExceptionList; +import org.omg.CORBA.MARSHAL; +import org.omg.CORBA.NVList; +import org.omg.CORBA.NamedValue; +import org.omg.CORBA.ORB; +import org.omg.CORBA.Request; +import org.omg.CORBA.portable.ApplicationException; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.RemarshalException; +import org.omg.PortableInterceptor.ForwardRequest; + +import java.io.IOException; + +/** + * The Classpath implementation of the {@link Delegate} functionality in the + * case, when the object was constructed from an IOR object. The IOR can be + * constructed from the stringified object reference. + * + * There is an different instance of this delegate for each CORBA object. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class IorDelegate extends SimpleDelegate +{ + /** + * Contructs an instance of object using the given IOR. + */ + public IorDelegate(ORB an_orb, IOR an_ior) + { + super(an_orb, an_ior); + } + + /** + * Creates the request to invoke the method on this object. + * + * @param target the object, for that the operation must be invoked. + * @param context context (null allowed) + * @param operation the method name + * @param parameters the method parameters + * @param returns the return value holder + * + * @return the created request. + */ + public Request create_request(org.omg.CORBA.Object target, Context context, + String operation, NVList parameters, NamedValue returns + ) + { + gnuRequest request = getRequestInstance(target); + + request.setIor(getIor()); + request.set_target(target); + + request.setOperation(operation); + request.set_args(parameters); + request.m_context = context; + request.set_result(returns); + request.setORB(orb); + + return request; + } + + /** + * Creates the request to invoke the method on this object. + * + * @param target the object, for that the operation must be invoked. + * @param context context (null allowed) + * @param operation the method name + * @param parameters the method parameters + * @param returns the return value holder + * + * @return the created request. + */ + public Request create_request(org.omg.CORBA.Object target, Context context, + String operation, NVList parameters, NamedValue returns, + ExceptionList exceptions, ContextList ctx_list + ) + { + gnuRequest request = getRequestInstance(target); + + request.setIor(ior); + request.set_target(target); + + request.setOperation(operation); + request.set_args(parameters); + request.m_context = context; + request.set_result(returns); + request.set_exceptions(exceptions); + request.set_context_list(ctx_list); + request.setORB(orb); + + return request; + } + + /** + * Get the instance of request. + */ + protected gnuRequest getRequestInstance(org.omg.CORBA.Object target) + { + return new gnuRequest(); + } + + /** + * Invoke operation on the given object, als handling temproray and permanent + * redirections. The ReplyHeader.LOCATION_FORWARD will cause to resend the + * request to the new direction. The ReplyHeader.LOCATION_FORWARD_PERM will + * cause additionally to remember the new location by this delegate, so + * subsequent calls will be immediately delivered to the new target. + * + * @param target the target object. + * @param output the output stream, previously returned by + * {@link #request(org.omg.CORBA.Object, String, boolean)}. + * + * @return the input stream, to read the response from or null for a one-way + * request. + * + * @throws SystemException if the SystemException has been thrown on the + * remote side (the exact type and the minor code matches the data of the + * remote exception that has been thrown). + * + * @throws org.omg.CORBA.portable.ApplicationException as specified. + * @throws org.omg.CORBA.portable.RemarshalException as specified. + */ + public InputStream invoke(org.omg.CORBA.Object target, OutputStream output) + throws ApplicationException, RemarshalException + { + StreamBasedRequest request = (StreamBasedRequest) output; + while (true) + { + try + { + if (request.response_expected) + { + RawReply response = request.request.submit(); + + // Read reply header. + ReplyHeader rh = response.header.create_reply_header(); + BufferredCdrInput input = response.getStream(); + input.setOrb(orb); + rh.read(input); + request.request.m_rph = rh; + + boolean moved_permanently = false; + + switch (rh.reply_status) + { + case ReplyHeader.NO_EXCEPTION: + if (request.request.m_interceptor != null) + request.request.m_interceptor.receive_reply(request.request.m_info); + if (response.header.version.since_inclusive(1, 2)) + input.align(8); + return input; + + case ReplyHeader.SYSTEM_EXCEPTION: + if (response.header.version.since_inclusive(1, 2)) + input.align(8); + showException(request, input); + + throw ObjectCreator.readSystemException(input, + rh.service_context); + + case ReplyHeader.USER_EXCEPTION: + if (response.header.version.since_inclusive(1, 2)) + input.align(8); + showException(request, input); + + throw new ApplicationException( + request.request.m_exception_id, input); + + case ReplyHeader.LOCATION_FORWARD_PERM: + moved_permanently = true; + + case ReplyHeader.LOCATION_FORWARD: + if (response.header.version.since_inclusive(1, 2)) + input.align(8); + + IOR forwarded = new IOR(); + try + { + forwarded._read_no_endian(input); + } + catch (IOException ex) + { + MARSHAL t = new MARSHAL("Cant read forwarding info", + 5102, CompletionStatus.COMPLETED_NO); + t.initCause(ex); + throw t; + } + + gnuRequest prev = request.request; + gnuRequest r = getRequestInstance(target); + + r.m_interceptor = prev.m_interceptor; + r.m_slots = prev.m_slots; + + r.m_args = prev.m_args; + r.m_context = prev.m_context; + r.m_context_list = prev.m_context_list; + r.m_environment = prev.m_environment; + r.m_exceptions = prev.m_exceptions; + r.m_operation = prev.m_operation; + r.m_parameter_buffer = prev.m_parameter_buffer; + r.m_parameter_buffer.request = r; + r.m_result = prev.m_result; + r.m_target = prev.m_target; + r.oneWay = prev.oneWay; + r.m_forward_ior = forwarded; + + if (r.m_interceptor != null) + r.m_interceptor.receive_other(r.m_info); + + r.setIor(forwarded); + + IorObject it = new IorObject(orb, + forwarded); + + r.m_target = it; + + request.request = r; + + IOR prev_ior = getIor(); + + setIor(forwarded); + + try + { + return invoke(it, request); + } + finally + { + if (!moved_permanently) + setIor(prev_ior); + } + + default: + throw new MARSHAL("Unknow reply status: " + + rh.reply_status, 8000 + rh.reply_status, + CompletionStatus.COMPLETED_NO); + } + } + else + { + request.request.send_oneway(); + return null; + } + } + catch (ForwardRequest forwarded) + { + ForwardRequest fw = forwarded; + Forwarding2: while (true) + { + try + { + gnuRequest prev = request.request; + gnuRequest r = getRequestInstance(target); + + r.m_interceptor = prev.m_interceptor; + r.m_args = prev.m_args; + r.m_context = prev.m_context; + r.m_context_list = prev.m_context_list; + r.m_environment = prev.m_environment; + r.m_exceptions = prev.m_exceptions; + r.m_operation = prev.m_operation; + r.m_parameter_buffer = prev.m_parameter_buffer; + r.m_parameter_buffer.request = r; + r.m_result = prev.m_result; + r.m_target = prev.m_target; + r.oneWay = prev.oneWay; + + r.m_forwarding_target = fw.forward; + + if (r.m_interceptor != null) + r.m_interceptor.receive_other(r.m_info); + + r.m_target = fw.forward; + request.request = r; + break Forwarding2; + } + catch (ForwardRequest e) + { + forwarded = e; + } + } + } + } + } + + /** + * Show exception to interceptor. + */ + void showException(StreamBasedRequest request, BufferredCdrInput input) + throws ForwardRequest + { + input.mark(2048); + request.request.m_exception_id = input.read_string(); + input.reset(); + + if (request.request.m_interceptor != null) + request.request.m_interceptor.receive_exception(request.request.m_info); + } + + /** + * Create a request to invoke the method of this CORBA object. + * + * @param target the CORBA object, to that this operation must be applied. + * @param operation the name of the method to invoke. + * + * @return the request. + */ + public Request request(org.omg.CORBA.Object target, String operation) + { + gnuRequest request = getRequestInstance(target); + + request.setIor(ior); + request.set_target(target); + + request.setOperation(operation); + request.setORB(orb); + + return request; + } + + /** + * Create a request to invoke the method of this CORBA object. + * + * @param target the CORBA object, to that this operation must be applied. + * @param operation the name of the method to invoke. + * @param response_expected specifies if this is one way message or the + * response to the message is expected. + * + * @return the stream where the method arguments should be written. + */ + public OutputStream request(org.omg.CORBA.Object target, String operation, + boolean response_expected + ) + { + gnuRequest request = getRequestInstance(target); + + request.setIor(ior); + request.set_target(target); + request.setOperation(operation); + + StreamBasedRequest out = request.getParameterStream(); + out.response_expected = response_expected; + request.setORB(orb); + out.setOrb(orb); + + return out; + } + + /** + * If there is an opened cache socket to access this object, close that + * socket. + * + * @param target The target is not used, this delegate requires a single + * instance per object. + */ + public void release(org.omg.CORBA.Object target) + { + // Do nothing here. + } + + /** + * Reset the remote_ior flag, forcing to check if the object is local on the + * next getRequestInstance call. + */ + public void setIor(IOR an_ior) + { + super.setIor(an_ior); + } + + /** + * Checks if the ior is local so far it is easy. + */ + public boolean is_local(org.omg.CORBA.Object self) + { + return false; + } +} diff --git a/libjava/classpath/gnu/CORBA/IorObject.java b/libjava/classpath/gnu/CORBA/IorObject.java new file mode 100644 index 000000000..921d18d00 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/IorObject.java @@ -0,0 +1,118 @@ +/* IorObject.java -- + 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.CORBA; + +import org.omg.CORBA.ORB; +import org.omg.CORBA.portable.ObjectImpl; + +/** + * Implements an object, constructed from an IOR reference. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class IorObject + extends ObjectImpl + implements IorProvider +{ + /** + * The IOR, from which the object was constructed. + */ + protected final IOR ior; + + /** + * The object id, as defined in IOR. + */ + protected final String[] id; + + /** + * Create the object from the given IOR. + * + * @param an_ior the IOR. + */ + public IorObject(ORB orb, IOR an_ior) + { + ior = an_ior; + _set_delegate(new IorDelegate(orb, ior)); + id = new String[] { ior.Id }; + } + + /** + * Create the object from the given string IOR representation. + * + * @param an_ior the IOR in the string form. + */ + public IorObject(OrbFunctional orb, String an_ior) + { + ior = IOR.parse(an_ior); + _set_delegate(new IorDelegate(orb, ior)); + id = new String[] { ior.Id }; + } + + /** + * Get the IOR of this object. + */ + public IOR getIor() + { + return ior; + } + + public String[] _ids() + { + return id; + } + + /** + * Get a string reference for this object. + * + * @return the class name:IOR profile + */ + public String toString() + { + return getClass().getName() + ":IOR:" + ior; + } + + /** + * Calls realease on the delegate. + */ + protected void finalize() + throws java.lang.Throwable + { + _get_delegate().release(this); + } +} diff --git a/libjava/classpath/gnu/CORBA/IorProvider.java b/libjava/classpath/gnu/CORBA/IorProvider.java new file mode 100644 index 000000000..875b5de1f --- /dev/null +++ b/libjava/classpath/gnu/CORBA/IorProvider.java @@ -0,0 +1,52 @@ +/* IorProvider.java -- + 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.CORBA; + +/** + * Marks the possibility of the implementing object to return the associated + * IOR. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public interface IorProvider +{ + /** + * Get the IOR of the associated object. + */ + IOR getIor(); +} diff --git a/libjava/classpath/gnu/CORBA/Minor.java b/libjava/classpath/gnu/CORBA/Minor.java new file mode 100644 index 000000000..8832162bc --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Minor.java @@ -0,0 +1,282 @@ +/* Minor.java -- + 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.CORBA; + + +/** + * Provides information and operations, related to about the 20 bit vendor minor + * code Id. This code is included into all CORBA system exceptions and is also + * transferred to remote side. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public interface Minor +{ + // Note: MARSHAL done. + + /* MARSHAL */ + + /** + * The GNU Classpath VMCID. The last 12 bits can be used to mark up to 4096 + * possible exceptions. + */ + int vendor = 0x47430000; + + /* + * Minor codes form MARSHAL exception. + */ + + /** + * The message being received is not a GIOP message. It does not start from + * the expected magic sequence byte[] { 'G', 'I', 'O', 'P' }. + */ + int Giop = 1 | vendor; + + /** + * The unexpected IOException while reading or writing the GIOP message header + * or the subsequent request or response header + */ + int Header = 2 | vendor; + + /** + * The data stream ended before reading all expected values from it. This + * usually means that the CORBA message is corrupted, but may also indicate + * that the server expects the remote method being invoked to have more or + * different parameters. + */ + int EOF = 3 | vendor; + + /** + * The unexpected IOException while reading or writing the data via Commond + * Data Representation stream. + */ + int CDR = 5 | vendor; + + /** + * The unexpected IOException while reading or writing the Value type. + */ + int Value = 6 | vendor; + + /** + * The unexpected IOException while handling request forwarding. + */ + int Forwarding = 7 | vendor; + + /** + * The unexpected IOException while handling data encapsulation, tagged + * components, tagged profiles, etc. + */ + int Encapsulation = 8 | vendor; + + /** + * The unexpected IOException while inserting or extracting data to/from the + * Any or DynamicAny. + */ + int Any = 9 | vendor; + + /** + * The unexpected UserException in the context where it cannot be handled and + * must be converted to the SystemException. + */ + int UserException = 10 | vendor; + + /** + * While the operation could formally be applied to the target, the OMG + * standard states that it is actually not applicable. For example, some CORBA + * objects like POA are always local and should not be passed to or returned + * from the remote side. + */ + int Inappropriate = 11 | vendor; + + /** + * When reading data, it was discovered that size of the data structure like + * string, sequence or character is written as the negative number. + */ + int Negative = 12 | vendor; + + /** + * Reference to non-existing node in the data grapth while reading the value + * types. + */ + int Graph = 14 | vendor; + + /** + * Unexpected exception was thrown from the IDL type helper while handling the + * object of this type as a boxed value. + */ + int Boxed = 15 | vendor; + + /** + * Unable to instantiate an value type object while reading it from the + * stream. + */ + int Instantiation = 16 | vendor; + + /** + * The header tag of the value type being read from the CDR stream contains an + * unexpected value outside 0x7fffff00 .. 0x7fffffff and also not null and not + * an indirection. + */ + int ValueHeaderTag = 17 | vendor; + + /** + * The header tag flags of the value type being read from the CDR stream make + * the invalid combination (for instance, 0x7fffff04). + */ + int ValueHeaderFlags = 18 | vendor; + + /** + * The value type class, written on the wire, is not compatible with the + * expected class, passed as a parameter to the InputStream.read_value. + */ + int ClassCast = 19 | vendor; + + /** + * Positive or otherwise invalid indirection offset when reading the data + * graph of the value type. + */ + int Offset = 20 | vendor; + + /** + * Errors while reading the chunked value type. + */ + int Chunks = 21 | vendor; + + /** + * No means are provided to write this value type. + */ + int UnsupportedValue = 22 | vendor; + + /** + * The value factory, required for the operation being invoked, is not + * registered with this ORB. + */ + int Factory = 23 | vendor; + + /** + * Unsupported object addressing method in GIOP request header. + */ + int UnsupportedAddressing = 24 | vendor; + + /** + * Invalid stringified object reference (IOR). + */ + int IOR = 25 | vendor; + + /** + * Problems with converting between stubs, ties, interfaces and + * implementations. + */ + int TargetConversion = 26 | vendor; + + /** + * Problems with reading or writing the fields of the value type object. + */ + int ValueFields = 27 | vendor; + + /** + * The instance of the value type is not serializable. + */ + int NonSerializable = 28 | vendor; + + /* BAD_OPERATION */ + + /** + * The remote side requested to invoke the method that is not available on + * that target (client and server probably disagree in the object definition). + */ + int Method = 0 | vendor; + + /** + * Failed to activate the inactive object. + */ + int Activation = 10 | vendor; + + /* + * Any - Attempt to extract from the Any value of the different type that was + * stored into that Any. + */ + + /* ClassCast - Unable to narrow the object into stub. */ + + /** + * The policies, applying to ORB or POA prevent the requested operation. + */ + int Policy = 11 | vendor; + + /** + * Socket related errors like failure to open socket on the expected port, + * failure to get a free port when required and so on. + */ + int Socket = 12 | vendor; + + /** + * The passed value for enumeration is outside the valid range for that + * enumeration. + */ + int Enumeration = 14 | vendor; + + /** + * The passed policy code is outside the valid range of the possible policies + * for the given policy type. + */ + int PolicyType = 15 | vendor; + + /* NO_RESOURCES */ + + /** + * Unable to get a free port for a new socket. Proably too many objects under + * unsuitable POA policy. + */ + int Ports = 20 | vendor; + + /** + * Too many parallel calls (too many parallel threads). The thread control + * prevents malicios client from knocking the server out by suddenly + * submitting large number of requests. + */ + int Threads = 21 | vendor; + + /** + * The IOR starts with file://, http:// or ftp://, but this local or remote + * resource is not accessible. + */ + int Missing_IOR = 22 | vendor; + +} diff --git a/libjava/classpath/gnu/CORBA/NameDynAnyPairHolder.java b/libjava/classpath/gnu/CORBA/NameDynAnyPairHolder.java new file mode 100644 index 000000000..e8047b8d7 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/NameDynAnyPairHolder.java @@ -0,0 +1,115 @@ +/* NameDynAnyPairHolder.java -- + 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.CORBA; + +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.Streamable; +import org.omg.DynamicAny.NameDynAnyPair; +import org.omg.DynamicAny.NameDynAnyPairHelper; + +/** + * A holder for the structure {@link NameDynAnyPair}. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class NameDynAnyPairHolder + implements Streamable +{ + /** + * The stored NameDynAnyPair value. + */ + public NameDynAnyPair value; + + /** + * Create the unitialised instance, leaving the value field + * with default null value. + */ + public NameDynAnyPairHolder() + { + } + + /** + * Create the initialised instance. + * @param initialValue the value that will be assigned to + * the value field. + */ + public NameDynAnyPairHolder(NameDynAnyPair initialValue) + { + value = initialValue; + } + + /** + * The method should read this object from the CDR input stream, but + * (following the JDK 1.5 API) it does not. + * + * @param input a org.omg.CORBA.portable stream to read from. + * + * @specenote Sun throws the same exception. + * + * @throws MARSHAL always. + */ + public void _read(InputStream input) + { + value = NameDynAnyPairHelper.read(input); + } + + /** + * The method should write this object to the CDR input stream, but + * (following the JDK 1.5 API) it does not. + * + * @param input a org.omg.CORBA.portable stream to read from. + * + * @specenote Sun throws the same exception. + * + * @throws MARSHAL always. + */ + public void _write(OutputStream output) + { + NameDynAnyPairHelper.write(output, value); + } + + /** + * Get the typecode of the NameDynAnyPair. + */ + public org.omg.CORBA.TypeCode _type() + { + return NameDynAnyPairHelper.type(); + } +} diff --git a/libjava/classpath/gnu/CORBA/NameDynAnyPairSeqHolder.java b/libjava/classpath/gnu/CORBA/NameDynAnyPairSeqHolder.java new file mode 100644 index 000000000..8bf8ee89d --- /dev/null +++ b/libjava/classpath/gnu/CORBA/NameDynAnyPairSeqHolder.java @@ -0,0 +1,115 @@ +/* NameDynAnyPairSeqHolder.java -- + 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.CORBA; + +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.Streamable; +import org.omg.DynamicAny.NameDynAnyPair; +import org.omg.DynamicAny.NameDynAnyPairSeqHelper; + +/** + * A holder for the sequence of {@link NameDynAnyPair}. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class NameDynAnyPairSeqHolder + implements Streamable +{ + /** + * The stored array of NameDynAnyPair. + */ + public NameDynAnyPair[] value; + + /** + * Create the unitialised instance, leaving the value array + * with default null value. + */ + public NameDynAnyPairSeqHolder() + { + } + + /** + * Create the initialised instance. + * @param initialValue the array that will be assigned to + * the value array. + */ + public NameDynAnyPairSeqHolder(NameDynAnyPair[] initialValue) + { + value = initialValue; + } + + /** + * The method should read this object from the CDR input stream, but + * (following the JDK 1.5 API) it does not. + * + * @param input a org.omg.CORBA.portable stream to read from. + * + * @specenote Sun throws the same exception. + * + * @throws MARSHAL always. + */ + public void _read(InputStream input) + { + value = NameDynAnyPairSeqHelper.read(input); + } + + /** + * The method should write this object to the CDR input stream, but + * (following the JDK 1.5 API) it does not. + * + * @param input a org.omg.CORBA.portable stream to read from. + * + * @specenote Sun throws the same exception. + * + * @throws MARSHAL always. + */ + public void _write(OutputStream output) + { + NameDynAnyPairSeqHelper.write(output, value); + } + + /** + * Get the typecode of the NameDynAnyPair. + */ + public org.omg.CORBA.TypeCode _type() + { + return NameDynAnyPairSeqHelper.type(); + } +} diff --git a/libjava/classpath/gnu/CORBA/NameValuePairHolder.java b/libjava/classpath/gnu/CORBA/NameValuePairHolder.java new file mode 100644 index 000000000..d757bdb39 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/NameValuePairHolder.java @@ -0,0 +1,105 @@ +/* NameValuePairHolder.java -- + 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.CORBA; + +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.Streamable; +import org.omg.DynamicAny.NameValuePair; +import org.omg.DynamicAny.NameValuePairHelper; + +/** + * A holder for the structure {@link NameValuePair}. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class NameValuePairHolder + implements Streamable +{ + /** + * The stored NameValuePair value. + */ + public NameValuePair value; + + /** + * Create the unitialised instance, leaving the value field + * with default null value. + */ + public NameValuePairHolder() + { + } + + /** + * Create the initialised instance. + * @param initialValue the value that will be assigned to + * the value field. + */ + public NameValuePairHolder(NameValuePair initialValue) + { + value = initialValue; + } + + /** + * Fill in the {@link value} by data from the CDR stream. + * + * @param input the org.omg.CORBA.portable stream to read. + */ + public void _read(InputStream input) + { + value = NameValuePairHelper.read(input); + } + + /** + * Write the stored value into the CDR stream. + * + * @param output the org.omg.CORBA.portable stream to write. + */ + public void _write(OutputStream output) + { + NameValuePairHelper.write(output, value); + } + + /** + * Get the typecode of the NameValuePair. + */ + public org.omg.CORBA.TypeCode _type() + { + return NameValuePairHelper.type(); + } +} diff --git a/libjava/classpath/gnu/CORBA/NameValuePairSeqHolder.java b/libjava/classpath/gnu/CORBA/NameValuePairSeqHolder.java new file mode 100644 index 000000000..5515bd306 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/NameValuePairSeqHolder.java @@ -0,0 +1,105 @@ +/* NameValuePairSeqHolder.java -- + 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.CORBA; + +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.Streamable; +import org.omg.DynamicAny.NameValuePair; +import org.omg.DynamicAny.NameValuePairSeqHelper; + +/** + * A holder for the sequence of {@link NameValuePair}. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class NameValuePairSeqHolder + implements Streamable +{ + /** + * The stored array of NameValuePair. + */ + public NameValuePair[] value; + + /** + * Create the unitialised instance, leaving the value array + * with default null value. + */ + public NameValuePairSeqHolder() + { + } + + /** + * Create the initialised instance. + * @param initialValue the array that will be assigned to + * the value array. + */ + public NameValuePairSeqHolder(NameValuePair[] initialValue) + { + value = initialValue; + } + + /** + * Read the {@link value} array from the CDR stream. + * + * @param input the org.omg.CORBA.portable stream to read. + */ + public void _read(InputStream input) + { + value = NameValuePairSeqHelper.read(input); + } + + /** + * Write the stored value into the CDR stream. + * + * @param output the org.omg.CORBA.portable stream to write. + */ + public void _write(OutputStream output) + { + NameValuePairSeqHelper.write(output, value); + } + + /** + * Get the typecode of the NameValuePair. + */ + public org.omg.CORBA.TypeCode _type() + { + return NameValuePairSeqHelper.type(); + } +} diff --git a/libjava/classpath/gnu/CORBA/NamingService/Binding_iterator_impl.java b/libjava/classpath/gnu/CORBA/NamingService/Binding_iterator_impl.java new file mode 100644 index 000000000..108ca270d --- /dev/null +++ b/libjava/classpath/gnu/CORBA/NamingService/Binding_iterator_impl.java @@ -0,0 +1,141 @@ +/* Binding_iterator.java -- + 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.CORBA.NamingService; + +import gnu.CORBA.SafeForDirectCalls; + +import org.omg.CosNaming.Binding; +import org.omg.CosNaming.BindingHolder; +import org.omg.CosNaming.BindingListHolder; +import org.omg.CosNaming.BindingType; +import org.omg.CosNaming.NameComponent; +import org.omg.CosNaming._BindingIteratorImplBase; + +/** + * The implementation of the {@link BindingIterator}. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class Binding_iterator_impl + extends _BindingIteratorImplBase implements SafeForDirectCalls +{ + /** + * The value, returned by the {@link #next_one} when there + * are no bindings available. + */ + private static final Binding no_more_bindings = + new Binding(new NameComponent[ 0 ], BindingType.nobject); + + /** + * The collection of the available bindings. + */ + private final Binding[] bindings; + + /** + * The position of the internal iterator pointer. + */ + private int p; + + public Binding_iterator_impl(Binding[] a_bindings) + { + bindings = a_bindings; + } + + /** + * Disconnect the iterator from its ORB. The iterator will + * no longer be accessible and will be a subject of the + * garbage collection. + */ + public void destroy() + { + _orb().disconnect(this); + } + + /** + * Return the desired amount of bindings. + * + * @param amount the maximal number of bindings to return. + * @param a_list a holder to store the returned bindings. + * + * @return false if there are no more bindings available, + * true otherwise. + */ + public boolean next_n(int amount, BindingListHolder a_list) + { + if (p < bindings.length) + { + int n = bindings.length - p; + if (n > amount) + n = amount; + + a_list.value = new Binding[ n ]; + for (int i = 0; i < n; i++) + a_list.value [ i ] = bindings [ p++ ]; + + return true; + } + else + { + a_list.value = new Binding[ 0 ]; + return false; + } + } + + /** + * Return the next binding. + * + * @param a_binding a holder, where the next binding will be stored. + * + * @return false if there are no more bindings available, true + * otherwise. + */ + public boolean next_one(BindingHolder a_binding) + { + if (p < bindings.length) + { + a_binding.value = (Binding) bindings [ p++ ]; + return true; + } + else + { + a_binding.value = no_more_bindings; + return false; + } + } +} diff --git a/libjava/classpath/gnu/CORBA/NamingService/Ext.java b/libjava/classpath/gnu/CORBA/NamingService/Ext.java new file mode 100644 index 000000000..d339cb194 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/NamingService/Ext.java @@ -0,0 +1,232 @@ +/* TransientContextExt.java -- + 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.CORBA.NamingService; + +import gnu.CORBA.SafeForDirectCalls; + +import org.omg.CORBA.NO_IMPLEMENT; +import org.omg.CORBA.Object; +import org.omg.CORBA.portable.Delegate; +import org.omg.CORBA.portable.ObjectImpl; +import org.omg.CosNaming.BindingIteratorHolder; +import org.omg.CosNaming.BindingListHolder; +import org.omg.CosNaming.NameComponent; +import org.omg.CosNaming.NamingContext; +import org.omg.CosNaming.NamingContextPackage.AlreadyBound; +import org.omg.CosNaming.NamingContextPackage.CannotProceed; +import org.omg.CosNaming.NamingContextPackage.InvalidName; +import org.omg.CosNaming.NamingContextPackage.NotEmpty; +import org.omg.CosNaming.NamingContextPackage.NotFound; +import org.omg.CosNaming._NamingContextExtImplBase; + +/** + * This naming context that adds the the string based extensions, + * defined by {@link NamingContextExt}. The basic functionality + * is handled by the enclosed instance of the {@link NamingContext}. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class Ext + extends _NamingContextExtImplBase implements SafeForDirectCalls +{ + /** + * The older version of the naming context, where all relevant calls + * are forwarded. + */ + private final NamingContext classic; + + /** + * The converter class converts between string and array form of the + * name. + */ + private NameTransformer converter = new NameTransformer(); + + /** + * Create the extensions for the given instance of the context. + * + * @param previous_version the previous version of the naming context. + */ + public Ext(NamingContext previous_version) + { + classic = previous_version; + } + + /** + * Sets a delegate to this context and, if appropriated, also + * sets the same delegate to the enclosing 'classic' context. + * + * @param a_delegate a delegate to set. + */ + public void _set_delegate(Delegate a_delegate) + { + super._set_delegate(a_delegate); + if (classic instanceof ObjectImpl) + ((ObjectImpl) classic)._set_delegate(a_delegate); + } + + /** {@inheritDoc} */ + public void bind(NameComponent[] a_name, Object an_object) + throws NotFound, CannotProceed, InvalidName, AlreadyBound + { + classic.bind(a_name, an_object); + } + + /** {@inheritDoc} */ + public void bind_context(NameComponent[] a_name, NamingContext context) + throws NotFound, CannotProceed, InvalidName, AlreadyBound + { + classic.bind_context(a_name, context); + } + + /** {@inheritDoc} */ + public NamingContext bind_new_context(NameComponent[] a_name) + throws NotFound, AlreadyBound, CannotProceed, + InvalidName + { + return classic.bind_new_context(a_name); + } + + /** {@inheritDoc} */ + public void destroy() + throws NotEmpty + { + classic.destroy(); + } + + /** {@inheritDoc} */ + public void list(int amount, BindingListHolder a_list, + BindingIteratorHolder an_iter + ) + { + classic.list(amount, a_list, an_iter); + } + + /** {@inheritDoc} */ + public NamingContext new_context() + { + return classic.new_context(); + } + + /** {@inheritDoc} */ + public void rebind(NameComponent[] a_name, Object an_object) + throws NotFound, CannotProceed, InvalidName + { + classic.rebind(a_name, an_object); + } + + /** {@inheritDoc} */ + public void rebind_context(NameComponent[] a_name, NamingContext context) + throws NotFound, CannotProceed, InvalidName + { + classic.rebind_context(a_name, context); + } + + /** {@inheritDoc} */ + public Object resolve(NameComponent[] a_name) + throws NotFound, CannotProceed, InvalidName + { + return classic.resolve(a_name); + } + + /** + * Resolves the name, represented in the form of the string. The name + * is first parsed into an array representation, then the call + * is forwarded to the {@link resolve(NameComponent[])}. + * + * @param a_name_string a name to resolve. + * + * @return the resolved object. + * + * @throws NotFound if the name cannot be resolved. + * @throws InvalidName if the name is invalid. + * @throws CannotProceed on unexpected circumstances. + */ + public Object resolve_str(String a_name_string) + throws NotFound, CannotProceed, InvalidName + { + return resolve(to_name(a_name_string)); + } + + /** + * Convert the name string representation into array representation. + * + * @param a_name_string a string to convert. + * @return a converted array of the name components + * + * @throws InvalidName on parsing error. + */ + public NameComponent[] to_name(String a_name_string) + throws InvalidName + { + return converter.toName(a_name_string); + } + + /** + * Convert a name component array representation into string representation. + * + * @param a_name a name to convert. + * + * @return a string form. + * + * @throws InvalidName if the passed name is invalid. + */ + public String to_string(NameComponent[] a_name) + throws InvalidName + { + return converter.toString(a_name); + } + + /** + * This method is not yet implemented. + * FIXME TODO implement it. + */ + public String to_url(String an_address, String a_name_string) + throws org.omg.CosNaming.NamingContextExtPackage.InvalidAddress, + InvalidName + { + throw new NO_IMPLEMENT("Method to_url() not yet implemented."); + } + + /** {@inheritDoc} */ + public void unbind(NameComponent[] a_name) + throws NotFound, CannotProceed, InvalidName + { + classic.unbind(a_name); + } +} diff --git a/libjava/classpath/gnu/CORBA/NamingService/NameComponentComparator.java b/libjava/classpath/gnu/CORBA/NamingService/NameComponentComparator.java new file mode 100644 index 000000000..6116ba94e --- /dev/null +++ b/libjava/classpath/gnu/CORBA/NamingService/NameComponentComparator.java @@ -0,0 +1,98 @@ +/* NameComponentComparator.java -- + 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.CORBA.NamingService; + +import org.omg.CORBA.BAD_PARAM; +import org.omg.CosNaming.NameComponent; + +import java.util.Comparator; + +/** + * This class implements the name component comparator, needed to + * sort and compare the name components in maps and sorted sets. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public final class NameComponentComparator + implements Comparator +{ + /** + * The singleton instance of the name comparator. + */ + public static final NameComponentComparator singleton = new NameComponentComparator(); + + /** + * It is enough to have a singleton. + */ + private NameComponentComparator() + { + } + + /** + * Compare the two names components. + * + * @param nc_a the first name component. + * @param nc_b the second name component. + * + * @return 0 if the name components are equal, non zero value + * as result of comparison otherwise. + * + * @throws BAD_PARAM if one of the components is empty or + * has {@link NameComponent#id} or {@link NameComponent#kind} + * field intialised to null. + */ + public final int compare(Object nc_a, Object nc_b) + { + NameComponent a = (NameComponent) nc_a; + NameComponent b = (NameComponent) nc_b; + + int cn = a.id.compareTo(b.id); + if (cn != 0) + return cn; + return a.kind.compareTo(b.kind); + } + + /** + * All instances of this class are equal. + */ + public boolean equals(Object x) + { + return x instanceof NameComponentComparator; + } +} diff --git a/libjava/classpath/gnu/CORBA/NamingService/NameParser.java b/libjava/classpath/gnu/CORBA/NamingService/NameParser.java new file mode 100644 index 000000000..93e4e3b16 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/NamingService/NameParser.java @@ -0,0 +1,527 @@ +/* NameParser.java -- + 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.CORBA.NamingService; + +import gnu.CORBA.Minor; +import gnu.CORBA.OrbFunctional; +import gnu.CORBA.IOR; +import gnu.CORBA.Unexpected; +import gnu.CORBA.Version; + +import gnu.java.lang.CPStringBuilder; + +import org.omg.CORBA.BAD_PARAM; +import org.omg.CORBA.DATA_CONVERSION; +import org.omg.CORBA.ORB; +import org.omg.CORBA.Object; +import org.omg.CORBA.ORBPackage.InvalidName; +import org.omg.CORBA.portable.Delegate; +import org.omg.CORBA.portable.ObjectImpl; +import org.omg.CosNaming.NamingContext; +import org.omg.CosNaming._NamingContextStub; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLDecoder; +import java.util.StringTokenizer; + +/** + * Parses the alternative IOR representations into our IOR structure. + * + * TODO This parser currently supports only one address per target string. A + * string with the multiple addresses will be accepted, but only the last + * address will be taken into consideration. The fault tolerance is not yet + * implemented. + * + * The key string is filtered using {@link java.net.URLDecoder} that replaces + * the agreed escape sequences by the corresponding non alphanumeric characters. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class NameParser + extends NameTransformer +{ + /** + * The corbaloc prefix. + */ + public static final String pxCORBALOC = "corbaloc"; + + /** + * The corbaname prefix. + */ + public static final String pxCORBANAME = "corbaname"; + + /** + * The IOR prefix. + */ + public static final String pxIOR = "ior"; + + /** + * The file:// prefix. + */ + public static final String pxFILE = "file://"; + + /** + * The ftp:// prefix. + */ + public static final String pxFTP = "ftp://"; + + /** + * The http:// prefix. + */ + public static final String pxHTTP = "http://"; + + /** + * Marks iiop protocol. + */ + public static final String IIOP = "iiop"; + + /** + * Marks rir protocol. + */ + public static final String RIR = "rir"; + + /** + * The default port value, as specified in OMG documentation. + */ + public static final int DEFAULT_PORT = 2809; + + /** + * The default name. + */ + public static final String DEFAULT_NAME = "NameService"; + + /** + * The string to name converter, initialized on demand. + */ + static NameTransformer converter; + + /** + * The current position. + */ + int p; + + /** + * The address being parsed, splitted into tokens. + */ + String[] t; + + /** + * Parse CORBALOC. + * + * The expected format is:
+ * 1. corbaloc:[iiop][version.subversion@]:host[:port]/key
+ * 2. corbaloc:rir:[/key]
+ * 3. corbaname:[iiop][version.subversion@]:host[:port]/key
+ * 4. corbaname:rir:[/key]
+ * 5. file://[file name]
+ * 6. http://[url]
+ * 7. ftp://[url]
+ * + * Protocol defaults to IOP, the object key defaults to the NameService. + * + * @param corbaloc the string to parse. + * @param orb the ORB, needed to create IORs and resolve rir references. + * + * @return the resolved object. + */ + public synchronized org.omg.CORBA.Object corbaloc(String corbaloc, + OrbFunctional orb) + throws BAD_PARAM + { + return corbaloc(corbaloc, orb, 0); + } + + /** + * Parse controlling against the infinite recursion loop. + */ + private org.omg.CORBA.Object corbaloc(String corbaloc, + OrbFunctional orb, int recursion) + { + // The used CORBA specification does not state how many times we should to + //redirect, but the infinite loop may be used to knock out the system. + // by malicious attempt. + if (recursion > 10) + throw new DATA_CONVERSION("More than 10 redirections"); + + if (corbaloc.startsWith(pxFILE)) + return corbaloc(readFile(corbaloc.substring(pxFILE.length())), orb, recursion+1); + else if (corbaloc.startsWith(pxHTTP)) + return corbaloc(readUrl(corbaloc), orb, recursion+1); + else if (corbaloc.startsWith(pxFTP)) + return corbaloc(readUrl(corbaloc), orb, recursion+1); + + boolean corbaname; + + // The version numbers with default values. + int major = 1; + int minor = 0; + + // The host address. + String host; + + // The port. + int port = DEFAULT_PORT; + + // The object key as string. + String key; + + StringTokenizer st = new StringTokenizer(corbaloc, ":@/.,#", true); + + t = new String[st.countTokens()]; + + for (int i = 0; i < t.length; i++) + { + t[i] = st.nextToken(); + } + + p = 0; + + if (t[p].startsWith(pxCORBANAME)) + corbaname = true; + else if (t[p].equalsIgnoreCase(pxCORBALOC)) + corbaname = false; + else if (t[p].equalsIgnoreCase(pxIOR)) + { + IOR ior = IOR.parse(corbaloc); + return orb.ior_to_object(ior); + } + else + throw new DATA_CONVERSION("Unsupported protocol: '" + t[p] + "'"); + + p++; + + if (!t[p++].equals(":")) + throw new BAD_PARAM("Syntax (':' expected after name prefix)"); + + // Check for rir: + if (t[p].equals(RIR)) + { + p++; + if (!t[p++].equals(":")) + throw new BAD_PARAM("':' expected after 'rir'"); + + key = readKey("/"); + + Object object; + try + { + object = orb.resolve_initial_references(key); + return corbaname ? resolve(object) : object; + } + catch (InvalidName e) + { + throw new BAD_PARAM("Unknown initial reference '" + key + "'"); + } + } + else + // Check for iiop. + if (t[p].equals(IIOP) || t[p].equals(":")) + { + IOR ior = new IOR(); + + Addresses: do + { // Read addresses. + if (t[p].equals(":")) + { + p++; + } + else + { + p++; + if (!t[p++].equals(":")) + throw new BAD_PARAM("':' expected after 'iiop'"); + // Check if version is present. + if (t[p + 1].equals(".")) + if (t[p + 3].equals("@")) + { + // Version info present. + try + { + major = Integer.parseInt(t[p++]); + } + catch (NumberFormatException e) + { + throw new BAD_PARAM("Major version number '" + + t[p - 1] + "'"); + } + p++; // '.' at this point. + try + { + minor = Integer.parseInt(t[p++]); + } + catch (NumberFormatException e) + { + throw new BAD_PARAM("Major version number '" + + t[p - 1] + "'"); + } + p++; // '@' at this point. + } + } + + ior.Internet.version = new Version(major, minor); + + // Then host data goes till '/' or ':'. + CPStringBuilder bhost = new CPStringBuilder(corbaloc.length()); + while (!t[p].equals(":") && !t[p].equals("/") && !t[p].equals(",")) + bhost.append(t[p++]); + + host = bhost.toString(); + + ior.Internet.host = host; + + if (t[p].equals(":")) + { + // Port specified. + p++; + try + { + port = Integer.parseInt(t[p++]); + } + catch (NumberFormatException e) + { + throw new BAD_PARAM("Invalid port '" + t[p - 1] + "'"); + } + } + + ior.Internet.port = port; + + // Id is not listed. + ior.Id = ""; + + if (t[p].equals(",")) + p++; + else + break Addresses; + } + while (true); + + key = readKey("/"); + ior.key = key.getBytes(); + + org.omg.CORBA.Object object = orb.ior_to_object(ior); + return corbaname ? resolve(object) : object; + } + + else + throw new DATA_CONVERSION("Unsupported protocol '" + t[p] + "'"); + } + + /** + * Read IOR from the file in the local file system. + */ + String readFile(String file) + { + File f = new File(file); + if (!f.exists()) + { + DATA_CONVERSION err = new DATA_CONVERSION(f.getAbsolutePath() + + " does not exist."); + err.minor = Minor.Missing_IOR; + } + try + { + char[] c = new char[(int) f.length()]; + FileReader fr = new FileReader(f); + fr.read(c); + fr.close(); + return new String(c).trim(); + } + catch (IOException ex) + { + DATA_CONVERSION d = new DATA_CONVERSION(); + d.initCause(ex); + d.minor = Minor.Missing_IOR; + throw (d); + } + } + + /** + * Read IOR from the remote URL. + */ + String readUrl(String url) + { + URL u; + try + { + u = new URL(url); + } + catch (MalformedURLException mex) + { + throw new BAD_PARAM("Malformed URL: '" + url + "'"); + } + + try + { + InputStreamReader r = new InputStreamReader(u.openStream()); + + CPStringBuilder b = new CPStringBuilder(); + int c; + + while ((c = r.read()) > 0) + b.append((char) c); + + return b.toString().trim(); + } + catch (Exception exc) + { + DATA_CONVERSION d = new DATA_CONVERSION("Reading " + url + " failed."); + d.minor = Minor.Missing_IOR; + throw d; + } + } + + private org.omg.CORBA.Object resolve(org.omg.CORBA.Object object) + { + NamingContext ns; + String key = "?"; + try + { + if (object instanceof NamingContext) + ns = (NamingContext) object; + else + { + Delegate delegate = ((ObjectImpl) object)._get_delegate(); + ns = new _NamingContextStub(); + ((_NamingContextStub) ns)._set_delegate(delegate); + } + } + catch (Exception ex) + { + BAD_PARAM bad = new BAD_PARAM("The CORBANAME target " + object + + " is not a NamingContext"); + bad.minor = 10; + bad.initCause(ex); + throw bad; + } + + if (converter == null) + converter = new NameTransformer(); + + try + { + key = readKey("#"); + object = ns.resolve(converter.toName(key)); + return object; + } + catch (Exception ex) + { + BAD_PARAM bad = new BAD_PARAM("Wrong CORBANAME '" + key + "'"); + bad.minor = 10; + bad.initCause(ex); + throw bad; + } + } + + private String readKey(String delimiter) + throws BAD_PARAM + { + if (p < t.length) + if (!t[p].equals(delimiter)) + { + if (t[p].equals("#")) + return DEFAULT_NAME; + else + throw new BAD_PARAM("'" + delimiter + "String' expected '" + t[p] + + "' found"); + } + + CPStringBuilder bKey = new CPStringBuilder(); + p++; + + while (p < t.length && !t[p].equals("#")) + bKey.append(t[p++]); + + if (bKey.length() == 0) + return DEFAULT_NAME; + + try + { + return URLDecoder.decode(bKey.toString(), "UTF-8"); + } + catch (UnsupportedEncodingException e) + { + throw new Unexpected("URLDecoder does not support UTF-8", e); + } + } + + static NameParser n = new NameParser(); + + static void corbalocT(String ior, OrbFunctional orb) + { + System.out.println(ior); + System.out.println(n.corbaloc(ior, orb)); + System.out.println(); + } + + public static void main(String[] args) + { + try + { + OrbFunctional orb = (OrbFunctional) ORB.init(args, null); + corbalocT("corbaloc:iiop:1.3@155axyz.com/Prod/aTradingService", orb); + corbalocT("corbaloc:iiop:2.7@255bxyz.com/Prod/bTradingService", orb); + corbalocT("corbaloc:iiop:355cxyz.com/Prod/cTradingService", orb); + corbalocT("corbaloc:iiop:2.7@255bxyz.com/Prod/bTradingService", orb); + corbalocT("corbaloc:iiop:355cxyz.com:7777/Prod/cTradingService", orb); + + corbalocT("corbaloc::556xyz.com:80/Dev/NameService", orb); + corbalocT("corbaloc:iiop:1.2@host1:3076/0", orb); + + corbalocT("corbaloc:rir:/NameService", orb); + corbalocT("corbaloc:rir:/", orb); + corbalocT("corbaloc:rir:", orb); + + corbalocT("corbaloc:rir:/NameService", orb); + corbalocT("corbaloc:rir:/", orb); + corbalocT("corbaloc:rir:", orb); + + corbalocT("corbaloc::555xyz.com,:556xyz.com:80/Dev/NameService", orb); + } + catch (BAD_PARAM e) + { + e.printStackTrace(System.out); + } + } +} diff --git a/libjava/classpath/gnu/CORBA/NamingService/NameTransformer.java b/libjava/classpath/gnu/CORBA/NamingService/NameTransformer.java new file mode 100644 index 000000000..132c5dd8f --- /dev/null +++ b/libjava/classpath/gnu/CORBA/NamingService/NameTransformer.java @@ -0,0 +1,326 @@ +/* NameTransformer.java -- + 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.CORBA.NamingService; + +import gnu.java.lang.CPStringBuilder; + +import org.omg.CORBA.IntHolder; +import org.omg.CosNaming.NameComponent; +import org.omg.CosNaming.NamingContextPackage.InvalidName; + +import java.util.ArrayList; +import java.util.StringTokenizer; + +/** + * This class converts between string and array representations of the + * multi component object names. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class NameTransformer +{ + /** + * A string, indicating the escape character. + */ + public static final String ESCAPE = "\\"; + + /** + * Convert the string name representation into the array name + * representation. See {@link #toString(NameComponent)} for the + * description of this format. + * + * @param a_name the string form of the name. + * + * @return the array form of the name. + * + * @throws InvalidName if the name cannot be parsed. + */ + public NameComponent[] toName(String a_name) + throws InvalidName + { + ArrayList components = new ArrayList(); + StringTokenizer st = new StringTokenizer(a_name, "./\\", true); + + // Create the buffer array, reserving the last element for null. + String[] n = new String[ st.countTokens() + 1 ]; + + int pp = 0; + while (st.hasMoreTokens()) + n [ pp++ ] = st.nextToken(); + + IntHolder p = new IntHolder(); + + NameComponent node = readNode(p, n); + + while (node != null) + { + components.add(node); + node = readNode(p, n); + } + + NameComponent[] name = new NameComponent[ components.size() ]; + for (int i = 0; i < name.length; i++) + { + name [ i ] = (NameComponent) components.get(i); + } + + NameValidator.check(name); + + return name; + } + + /** + * Converts the name into its string representation, as defined in + * the specification CORBA naming service. + * + * A string representation for the name consists of the name components, + * separated by a slash '/' character (for example, 'a/b/c'). If the + * {@link NameComponent#kind} field is not empty, it is given after + * period ('.'), for example 'a.b/c.d/.' . + * The period alone represents node where part where both + * {@link NameComponent#kind} and {@link NameComponent#id} are empty strings. + * + * If slash or dot are part of the name, they are escaped by backslash ('\'). + * If the backslash itself is part of the name, it is doubled. + * + * @param a_name a name to convert. + * @return a string representation. + */ + public String toString(NameComponent[] a_name) + throws InvalidName + { + NameValidator.check(a_name); + + CPStringBuilder b = new CPStringBuilder(); + + NameComponent n; + + for (int ni = 0; ni < a_name.length; ni++) + { + n = a_name [ ni ]; + appEscaping(b, n.id); + if (n.kind.length() > 0) + { + b.append('.'); + appEscaping(b, n.kind); + } + + if (ni < a_name.length - 1) + b.append('/'); + } + return b.toString(); + } + + /** + * Append the contents of the string to this + * string buffer, inserting the escape sequences, where required. + * + * @param b a buffer to append the contents to. + * @param s a string to append. + */ + private void appEscaping(CPStringBuilder b, String s) + { + char c; + for (int i = 0; i < s.length(); i++) + { + c = s.charAt(i); + switch (c) + { + case '.' : + case '/' : + case '\\' : + b.append('\\'); + b.append(c); + break; + + default : + b.append(c); + break; + } + } + } + + /** + * Assert the end of the current name component. + */ + private void assertEndOfNode(IntHolder p, String[] t) + throws InvalidName + { + if (t [ p.value ] != null) + if (!t [ p.value ].equals("/")) + throw new InvalidName("End of node expected at token " + p.value); + } + + /** + * Read the named component node. After reading the current positon + * advances to the beginning of the next node in an array. + * + * @param p the current position being wrapped inside the passed + * IntHolder. + * + * @param t the text buffer. + * + * @return the created node. + */ + private NameComponent readNode(IntHolder p, String[] t) + throws InvalidName + { + // End of stream has been reached. + if (t [ p.value ] == null) + return null; + + NameComponent n = new NameComponent(); + + if (t [ p.value ].equals(".")) + { + // The 'id' is missing, but the 'kind' may follow. + n.id = ""; + p.value++; + n.kind = readPart(p, t); + assertEndOfNode(p, t); + if (t [ p.value ] != null) + p.value++; + } + else if (t [ p.value ].equals("/")) + { + // This is not allowed here and may happen only + // on two subsequent slashes. + throw new InvalidName("Unexpected '/' token " + p.value); + } + else + { + n.id = readPart(p, t); + + // If some chars follow the id. + if (t [ p.value ] != null) + { + // Dot means that the kind part follows + if (t [ p.value ].equals(".")) + { + p.value++; + n.kind = readPart(p, t); + assertEndOfNode(p, t); + if (t [ p.value ] != null) + p.value++; + } + + // The next name component follows - advance to + // the beginning of the next name component. + else if (t [ p.value ].equals("/")) + { + n.kind = ""; + p.value++; + } + else + throw new InvalidName("Unexpected '" + t [ p.value ] + + "' at token " + p.value + ); + } + else + + // Id, and then end of sequence. + n.kind = ""; + } + + return n; + } + + /** + * Read the name part (id or kind). + * + * @param p the current position. After reading, advances + * to the beginning of the next name fragment. + * + * @param t the string buffer. + * + * @return the name part with resolved escape sequences. + */ + private String readPart(IntHolder p, String[] t) + { + CPStringBuilder part = new CPStringBuilder(); + + while (t [ p.value ] != null && !t [ p.value ].equals(".") && + !t [ p.value ].equals("/") + ) + { + if (t [ p.value ].equals(ESCAPE)) + { + p.value++; + part.append(t [ p.value ]); + } + else + part.append(t [ p.value ]); + + p.value++; + } + + return part.toString(); + } + + public static void main(String[] args) + { + NameComponent a = new NameComponent("a", "ak"); + NameComponent b = new NameComponent("b/z", "b.k"); + NameComponent c = new NameComponent("c", ""); + + NameTransformer sn = new NameTransformer(); + + try + { + String s = sn.toString(new NameComponent[] { a, b, c }); + System.out.println(s); + + //NameComponent[] k = toName("a.k/b.k2/c/d/."); + //NameComponent[] k = toName("a.bc/.b/c.x"); + + NameComponent[] k = sn.toName(s); + System.out.println("ToString"); + + for (int i = 0; i < k.length; i++) + { + System.out.println(k [ i ].id + ":" + k [ i ].kind); + } + } + catch (InvalidName ex) + { + ex.printStackTrace(); + } + } + +} diff --git a/libjava/classpath/gnu/CORBA/NamingService/NameValidator.java b/libjava/classpath/gnu/CORBA/NamingService/NameValidator.java new file mode 100644 index 000000000..d7d5a14bb --- /dev/null +++ b/libjava/classpath/gnu/CORBA/NamingService/NameValidator.java @@ -0,0 +1,79 @@ +/* NameValidator.java -- + 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.CORBA.NamingService; + + +import org.omg.CosNaming.NameComponent; +import org.omg.CosNaming.NamingContextPackage.InvalidName; + +/** + * Checks the given name for validity. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class NameValidator +{ + /** + * Check the given name. This method must be package level, as it is + * not defined in the API. + * + * @param name the name to check. + * + * @throws InvalidName if the given name is not valid. + */ + public static void check(NameComponent[] name) + throws InvalidName + { + if (name == null) + throw new InvalidName("name=null"); + + if (name.length == 0) + throw new InvalidName("name.length=0"); + + for (int i = 0; i < name.length; i++) + { + if (name [ i ] == null) + throw new InvalidName("name[" + i + "]=null"); + if (name [ i ].id == null) + throw new InvalidName("name[" + i + "].id=null"); + if (name [ i ].kind == null) + throw new InvalidName("name[" + i + "].kind=null"); + } + } +} diff --git a/libjava/classpath/gnu/CORBA/NamingService/NamingMap.java b/libjava/classpath/gnu/CORBA/NamingService/NamingMap.java new file mode 100644 index 000000000..40fef0a3a --- /dev/null +++ b/libjava/classpath/gnu/CORBA/NamingService/NamingMap.java @@ -0,0 +1,190 @@ +/* NamingMap.java -- + 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.CORBA.NamingService; + +import org.omg.CosNaming.NameComponent; +import org.omg.CosNaming.NamingContextPackage.AlreadyBound; +import org.omg.CosNaming.NamingContextPackage.InvalidName; + +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +/** + * The Naming Map maps the single names components into associated objects or + * naming contexts. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class NamingMap +{ + /** + * The actual map. + */ + protected final TreeMap map; + + /** + * Creates an instance of the naming map, intialising the comparator + * to the {@link NameComponentComparator}. + */ + public NamingMap() + { + map = new TreeMap(NameComponentComparator.singleton); + } + + /** + * 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. + * + * @param name the name + * @param object the object + */ + public void bind(NameComponent name, org.omg.CORBA.Object object) + throws AlreadyBound, InvalidName + { + if (containsKey(name)) + { + Object x = get(name); + + // Do not throw an exception if the same object is named by + // the same name. + if (x.equals(object)) + throw new AlreadyBound("The name is in use for another object"); + } + else + { + if (containsValue(object)) + throw new AlreadyBound("The object has another name"); + } + + // There are no restrictions in binding the object. + rebind(name, object); + } + + /** + * Checks if this map contains the definition of the given name. + * + * @param key the name to check. + */ + public boolean containsKey(NameComponent key) + { + return map.containsKey(key); + } + + /** + * Checks if this map contains the definition of the given object. + * + * @param object the object to check. + */ + public boolean containsValue(org.omg.CORBA.Object object) + { + return map.containsValue(object); + } + + /** + * Returns the map entry set. + * + * @return the map entry set, containing the instances of the + * Map.Entry. + */ + public Set entries() + { + return map.entrySet(); + } + + /** + * Get the CORBA object, associated with the given name. + * + * @param name the name. + * + * @return the associated object, null if none. + */ + public org.omg.CORBA.Object get(NameComponent name) + { + return (org.omg.CORBA.Object) map.get(name); + } + + /** + * 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. + * @param object + */ + public void rebind(NameComponent name, org.omg.CORBA.Object object) + throws InvalidName + { + // Remove the existing mapping for the given name, if present. + remove(name); + + Iterator iter = entries().iterator(); + Map.Entry item; + + // Remove the existing mapping for the given object, if present. + while (iter.hasNext()) + { + item = (Map.Entry) iter.next(); + if (item.getValue().equals(object)) + iter.remove(); + } + + map.put(name, object); + } + + /** + * Removes the given name, if present. + * + * @param name a name to remove. + */ + public void remove(NameComponent name) + { + map.remove(name); + } + + /** + * Get the size of the map. + */ + public int size() + { + return map.size(); + } +} diff --git a/libjava/classpath/gnu/CORBA/NamingService/NamingServiceTransient.java b/libjava/classpath/gnu/CORBA/NamingService/NamingServiceTransient.java new file mode 100644 index 000000000..5ccc4d8cc --- /dev/null +++ b/libjava/classpath/gnu/CORBA/NamingService/NamingServiceTransient.java @@ -0,0 +1,146 @@ +/* NamingServiceTransient.java -- + 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.CORBA.NamingService; + +import gnu.CORBA.OrbFunctional; +import gnu.CORBA.IOR; + +import org.omg.CosNaming.NamingContextExt; + +import java.io.FileOutputStream; +import java.io.PrintStream; +import java.io.UnsupportedEncodingException; + +/** + * The server for the gnu classpath naming service. This is an executable class + * that must be started to launch the GNU Classpath CORBA transient naming + * service. + * + * GNU Classpath currently works with this naming service and is also + * interoperable with the Sun Microsystems naming services from releases 1.3 and + * 1.4, both transient tnameserv and persistent orbd. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class NamingServiceTransient +{ + /** + * The default port (900), on that the naming service starts if no + * -ORBInitialPort is specified in the command line. + */ + public static final int PORT = 900; + + /** + * Get the object key for the naming service. The default key is the string + * "NameService" in ASCII. + * + * @return the byte array. + */ + public static byte[] getDefaultKey() + { + try + { // NameService + return "NameService".getBytes("UTF-8"); + } + catch (UnsupportedEncodingException ex) + { + throw new InternalError("UTF-8 unsupported"); + } + } + + /** + * Start the naming service on the current host at the given port. + * + * @param portArgument the port on which the service will be + * started, or -1 to use the default port, 900 + * @param fileArgument if non-null, store the IOR string of this + * naming service in a file by this name + */ + public static void start(int portArgument, String fileArgument) + { + int port = PORT; + + if (portArgument > -1) + port = portArgument; + + String iorf = fileArgument; + try + { + // Create and initialize the ORB + final OrbFunctional orb = new OrbFunctional(); + + OrbFunctional.setPort(port); + + // Create the servant and register it with the ORB + NamingContextExt namer = new Ext(new TransientContext()); + + // Case with the key "NameService". + orb.connect(namer, "NameService".getBytes()); + + // Storing the IOR reference. + String ior = orb.object_to_string(namer); + IOR iorr = IOR.parse(ior); + if (iorf != null) + { + FileOutputStream f = new FileOutputStream(iorf); + PrintStream p = new PrintStream(f); + p.print(ior); + p.close(); + } + + new Thread() + { + public void run() + { + // Wait for invocations from clients. + orb.run(); + } + }.start(); + } + catch (Exception e) + { + System.err.println("ERROR: " + e); + e.printStackTrace(System.err); + } + + // Restore the default value for allocating ports for the subsequent + // objects. + OrbFunctional.setPort(OrbFunctional.DEFAULT_INITIAL_PORT); + } +} diff --git a/libjava/classpath/gnu/CORBA/NamingService/TransientContext.java b/libjava/classpath/gnu/CORBA/NamingService/TransientContext.java new file mode 100644 index 000000000..6ed07d799 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/NamingService/TransientContext.java @@ -0,0 +1,443 @@ +/* nContext.java -- implementation of NamingContext + 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.CORBA.NamingService; + +import org.omg.CORBA.Object; +import org.omg.CosNaming.Binding; +import org.omg.CosNaming.BindingIteratorHolder; +import org.omg.CosNaming.BindingListHolder; +import org.omg.CosNaming.BindingType; +import org.omg.CosNaming.NameComponent; +import org.omg.CosNaming.NamingContext; +import org.omg.CosNaming.NamingContextOperations; +import org.omg.CosNaming.NamingContextPackage.AlreadyBound; +import org.omg.CosNaming.NamingContextPackage.CannotProceed; +import org.omg.CosNaming.NamingContextPackage.InvalidName; +import org.omg.CosNaming.NamingContextPackage.NotEmpty; +import org.omg.CosNaming.NamingContextPackage.NotFound; +import org.omg.CosNaming.NamingContextPackage.NotFoundReason; +import org.omg.CosNaming._NamingContextImplBase; + +import gnu.CORBA.SafeForDirectCalls; + +import java.util.Iterator; +import java.util.Map; + +/** + * This class implements the transient naming service, defined by + * {@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. + * + * TODO Write the persistent naming service. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class TransientContext + extends _NamingContextImplBase + implements NamingContext, NamingContextOperations, SafeForDirectCalls +{ + /** + * Use serial version UID for interoperability. + */ + private static final long serialVersionUID = 2; + + /** + * The already named contexts. + */ + protected final NamingMap named_contexts; + + /** + * The already named objects. + */ + 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. + * + * @param a_name the name, being given to the object. + * @param an_object the object, being named. + * + * @throws AlreadyBound if the object is already named in this context. + * @throws InvalidName if the name has zero length or otherwise invalid. + */ + public void bind(NameComponent[] a_name, Object an_object) + throws NotFound, CannotProceed, InvalidName, AlreadyBound + { + if (a_name.length == 1) + named_objects.bind(a_name [ 0 ], an_object); + else + { + NamingContext context = + (NamingContext) named_contexts.get(a_name [ 0 ]); + context.bind(getSuffix(a_name), an_object); + } + } + + /** + * Gives a child context name, valid in this context. + * + * @param a_name the name, being given to the child context. + * @param a_context the child context being named. + * + * @throws AlreadyBound if the child context is already named in + * the current context. + */ + public void bind_context(NameComponent[] a_name, NamingContext a_context) + throws NotFound, CannotProceed, InvalidName, AlreadyBound + { + if (a_name.length == 1) + named_contexts.bind(a_name [ 0 ], a_context); + else + { + NamingContext context = + (NamingContext) named_contexts.get(a_name [ 0 ]); + context.bind_context(getSuffix(a_name), a_context); + } + } + + /** + * Create a new context and give it a given name (bound it) + * in the current context. + * + * The context being created is returned by calling + * {@link #new_context()}. + * + * @param a_name the name being given to the new context. + * + * @return the newly created context. + * + * @throws AlreadyBound if the name is already in use. + * @throws InvalidName if the name has zero length or otherwise invalid. + */ + public NamingContext bind_new_context(NameComponent[] a_name) + throws NotFound, AlreadyBound, CannotProceed, + InvalidName + { + if (named_contexts.containsKey(a_name [ 0 ]) || + named_objects.containsKey(a_name [ 0 ]) + ) + throw new AlreadyBound(); + + NamingContext child = new_context(); + bind_context(a_name, child); + return child; + } + + /** + * Destroy this context (must be empty). + * @throws NotEmpty if the context being destroyed is not empty. + */ + public void destroy() + throws NotEmpty + { + if (named_contexts.size() > 0 || named_objects.size() > 0) + throw new NotEmpty(); + } + + /** + * Iterate over all bindings, defined in this namind context. + * + * @param amount the maximal number of context to return in the + * holder a_list. The remaining bindings are accessible via iterator + * an_iter. If the parameter amount is zero, all bindings are accessed only + * via this iterator. + * + * This implementation list contexts first, then objects. + * + * @param a_list the holder, where the returned bindigs are stored. + * @param an_iter the iterator that can be used to access the remaining + * bindings. + */ + public void list(int amount, BindingListHolder a_list, + BindingIteratorHolder an_iter + ) + { + int nb = named_contexts.size() + named_objects.size(); + int nl = nb; + if (nl > amount) + nl = amount; + + a_list.value = new Binding[ nl ]; + + Iterator contexts = named_contexts.entries().iterator(); + Iterator objects = named_objects.entries().iterator(); + + // Create a binding list. + for (int i = 0; i < nl; i++) + { + if (contexts.hasNext()) + a_list.value [ i ] = mkBinding(contexts.next(), BindingType.ncontext); + else if (objects.hasNext()) + a_list.value [ i ] = mkBinding(objects.next(), BindingType.nobject); + else + throw new InternalError(); + } + + // Create an iterator. + Binding[] remainder = new Binding[ nb - nl ]; + int p = 0; + + while (contexts.hasNext()) + remainder [ p++ ] = mkBinding(contexts.next(), BindingType.ncontext); + + while (objects.hasNext()) + remainder [ p++ ] = mkBinding(objects.next(), BindingType.nobject); + + Binding_iterator_impl bit = new Binding_iterator_impl(remainder); + _orb().connect(bit); + an_iter.value = bit; + } + + /** + * Creates a new naming context, not bound to any name. + */ + public NamingContext new_context() + { + Ext context = new Ext(new TransientContext()); + + // Connect the context to the current ORB: + _orb().connect(context); + return context; + } + + /** + * Names or renames the object. + * + * @param a_name the new name, being given to the object + * in the scope of the current context. If the object is already + * named in this context, it is renamed. + * + * @param an_object the object, being named. + * + * @throws InvalidName if the name has zero length or otherwise invalid. + */ + public void rebind(NameComponent[] a_name, Object an_object) + throws NotFound, CannotProceed, InvalidName + { + if (a_name.length == 1) + named_objects.rebind(a_name [ 0 ], an_object); + else + { + NamingContext context = + (NamingContext) named_contexts.get(a_name [ 0 ]); + context.rebind(getSuffix(a_name), an_object); + } + } + + /** + * Names or renames the child context. + * If the child context is already named in + * the current context, it is renamed. The the name being given is in + * use, the old meaning of the name is discarded. + * + * @param a_name the name, being given to the child context in the scope + * of the current context. + * + * @param a_context the child context being named. + * + * @throws InvalidName if the name has zero length or otherwise invalid. + */ + public void rebind_context(NameComponent[] a_name, NamingContext a_context) + throws NotFound, CannotProceed, InvalidName + { + if (a_name.length == 1) + named_contexts.rebind(a_name [ 0 ], a_context); + else + { + NamingContext context = + (NamingContext) named_contexts.get(a_name [ 0 ]); + context.rebind_context(getSuffix(a_name), a_context); + } + } + + /** + * Get the object, bound to the specified name in this + * context. The given object must match the bound + * name. + * + * This implementation resolves the names as defined in specification + * of the CORBA naming service. This means, if the beginning of the + * name can be resolved to some naming context, the request is + * forwarded to this context, passing the unresolved name part as a + * parameter. In this way, it is possible to have a hierarchy of the + * naming services. The central services resolve the the beginning + * of the name. The local services resolve the remaining nodes of the + * name that may be relevant to some local details. It can be three or + * more ranks of the naming services. + * + * @param a_name the object name. + * + * @return the object, matching this name. The client + * usually casts or narrows (using the helper) the returned value + * to the more specific type. + * + * @throws NotFound if the name cannot be resolved. + * @throws InvalidName if the name has zero length or otherwise invalid. + */ + public Object resolve(NameComponent[] a_name) + throws NotFound, CannotProceed, InvalidName + { + NameValidator.check(a_name); + + if (a_name.length > 1) + return resolveSubContext(a_name); + else + { + // A single node name. + org.omg.CORBA.Object object; + + object = named_objects.get(a_name [ 0 ]); + if (object != null) + return object; + + object = named_contexts.get(a_name [ 0 ]); + if (object != null) + return object; + } + + throw new NotFound(NotFoundReason.missing_node, a_name); + } + + /** + * Removes the name from the binding context. + * + * @param a_name a name to remove. + * + * @throws InvalidName if the name has zero length or otherwise invalid. + */ + public void unbind(NameComponent[] a_name) + throws NotFound, CannotProceed, InvalidName + { + NameValidator.check(a_name); + + // Single node name - handle it. + if (a_name.length == 1) + { + if (named_objects.containsKey(a_name [ 0 ])) + named_objects.remove(a_name [ 0 ]); + else if (named_contexts.containsKey(a_name [ 0 ])) + named_contexts.remove(a_name [ 0 ]); + else + throw new NotFound(NotFoundReason.missing_node, a_name); + } + else + { + // Handle the first node and forward the command. + NamingContext subcontext = + (NamingContext) named_contexts.get(a_name [ 0 ]); + + if (subcontext == null) + throw new NotFound(NotFoundReason.missing_node, a_name); + + subcontext.unbind(getSuffix(a_name)); + } + } + + /** + * Get the name suffix, discarding the first member. + */ + private NameComponent[] getSuffix(NameComponent[] a_name) + { + NameComponent[] suffix = new NameComponent[ a_name.length - 1 ]; + System.arraycopy(a_name, 1, suffix, 0, suffix.length); + return suffix; + } + + /** + * Create a binding. + * + * @param an_entry the entry, defining the bound object. + * @param type the binding type. + * @return the created binding. + */ + private Binding mkBinding(java.lang.Object an_entry, BindingType type) + { + Map.Entry entry = (Map.Entry) an_entry; + Binding b = new Binding(); + + // The name component has always only one node (the current context) + b.binding_name = new NameComponent[] { (NameComponent) entry.getKey() }; + b.binding_type = type; + return b; + } + + /** + * Find the context, bound to the first name of the given + * name, and pass the remainder (without the first node) + * of the name for that context to resolve. + * + * @param a_name the name to resolve. + * + * @return the resolved context + */ + private Object resolveSubContext(NameComponent[] a_name) + throws NotFound, CannotProceed, InvalidName + { + // A multiple node name. + // This context resolves the first node only. + NamingContext context = (NamingContext) named_contexts.get(a_name [ 0 ]); + if (context == null) + throw new NotFound(NotFoundReason.missing_node, a_name); + + NameComponent[] suffix = getSuffix(a_name); + + return context.resolve(suffix); + } +} diff --git a/libjava/classpath/gnu/CORBA/ObjectCreator.java b/libjava/classpath/gnu/CORBA/ObjectCreator.java new file mode 100644 index 000000000..292495a1f --- /dev/null +++ b/libjava/classpath/gnu/CORBA/ObjectCreator.java @@ -0,0 +1,590 @@ +/* ObjectCreator.java -- + 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.CORBA; + +import gnu.CORBA.CDR.UnknownExceptionCtxHandler; +import gnu.CORBA.CDR.BufferredCdrInput; +import gnu.CORBA.CDR.BufferedCdrOutput; +import gnu.CORBA.CDR.AbstractCdrInput; +import gnu.CORBA.GIOP.ServiceContext; +import gnu.CORBA.typecodes.RecordTypeCode; +import gnu.classpath.VMStackWalker; + +import org.omg.CORBA.Any; +import org.omg.CORBA.CompletionStatus; +import org.omg.CORBA.CompletionStatusHelper; +import org.omg.CORBA.MARSHAL; +import org.omg.CORBA.SystemException; +import org.omg.CORBA.TCKind; +import org.omg.CORBA.UNKNOWN; +import org.omg.CORBA.UserException; +import org.omg.CORBA.portable.IDLEntity; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.ValueBase; + +import java.lang.reflect.Method; +import java.util.Map; +import java.util.WeakHashMap; + +import javax.rmi.CORBA.Util; + +/** + * Creates java objects from the agreed IDL names for the simple case when the + * CORBA object is directly mapped into the locally defined java class. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class ObjectCreator +{ + /** + * The standard OMG prefix. + */ + public static final String OMG_PREFIX = "omg.org/"; + + /** + * The standard java prefix. + */ + public static final String JAVA_PREFIX = "org.omg."; + + /** + * The prefix for classes that are placed instide the gnu.CORBA namespace. + */ + public static final String CLASSPATH_PREFIX = "gnu.CORBA."; + + /** + * Maps classes to they IDL or RMI names. Computing RMI name is an expensive + * operations, so frequently used RMI keys are reused. The map must be weak to + * ensure that the class can be unloaded, when applicable. + */ + public static Map m_names = new WeakHashMap(); + + /** + * Maps IDL strings into known classes. The map must be weak to ensure that + * the class can be unloaded, when applicable. + */ + public static Map m_classes = new WeakHashMap(); + + /** + * Maps IDL types to they helpers. + */ + public static Map m_helpers = new WeakHashMap(); + + /** + * Try to instantiate an object with the given IDL name. The object must be + * mapped to the local java class. The omg.org domain must be mapped into the + * object in either org/omg or gnu/CORBA namespace. + * + * @param idl name + * @return instantiated object instance or null if no such available. + */ + public static java.lang.Object createObject(String idl, String suffix) + { + synchronized (m_classes) + { + Class known = (Class) (suffix == null ? m_classes.get(idl) + : m_classes.get(idl + 0xff + suffix)); + Object object; + + if (known != null) + { + try + { + return known.newInstance(); + } + catch (Exception ex) + { + RuntimeException rex = new RuntimeException(idl + " suffix " + + suffix, ex); + throw rex; + } + } + else + { + if (suffix == null) + suffix = ""; + try + { + known = forName(toClassName(JAVA_PREFIX, idl) + suffix); + object = known.newInstance(); + } + catch (Exception ex) + { + try + { + known = forName(toClassName(CLASSPATH_PREFIX, idl) + + suffix); + object = known.newInstance(); + } + catch (Exception exex) + { + return null; + } + } + m_classes.put(idl + 0xff + suffix, known); + return object; + } + } + } + + /** + * Read the system exception from the given stream. + * + * @param input the CDR stream to read from. + * @param contexts the service contexts in request/reply header/ + * + * @return the exception that has been stored in the stream (IDL name, minor + * code and completion status). + */ + public static SystemException readSystemException(InputStream input, + ServiceContext[] contexts) + { + SystemException exception; + + String idl = input.read_string(); + int minor = input.read_ulong(); + CompletionStatus completed = CompletionStatusHelper.read(input); + + try + { + exception = (SystemException) createObject(idl, null); + exception.minor = minor; + exception.completed = completed; + } + catch (Exception ex) + { + UNKNOWN u = new UNKNOWN("Unsupported system exception " + idl, minor, + completed); + u.initCause(ex); + throw u; + } + + try + { + // If UnknownExceptionInfo is present in the contexts, read it and + // set as a cause of this exception. + ServiceContext uEx = ServiceContext.find( + ServiceContext.UnknownExceptionInfo, contexts); + + if (uEx != null) + { + BufferredCdrInput in = new BufferredCdrInput(uEx.context_data); + in.setOrb(in.orb()); + if (input instanceof AbstractCdrInput) + { + ((AbstractCdrInput) input).cloneSettings(in); + } + + Throwable t = UnknownExceptionCtxHandler.read(in, contexts); + exception.initCause(t); + } + } + catch (Exception ex) + { + // Unsupported context format. Do not terminate as the user program may + // not need it. + } + + return exception; + } + + /** + * Reads the user exception, having the given Id, from the input stream. The + * id is expected to be in the form like + * 'IDL:test/org/omg/CORBA/ORB/communication/ourUserException:1.0' + * + * @param idl the exception idl name. + * @param input the stream to read from. + * + * @return the loaded exception. + * @return null if the helper class cannot be found. + */ + public static UserException readUserException(String idl, InputStream input) + { + try + { + Class helperClass = findHelper(idl); + + Method read = helperClass.getMethod("read", + new Class[] { org.omg.CORBA.portable.InputStream.class }); + + return (UserException) read.invoke(null, new Object[] { input }); + } + catch (MARSHAL mex) + { + // This one is ok to throw + throw mex; + } + catch (Exception ex) + { + ex.printStackTrace(); + return null; + } + } + + /** + * Gets the helper class name from the string like + * 'IDL:test/org/omg/CORBA/ORB/communication/ourUserException:1.0' + * + * @param IDL the idl name. + */ + public static String toHelperName(String IDL) + { + String s = IDL; + int a = s.indexOf(':') + 1; + int b = s.lastIndexOf(':'); + + s = IDL.substring(a, b); + + if (s.startsWith(OMG_PREFIX)) + s = JAVA_PREFIX + s.substring(OMG_PREFIX.length()); + + return s.replace('/', '.') + "Helper"; + } + + /** + * Writes the system exception data to CDR output stream. + * + * @param output a stream to write data to. + * @param ex an exception to write. + */ + public static void writeSystemException(OutputStream output, + SystemException ex) + { + String exIDL = getRepositoryId(ex.getClass()); + output.write_string(exIDL); + output.write_ulong(ex.minor); + CompletionStatusHelper.write(output, ex.completed); + } + + /** + * Converts the given IDL name to class name. + * + * @param IDL the idl name. + * + */ + protected static String toClassName(String prefix, String IDL) + { + String s = IDL; + int a = s.indexOf(':') + 1; + int b = s.lastIndexOf(':'); + + s = IDL.substring(a, b); + + if (s.startsWith(OMG_PREFIX)) + s = prefix + s.substring(OMG_PREFIX.length()); + + return s.replace('/', '.'); + } + + /** + * Converts the given IDL name to class name and tries to load the matching + * class. The OMG prefix (omg.org) is replaced by the java prefix org.omg. No + * other prefixes are added. + * + * @param IDL the idl name. + * + * @return the matching class or null if no such is available. + */ + public static Class Idl2class(String IDL) + { + synchronized (m_classes) + { + Class c = (Class) m_classes.get(IDL); + + if (c != null) + return c; + else + { + String s = IDL; + int a = s.indexOf(':') + 1; + int b = s.lastIndexOf(':'); + + s = IDL.substring(a, b); + + if (s.startsWith(OMG_PREFIX)) + s = JAVA_PREFIX + s.substring(OMG_PREFIX.length()); + + String cn = s.replace('/', '.'); + + try + { + c = forName(cn); + m_classes.put(IDL, c); + return c; + } + catch (ClassNotFoundException ex) + { + return null; + } + } + } + } + + /** + * Converts the given IDL name to class name, tries to load the matching class + * and create an object instance with parameterless constructor. The OMG + * prefix (omg.org) is replaced by the java prefix org.omg. No other prefixes + * are added. + * + * @param IDL the idl name. + * + * @return instantiated object instance or null if such attempt was not + * successful. + */ + public static java.lang.Object Idl2Object(String IDL) + { + Class cx = Idl2class(IDL); + + try + { + if (cx != null) + return cx.newInstance(); + else + return null; + } + catch (Exception ex) + { + return null; + } + } + + /** + * Convert the class name to IDL or RMI name (repository id). If the class + * inherits from IDLEntity, ValueBase or SystemException, returns repository + * Id in the IDL:(..) form. If it does not, returns repository Id in the + * RMI:(..) form. + * + * @param cx the class for that the name must be computed. + * + * @return the idl or rmi name. + */ + public static synchronized String getRepositoryId(Class cx) + { + String name = (String) m_names.get(cx); + if (name != null) + return name; + + String cn = cx.getName(); + if (!(IDLEntity.class.isAssignableFrom(cx) + || ValueBase.class.isAssignableFrom(cx) || SystemException.class.isAssignableFrom(cx))) + { + // Not an IDL entity. + name = Util.createValueHandler().getRMIRepositoryID(cx); + } + else + { + if (cn.startsWith(JAVA_PREFIX)) + cn = OMG_PREFIX + + cn.substring(JAVA_PREFIX.length()).replace('.', '/'); + else if (cn.startsWith(CLASSPATH_PREFIX)) + cn = OMG_PREFIX + + cn.substring(CLASSPATH_PREFIX.length()).replace('.', '/'); + + name = "IDL:" + cn + ":1.0"; + } + m_names.put(cx, name); + return name; + } + + /** + * Insert the passed parameter into the given Any, assuming that the helper + * class is available. The helper class must have the "Helper" suffix and be + * in the same package as the class of the object being inserted. + * + * @param into the target to insert. + * + * @param object the object to insert. It can be any object as far as the + * corresponding helper is provided. + * + * @return true on success, false otherwise. + */ + public static boolean insertWithHelper(Any into, Object object) + { + try + { + String helperClassName = object.getClass().getName() + "Helper"; + Class helperClass = forName(helperClassName); + + Method insert = helperClass.getMethod("insert", new Class[] { + Any.class, object.getClass() }); + + insert.invoke(null, new Object[] { into, object }); + + return true; + } + catch (Exception exc) + { + // Failed due some reason. + return false; + } + } + + /** + * Insert the system exception into the given Any. + */ + public static boolean insertSysException(Any into, SystemException exception) + { + try + { + BufferedCdrOutput output = new BufferedCdrOutput(); + + String m_exception_id = getRepositoryId(exception.getClass()); + output.write_string(m_exception_id); + output.write_ulong(exception.minor); + CompletionStatusHelper.write(output, exception.completed); + + String name = getDefaultName(m_exception_id); + + GeneralHolder h = new GeneralHolder(output); + + into.insert_Streamable(h); + + RecordTypeCode r = new RecordTypeCode(TCKind.tk_except); + r.setId(m_exception_id); + r.setName(name); + into.type(r); + + return true; + } + catch (Exception ex) + { + ex.printStackTrace(); + return false; + } + } + + /** + * Get the type name from the IDL string. + */ + public static String getDefaultName(String idl) + { + int f1 = idl.lastIndexOf("/"); + int p1 = (f1 < 0) ? 0 : f1; + int p2 = idl.indexOf(":", p1); + if (p2 < 0) + p2 = idl.length(); + + String name = idl.substring(f1 + 1, p2); + return name; + } + + /** + * Insert this exception into the given Any. On failure, insert the UNKNOWN + * exception. + */ + public static void insertException(Any into, Throwable exception) + { + boolean ok = false; + if (exception instanceof SystemException) + ok = insertSysException(into, (SystemException) exception); + else if (exception instanceof UserException) + ok = insertWithHelper(into, exception); + + if (!ok) + ok = insertSysException(into, new UNKNOWN()); + if (!ok) + throw new InternalError("Exception wrapping broken"); + } + + /** + * Find helper for the class with the given name. + */ + public static Class findHelper(String idl) + { + synchronized (m_helpers) + { + Class c = (Class) m_helpers.get(idl); + if (c != null) + return c; + try + { + String helper = toHelperName(idl); + c = forName(helper); + + m_helpers.put(idl, c); + return c; + } + catch (Exception ex) + { + return null; + } + } + } + + /** + * Load the class with the given name. This method tries to use the context + * class loader first. If this fails, it searches for the suitable class + * loader in the caller stack trace. This method is a central point where all + * requests to find a class by name are delegated. + */ + public static Class forName(String className) throws ClassNotFoundException + { + try + { + return Class.forName(className, true, + Thread.currentThread().getContextClassLoader()); + } + catch (ClassNotFoundException nex) + { + /** + * Returns the first user defined class loader on the call stack, or + * null when no non-null class loader was found. + */ + Class[] ctx = VMStackWalker.getClassContext(); + for (int i = 0; i < ctx.length; i++) + { + // Since we live in a class loaded by the bootstrap + // class loader, getClassLoader is safe to call without + // needing to be wrapped in a privileged action. + ClassLoader cl = ctx[i].getClassLoader(); + try + { + if (cl != null) + return Class.forName(className, true, cl); + } + catch (ClassNotFoundException nex2) + { + // Try next. + } + } + } + throw new ClassNotFoundException(className); + } +} diff --git a/libjava/classpath/gnu/CORBA/OctetHolder.java b/libjava/classpath/gnu/CORBA/OctetHolder.java new file mode 100644 index 000000000..06d7538d7 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/OctetHolder.java @@ -0,0 +1,129 @@ +/* OctetHolder.java -- + 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.CORBA; + +import gnu.CORBA.typecodes.PrimitiveTypeCode; + +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.Streamable; +import org.omg.CORBA.TCKind; +import org.omg.CORBA.TypeCode; + +/** + * A holder for CORBA octet that is mapped into + * java long. + * + * The holders have several application areas. The end user usually + * sees them implementing CORBA methods where the primitive type + * is passed by reference. While CORBA (or, for example, C) supports + * this, the java does not and a wrapper class is required. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public final class OctetHolder + implements Streamable +{ + /** + * The default type code for this holder. + */ + private static final TypeCode t_octet = + new PrimitiveTypeCode(TCKind.tk_octet); + + /** + * The long (CORBA octet) value, + * held by this OctetHolder. + */ + public byte value; + + /** + * Constructs an instance of OctetHolder, + * initializing {@link #value} to 0 . + */ + public OctetHolder() + { + } + + /** + * Constructs an instance of OctetHolder, + * initializing {@link #value} to the given octed (byte). + * + * @param initial_value a value that will be assigned to the + * {@link #value} field. + */ + public OctetHolder(byte initial_value) + { + value = initial_value; + } + + /** + * Fill in the {@link value } field by reading the required data + * from the given stream. For octet, the functionality + * is delegated to + * {@link org.omg.CORBA.portable.InputStream#read_octet}. + * + * @param input the input stream to read from. + */ + public void _read(InputStream input) + { + value = input.read_octet(); + } + + /** + * Returns the TypeCode, corresponding the CORBA type that is stored + * using this holder. + */ + public TypeCode _type() + { + return t_octet; + } + + /** + * Write the {@link value } field to the given stream. + * For octet, the functionality + * is delegated to + * {@link org.omg.CORBA.portable.OutputStream#write_octet(long) }. + * + * @param output the output stream to write into. + */ + public void _write(OutputStream output) + { + output.write_octet(value); + } +} diff --git a/libjava/classpath/gnu/CORBA/OrbFocused.java b/libjava/classpath/gnu/CORBA/OrbFocused.java new file mode 100644 index 000000000..de5d49e36 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/OrbFocused.java @@ -0,0 +1,375 @@ +/* OrbFocused.java -- + 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.CORBA; + +import gnu.CORBA.Poa.ORB_1_4; + +import org.omg.CORBA.BAD_INV_ORDER; +import org.omg.CORBA.BAD_OPERATION; +import org.omg.CORBA.BAD_PARAM; +import org.omg.CORBA.CompletionStatus; +import org.omg.CORBA.NO_RESOURCES; +import org.omg.CORBA.portable.InvokeHandler; + +import java.applet.Applet; +import java.net.ServerSocket; +import java.util.Iterator; +import java.util.Properties; +import java.util.Random; +import java.util.StringTokenizer; + +/** + * This class implements the ORB that uses a single port or the restricted port + * range for all its objects. It is required to for use together with various + * firewalls that does not allow opening multiple randomly selected ports, as + * the defauld CORBA implementation used to do. The firewal must be configured + * to allow CORBA to work on one fixed port or (for better performance) on a + * small fixed range of ports. This does not restrict the maximal number of the + * connected objects as the objects can share the same port. + * + * The used port or the used port range can be specified via property + * gnu.CORBA.ListenerPort. The value of this property is a single port or range + * of ports, boundary values (inclusive) being separeted by dash (for instance, + * "1245-1250"). + * + * It is possible to instantiate multiple instances of the focused ORBs and + * combine them with the ordinary ORBs. If you instantiate several instances of + * the focused ORBs on the same host, they used port sets should not overlap. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class OrbFocused + extends ORB_1_4 +{ + /** + * The name of the fixed port range property. The presence of this property + * indicates that the default focused ORB must be used. + */ + public static final String LISTENER_PORT = "gnu.CORBA.ListenerPort"; + + /** + * The start of the range of the available ports, inclusive. + */ + int m_ports_from = -1; + + /** + * The end of the range of the available ports, inclusive. + */ + int m_ports_to = -1; + + /** + * The requests to port are served in parallel threads. + */ + static final int PARALLEL = 0; + + /** + * The requests to port are served in the same thread. + */ + static final int SEQUENTIAL = 1; + + /** + * The random number generator to get a random port in the valid range. + */ + Random m_random = new Random(); + + /** + * Parse the "gnu.CORBA.ListenerPort" property and initialize the valid port + * set range. + */ + public void setPortRange(String property) + { + int from, to; + try + { + StringTokenizer st = new StringTokenizer(property, " -"); + if (st.countTokens() == 1) + from = to = Integer.parseInt(st.nextToken()); + else + { + from = Integer.parseInt(st.nextToken()); + to = Integer.parseInt(st.nextToken()); + m_random = new Random(); + } + setPortRange(from, to); + } + catch (Exception ex) + { + throw new BAD_PARAM("Unable to parse port range '" + property + "'"); + } + } + + /** + * Set the port range. + * + * @param from - start of the port range, inclusive. + * @param to - end of the port range, inclusive. + */ + public void setPortRange(int from, int to) + { + if (from < 0 || to < 0 || to < from) + throw new BAD_PARAM("Invalid range"); + m_ports_from = from; + m_ports_to = to; + } + + /** + * Get the port from the previously specified usage range. + */ + int getPortFromRange(int attempt) + { + if (m_ports_from == m_ports_to) + return m_ports_from; + else if (m_ports_to - m_ports_from < RANDOM_PORT_ATTEMPTS) + return m_ports_from + (attempt % (m_ports_to - m_ports_from + 1)); + else + return m_random.nextInt(m_ports_to - m_ports_from + 1) + m_ports_from; + } + + /** + * Get the shared port server where the new object can be added. This may + * result reusing the existing server or instantiating a new server. If the + * new server is instantiated and the ORB is already running, the server is + * started. + */ + protected portServer getPortServer(int type) + { + portServer p; + + int n; + if (m_ports_from < m_ports_to) + n = RANDOM_PORT_ATTEMPTS; + else + n = 1; + + Ports: for (int a = 0; a < n; a++) + { + int port = getPortFromRange(a); + for (int i = 0; i < portServers.size(); i++) + { + p = (portServer) portServers.get(i); + if (p.s_port == port) + { + return p; + } + } + // The server is not yet instantiated. Instantiate. + try + { + // Check if the port is ok: + ServerSocket s = socketFactory.createServerSocket(port); + s.close(); + + portServer shared; + + switch (type) + { + case PARALLEL: + shared = new portServer(port); + break; + + case SEQUENTIAL: + shared = new sharedPortServer(port); + break; + + default: + throw new InternalError("Invalid server type " + type); + } + + portServers.add(shared); + + if (running) + shared.start(); + + return shared; + } + catch (Exception ex) + { + // Port is taken or probably other problems. + continue Ports; + } + } + throw new NO_RESOURCES("No free port available at " + m_ports_from + "-" + + m_ports_to, Minor.Ports, CompletionStatus.COMPLETED_NO); + } + + /** + * Start the ORBs main working cycle (receive invocation - invoke on the local + * object - send response - wait for another invocation). + * + * The method only returns after calling {@link #shutdown(boolean)}. + */ + public void run() + { + if (m_ports_from < 0 || m_ports_to < 0) + throw new BAD_INV_ORDER("For " + getClass().getName() + " " + + LISTENER_PORT + " property must be set"); + + running = true; + + // Start all port servers. In the current subclass, the portServers + // collection must be already filled in. + Iterator iter = portServers.iterator(); + + while (iter.hasNext()) + { + portServer subserver = (portServer) iter.next(); + + if (!subserver.isAlive()) + { + // Reuse the current thread for the last portServer. + if (!iter.hasNext()) + { + // Discard the iterator. + iter = null; + subserver.run(); + return; + } + else + subserver.start(); + } + } + } + + /** + * Get free port from the allowed range. This method instantiates the port + * server for the returned port. + */ + public int getFreePort() + throws BAD_OPERATION + { + portServer s = getPortServer(PARALLEL); + return s.s_port; + } + + /** + * Connect the given CORBA object to this ORB, explicitly specifying the + * object key and the identity of the thread (and port), where the object must + * be served. The identity is normally the POA. + * + * The new port server will be started only if there is no one already running + * for the same identity. Otherwise, the task of the existing port server will + * be widened, including duty to serve the given object. All objects, + * connected to a single identity by this method, will process they requests + * subsequently in the same thread. The method is used when the expected + * number of the objects is too large to have a single port and thread per + * object. This method is used by POAs, having a single thread policy. + * + * @param object the object, must implement the {@link InvokeHandler}) + * interface. + * @param key the object key, usually used to identify the object from remote + * side. + * @param port the port, where the object must be connected. + * + * @throws BAD_PARAM if the object does not implement the + * {@link InvokeHandler}). + */ + public void connect_1_thread(org.omg.CORBA.Object object, byte[] key, + java.lang.Object identity) + { + sharedPortServer shared = (sharedPortServer) identities.get(identity); + if (shared == null) + { + shared = (sharedPortServer) getPortServer(SEQUENTIAL); + identities.put(identity, shared); + if (running) + { + shared.start(); + } + } + + Connected_objects.cObject ref = connected_objects.add(key, object, + shared.s_port, identity); + IOR ior = createIOR(ref); + prepareObject(object, ior); + } + + /** + * In this type of ORB, the service is started by {@link #getPortServer}. The + * method below is not in use and should return without action. + */ + public void startService(IOR ior) + { + } + + /** + * Set parameters (additionally search for the port range property). + */ + protected void set_parameters(Applet applet, Properties props) + { + super.set_parameters(applet, props); + String lp = applet.getParameter(LISTENER_PORT); + if (lp != null) + setPortRange(lp); + } + + /** + * Set parameters (additionally search for the port range property). + */ + protected void set_parameters(String[] args, Properties props) + { + super.set_parameters(args, props); + String lp = null; + + String lpKey = "-" + LISTENER_PORT; + + if (args != null) + if (args.length >= 2) + { + for (int i = 0; i < args.length - 1; i++) + if (args[i].equals(lpKey)) + lp = args[i + 1]; + } + + if (lp != null) + setPortRange(lp); + + } + + /** + * Additionally set the port range property, when applicable. + */ + protected void useProperties(Properties props) + { + super.useProperties(props); + String lp = props.getProperty(LISTENER_PORT); + if (lp != null) + setPortRange(lp); + } + +} diff --git a/libjava/classpath/gnu/CORBA/OrbFunctional.java b/libjava/classpath/gnu/CORBA/OrbFunctional.java new file mode 100644 index 000000000..88848dd1b --- /dev/null +++ b/libjava/classpath/gnu/CORBA/OrbFunctional.java @@ -0,0 +1,1794 @@ +/* OrbFunctional.java -- + 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.CORBA; + +import gnu.CORBA.CDR.UnknownExceptionCtxHandler; +import gnu.CORBA.CDR.BufferredCdrInput; +import gnu.CORBA.CDR.BufferedCdrOutput; +import gnu.CORBA.GIOP.CloseMessage; +import gnu.CORBA.GIOP.ErrorMessage; +import gnu.CORBA.GIOP.MessageHeader; +import gnu.CORBA.GIOP.ReplyHeader; +import gnu.CORBA.GIOP.RequestHeader; +import gnu.CORBA.NamingService.NameParser; +import gnu.CORBA.NamingService.NamingServiceTransient; +import gnu.CORBA.Poa.gnuForwardRequest; +import gnu.CORBA.interfaces.SocketFactory; + +import org.omg.CORBA.BAD_OPERATION; +import org.omg.CORBA.BAD_PARAM; +import org.omg.CORBA.CompletionStatus; +import org.omg.CORBA.MARSHAL; +import org.omg.CORBA.NO_RESOURCES; +import org.omg.CORBA.OBJECT_NOT_EXIST; +import org.omg.CORBA.Request; +import org.omg.CORBA.SystemException; +import org.omg.CORBA.UNKNOWN; +import org.omg.CORBA.WrongTransaction; +import org.omg.CORBA.ORBPackage.InvalidName; +import org.omg.CORBA.portable.Delegate; +import org.omg.CORBA.portable.InvokeHandler; +import org.omg.CORBA.portable.ObjectImpl; +import org.omg.CORBA.portable.UnknownException; +import org.omg.CosNaming.NamingContextExt; +import org.omg.CosNaming.NamingContextExtHelper; + +import java.applet.Applet; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Map; +import java.util.Properties; +import java.util.Random; +import java.util.StringTokenizer; +import java.util.TreeMap; + +/** + * The ORB implementation, capable to handle remote invocations on the + * registered object. This class implements all features, required till the jdk + * 1.3 inclusive, but does not support the POA that appears since 1.4. The POA + * is supported by {@link gnu.CORBA.Poa.ORB_1_4}. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class OrbFunctional extends OrbRestricted +{ + /** + * A server, responsible for listening on requests on some local port. The ORB + * may listen on multiple ports and process the requests in separate threads. + * Normally the server takes one port per object being served. + */ + protected class portServer + extends Thread + { + /** + * The number of the currently running parallel threads. + */ + int running_threads; + + /** + * The port on that this portServer is listening for requests. + */ + int s_port; + + /** + * The server socket of this portServer. + */ + ServerSocket service; + + /** + * True if the serving node must shutdown due call of the close_now(). + */ + boolean terminated; + + /** + * Create a new portServer, serving on specific port. + */ + portServer(int _port) + { + s_port = _port; + setDaemon(true); + try + { + service = socketFactory.createServerSocket(s_port); + } + catch (IOException ex) + { + BAD_OPERATION bad = new BAD_OPERATION( + "Unable to open the server socket at " + s_port); + bad.minor = Minor.Socket; + bad.initCause(ex); + throw bad; + } + } + + /** + * Enter the serving loop (get request/process it). All portServer normally + * terminate thy threads when the OrbFunctional.running is set to false. + */ + public void run() + { + while (running) + { + try + { + tick(); + } + catch (SocketException ex) + { + // May be thrown when the service is closed by + // the close_now(). + if (terminated) + return; + } + catch (Exception iex) + { + // Wait. Do not terminate the + // service due potentially transient error. + try + { + Thread.sleep(TWAIT_SERVER_ERROR_PAUSE); + } + catch (InterruptedException ex) + { + } + } + } + } + + /** + * Perform a single serving step. + * + * @throws java.lang.Exception + */ + void tick() + throws Exception + { + serve(this, service); + } + + /** + * Forcibly close the server socket and mark this port as free. + */ + public void close_now() + { + try + { + terminated = true; + service.close(); + } + catch (Exception ex) + { + // This may happen if the service has not been opened or + // cannot be closed. Return without action. + } + } + + /** + * If the thread is no longer in use, close the socket (if opened). + */ + protected void finalize() + { + close_now(); + } + } + + /** + * A server, responsible for listening on requests on some local port and + * serving multiple requests (probably to the different objects) on the same + * thread. + */ + protected class sharedPortServer extends portServer + { + /** + * Create a new portServer, serving on specific port. + */ + sharedPortServer(int _port) + { + super(_port); + } + + /** + * Perform a single serving step. + * + * @throws java.lang.Exception + */ + void tick() throws Exception + { + Socket request = service.accept(); + serveStep(request, false); + } + } + + /** + * The default value where the first instance of this ORB will start looking + * for a free port. + */ + public static int DEFAULT_INITIAL_PORT = 1126; + + /** + * When trying to open the socket on a random port, start of the interval to + * try. + */ + public static int RANDOM_PORT_FROM = 1024; + + /** + * When trying to open the socket on a random port, end of the interval to + * try. + */ + public static int RANDOM_PORT_TO = 4024; + + /** + * The number of attempts to try when opening random port. + */ + public static int RANDOM_PORT_ATTEMPTS = 64; + + /** + * The property of port, on that this ORB is listening for requests from + * clients. This class supports one port per ORB only. + */ + public static final String LISTEN_ON = "gnu.classpath.CORBA.ListenOn"; + + /** + * The property, defining the IOR of the intial reference to resolve. + */ + public static final String REFERENCE = "org.omg.CORBA.ORBInitRef"; + + /** + * The property, defining the port on that the default name service is + * running. + */ + public static final String NS_PORT = "org.omg.CORBA.ORBInitialPort"; + + /** + * The property, defining the host on that the default name service is + * running. + */ + public static final String NS_HOST = "org.omg.CORBA.ORBInitialHost"; + + /** + * The string, defining the naming service initial reference. + */ + public static final String NAME_SERVICE = "NameService"; + + /** + * Defines the ORB ID that is accessible by IOR interceptors. + */ + public static final String ORB_ID = "org.omg.CORBA.ORBid"; + + + /** + * Defines the SERVER ID that is accessible by IOR interceptors. + */ + public static final String SERVER_ID = "org.omg.CORBA.ServerId"; + + /** + * The if the client has once opened a socket, it should start sending the + * message header in a given time. Otherwise the server will close the socket. + * This prevents server hang when the client opens the socket, but does not + * send any message, usually due crash on the client side. + */ + public static String START_READING_MESSAGE = + "gnu.classpath.CORBA.TOUT_START_READING_MESSAGE"; + + /** + * If the client has started to send the request message, the socket time out + * changes to the specified value. + */ + public static String WHILE_READING = + "gnu.classpath.CORBA.TOUT_WHILE_READING"; + + /** + * If the message body is received, the time out changes to the specifice + * value. This must be longer, as includes time, required to process the + * received task. We make it 40 minutes. + */ + public static String AFTER_RECEIVING = + "gnu.classpath.CORBA.TOUT_AFTER_RECEIVING"; + + /** + * The server waits for this duration after the potentially transient error + * during its servicing cycle. + */ + public static String SERVER_ERROR_PAUSE = + "gnu.classpath.CORBA.SERVER_ERROR_PAUSE"; + + /** + * The address of the local host. + */ + public final String LOCAL_HOST; + + /** + * The if the client has once opened a socket, it should start sending the + * message header in a given time. Otherwise the server will close the socket. + * This prevents server hang when the client opens the socket, but does not + * send any message, usually due crash on the client side. + */ + public int TOUT_START_READING_MESSAGE = 20 * 1000; + + // (Here and below, we use * to make the meaning of the constant clearler). + + /** + * If the client has started to send the request message, the socket time out + * changes to the specified value. + */ + public int TOUT_WHILE_READING = 2 * 60 * 1000; + + /** + * If the message body is received, the time out changes to the specifice + * value. This must be longer, as includes time, required to process the + * received task. We make it 40 minutes. + */ + public int TOUT_AFTER_RECEIVING = 40 * 60 * 1000; + + /** + * The server waits for this duration after the potentially transient error + * during its servicing cycle. + */ + public int TWAIT_SERVER_ERROR_PAUSE = 5000; + + /** + * Some clients tend to submit multiple requests over the same socket. The + * server waits for the next request on the same socket for the duration, + * specified below. In additions, the request of this implementation also + * waits for the same duration before closing the socket. The default time is + * seven seconds. + */ + public static int TANDEM_REQUESTS = 7000; + + /** + * The Id of this ORB. + */ + public String orb_id = "orb_"+hashCode(); + + /** + * The Id of this Server. This field is defined static to ensure it has + * the same value over all ORB's in this machine. + */ + public static String server_id = "server_"+OrbFunctional.class.hashCode(); + + /** + * The map of the already conncted objects. + */ + protected final Connected_objects connected_objects = + new Connected_objects(); + + /** + * The maximal CORBA version, supported by this ORB. The default value 0 means + * that the ORB will not check the request version while trying to respond. + */ + protected Version max_version; + + /** + * Setting this value to false causes the ORB to shutdown after the latest + * serving operation is complete. + */ + protected boolean running; + + /** + * The map of the initial references. + */ + protected Map initial_references = new TreeMap(); + + /** + * The currently active portServers. + */ + protected ArrayList portServers = new ArrayList(); + + /** + * The host, on that the name service is expected to be running. + */ + private String ns_host; + + /** + * Probably free port, under that the ORB will try listening for remote + * requests first. When the new object is connected, this port is used first, + * then it is incremented by 1, etc. If the given port is not available, up to + * 20 subsequent values are tried and then the parameterless server socket + * contructor is called. The constant is shared between multiple instances of + * this ORB. + */ + private static int Port = DEFAULT_INITIAL_PORT; + + /** + * The port, on that the name service is expected to be running. + */ + private int ns_port = 900; + + /** + * The name parser. + */ + NameParser nameParser = new NameParser(); + + /** + * The instance, stored in this field, handles the asynchronous dynamic + * invocations. + */ + protected Asynchron asynchron = new Asynchron(); + + /** + * The list of the freed ports. The ORB reuses ports, when possible. + */ + protected LinkedList freed_ports = new LinkedList(); + + /** + * Maps a single-threaded POAs to they sharedPortServants. + */ + protected Hashtable identities = new Hashtable(); + + /** + * The maximal allowed number of the currently running parallel threads per + * object. For security reasons, this is made private and unchangeable. After + * exceeding this limit, the NO_RESOURCES is thrown back to the client. + */ + private int MAX_RUNNING_THREADS = 256; + + /** + * The producer of the client and server sockets for this ORB. + */ + public SocketFactory socketFactory = DefaultSocketFactory.Singleton; + + /** + * Create the instance of the Functional ORB. + */ + public OrbFunctional() + { + try + { + LOCAL_HOST = ns_host = InetAddress.getLocalHost().getHostAddress(); + initial_references.put("CodecFactory", new gnuCodecFactory(this)); + } + catch (UnknownHostException ex) + { + BAD_OPERATION bad = + new BAD_OPERATION("Unable to open the server socket."); + bad.initCause(ex); + throw bad; + } + } + + /** + * If the max version is assigned, the orb replies with the error message if + * the request version is above the supported 1.2 version. This behavior is + * recommended by OMG, but not all implementations respond that error message + * by re-sending the request, encoded in the older version. + */ + public void setMaxVersion(Version max_supported) + { + max_version = max_supported; + } + + /** + * Get the maximal supported GIOP version or null if the version is not + * checked. + */ + public Version getMaxVersion() + { + return max_version; + } + + /** + * Get the currently free port, starting from the initially set port and going + * up max 20 steps, then trying to bind into any free address. + * + * @return the currently available free port. + * + * @throws NO_RESOURCES if the server socked cannot be opened on the local + * host. + */ + public int getFreePort() + throws BAD_OPERATION + { + ServerSocket s; + int a_port; + + try + { + // If there are some previously freed ports, use them first. + if (!freed_ports.isEmpty()) + { + Integer free = (Integer) freed_ports.getLast(); + freed_ports.removeLast(); + s = socketFactory.createServerSocket(free.intValue()); + s.close(); + return free.intValue(); + } + } + catch (Exception ex) + { + // This may be thrown if the request for the new port has arrived + // before the current service is completly shutdown. + // OK then, use a new port. + } + + for (a_port = Port; a_port < Port + 20; a_port++) + { + try + { + s = socketFactory.createServerSocket(a_port); + s.close(); + Port = a_port + 1; + return a_port; + } + catch (IOException ex) + { + // Repeat the loop if this exception has been thrown. + } + } + + Random rand = new Random(); + // Try any random port in the interval RANDOM_PORT_FROM.RANDOM_PORT_TO. + int range = RANDOM_PORT_TO - RANDOM_PORT_FROM; + IOException ioex = null; + for (int i = 0; i < RANDOM_PORT_ATTEMPTS; i++) + { + try + { + a_port = RANDOM_PORT_FROM + rand.nextInt(range); + s = socketFactory.createServerSocket(a_port); + s.close(); + return a_port; + } + catch (IOException ex) + { + // Repeat the loop if this exception has been thrown. + ioex = ex; + } + } + + NO_RESOURCES bad = new NO_RESOURCES("Unable to open the server socket."); + bad.minor = Minor.Ports; + if (ioex != null) + bad.initCause(ioex); + throw bad; + } + + /** + * Set the port, on that the server is listening for the client requests. If + * only one object is connected to the orb, the server will be try listening + * on this port first. It the port is busy, or if more objects are connected, + * the subsequent object will receive a larger port values, skipping + * unavailable ports, if required. The change applies globally. + * + * @param a_Port a port, on that the server is listening for requests. + */ + public static void setPort(int a_Port) + { + Port = a_Port; + } + + /** + * Connect the given CORBA object to this ORB. After the object is connected, + * it starts receiving remote invocations via this ORB. + * + * The ORB tries to connect the object to the port, that has been previously + * set by {@link setPort(int)}. On failure, it tries 20 subsequent larger + * values and then calls the parameterless server socked constructor to get + * any free local port. If this fails, the {@link NO_RESOURCES} is thrown. + * + * @param object the object, must implement the {@link InvokeHandler}) + * interface. + * + * @throws BAD_PARAM if the object does not implement the + * {@link InvokeHandler}). + */ + public void connect(org.omg.CORBA.Object object) + { + int a_port = getFreePort(); + + Connected_objects.cObject ref = connected_objects.add(object, a_port); + IOR ior = createIOR(ref); + prepareObject(object, ior); + if (running) + startService(ior); + } + + /** + * Connect the given CORBA object to this ORB, explicitly specifying the + * object key. + * + * The ORB tries to connect the object to the port, that has been previously + * set by {@link setPort(int)}. On failure, it tries 20 subsequent larger + * values and then calls the parameterless server socked constructor to get + * any free local port. If this fails, the {@link NO_RESOURCES} is thrown. + * + * @param object the object, must implement the {@link InvokeHandler}) + * interface. + * @param key the object key, usually used to identify the object from remote + * side. + * + * @throws BAD_PARAM if the object does not implement the + * {@link InvokeHandler}). + */ + public void connect(org.omg.CORBA.Object object, byte[] key) + { + int a_port = getFreePort(); + + Connected_objects.cObject ref = + connected_objects.add(key, object, a_port, null); + IOR ior = createIOR(ref); + prepareObject(object, ior); + if (running) + startService(ior); + } + + /** + * Connect the given CORBA object to this ORB, explicitly specifying the + * object key and the identity of the thread (and port), where the object must + * be served. The identity is normally the POA. + * + * The new port server will be started only if there is no one already running + * for the same identity. Otherwise, the task of the existing port server will + * be widened, including duty to serve the given object. All objects, + * connected to a single identity by this method, will process they requests + * subsequently in the same thread. The method is used when the expected + * number of the objects is too large to have a single port and thread per + * object. This method is used by POAs, having a single thread policy. + * + * @param object the object, must implement the {@link InvokeHandler}) + * interface. + * @param key the object key, usually used to identify the object from remote + * side. + * @param port the port, where the object must be connected. + * + * @throws BAD_PARAM if the object does not implement the + * {@link InvokeHandler}). + */ + public void connect_1_thread(org.omg.CORBA.Object object, byte[] key, + java.lang.Object identity + ) + { + sharedPortServer shared = (sharedPortServer) identities.get(identity); + if (shared == null) + { + int a_port = getFreePort(); + shared = new sharedPortServer(a_port); + identities.put(identity, shared); + if (running) + { + portServers.add(shared); + shared.start(); + } + } + + Connected_objects.cObject ref = + connected_objects.add(key, object, shared.s_port, identity); + IOR ior = createIOR(ref); + prepareObject(object, ior); + } + + /** + * Start the service on the given port of this IOR. + * + * @param ior the ior (only Internet.port is used). + */ + public void startService(IOR ior) + { + portServer p = new portServer(ior.Internet.port); + portServers.add(p); + p.start(); + } + + /** + * Destroy this server, releasing the occupied resources. + */ + public void destroy() + { + portServer p; + for (int i = 0; i < portServers.size(); i++) + { + p = (portServer) portServers.get(i); + p.close_now(); + } + super.destroy(); + } + + /** + * Disconnect the given CORBA object from this ORB. The object will be no + * longer receiving the remote invocations. In response to the remote + * invocation on this object, the ORB will send the exception + * {@link OBJECT_NOT_EXIST}. The object, however, is not destroyed and can + * receive the local invocations. + * + * @param object the object to disconnect. + */ + public void disconnect(org.omg.CORBA.Object object) + { + Connected_objects.cObject rmKey = null; + + // Handle the case when it is possible to get the object key. + // Handle the case when the object is known, but not local. + if (object instanceof ObjectImpl) + { + Delegate delegate = ((ObjectImpl) object)._get_delegate(); + if (delegate instanceof SimpleDelegate) + { + byte[] key = ((SimpleDelegate) delegate).getIor().key; + rmKey = connected_objects.get(key); + } + } + + // Try to find and disconned the object that is not an instance of the + // object implementation. + if (rmKey == null) + rmKey = connected_objects.getKey(object); + if (rmKey != null) + { + // Find and stop the corresponding portServer. + portServer p; + StopService: + for (int i = 0; i < portServers.size(); i++) + { + p = (portServer) portServers.get(i); + if (p.s_port == rmKey.port && !(p instanceof sharedPortServer)) + { + p.close_now(); + freed_ports.addFirst(new Integer(rmKey.port)); + break StopService; + } + connected_objects.remove(rmKey.key); + } + } + } + + /** + * Notifies ORB that the shared service indentity (usually POA) is destroyed. + * The matching shared port server is terminated and the identity table entry + * is deleted. If this identity is not known for this ORB, the method returns + * without action. + * + * @param identity the identity that has been destroyed. + */ + public void identityDestroyed(java.lang.Object identity) + { + if (identity == null) + return; + + sharedPortServer ise = (sharedPortServer) identities.get(identity); + if (ise != null) + { + synchronized (connected_objects) + { + ise.close_now(); + identities.remove(identity); + + Connected_objects.cObject obj; + Map.Entry m; + Iterator iter = connected_objects.entrySet().iterator(); + while (iter.hasNext()) + { + m = (Map.Entry) iter.next(); + obj = (Connected_objects.cObject) m.getValue(); + if (obj.identity == identity) + iter.remove(); + } + } + } + } + + /** + * Find the local object, connected to this ORB. + * + * @param ior the ior of the potentially local object. + * + * @return the local object, represented by the given IOR, or null if this is + * not a local connected object. + */ + public org.omg.CORBA.Object find_local_object(IOR ior) + { + // Must be the same host. + if (!ior.Internet.host.equals(LOCAL_HOST)) + return null; + + return find_connected_object(ior.key, ior.Internet.port); + } + + /** + * List the initially available CORBA objects (services). + * + * @return a list of services. + * + * @see resolve_initial_references(String) + */ + public String[] list_initial_services() + { + String[] refs = new String[ initial_references.size() ]; + int p = 0; + + Iterator iter = initial_references.keySet().iterator(); + while (iter.hasNext()) + { + refs [ p++ ] = (String) iter.next(); + } + return refs; + } + + /** + * Get the IOR reference string for the given object. The string embeds + * information about the object repository Id, its access key and the server + * internet address and port. With this information, the object can be found + * by another ORB, possibly located on remote computer. + * + * @param forObject CORBA object + * @return the object IOR representation. + * + * @throws BAD_PARAM if the object has not been previously connected to this + * ORB. + * + * @throws BAD_OPERATION in the unlikely case if the local host address cannot + * be resolved. + * + * @see string_to_object(String) + */ + public String object_to_string(org.omg.CORBA.Object forObject) + { + // Handle the case when the object is known, but not local. + if (forObject instanceof ObjectImpl) + { + Delegate delegate = ((ObjectImpl) forObject)._get_delegate(); + if (delegate instanceof SimpleDelegate) + return ((SimpleDelegate) delegate).getIor().toStringifiedReference(); + } + + // Handle the case when the object is local. + Connected_objects.cObject rec = connected_objects.getKey(forObject); + + if (rec == null) + throw new BAD_PARAM("The object " + forObject + + " has not been previously connected to this ORB" + ); + + IOR ior = createIOR(rec); + + return ior.toStringifiedReference(); + } + + /** + * Get the local IOR for the given object, null if the object is not local. + */ + public IOR getLocalIor(org.omg.CORBA.Object forObject) + { + Connected_objects.cObject rec = connected_objects.getKey(forObject); + if (rec == null) + return null; + else + return createIOR(rec); + } + + /** + * Find and return the easily accessible CORBA object, addressed by name. + * + * @param name the object name. + * @return the object + * + * @throws org.omg.CORBA.ORBPackage.InvalidName if the given name is not + * associated with the known object. + */ + public org.omg.CORBA.Object resolve_initial_references(String name) + throws InvalidName + { + org.omg.CORBA.Object object = null; + try + { + object = (org.omg.CORBA.Object) initial_references.get(name); + if (object == null && name.equals(NAME_SERVICE)) + { + object = getDefaultNameService(); + if (object != null) + initial_references.put(NAME_SERVICE, object); + } + } + catch (Exception ex) + { + InvalidName err = new InvalidName(name); + err.initCause(ex); + throw err; + } + if (object != null) + return object; + else + throw new InvalidName("Not found: '" + name + "'"); + } + + /** + * Start the ORBs main working cycle (receive invocation - invoke on the local + * object - send response - wait for another invocation). The method only + * returns after calling {@link #shutdown(boolean)}. + */ + public void run() + { + CollocatedOrbs.registerOrb(this); + try + { + running = true; + + // Instantiate the port server for each socket. + Iterator iter = connected_objects.entrySet().iterator(); + Map.Entry m; + Connected_objects.cObject obj; + + while (iter.hasNext()) + { + m = (Map.Entry) iter.next(); + obj = (Connected_objects.cObject) m.getValue(); + + portServer subserver; + + if (obj.identity == null) + { + subserver = new portServer(obj.port); + portServers.add(subserver); + } + else + subserver = (portServer) identities.get(obj.identity); + + if (! subserver.isAlive()) + { + // Reuse the current thread for the last portServer. + if (! iter.hasNext()) + { + // Discard the iterator, eliminating lock checks. + iter = null; + subserver.run(); + return; + } + else + subserver.start(); + } + } + } + finally + { + CollocatedOrbs.unregisterOrb(this); + } + } + + /** + * Start the server in a new thread, if not already running. This method is + * used to ensure that the objects being transfered will be served from the + * remote side, if required. If the ORB is started using this method, it + * starts as a daemon thread. + */ + public void ensureRunning() + { + final OrbFunctional THIS = this; + + if (!running) + { + Thread t = new Thread() + { + public void run() + { + THIS.run(); + } + }; + t.setDaemon(true); + t.start(); + } + } + + /** + * Shutdown the ORB server. + * + * @param wait_for_completion if true, the current thread is suspended until + * the shutdown process is complete. + */ + public void shutdown(boolean wait_for_completion) + { + super.shutdown(wait_for_completion); + running = false; + + if (!wait_for_completion) + { + for (int i = 0; i < portServers.size(); i++) + { + portServer p = (portServer) portServers.get(i); + p.close_now(); + } + } + } + + /** + * Find and return the CORBA object, addressed by the given IOR string + * representation. The object can (an usually is) located on a remote + * computer, possibly running a different (not necessary java) CORBA + * implementation. + * + * @param an_ior the object IOR representation string. + * + * @return the found CORBA object. + * @see object_to_string(org.omg.CORBA.Object) + */ + public org.omg.CORBA.Object string_to_object(String an_ior) + { + return nameParser.corbaloc(an_ior, this); + } + + /** + * Convert ior reference to CORBA object. + */ + public org.omg.CORBA.Object ior_to_object(IOR ior) + { + org.omg.CORBA.Object object = find_local_object(ior); + if (object == null) + { + // Check maybe the local object on another ORB, but same VM. + object = CollocatedOrbs.searchLocalObject(ior); + if (object == null) + { + // Surely remote object. + ObjectImpl impl = StubLocator.search(this, ior); + try + { + if (impl._get_delegate() == null) + impl._set_delegate(new IorDelegate(this, ior)); + } + catch (BAD_OPERATION ex) + { + // Some colaborants may throw this exception + // in response to the attempt to get the unset delegate. + impl._set_delegate(new IorDelegate(this, ior)); + } + + object = impl; + } + } + return object; + } + + /** + * Get the default naming service for the case when there no NameService + * entries. + */ + protected org.omg.CORBA.Object getDefaultNameService() + { + if (initial_references.containsKey(NAME_SERVICE)) + return (org.omg.CORBA.Object) initial_references.get(NAME_SERVICE); + + IOR ior = new IOR(); + ior.Id = NamingContextExtHelper.id(); + ior.Internet.host = ns_host; + ior.Internet.port = ns_port; + ior.key = NamingServiceTransient.getDefaultKey(); + + IorObject iorc = new IorObject(this, ior); + NamingContextExt namer = NamingContextExtHelper.narrow(iorc); + initial_references.put(NAME_SERVICE, namer); + return namer; + } + + /** + * Find and return the object, that must be previously connected to this ORB. + * Return null if no such object is available. + * + * @param key the object key. + * @param port the port where the object is connected. + * + * @return the connected object, null if none. + */ + protected org.omg.CORBA.Object find_connected_object(byte[] key, int port) + { + Connected_objects.cObject ref = connected_objects.get(key); + if (ref == null) + return null; + if (port >= 0 && ref.port != port) + return null; + else + return ref.object; + } + + /** + * Set the ORB parameters. This method is normally called from + * {@link #init(Applet, Properties)}. + * + * @param app the current applet. + * + * @param props application specific properties, passed as the second + * parameter in {@link #init(Applet, Properties)}. Can be null. + */ + protected void set_parameters(Applet app, Properties props) + { + useProperties(props); + + String[][] para = app.getParameterInfo(); + if (para != null) + { + for (int i = 0; i < para.length; i++) + { + if (para[i][0].equals(LISTEN_ON)) + Port = Integer.parseInt(para[i][1]); + if (para[i][0].equals(REFERENCE)) + { + StringTokenizer st = new StringTokenizer(para[i][1], "="); + initial_references.put(st.nextToken(), + string_to_object(st.nextToken())); + } + + if (para[i][0].equals(ORB_ID)) + orb_id = para[i][1]; + + if (para[i][0].equals(SERVER_ID)) + server_id = para[i][1]; + + if (para[i][0].equals(NS_HOST)) + ns_host = para[i][1]; + if (para[i][0].equals(START_READING_MESSAGE)) + TOUT_START_READING_MESSAGE = Integer.parseInt(para[i][1]); + if (para[i][0].equals(WHILE_READING)) + TOUT_WHILE_READING = Integer.parseInt(para[i][1]); + if (para[i][0].equals(AFTER_RECEIVING)) + TOUT_AFTER_RECEIVING = Integer.parseInt(para[i][1]); + try + { + if (para[i][0].equals(NS_PORT)) + ns_port = Integer.parseInt(para[i][1]); + } + catch (NumberFormatException ex) + { + BAD_PARAM bad = new BAD_PARAM("Invalid " + NS_PORT + + "property, unable to parse '" + props.getProperty(NS_PORT) + + "'"); + bad.initCause(ex); + throw bad; + } + } + } + } + + /** + * Set the ORB parameters. This method is normally called from + * {@link #init(String[], Properties)}. + * + * @param para the parameters, that were passed as the parameters to the + * main(String[] args) method of the current standalone + * application. + * + * @param props application specific properties that were passed as a second + * parameter in {@link init(String[], Properties)}). Can be null. + */ + protected void set_parameters(String[] para, Properties props) + { + if ((para != null) && para.length > 1) + { + for (int i = 0; i < para.length - 1; i++) + { + if (para[i].endsWith("ListenOn")) + Port = Integer.parseInt(para[i + 1]); + if (para[i].endsWith("ORBInitRef")) + { + StringTokenizer st = new StringTokenizer(para[i + 1], "="); + initial_references.put(st.nextToken(), + string_to_object(st.nextToken())); + } + + if (para[i].endsWith("ORBInitialHost")) + ns_host = para[i + 1]; + + if (para[i].endsWith("ServerId")) + server_id = para[i++]; + else if (para[i].endsWith("ORBid")) + orb_id = para[i++]; + + try + { + if (para[i].endsWith("ORBInitialPort")) + ns_port = Integer.parseInt(para[i + 1]); + } + catch (NumberFormatException ex) + { + throw new BAD_PARAM("Invalid " + para[i] + + "parameter, unable to parse '" + + props.getProperty(para[i + 1]) + "'"); + } + } + } + + useProperties(props); + } + + /** + * Create IOR for the given object references. + */ + protected IOR createIOR(Connected_objects.cObject ref) + throws BAD_OPERATION + { + IOR ior = new IOR(); + ior.key = ref.key; + ior.Internet.port = ref.port; + + if (ref.object instanceof ObjectImpl) + { + ObjectImpl imp = (ObjectImpl) ref.object; + if (imp._ids().length > 0) + ior.Id = imp._ids() [ 0 ]; + } + if (ior.Id == null) + ior.Id = ref.object.getClass().getName(); + + ior.Internet.host = CollocatedOrbs.localHost; + ior.Internet.port = ref.port; + + return ior; + } + + /** + * Prepare object for connecting it to this ORB. + * + * @param object the object being connected. + * + * @throws BAD_PARAM if the object does not implement the + * {@link InvokeHandler}). + */ + protected void prepareObject(org.omg.CORBA.Object object, IOR ior) + throws BAD_PARAM + { + /* + * if (!(object instanceof InvokeHandler)) throw new + * BAD_PARAM(object.getClass().getName() + " does not implement + * InvokeHandler. " ); + */ + + // If no delegate is set, set the default delegate. + if (object instanceof ObjectImpl) + { + ObjectImpl impl = (ObjectImpl) object; + try + { + if (impl._get_delegate() == null) + impl._set_delegate(new SimpleDelegate(this, ior)); + } + catch (BAD_OPERATION ex) + { + // Some colaborants may throw this exception. + impl._set_delegate(new SimpleDelegate(this, ior)); + } + } + } + + /** + * Write the response message. + * + * @param net_out the stream to write response into + * @param msh_request the request message header + * @param rh_request the request header + * @param handler the invocation handler that has been used to invoke the + * operation + * @param sysEx the system exception, thrown during the invocation, null if + * none. + * + * @throws IOException + */ + private void respond_to_client(OutputStream net_out, + MessageHeader msh_request, RequestHeader rh_request, + ResponseHandlerImpl handler, SystemException sysEx + ) throws IOException + { + // Set the reply header properties. + ReplyHeader reply = handler.reply_header; + + if (sysEx != null) + reply.reply_status = ReplyHeader.SYSTEM_EXCEPTION; + else if (handler.isExceptionReply()) + reply.reply_status = ReplyHeader.USER_EXCEPTION; + else + reply.reply_status = ReplyHeader.NO_EXCEPTION; + reply.request_id = rh_request.request_id; + + BufferedCdrOutput out = + new BufferedCdrOutput(50 + handler.getBuffer().buffer.size()); + out.setOrb(this); + + out.setOffset(msh_request.getHeaderSize()); + + reply.write(out); + + if (msh_request.version.since_inclusive(1, 2)) + { + out.align(8); + + // Write the reply data from the handler. The handler data already + // include the necessary heading zeroes for alignment. + } + handler.getBuffer().buffer.writeTo(out); + + MessageHeader msh_reply = new MessageHeader(); + + msh_reply.version = msh_request.version; + msh_reply.message_type = MessageHeader.REPLY; + msh_reply.message_size = out.buffer.size(); + + // Write the reply. + msh_reply.write(net_out); + out.buffer.writeTo(net_out); + net_out.flush(); + } + + /** + * Forward request to another target, as indicated by the passed exception. + */ + private void forward_request(OutputStream net_out, + MessageHeader msh_request, RequestHeader rh_request, gnuForwardRequest info + ) throws IOException + { + MessageHeader msh_forward = new MessageHeader(); + msh_forward.version = msh_request.version; + + ReplyHeader rh_forward = msh_forward.create_reply_header(); + msh_forward.message_type = MessageHeader.REPLY; + rh_forward.reply_status = info.forwarding_code; + rh_forward.request_id = rh_request.request_id; + + // The forwarding code is either LOCATION_FORWARD or LOCATION_FORWARD_PERM. + BufferedCdrOutput out = new BufferedCdrOutput(); + out.setOrb(this); + out.setOffset(msh_forward.getHeaderSize()); + + rh_forward.write(out); + + if (msh_forward.version.since_inclusive(1, 2)) + out.align(8); + out.write_Object(info.forward_reference); + + msh_forward.message_size = out.buffer.size(); + + // Write the forwarding instruction. + msh_forward.write(net_out); + out.buffer.writeTo(net_out); + net_out.flush(); + } + + /** + * Contains a single servicing task. + * + * Normally, each task matches a single remote invocation. However under + * frequent tandem submissions the same task may span over several + * invocations. + * + * @param serverSocket the ORB server socket. + * + * @throws MARSHAL + * @throws IOException + */ + void serve(final portServer p, ServerSocket serverSocket) + throws MARSHAL, IOException + { + final Socket service; + service = serverSocket.accept(); + + // Tell the server there are no more resources. + if (p.running_threads >= MAX_RUNNING_THREADS) + { + serveStep(service, true); + return; + } + + new Thread() + { + public void run() + { + try + { + synchronized (p) + { + p.running_threads++; + } + serveStep(service, false); + } + finally + { + synchronized (p) + { + p.running_threads--; + } + } + } + }.start(); + } + + /** + * A single servicing step, when the client socket is alrady open. + * + * Normally, each task matches a single remote invocation. However under + * frequent tandem submissions the same task may span over several + * invocations. + * + * @param service the opened client socket. + * @param no_resources if true, the "NO RESOURCES" exception is thrown to the + * client. + */ + void serveStep(Socket service, boolean no_resources) + { + try + { + Serving: while (true) + { + InputStream in = service.getInputStream(); + service.setSoTimeout(TOUT_START_READING_MESSAGE); + + MessageHeader msh_request = new MessageHeader(); + + try + { + msh_request.read(in); + } + catch (MARSHAL ex) + { + // This exception may be thrown due closing the connection. + return; + } + + if (max_version != null) + { + if (!msh_request.version.until_inclusive(max_version.major, + max_version.minor)) + { + OutputStream out = service.getOutputStream(); + new ErrorMessage(max_version).write(out); + return; + } + } + + byte[] r = msh_request.readMessage(in, service, TOUT_WHILE_READING, + TOUT_AFTER_RECEIVING); + + if (msh_request.message_type == MessageHeader.REQUEST) + { + RequestHeader rh_request; + + BufferredCdrInput cin = new BufferredCdrInput(r); + cin.setOrb(this); + cin.setVersion(msh_request.version); + cin.setOffset(msh_request.getHeaderSize()); + cin.setBigEndian(msh_request.isBigEndian()); + + rh_request = msh_request.create_request_header(); + + // Read header and auto set the charset. + rh_request.read(cin); + + // in 1.2 and higher, align the current position at + // 8 octet boundary. + if (msh_request.version.since_inclusive(1, 2)) + { + cin.align(8); + + // find the target object. + } + + InvokeHandler target = (InvokeHandler) find_connected_object( + rh_request.object_key, -1); + + // Prepare the reply header. This must be done in advance, + // as the size must be known for handler to set alignments + // correctly. + ReplyHeader rh_reply = msh_request.create_reply_header(); + + // TODO log errors about not existing objects and methods. + ResponseHandlerImpl handler = new ResponseHandlerImpl( + this, msh_request, rh_reply, rh_request); + + SystemException sysEx = null; + + try + { + if (no_resources) + { + NO_RESOURCES no = new NO_RESOURCES("Too many parallel calls"); + no.minor = Minor.Threads; + throw no; + } + if (target == null) + throw new OBJECT_NOT_EXIST(); + target._invoke(rh_request.operation, cin, handler); + } + catch (gnuForwardRequest forwarded) + { + OutputStream sou = service.getOutputStream(); + forward_request(sou, msh_request, rh_request, forwarded); + if (service != null && !service.isClosed()) + { + // Wait for the subsequent invocations on the + // same socket for the TANDEM_REQUEST duration. + service.setSoTimeout(TANDEM_REQUESTS); + continue Serving; + } + } + catch (UnknownException uex) + { + sysEx = new UNKNOWN("Unknown", 2, + CompletionStatus.COMPLETED_MAYBE); + sysEx.initCause(uex.originalEx); + + org.omg.CORBA.portable.OutputStream ech = handler.createExceptionReply(); + + rh_reply.service_context = UnknownExceptionCtxHandler.addExceptionContext( + rh_reply.service_context, uex.originalEx, ech); + + ObjectCreator.writeSystemException(ech, sysEx); + } + catch (SystemException ex) + { + sysEx = ex; + + org.omg.CORBA.portable.OutputStream ech = handler.createExceptionReply(); + + rh_reply.service_context = UnknownExceptionCtxHandler.addExceptionContext( + rh_reply.service_context, ex, ech); + + ObjectCreator.writeSystemException(ech, ex); + } + catch (Exception except) + { + // This should never happen under normal operation and + // can only indicate errors in user object implementation. + // We inform the user. + except.printStackTrace(); + + sysEx = new UNKNOWN("Unknown", 2, + CompletionStatus.COMPLETED_MAYBE); + sysEx.initCause(except); + + org.omg.CORBA.portable.OutputStream ech = handler.createExceptionReply(); + + rh_reply.service_context = UnknownExceptionCtxHandler.addExceptionContext( + rh_reply.service_context, except, ech); + + ObjectCreator.writeSystemException(ech, sysEx); + } + + // Write the response. + if (rh_request.isResponseExpected()) + { + OutputStream sou = service.getOutputStream(); + respond_to_client(sou, msh_request, rh_request, handler, + sysEx); + } + } + else if (msh_request.message_type == MessageHeader.CLOSE_CONNECTION + || msh_request.message_type == MessageHeader.MESSAGE_ERROR) + { + CloseMessage.close(service.getOutputStream()); + service.close(); + return; + } + + if (service != null && !service.isClosed()) + + // Wait for the subsequent invocations on the + // same socket for the TANDEM_REQUEST duration. + service.setSoTimeout(TANDEM_REQUESTS); + else + return; + } + } + catch (SocketException ex) + { + // OK. + return; + } + catch (IOException ioex) + { + // Network error, probably transient. + // TODO log it. + return; + } + finally + { + try + { + if (service!=null && !service.isClosed()) + service.close(); + } + catch (IOException ioex) + { + // OK. + } + } + } + + /** + * Set the ORB parameters from the properties that were accumulated + * from several locations. + */ + protected void useProperties(Properties props) + { + if (props != null) + { + if (props.containsKey(LISTEN_ON)) + Port = Integer.parseInt(props.getProperty(LISTEN_ON)); + if (props.containsKey(NS_HOST)) + ns_host = props.getProperty(NS_HOST); + try + { + if (props.containsKey(NS_PORT)) + ns_port = Integer.parseInt(props.getProperty(NS_PORT)); + if (props.containsKey(START_READING_MESSAGE)) + TOUT_START_READING_MESSAGE = + Integer.parseInt(props.getProperty(START_READING_MESSAGE)); + if (props.containsKey(WHILE_READING)) + TOUT_WHILE_READING = + Integer.parseInt(props.getProperty(WHILE_READING)); + if (props.containsKey(AFTER_RECEIVING)) + TOUT_AFTER_RECEIVING = + Integer.parseInt(props.getProperty(AFTER_RECEIVING)); + if (props.containsKey(SERVER_ERROR_PAUSE)) + TWAIT_SERVER_ERROR_PAUSE = + Integer.parseInt(props.getProperty(SERVER_ERROR_PAUSE)); + } + catch (NumberFormatException ex) + { + throw new BAD_PARAM("Invalid " + NS_PORT + + "property, unable to parse '" + props.getProperty(NS_PORT) + + "'" + ); + } + + if (props.containsKey(SocketFactory.PROPERTY)) + { + String factory = null; + try + { + factory = props.getProperty(SocketFactory.PROPERTY); + if (factory!=null) + socketFactory = (SocketFactory) + ObjectCreator.forName(factory).newInstance(); + } + catch (Exception ex) + { + BAD_PARAM p = new BAD_PARAM("Bad socket factory "+factory); + p.initCause(ex); + throw p; + } + } + + if (props.containsKey(ORB_ID)) + orb_id = props.getProperty(ORB_ID); + + if (props.containsKey(SERVER_ID)) + server_id = props.getProperty(SERVER_ID); + + Enumeration en = props.elements(); + while (en.hasMoreElements()) + { + String item = (String) en.nextElement(); + if (item.equals(REFERENCE)) + initial_references.put(item, + string_to_object(props.getProperty(item)) + ); + } + } + } + + /** + * Get the next instance with a response being received. If all currently sent + * responses not yet processed, this method pauses till at least one of them + * is complete. If there are no requests currently sent, the method pauses + * till some request is submitted and the response is received. This strategy + * is identical to the one accepted by Suns 1.4 ORB implementation. + * + * The returned response is removed from the list of the currently submitted + * responses and is never returned again. + * + * @return the previously sent request that now contains the received + * response. + * + * @throws WrongTransaction If the method was called from the transaction + * scope different than the one, used to send the request. The exception can + * be raised only if the request is implicitly associated with some particular + * transaction. + */ + public Request get_next_response() throws org.omg.CORBA.WrongTransaction + { + return asynchron.get_next_response(); + } + + /** + * Find if any of the requests that have been previously sent with + * {@link #send_multiple_requests_deferred}, have a response yet. + * + * @return true if there is at least one response to the previously sent + * request, false otherwise. + */ + public boolean poll_next_response() + { + return asynchron.poll_next_response(); + } + + /** + * Send multiple prepared requests expecting to get a reply. All requests are + * send in parallel, each in its own separate thread. When the reply arrives, + * it is stored in the agreed fields of the corresponing request data + * structure. If this method is called repeatedly, the new requests are added + * to the set of the currently sent requests, but the old set is not + * discarded. + * + * @param requests the prepared array of requests. + * + * @see #poll_next_response() + * @see #get_next_response() + * @see Request#send_deferred() + */ + public void send_multiple_requests_deferred(Request[] requests) + { + asynchron.send_multiple_requests_deferred(requests); + } + + /** + * Send multiple prepared requests one way, do not caring about the answer. + * The messages, containing requests, will be marked, indicating that the + * sender is not expecting to get a reply. + * + * @param requests the prepared array of requests. + * + * @see Request#send_oneway() + */ + public void send_multiple_requests_oneway(Request[] requests) + { + asynchron.send_multiple_requests_oneway(requests); + } + + /** + * Set the flag, forcing all server threads to terminate. + */ + protected void finalize() throws java.lang.Throwable + { + running = false; + super.finalize(); + } + + /** + * Get the number of objects that are connected to this ORB. + * + * @return the number of objects, connected to this ORB. + */ + public int countConnectedObjects() + { + return connected_objects.size(); + } +} diff --git a/libjava/classpath/gnu/CORBA/OrbRestricted.java b/libjava/classpath/gnu/CORBA/OrbRestricted.java new file mode 100644 index 000000000..35f0b1724 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/OrbRestricted.java @@ -0,0 +1,583 @@ +/* RestrictedORB.java -- + 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.CORBA; + +import gnu.CORBA.CDR.BufferedCdrOutput; +import gnu.CORBA.typecodes.AliasTypeCode; +import gnu.CORBA.typecodes.ArrayTypeCode; +import gnu.CORBA.typecodes.PrimitiveTypeCode; +import gnu.CORBA.typecodes.RecordTypeCode; +import gnu.CORBA.typecodes.StringTypeCode; + +import org.omg.CORBA.Any; +import org.omg.CORBA.BAD_PARAM; +import org.omg.CORBA.Context; +import org.omg.CORBA.ContextList; +import org.omg.CORBA.Environment; +import org.omg.CORBA.ExceptionList; +import org.omg.CORBA.NO_IMPLEMENT; +import org.omg.CORBA.NVList; +import org.omg.CORBA.NamedValue; +import org.omg.CORBA.ORB; +import org.omg.CORBA.ORBPackage.InvalidName; +import org.omg.CORBA.Request; +import org.omg.CORBA.StructMember; +import org.omg.CORBA.TCKind; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.TypeCodePackage.BadKind; +import org.omg.CORBA.UnionMember; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.ValueFactory; +import org.omg.PortableInterceptor.ClientRequestInterceptorOperations; +import org.omg.PortableInterceptor.IORInterceptor_3_0Operations; +import org.omg.PortableInterceptor.ServerRequestInterceptorOperations; + +import java.applet.Applet; + +import java.util.Hashtable; +import java.util.Properties; + +/** + * This class implements so-called Singleton ORB, a highly restricted version + * that cannot communicate over network. This ORB is provided for the + * potentially malicious applets with heavy security restrictions. It, however, + * supports some basic features that might be needed even when the network + * access is not granted. + * + * This ORB can only create typecodes, {@link Any}, {@link ContextList}, + * {@link NVList} and {@link org.omg.CORBA.portable.OutputStream} that writes to + * an internal buffer. + * + * All other methods throw the {@link NO_IMPLEMENT} exception. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class OrbRestricted extends org.omg.CORBA_2_3.ORB +{ + /** + * The singleton instance of this ORB. + */ + public static final ORB Singleton = new OrbRestricted(); + + /** + * The cumulated listener for all IOR interceptors. Interceptors are used by + * {@link gnu.CORBA.Poa.ORB_1_4}. + */ + public IORInterceptor_3_0Operations iIor; + + /** + * The cumulated listener for all server request interceptors. Interceptors + * are used by {@link gnu.CORBA.Poa.ORB_1_4}. + */ + public ServerRequestInterceptorOperations iServer; + + /** + * The cumulated listener for all client request interceptros. Interceptors + * are used by {@link gnu.CORBA.Poa.ORB_1_4}. + */ + public ClientRequestInterceptorOperations iClient; + + /** + * The required size of the interceptor slot array. + */ + public int icSlotSize = 0; + + /** + * The value factories. + */ + protected Hashtable factories = new Hashtable(); + + /** + * The policy factories. + */ + protected Hashtable policyFactories = new Hashtable(); + + /** + * Create a new instance of the RestrictedORB. This is used in derived classes + * only. + */ + protected OrbRestricted() + { + } + + /** {@inheritDoc} */ + public TypeCode create_alias_tc(String id, String name, TypeCode typecode) + { + return new AliasTypeCode(typecode, id, name); + } + + /** {@inheritDoc} */ + public Any create_any() + { + gnuAny any = new gnuAny(); + any.setOrb(this); + return any; + } + + /** {@inheritDoc} */ + public TypeCode create_array_tc(int length, TypeCode element_type) + { + ArrayTypeCode p = + new ArrayTypeCode(TCKind.tk_array, element_type); + p.setLength(length); + return p; + } + + /** {@inheritDoc} */ + public ContextList create_context_list() + { + return new gnuContextList(); + } + + /** {@inheritDoc} */ + public TypeCode create_enum_tc(String id, String name, String[] values) + { + RecordTypeCode r = new RecordTypeCode(TCKind.tk_enum); + for (int i = 0; i < values.length; i++) + { + r.field().name = values [ i ]; + } + + r.setId(id); + r.setName(name); + + return r; + } + + /** {@inheritDoc} */ + public Environment create_environment() + { + return new gnuEnvironment(); + } + + /** {@inheritDoc} */ + public ExceptionList create_exception_list() + { + return new gnuExceptionList(); + } + + /** {@inheritDoc} */ + public TypeCode create_exception_tc(String id, String name, + StructMember[] members + ) + { + RecordTypeCode r = new RecordTypeCode(TCKind.tk_except); + r.setId(id); + r.setName(name); + + for (int i = 0; i < members.length; i++) + { + r.add(members [ i ]); + } + + return r; + } + + /** + * This method is not allowed for a RestrictedORB. + * + * @throws NO_IMPLEMENT, always. + */ + public TypeCode create_interface_tc(String id, String name) + { + no(); + return null; + } + + /** {@inheritDoc} */ + public NVList create_list(int count) + { + return new gnuNVList(count); + } + + /** {@inheritDoc} */ + public NamedValue create_named_value(String s, Any any, int flags) + { + return new gnuNamedValue(); + } + + /** {@inheritDoc} */ + public OutputStream create_output_stream() + { + BufferedCdrOutput stream = new BufferedCdrOutput(); + stream.setOrb(this); + return stream; + } + + /** {@inheritDoc} */ + public TypeCode create_sequence_tc(int bound, TypeCode element_type) + { + ArrayTypeCode p = + new ArrayTypeCode(TCKind.tk_sequence, element_type); + p.setLength(bound); + return p; + } + + /** {@inheritDoc} */ + public TypeCode create_string_tc(int bound) + { + StringTypeCode p = new StringTypeCode(TCKind.tk_string); + p.setLength(bound); + return p; + } + + /** {@inheritDoc} */ + public TypeCode create_struct_tc(String id, String name, + StructMember[] members + ) + { + RecordTypeCode r = new RecordTypeCode(TCKind.tk_struct); + r.setId(id); + r.setName(name); + + for (int i = 0; i < members.length; i++) + { + r.add(members [ i ]); + } + + return r; + } + + /** {@inheritDoc} */ + public TypeCode create_union_tc(String id, String name, + TypeCode discriminator_type, UnionMember[] members + ) + { + RecordTypeCode r = new RecordTypeCode(TCKind.tk_union); + r.setId(id); + r.setName(name); + r.setDiscriminator_type(discriminator_type); + r.setDefaultIndex(0); + + for (int i = 0; i < members.length; i++) + { + r.add(members [ i ]); + } + + return r; + } + + /** {@inheritDoc} */ + public TypeCode create_wstring_tc(int bound) + { + StringTypeCode p = new StringTypeCode(TCKind.tk_wstring); + p.setLength(bound); + return p; + } + + /** {@inheritDoc} */ + public TypeCode get_primitive_tc(TCKind tcKind) + { + try + { + return TypeKindNamer.getPrimitveTC(tcKind); + } + catch (BadKind ex) + { + throw new BAD_PARAM("This is not a primitive type code: " + + tcKind.value() + ); + } + } + + /** + * This method is not allowed for a RestrictedORB. + * + * @throws NO_IMPLEMENT, always. + */ + public String[] list_initial_services() + { + no(); + throw new InternalError(); + } + + /** + * This method is not allowed for a RestrictedORB. + * + * @throws NO_IMPLEMENT, always. + */ + public String object_to_string(org.omg.CORBA.Object forObject) + { + no(); + throw new InternalError(); + } + + /** + * This method is not allowed for a RestrictedORB. + * + * @throws InvalidName never in this class, but it is thrown in the derived + * classes. + * + * @throws NO_IMPLEMENT, always. + */ + public org.omg.CORBA.Object resolve_initial_references(String name) + throws InvalidName + { + no(); + throw new InternalError(); + } + + /** + * Shutdown the ORB server. + * + * For RestrictedORB, returns witout action. + */ + public void run() + { + } + + /** + * Shutdown the ORB server. + * + * For RestrictedORB, returns witout action. + */ + public void shutdown(boolean wait_for_completion) + { + } + + /** + * This method is not allowed for a RestrictedORB. + * + * @throws NO_IMPLEMENT, always. + */ + public org.omg.CORBA.Object string_to_object(String IOR) + { + no(); + throw new InternalError(); + } + + /** + * This method is not allowed for a RestrictedORB. + * + * @throws NO_IMPLEMENT, always. + */ + protected void set_parameters(Applet app, Properties props) + { + no(); + } + + /** + * This method is not allowed for a RestrictedORB. + * + * @throws NO_IMPLEMENT, always. + */ + protected void set_parameters(String[] args, Properties props) + { + no(); + } + + /** + * Throws an exception, stating that the given method is not supported by the + * Restricted ORB. + */ + private final void no() + { + // Apart the programming errors, this can only happen if the + // malicious code is trying to do that it is not allowed. + throw new NO_IMPLEMENT("Use init(args, props) for the functional version."); + } + + /** + * This method is not allowed for a RestrictedORB. + * + * @throws NO_IMPLEMENT, always. + */ + public Request get_next_response() throws org.omg.CORBA.WrongTransaction + { + no(); + throw new InternalError(); + } + + /** + * This method is not allowed for a RestrictedORB. + * + * @throws NO_IMPLEMENT, always. + */ + public boolean poll_next_response() + { + no(); + throw new InternalError(); + } + + /** + * This method is not allowed for a RestrictedORB. + * + * @throws NO_IMPLEMENT, always. + */ + public void send_multiple_requests_deferred(Request[] requests) + { + no(); + } + + /** + * This method is not allowed for a RestrictedORB. + * + * @throws NO_IMPLEMENT, always. + */ + public void send_multiple_requests_oneway(Request[] requests) + { + no(); + } + + /** + * Register the value factory under the given repository id. + */ + public ValueFactory register_value_factory(String repository_id, + ValueFactory factory + ) + { + factories.put(repository_id, factory); + return factory; + } + + /** + * Unregister the value factroy. + */ + public void unregister_value_factory(String id) + { + factories.remove(id); + } + + /** + * Look for the value factory for the value, having the given repository id. + * The implementation checks for the registered value factories first. If none + * found, it tries to load and instantiate the class, mathing the given naming + * convention. If this faild, null is returned. + * + * @param repository_id a repository id. + * + * @return a found value factory, null if none. + */ + public ValueFactory lookup_value_factory(String repository_id) + { + ValueFactory f = (ValueFactory) factories.get(repository_id); + if (f != null) + { + return f; + } + + f = (ValueFactory) ObjectCreator.createObject(repository_id, + "DefaultFactory" + ); + if (f != null) + { + factories.put(repository_id, f); + } + return f; + } + + /** + * Destroy the interceptors, if they are present. + */ + public void destroy() + { + if (iIor != null) + { + iIor.destroy(); + iIor = null; + } + + if (iServer != null) + { + iServer.destroy(); + iServer = null; + } + + if (iClient != null) + { + iClient.destroy(); + iClient = null; + } + + super.destroy(); + } + + /** + * Create a typecode, representing a tree-like structure. + * This structure contains a member that is a sequence of the same type, + * as the structure itself. You can imagine as if the folder definition + * contains a variable-length array of the enclosed (nested) folder + * definitions. In this way, it is possible to have a tree like + * structure that can be transferred via CORBA CDR stream. + * + * @deprecated It is easier and clearler to use a combination of + * create_recursive_tc and create_sequence_tc instead. + * + * @param bound the maximal expected number of the nested components + * on each node; 0 if not limited. + * + * @param offset the position of the field in the returned structure + * that contains the sequence of the structures of the same field. + * The members before this field are intialised using parameterless + * StructMember constructor. + * + * @return a typecode, defining a stucture, where a member at the + * offset position defines an array of the identical + * structures. + * + * @see #create_recursive_tc(String) + * @see #create_sequence_tc(int, TypeCode) + */ + public TypeCode create_recursive_sequence_tc(int bound, int offset) + { + RecordTypeCode r = new RecordTypeCode(TCKind.tk_struct); + for (int i = 0; i < offset; i++) + r.add(new StructMember()); + + TypeCode recurs = new PrimitiveTypeCode(TCKind.tk_sequence); + + r.add(new StructMember("", recurs, null)); + return r; + } + + /** + * Get the default context of this ORB. This is an initial root of all + * contexts. + * + * The default method returns a new context with the empty name and + * no parent context. + * + * @return the default context of this ORB. + */ + public Context get_default_context() + { + return new gnuContext("", null); + } + +} diff --git a/libjava/classpath/gnu/CORBA/Poa/AOM.java b/libjava/classpath/gnu/CORBA/Poa/AOM.java new file mode 100644 index 000000000..4b2264f3c --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Poa/AOM.java @@ -0,0 +1,406 @@ +/* AOM.java -- + 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.CORBA.Poa; + +import gnu.CORBA.ByteArrayComparator; + +import org.omg.CORBA.portable.Delegate; +import org.omg.CORBA.portable.ObjectImpl; +import org.omg.PortableServer.Servant; + +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +/** + * Implements the conception of the Active Object Map. + * If the POA supports the RETAIN policy, it maintains an Active + * Object Map, that associates Object Ids with active servants. + * Each association constitutes an active object. We use a single map + * for all POAs on the given orb. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class AOM +{ + /** + * The reference data about the object, placed on the AOM. + */ + public class Obj + { + /** + * Create an initialised instance. + */ + Obj(gnuServantObject _object, byte[] _key, Servant _servant, gnuPOA _poa) + { + object = _object; + key = _key; + servant = _servant; + poa = _poa; + } + + /** + * The object. + */ + public final gnuServantObject object; + + /** + * The servant, serving the given object. + */ + public Servant servant; + + /** + * The local servant that once served this object. + * This field is used by {@link ForwardedServant} when it discovers that + * the forwarding chaing returns back to the original location. + * It should not be used anywhere else. + */ + Servant primary_servant; + + /** + * The POA, where the object is connected. + */ + public final gnuPOA poa; + + /** + * The object key. + */ + public final byte[] key; + + /** + * If true, this entry is deactivated. + */ + public boolean deactivated; + + /** + * Set the servant value, preserving any non null + * value as the primary servant. + */ + public void setServant(Servant s) + { + if (primary_servant == null) + primary_servant = s; + servant = s; + } + + /** + * Get the servant. + */ + public Servant getServant() + { + return servant; + } + + /** + * Get the deactivation state. + */ + public boolean isDeactiveted() + { + return deactivated; + } + + /** + * Set the deactivation state. + */ + public void setDeactivated(boolean state) + { + deactivated = state; + } + } + + /** + * The free number to give for the next instance. + * This field is incremented each time the + * new collection of the connected objects is created. + * Each collection has its own unique instance number. + */ + private static long free_id; + + /** + * The map of the all connected objects, maps the object key to the + * object. + */ + Map objects = new TreeMap(new ByteArrayComparator()); + + /** + * Get the record of the stored object. If the object is mapped several times + * under the different keys, one of the mappings is used. + * + * @param stored_object the stored object + * + * @return the record about the stored object, null if this object is not + * stored here. + */ + public Obj findObject(org.omg.CORBA.Object stored_object) + { + if (stored_object == null) + return null; + + Map.Entry item; + Iterator iter; + Obj ref; + + if (stored_object instanceof ObjectImpl) + { + // If the delegate is available, search by delegate. + Delegate d = ((ObjectImpl) stored_object)._get_delegate(); + Delegate d2; + + if (d != null) + { + iter = objects.entrySet().iterator(); + while (iter.hasNext()) + { + item = (Map.Entry) iter.next(); + ref = (Obj) item.getValue(); + d2 = ref.object._get_delegate(); + + if (d == d2 || (d2 != null && d2.equals(d))) + return ref; + } + } + } + + // For other objects (or if not possible to get the delegate), + // search by .equals + iter = objects.entrySet().iterator(); + while (iter.hasNext()) + { + item = (Map.Entry) iter.next(); + ref = (Obj) item.getValue(); + if (stored_object.equals(ref.object)) + return ref; + } + return null; + } + + /** + * Find the reference info for the given servant. If the servant is mapped to + * several objects, this returns the first found occurence. + * + * @param servant a servant to find. + * + * @return the servant/object/POA binding or null if no such found. + */ + public Obj findServant(Servant servant) + { + if (servant == null) + return null; + + Map.Entry item; + Iterator iter = objects.entrySet().iterator(); + Obj ref; + + while (iter.hasNext()) + { + item = (Map.Entry) iter.next(); + ref = (Obj) item.getValue(); + if (servant.equals(ref.servant)) + return ref; + } + return null; + } + + /** + * Find the reference info for the given servant. + * If the servant is mapped to several objects, this + * returns the first found occurence. + * + * @param servant a servant to find. + * @param speficies if to search for the inactive (true) or active + * (false) servant. A servant with unmatching activity is ignored + * by this method. + * + * @return the servant/object/POA binding or null if no such found. + */ + public Obj findServant(Servant servant, boolean inactive) + { + if (servant == null) + return null; + + Map.Entry item; + Iterator iter = objects.entrySet().iterator(); + Obj ref; + + while (iter.hasNext()) + { + item = (Map.Entry) iter.next(); + ref = (Obj) item.getValue(); + if (ref.deactivated == inactive) + if (ref.servant != null) + if (servant.equals(ref.servant)) + return ref; + } + return null; + } + + /** + * Add the new object to the repository. The object key is + * generated automatically. + * + * @param object the object to add. + * @param servant a servant, serving the given object. + * @param poa the poa, where the object is connected. + * + * @return the newly created object record. + */ + public Obj add(gnuServantObject object, Servant servant, gnuPOA poa) + { + return add(generateObjectKey(object), object, servant, poa); + } + + /** + * Add the new object to the repository. + * + * @param key the object key. + * @param object the object to add. + * @param servant a servant, serving the given object. + * @param poa the POA, where the object is connected. + */ + public Obj add(byte[] key, gnuServantObject object, Servant servant, + gnuPOA poa + ) + { + Obj rec = new Obj(object, key, servant, poa); + objects.put(key, rec); + return rec; + } + + /** + * Add the new object to the repository. + * + * @param delegate the delegate, providing data about the servant, key, POA + * and object. + * @param port the port that this object would take. + */ + public Obj add(ServantDelegateImpl delegate) + { + Obj rec = + new Obj(delegate.object, delegate.servant_id, delegate.servant, + delegate.poa + ); + objects.put(delegate.servant_id, rec); + return rec; + } + + /** + * Put back the definition structure that has probably been removed earlier. + */ + public void put(Obj obj) + { + objects.put(obj.key, obj); + } + + /** + * Get the stored object. + * + * @param key the key (in the byte array form). + * + * @return the matching object, null if none is matching. + */ + public Obj get(byte[] key) + { + return (Obj) objects.get(key); + } + + /** + * Get the map key set. + */ + public Set keySet() + { + return objects.keySet(); + } + + /** + * Remove the given object, indiciating it by the key. + * + * @param object the object to remove. + */ + public void remove(byte[] key) + { + objects.remove(key); + } + + /** + * Generate the object key, unique in the currently + * running java virtual machine. The passed object + * parameter is currently not in use. + * + * @return the generated key. + */ + protected byte[] generateObjectKey(org.omg.CORBA.Object object) + { + byte[] key; + + // The repetetive keys cannot be generated, but theoretically + // the same keys can be passed when calling add(byte[]...). + // Hence we check if the key is not already in the map and, + // if it is, use the subsequent value. + do + { + key = getFreeId(); + } + while (objects.containsKey(key)); + return key; + } + + /** + * Get the next free 8 byte id, surely unique between calls of this + * method for the currently running virtual machine. + */ + public static synchronized byte[] getFreeId() + { + byte[] r = new byte[ 8 ]; + + // Start from the faster-changing. + r [ 0 ] = ((byte) (0xff & free_id)); + r [ 1 ] = ((byte) (0xff & (free_id >> 8))); + r [ 2 ] = ((byte) (0xff & (free_id >> 16))); + r [ 3 ] = ((byte) (0xff & (free_id >> 24))); + r [ 4 ] = ((byte) (0xff & (free_id >> 32))); + r [ 5 ] = ((byte) (0xff & (free_id >> 40))); + r [ 6 ] = ((byte) (0xff & (free_id >> 48))); + r [ 7 ] = ((byte) (0xff & (free_id >> 56))); + + free_id++; + + return r; + } +} diff --git a/libjava/classpath/gnu/CORBA/Poa/AccessiblePolicy.java b/libjava/classpath/gnu/CORBA/Poa/AccessiblePolicy.java new file mode 100644 index 000000000..5468d2292 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Poa/AccessiblePolicy.java @@ -0,0 +1,62 @@ +/* AccessiblePolicy.java -- + 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.CORBA.Poa; + +import org.omg.CORBA.Policy; + +/** + * The Classpath implementation of the policy, providing the policy + * value and the code of the policy type. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public interface AccessiblePolicy + extends Policy +{ + /** + * Get the value of this policy + */ + java.lang.Object getValue(); + + /** + * Get the integer code of this policy value. + */ + int getCode(); + +} diff --git a/libjava/classpath/gnu/CORBA/Poa/DynamicImpHandler.java b/libjava/classpath/gnu/CORBA/Poa/DynamicImpHandler.java new file mode 100644 index 000000000..4ee02995d --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Poa/DynamicImpHandler.java @@ -0,0 +1,85 @@ +/* DynamicImpHandler.java -- + 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.CORBA.Poa; + +import org.omg.CORBA.BAD_OPERATION; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.InvokeHandler; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.ResponseHandler; +import org.omg.PortableServer.DynamicImplementation; + +/** + * The InvokeHandler, indicating, that the target is a dynamic + * implementation rather than an invoke handler. These two + * types are not substitutable, but in some methods have possibility + * just to handle them differently. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class DynamicImpHandler + implements InvokeHandler +{ + /** + * The servant that is a dynamic implementation rather than + * invoke handler. + */ + public final DynamicImplementation servant; + + /** + * Create a new instance, wrapping some dyn implementation. + * @param _servant + */ + public DynamicImpHandler(DynamicImplementation _servant) + { + servant = _servant; + } + + /** + * We cannot invoke properly without having parameter info. + * + * @throws BAD_OPERATION, always. + */ + public OutputStream _invoke(String method, InputStream input, + ResponseHandler handler + ) + { + throw new BAD_OPERATION(servant + " is not an InvokeHandler."); + } +} diff --git a/libjava/classpath/gnu/CORBA/Poa/ForwardRequestHolder.java b/libjava/classpath/gnu/CORBA/Poa/ForwardRequestHolder.java new file mode 100644 index 000000000..a85173526 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Poa/ForwardRequestHolder.java @@ -0,0 +1,107 @@ +/* ForwardRequestHolder.java -- + 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.CORBA.Poa; + +import gnu.CORBA.ForwardRequestHelper; + +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.Streamable; +import org.omg.PortableServer.ForwardRequest; + +/** +* A holder for the exception {@link ForwardRequest}. + +* @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) +*/ +public class ForwardRequestHolder + implements Streamable +{ + /** + * The stored ForwardRequest value. + */ + public ForwardRequest value; + + /** + * Create the unitialised instance, leaving the value field + * with default null value. + */ + public ForwardRequestHolder() + { + } + + /** + * Create the initialised instance. + * @param initialValue the value that will be assigned to + * the value field. + */ + public ForwardRequestHolder(ForwardRequest initialValue) + { + value = initialValue; + } + + /** + * Fill in the {@link value} by data from the CDR stream. + * + * @param input the org.omg.CORBA.portable stream to read. + */ + public void _read(InputStream input) + { + value = ForwardRequestHelper.read(input); + } + + /** + * Get the typecode of the ForwardRequest. + */ + public TypeCode _type() + { + return ForwardRequestHelper.type(); + } + + /** + * Write the stored value into the CDR stream. + * + * @param output the org.omg.CORBA.portable stream to write. + */ + public void _write(OutputStream output) + { + ForwardRequestHelper.write(output, value); + } +} diff --git a/libjava/classpath/gnu/CORBA/Poa/ForwardedServant.java b/libjava/classpath/gnu/CORBA/Poa/ForwardedServant.java new file mode 100644 index 000000000..c54a02654 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Poa/ForwardedServant.java @@ -0,0 +1,209 @@ +/* ForwardedServant.java -- + 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.CORBA.Poa; + +import gnu.CORBA.IOR; +import gnu.CORBA.IorDelegate; +import gnu.CORBA.IorObject; +import gnu.CORBA.Minor; + +import org.omg.CORBA.BAD_PARAM; +import org.omg.CORBA.CompletionStatus; +import org.omg.CORBA.MARSHAL; +import org.omg.CORBA.ORB; +import org.omg.CORBA.SystemException; +import org.omg.CORBA.portable.ApplicationException; +import org.omg.CORBA.portable.Delegate; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.InvokeHandler; +import org.omg.CORBA.portable.ObjectImpl; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.RemarshalException; +import org.omg.CORBA.portable.ResponseHandler; +import org.omg.PortableServer.POA; +import org.omg.PortableServer.Servant; + +import java.io.IOException; + +/** + * A "virtual servant", delegating all invocation to the wrapped + * object (usually remote). Used in cases when it is necessary to + * handle the request forwarding. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class ForwardedServant + extends Servant + implements InvokeHandler +{ + /** + * The reference object, handling requests. + */ + public final ObjectImpl ref; + + /** + * Create an instance, forwarding requests to the given object. + */ + ForwardedServant(ObjectImpl a_ref) + { + ref = a_ref; + } + + /** + * Create an instance of the forwarded servant. + * + * @param a_ref a reference where request should be forwarded. + * + * @return a created forwarded servant or null if the parameter + * forwards request to itself. Returning null will force to find + * a right servant in one of many possible ways, depending on + * policies. + */ + public static Servant create(org.omg.CORBA.Object a_ref) + { + try + { + ObjectImpl fto = (ObjectImpl) a_ref; + + // Check maybe the remote side forwarded back to our local object. + if (fto instanceof IorObject) + { + IorObject iref = (IorObject) fto; + + // Check maybe the IOR is local. + ORB t_orb = iref._orb(); + if (t_orb instanceof ORB_1_4) + { + ORB_1_4 orb = (ORB_1_4) t_orb; + Delegate d = iref._get_delegate(); + if (d instanceof IorDelegate) + { + IorDelegate ird = (IorDelegate) iref._get_delegate(); + IOR ior = ird.getIor(); + if (orb.LOCAL_HOST.equalsIgnoreCase(ior.Internet.host)) + { + AOM.Obj rx = orb.rootPOA.findIorKey(ior.key); + if (rx != null) + { + if (rx.object == fto || + rx.object._is_equivalent(fto) + ) + return rx.primary_servant; + else + fto = (ObjectImpl) rx.object; + } + } + } + } + } + return new ForwardedServant(fto); + } + catch (ClassCastException ex) + { + throw new BAD_PARAM("ObjectImpl required but " + a_ref + " passed ", + 0x5005, CompletionStatus.COMPLETED_NO + ); + } + } + + /** + * Forward the call to the wrapped object. + */ + public OutputStream _invoke(String method, InputStream input, + ResponseHandler handler + ) + throws SystemException + { + org.omg.CORBA.portable.InputStream in = null; + org.omg.CORBA.portable.OutputStream out = null; + try + { + try + { + out = ref._request(method, true); + + // Transfer request information. + int b; + while ((b = input.read()) >= 0) + { + out.write(b); + } + in = ref._invoke(out); + + // Read the returned data. + out = handler.createReply(); + while ((b = in.read()) >= 0) + { + out.write(b); + } + } + catch (IOException io_ex) + { + MARSHAL m = new MARSHAL(); + m.minor = Minor.Forwarding; + m.initCause(io_ex); + throw m; + } + } + catch (ApplicationException ex) + { + in = ex.getInputStream(); + + String _id = ex.getId(); + throw new MARSHAL(_id, 5101, CompletionStatus.COMPLETED_NO); + } + catch (RemarshalException remarsh) + { + _invoke(method, input, handler); + } + finally + { + ref._releaseReply(in); + } + return out; + } + + /** + * Delegates to the wrapped object. + */ + public String[] _all_interfaces(POA poa, byte[] key) + { + return ref._ids(); + } +} diff --git a/libjava/classpath/gnu/CORBA/Poa/InvalidPolicyHolder.java b/libjava/classpath/gnu/CORBA/Poa/InvalidPolicyHolder.java new file mode 100644 index 000000000..b415034a3 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Poa/InvalidPolicyHolder.java @@ -0,0 +1,106 @@ +/* InvalidPolicyHolder.java -- + 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.CORBA.Poa; + +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.Streamable; +import org.omg.PortableServer.POAPackage.InvalidPolicy; +import org.omg.PortableServer.POAPackage.InvalidPolicyHelper; + +/** +* A holder for the exception {@link InvalidPolicy}. + +* @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) +*/ +public class InvalidPolicyHolder + implements Streamable +{ + /** + * The stored InvalidPolicy value. + */ + public InvalidPolicy value; + + /** + * Create the unitialised instance, leaving the value field + * with default null value. + */ + public InvalidPolicyHolder() + { + } + + /** + * Create the initialised instance. + * @param initialValue the value that will be assigned to + * the value field. + */ + public InvalidPolicyHolder(InvalidPolicy initialValue) + { + value = initialValue; + } + + /** + * Fill in the {@link value} by data from the CDR stream. + * + * @param input the org.omg.CORBA.portable stream to read. + */ + public void _read(InputStream input) + { + value = InvalidPolicyHelper.read(input); + } + + /** + * Write the stored value into the CDR stream. + * + * @param output the org.omg.CORBA.portable stream to write. + */ + public void _write(OutputStream output) + { + InvalidPolicyHelper.write(output, value); + } + + /** + * Get the typecode of the InvalidPolicy. + */ + public TypeCode _type() + { + return InvalidPolicyHelper.type(); + } +} diff --git a/libjava/classpath/gnu/CORBA/Poa/LocalDelegate.java b/libjava/classpath/gnu/CORBA/Poa/LocalDelegate.java new file mode 100644 index 000000000..7b42fde1e --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Poa/LocalDelegate.java @@ -0,0 +1,385 @@ +/* LocalDelegate.java -- + 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.CORBA.Poa; + +import gnu.CORBA.CDR.AbstractCdrOutput; +import gnu.CORBA.IOR; +import gnu.CORBA.IorProvider; +import gnu.CORBA.StreamBasedRequest; + +import org.omg.CORBA.ARG_INOUT; +import org.omg.CORBA.Bounds; +import org.omg.CORBA.Context; +import org.omg.CORBA.ContextList; +import org.omg.CORBA.ExceptionList; +import org.omg.CORBA.NO_IMPLEMENT; +import org.omg.CORBA.NVList; +import org.omg.CORBA.NamedValue; +import org.omg.CORBA.OBJECT_NOT_EXIST; +import org.omg.CORBA.ORB; +import org.omg.CORBA.Request; +import org.omg.CORBA.TypeCodePackage.BadKind; +import org.omg.CORBA.UnknownUserException; +import org.omg.CORBA.portable.ApplicationException; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.InvokeHandler; +import org.omg.CORBA.portable.ObjectImpl; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.RemarshalException; +import org.omg.PortableServer.ServantLocatorPackage.CookieHolder; + +import java.util.Arrays; + +/** + * A local delegate, transferring all object requests to the locally available + * servant. This class is involved in handling the method invocations on the + * local object, obtained by POA.create_reference_with_id. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class LocalDelegate + extends org.omg.CORBA_2_3.portable.Delegate + implements IorProvider +{ + /** + * The same servant as an invocation handler. + */ + gnuServantObject object; + + String operation; + + public final gnuPOA poa; + + final byte[] Id; + + /** + * Create a local delegate, forwarding requests to the servant that must also + * be an invocation handler. + */ + public LocalDelegate(gnuServantObject an_object, gnuPOA a_poa, byte[] an_id) + { + object = an_object; + poa = a_poa; + Id = an_id; + } + + /** + * Get the IOR of the connected object. + */ + public IOR getIor() + { + return object.getIor(); + } + + public Request request(org.omg.CORBA.Object target, String method) + { + operation = method; + + LocalRequest rq = new LocalRequest(object, poa, Id); + rq.setOperation(method); + rq.setORB(orb(target)); + return rq; + } + + public void release(org.omg.CORBA.Object target) + { + } + + public boolean is_equivalent(org.omg.CORBA.Object target, + org.omg.CORBA.Object other) + { + if (target == other) + return true; + else if (target instanceof ObjectImpl && other instanceof ObjectImpl) + { + org.omg.CORBA.portable.Delegate a = null; + org.omg.CORBA.portable.Delegate b = null; + try + { + a = ((ObjectImpl) target)._get_delegate(); + b = ((ObjectImpl) other)._get_delegate(); + } + catch (Exception ex) + { + // Unable to get one of the delegates. + return false; + } + if (a instanceof LocalDelegate && b instanceof LocalDelegate) + { + byte[] k1 = ((LocalDelegate) a).Id; + byte[] k2 = ((LocalDelegate) b).Id; + return Arrays.equals(k1, k2); + } + else + return false; + } + else + return false; + } + + /** + * Always return false. + */ + public boolean non_existent(org.omg.CORBA.Object target) + { + return false; + } + + /** + * Get hash code. + */ + public int hash(org.omg.CORBA.Object target, int maximum) + { + return hashCode() % maximum; + } + + /** + * Check if this object could be named by the given repository id. + * + * @param idl_id the repository id to check. + * + * @return true if it is one of the possible repository ids of this object. + */ + public boolean is_a(org.omg.CORBA.Object a_servant, String idl_id) + { + String[] maybe = object._ids(); + for (int i = 0; i < maybe.length; i++) + { + if (maybe[i].equals(idl_id)) + return true; + } + return false; + } + + /** + * Return this. + */ + public org.omg.CORBA.Object duplicate(org.omg.CORBA.Object target) + { + return target; + } + + /** + * Create request for using with DII. + */ + public Request create_request(org.omg.CORBA.Object target, Context context, + String method, NVList parameters, NamedValue returns, + ExceptionList exceptions, ContextList ctx_list) + { + operation = method; + + LocalRequest rq = new LocalRequest(object, poa, Id); + rq.setOperation(method); + rq.set_args(parameters); + rq.set_result(returns); + rq.set_exceptions(exceptions); + rq.set_context_list(ctx_list); + return rq; + } + + /** + * Create request for using with DII. + */ + public Request create_request(org.omg.CORBA.Object target, Context context, + String method, NVList parameters, NamedValue returns) + { + operation = method; + + LocalRequest rq = new LocalRequest(object, poa, Id); + rq.setOperation(method); + rq.set_args(parameters); + rq.set_result(returns); + return rq; + } + + /** + * Not in use. + */ + public org.omg.CORBA.Object get_interface_def(org.omg.CORBA.Object target) + { + throw new NO_IMPLEMENT(); + } + + /** + * Create a request to invoke the method of this CORBA object. + * + * @param operation the name of the method to invoke. + * @param response_expected specifies if this is one way message or the + * response to the message is expected. + * + * @return the stream where the method arguments should be written. + */ + public org.omg.CORBA.portable.OutputStream request( + org.omg.CORBA.Object target, String method, boolean response_expected) + { + operation = method; + + // Check if the object is not explicitly deactivated. + AOM.Obj e = poa.aom.get(Id); + if (e != null && e.isDeactiveted()) + { + if (poa.servant_activator != null || poa.servant_locator != null) + { + // This will force the subsequent activation. + object.setServant(null); + e.setServant(null); + e.setDeactivated(false); + } + else + throw new OBJECT_NOT_EXIST("Deactivated"); + } + + LocalRequest rq = new LocalRequest(object, poa, Id); + rq.setOperation(method); + rq.setORB(orb(target)); + return rq.getParameterStream(); + } + + /** + * Return the associated invocation handler. + */ + public InvokeHandler getHandler(String method, CookieHolder cookie) + { + return object.getHandler(method, cookie, false); + } + + /** + * Return the ORB of the associated POA. The parameter is not in use. + */ + public ORB orb(org.omg.CORBA.Object target) + { + return poa.orb(); + } + + /** + * Make an invocation. + * + * @param target not in use. + * @param output the stream request that should be returned by + * {@link #m_request} in this method. + * @throws ApplicationException if the use exception is thrown by the servant + * method. + */ + public InputStream invoke(org.omg.CORBA.Object target, OutputStream output) + throws ApplicationException + { + try + { + StreamBasedRequest sr = (StreamBasedRequest) output; + + LocalRequest lr = (LocalRequest) sr.request; + InvokeHandler handler = lr.object.getHandler(lr.operation(), lr.cookie, + false); + + if (handler instanceof DynamicImpHandler) + { + // The local request known how to handle it, but the different + // method must be called. + lr.invoke(); + + // The encapsulation will inherit orb, endian, charsets, etc. + AbstractCdrOutput buf = sr.createEncapsulation(); + + // Write all request parameters to the buffer stream. + if (lr.env().exception() != null) + { + try + { + UnknownUserException uex = (UnknownUserException) lr.env().exception(); + throw new ApplicationException(uex.except.type().id(), + uex.except.create_input_stream()); + } + catch (BadKind ex) + { + InternalError ierr = new InternalError(); + ierr.initCause(ex); + throw ierr; + } + } + if (lr.return_value() != null) + lr.return_value().write_value(buf); + + NamedValue a; + try + { + for (int i = 0; i < lr.arguments().count(); i++) + { + a = lr.arguments().item(i); + if (a.flags() == ARG_INOUT.value + || a.flags() == ARG_INOUT.value) + { + a.value().write_value(buf); + } + } + } + catch (Bounds ex) + { + InternalError ierr = new InternalError(); + ierr.initCause(ex); + throw ierr; + } + + return buf.create_input_stream(); + } + else + { + LocalRequest lrq = (LocalRequest) sr.request; + return lrq.s_invoke(handler); + } + } + catch (gnuForwardRequest f) + { + try + { + return ((ObjectImpl) f.forward_reference)._invoke(f.forward_reference._request( + operation, true)); + } + catch (RemarshalException e) + { + // Never thrown in this place by Classpath implementation. + throw new NO_IMPLEMENT(); + } + } + } + + public void releaseReply(org.omg.CORBA.Object target, InputStream input) + { + release(target); + } +} diff --git a/libjava/classpath/gnu/CORBA/Poa/LocalRequest.java b/libjava/classpath/gnu/CORBA/Poa/LocalRequest.java new file mode 100644 index 000000000..ca5b57b00 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Poa/LocalRequest.java @@ -0,0 +1,687 @@ +/* LocalRequest.java -- + 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.CORBA.Poa; + +import gnu.CORBA.CDR.BufferedCdrOutput; +import gnu.CORBA.GIOP.MessageHeader; +import gnu.CORBA.GIOP.v1_2.ReplyHeader; +import gnu.CORBA.GIOP.v1_2.RequestHeader; +import gnu.CORBA.Interceptor.gnuClientRequestInfo; +import gnu.CORBA.Interceptor.gnuServerRequestInfo; +import gnu.CORBA.typecodes.RecordTypeCode; +import gnu.CORBA.ObjectCreator; +import gnu.CORBA.Unexpected; +import gnu.CORBA.gnuAny; +import gnu.CORBA.gnuRequest; +import gnu.CORBA.StreamHolder; +import gnu.CORBA.StreamBasedRequest; + +import org.omg.CORBA.ARG_OUT; +import org.omg.CORBA.Any; +import org.omg.CORBA.BAD_INV_ORDER; +import org.omg.CORBA.BAD_OPERATION; +import org.omg.CORBA.Bounds; +import org.omg.CORBA.NamedValue; +import org.omg.CORBA.ORB; +import org.omg.CORBA.SystemException; +import org.omg.CORBA.TCKind; +import org.omg.CORBA.UnknownUserException; +import org.omg.CORBA.UserException; +import org.omg.CORBA.portable.ApplicationException; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.InvokeHandler; +import org.omg.CORBA.portable.ObjectImpl; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.ResponseHandler; +import org.omg.PortableInterceptor.ClientRequestInterceptorOperations; +import org.omg.PortableInterceptor.ForwardRequest; +import org.omg.PortableInterceptor.ServerRequestInterceptorOperations; +import org.omg.PortableServer.CurrentOperations; +import org.omg.PortableServer.CurrentPackage.NoContext; +import org.omg.PortableServer.DynamicImplementation; +import org.omg.PortableServer.POA; +import org.omg.PortableServer.Servant; +import org.omg.PortableServer.ServantLocatorPackage.CookieHolder; +import org.omg.PortableServer.portable.Delegate; + +import java.io.IOException; + +/** + * Directs the invocation to the locally available servant. The POA servant does + * not longer implement the CORBA object and cannot be substituted directly. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class LocalRequest extends gnuRequest implements ResponseHandler, + CurrentOperations +{ + /** + * Used by servant locator, if involved. + */ + CookieHolder cookie; + + /** + * The object Id. + */ + final byte[] Id; + + /** + * The message header (singleton is sufficient). + */ + private static final MessageHeader header = new MessageHeader(); + + /** + * True if the stream was obtained by invoking {@link #createExceptionReply()}, + * false otherwise. + */ + boolean exceptionReply; + + /** + * The buffer to write into. + */ + BufferedCdrOutput buffer; + + /** + * The responsible POA. + */ + final gnuPOA poa; + + /** + * The servant delegate to obtain the handler. + */ + gnuServantObject object; + + /** + * Used (reused) with dynamic implementation. + */ + LocalServerRequest serverRequest; + + /** + * Create an instance of the local request. + */ + public LocalRequest(gnuServantObject local_object, gnuPOA a_poa, byte[] an_id) + { + Id = an_id; + poa = a_poa; + + // Instantiate the cookie holder only if required. + if (poa.servant_locator != null) + { + cookie = new CookieHolder(); + } + object = local_object; + prepareStream(); + } + + /** + * Make an invocation and return a stream from where the results can be read + * and throw ApplicationException, where applicable. + */ + org.omg.CORBA.portable.InputStream s_invoke(InvokeHandler handler) + throws ApplicationException + { + try + { + poa.m_orb.currents.put(Thread.currentThread(), this); + + org.omg.CORBA.portable.InputStream input = v_invoke(handler); + + if (!exceptionReply) + { + return input; + } + else + { + input.mark(500); + + String id = input.read_string(); + try + { + input.reset(); + } + catch (IOException ex) + { + InternalError ierr = new InternalError(); + ierr.initCause(ex); + throw ierr; + } + throw new ApplicationException(id, input); + } + } + finally + { + poa.m_orb.currents.remove(Thread.currentThread()); + } + } + + /** + * Make an invocation and return a stream from where the results can be read. + * + * @param handler the invoke handler (can be null, then it is obtained self + * dependently). + */ + public org.omg.CORBA.portable.InputStream v_invoke(InvokeHandler handler) + { + // Check maybe POA is in the discarding mode (will throw TRANSIENT if it is). + poa.checkDiscarding(); + + // Local request must be intercepted both by server and request + // interceptors. + boolean s_intercept = false; + ServerRequestInterceptorOperations s_interceptor = null; + gnuServerRequestInfo s_info = null; + + boolean c_intercept = false; + ClientRequestInterceptorOperations c_interceptor = null; + gnuClientRequestInfo c_info = null; + + try + { + if (poa.m_orb.iServer != null || poa.m_orb.iClient != null) + { + setORB(poa.m_orb); + + // These two are only needed with interceptors. + m_rqh = new RequestHeader(); + m_rqh.operation = m_operation; + m_rph = new ReplyHeader(); + + m_rqh.object_key = object.Id; + m_rph.request_id = m_rqh.request_id; + } + + if (poa.m_orb.iClient != null) + { + c_interceptor = poa.m_orb.iClient; + + c_info = new gnuClientRequestInfo(this); + c_intercept = true; + + c_interceptor.send_request(c_info); + + m_target = object; + } + + if (poa.m_orb.iServer != null) + { + s_interceptor = poa.m_orb.iServer; + + s_info = new gnuServerRequestInfo(object, m_rqh, m_rph); + s_info.m_request = this; + + s_intercept = true; + + s_interceptor.receive_request_service_contexts(s_info); + } + + if (handler == null) + { + handler = object.getHandler(operation(), cookie, false); + } + + BufferedCdrOutput request_part = new BufferedCdrOutput(); + + request_part.setOrb(orb()); + + if (m_args != null && m_args.count() > 0) + { + write_parameters(header, request_part); + + if (m_parameter_buffer != null) + { + throw new BAD_INV_ORDER("Please either add parameters or " + + "write them into stream, but not both " + "at once." + ); + } + } + + if (m_parameter_buffer != null) + { + write_parameter_buffer(header, request_part); + } + + Servant servant; + + if (handler instanceof Servant) + { + servant = (Servant) handler; + } + else + { + throw new BAD_OPERATION("Unexpected handler type " + handler); + } + + org.omg.CORBA.portable.InputStream input = + request_part.create_input_stream(); + + // Ensure the servant (handler) has a delegate set. + ServantDelegateImpl sd = null; + + Delegate d = null; + + try + { + d = servant._get_delegate(); + } + catch (Exception ex) + { + // In some cases exception is thrown if the delegate is not set. + } + if (d instanceof ServantDelegateImpl) + { + // If the delegate is already set, try to reuse the existing + // instance. + sd = (ServantDelegateImpl) d; + if (sd.object != object) + { + sd = new ServantDelegateImpl(servant, poa, Id); + } + } + else + { + sd = new ServantDelegateImpl(servant, poa, Id); + } + servant._set_delegate(sd); + + try + { + ORB o = orb(); + if (o instanceof ORB_1_4) + { + ((ORB_1_4) o).currents.put(Thread.currentThread(), this); + } + + try + { + if (s_intercept) + { + s_interceptor.receive_request(s_info); + } + handler._invoke(m_operation, input, this); + + // Handler is casted into i_handler. + if ((s_intercept || c_intercept) && isExceptionReply()) + { + s_info.m_reply_header.reply_status = + ReplyHeader.USER_EXCEPTION; + m_rph.reply_status = ReplyHeader.USER_EXCEPTION; + + // Make Any, holding the user exception. + Any a = new gnuAny(); + OutputStream buf = getBuffer(); + InputStream in = buf.create_input_stream(); + String uex_idl = "unknown"; + try + { + in.mark(Integer.MAX_VALUE); + uex_idl = in.read_string(); + m_exception_id = uex_idl; + in.reset(); + } + catch (IOException e) + { + throw new Unexpected(e); + } + + try + { + UserException exception = + ObjectCreator.readUserException(uex_idl, in); + + m_environment.exception(exception); + ObjectCreator.insertWithHelper(a, exception); + } + catch (Exception e) + { + // Failed due any reason, insert without + // helper. + a.insert_Streamable(new StreamHolder( + buf.create_input_stream() + ) + ); + + RecordTypeCode r = + new RecordTypeCode(TCKind.tk_except); + r.setId(uex_idl); + r.setName(ObjectCreator.getDefaultName(uex_idl)); + } + + s_info.m_usr_exception = a; + c_info.m_wrapped_exception = a; + s_interceptor.send_exception(s_info); + c_interceptor.receive_exception(c_info); + } + else + { + if (s_intercept) + { + s_info.m_reply_header.reply_status = + ReplyHeader.NO_EXCEPTION; + s_interceptor.send_reply(s_info); + } + if (c_intercept) + { + m_rph.reply_status = ReplyHeader.NO_EXCEPTION; + c_interceptor.receive_reply(c_info); + } + } + } + catch (SystemException sys_ex) + { + if (s_intercept) + { + s_info.m_reply_header.reply_status = + ReplyHeader.SYSTEM_EXCEPTION; + s_info.m_sys_exception = sys_ex; + s_interceptor.send_exception(s_info); + } + + if (c_intercept) + { + m_rph.reply_status = ReplyHeader.SYSTEM_EXCEPTION; + + Any a = new gnuAny(); + if (ObjectCreator.insertSysException(a, sys_ex)) + { + c_info.m_wrapped_exception = a; + } + c_interceptor.receive_exception(c_info); + } + + throw sys_ex; + } + } + finally + { + ORB o = orb(); + if (o instanceof ORB_1_4) + { + ((ORB_1_4) o).currents.remove(Thread.currentThread()); + } + } + + if (poa.servant_locator != null) + { + poa.servant_locator.postinvoke(object.Id, poa, operation(), + cookie.value, object.getServant() + ); + } + return buffer.create_input_stream(); + } + + catch (ForwardRequest fex) + { + // May be thrown by interceptor. + if (s_intercept) + { + Forwarding: + while (true) + { + s_info.m_reply_header.reply_status = + ReplyHeader.LOCATION_FORWARD; + s_info.m_forward_reference = fex.forward; + try + { + s_interceptor.send_other(s_info); + break Forwarding; + } + catch (ForwardRequest fex2) + { + s_info.m_forward_reference = fex2.forward; + fex.forward = s_info.m_forward_reference; + } + } + } + + if (c_intercept) + { + this.m_rph.reply_status = ReplyHeader.LOCATION_FORWARD; + this.m_forwarding_target = fex.forward; + try + { + c_interceptor.receive_other(c_info); + } + catch (ForwardRequest fex2) + { + fex.forward = fex2.forward; + } + } + throw new gnuForwardRequest(fex.forward); + } + catch (gnuForwardRequest fex) + { + // May be thrown during activation. + // May be thrown during activation. + if (s_intercept) + { + Forwarding: + while (true) + { + s_info.m_reply_header.reply_status = + ReplyHeader.LOCATION_FORWARD; + s_info.m_forward_reference = fex.forward_reference; + try + { + s_interceptor.send_other(s_info); + break Forwarding; + } + catch (ForwardRequest fex2) + { + s_info.m_forward_reference = fex2.forward; + fex.forward_reference = (ObjectImpl) fex2.forward; + } + } + } + + if (c_intercept) + { + this.m_rph.reply_status = ReplyHeader.LOCATION_FORWARD; + this.m_forwarding_target = fex.forward_reference; + try + { + c_interceptor.receive_other(c_info); + } + catch (ForwardRequest fex2) + { + fex.forward_reference = (ObjectImpl) fex2.forward; + } + } + throw fex; + } + } + + /** + * Make an invocation and store the result in the fields of this Request. Used + * with DII only. + */ + public void invoke() + { + InvokeHandler handler = object.getHandler(operation(), cookie, false); + + if (handler instanceof DynamicImpHandler) + { + DynamicImplementation dyn = ((DynamicImpHandler) handler).servant; + if (serverRequest == null) + { + serverRequest = new LocalServerRequest(this); + } + try + { + poa.m_orb.currents.put(Thread.currentThread(), this); + dyn.invoke(serverRequest); + } + finally + { + poa.m_orb.currents.remove(Thread.currentThread()); + } + } + else + { + org.omg.CORBA.portable.InputStream input = v_invoke(handler); + + if (!exceptionReply) + { + NamedValue arg; + + // Read return value, if set. + if (m_result != null) + { + m_result.value().read_value(input, m_result.value().type()); + } + + // Read returned parameters, if set. + if (m_args != null) + { + for (int i = 0; i < m_args.count(); i++) + { + try + { + arg = m_args.item(i); + + // Both ARG_INOUT and ARG_OUT have this binary flag set. + if ((arg.flags() & ARG_OUT.value) != 0) + { + arg.value().read_value(input, arg.value().type()); + } + } + catch (Bounds ex) + { + Unexpected.error(ex); + } + } + } + } + else// User exception reply + { + // Prepare an Any that will hold the exception. + gnuAny exc = new gnuAny(); + + exc.insert_Streamable(new StreamHolder(input)); + + UnknownUserException unuex = new UnknownUserException(exc); + m_environment.exception(unuex); + } + } + } + + /** + * Get an output stream for providing details about the exception. Before + * returning the stream, the handler automatically writes the message header + * and the reply about exception header, but not the message header. + * + * @return the stream to write exception details into. + */ + public OutputStream createExceptionReply() + { + exceptionReply = true; + prepareStream(); + return buffer; + } + + /** + * Get an output stream for writing a regular reply (not an exception). + * + * Before returning the stream, the handler automatically writes the regular + * reply header, but not the message header. + * + * @return the output stream for writing a regular reply. + */ + public OutputStream createReply() + { + exceptionReply = false; + prepareStream(); + return buffer; + } + + /** + * Get the buffer, normally containing the written reply. The reply includes + * the reply header (or the exception header) but does not include the message + * header. + * + * The stream buffer can also be empty if no data have been written into + * streams, returned by {@link #createReply()} or + * {@link #createExceptionReply()}. + * + * @return the CDR output stream, containing the written output. + */ + BufferedCdrOutput getBuffer() + { + return buffer; + } + + /** + * True if the stream was obtained by invoking {@link #createExceptionReply()}, + * false otherwise (usually no-exception reply). + */ + boolean isExceptionReply() + { + return exceptionReply; + } + + /** + * Compute the header offset, set the correct version number and codeset. + */ + private void prepareStream() + { + buffer = new BufferedCdrOutput(); + buffer.setOrb(orb()); + } + + /** + * Get the parameter stream, where the invocation arguments should be written + * if they are written into the stream directly. + */ + public StreamBasedRequest getParameterStream() + { + m_parameter_buffer = new StreamBasedRequest(); + m_parameter_buffer.request = this; + m_parameter_buffer.setOrb(poa.orb()); + return m_parameter_buffer; + } + + public byte[] get_object_id() throws NoContext + { + return Id; + } + + public POA get_POA() throws NoContext + { + return poa; + } +} diff --git a/libjava/classpath/gnu/CORBA/Poa/LocalServerRequest.java b/libjava/classpath/gnu/CORBA/Poa/LocalServerRequest.java new file mode 100644 index 000000000..714e029fe --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Poa/LocalServerRequest.java @@ -0,0 +1,199 @@ +/* LocalServerRequest.java -- + 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.CORBA.Poa; + +import gnu.CORBA.gnuNamedValue; + +import org.omg.CORBA.ARG_INOUT; +import org.omg.CORBA.ARG_OUT; +import org.omg.CORBA.Any; +import org.omg.CORBA.BAD_PARAM; +import org.omg.CORBA.Bounds; +import org.omg.CORBA.Context; +import org.omg.CORBA.NVList; +import org.omg.CORBA.NamedValue; +import org.omg.CORBA.ServerRequest; +import org.omg.CORBA.UnknownUserException; + +/** + * Used to make local invocations via LocalRequest. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class LocalServerRequest + extends ServerRequest +{ + /** + * The local request, on the base of that this instance is created. + */ + final LocalRequest request; + + /** + * Create a new instance. + */ + public LocalServerRequest(LocalRequest _request) + { + request = _request; + } + + /** + * Get the argument list that can be modified. + */ + public void params(NVList args) + { + arguments(args); + } + + /** + * Get contexts. + */ + public Context ctx() + { + return request.ctx(); + } + + /** + * Get the operatin being performed. + */ + public String operation() + { + return request.operation(); + } + + /** + * Get the argument list that can be modified. + * The direction depends on the size of the passed list. + * The empty list is filled with the request arguments. + * The non-empty list is used to set the request arguments. + */ + public void arguments(NVList args) + { + NVList l = request.arguments(); + NamedValue a; + + try + { + if (args.count() == 0) + { + // Transfer to the passed parameter. + for (int i = 0; i < l.count(); i++) + { + a = l.item(i); + args.add_value(a.name(), a.value(), a.flags()); + } + } + else + { + // Transfer from the passed parameter. + if (l.count() != args.count()) + throw new BAD_PARAM("Argument number mismatch, current " + + l.count() + ", passed " + args.count() + ); + try + { + for (int i = 0; i < l.count(); i++) + { + a = l.item(i); + if (a.flags() == ARG_INOUT.value || + a.flags() == ARG_OUT.value + ) + { + ((gnuNamedValue) a).setValue(args.item(i).value()); + } + } + } + catch (ClassCastException cex) + { + InternalError ierr = new InternalError(); + ierr.initCause(cex); + throw ierr; + } + } + } + catch (Bounds ex) + { + InternalError ierr = new InternalError(); + ierr.initCause(ex); + throw ierr; + } + } + + /** + * Set the result. + */ + public void set_result(Any result) + { + gnuNamedValue g = new gnuNamedValue(); + g.setValue(result); + g.setFlags(ARG_OUT.value); + request.set_result(g); + } + + /** + * Get the name of the method being called. + */ + public String op_name() + { + return request.operation(); + } + + /** + * Set the exception that has been thrown. + */ + public void set_exception(Any exc) + { + request.env().exception(new UnknownUserException(exc)); + } + + /** + * Set the result. + */ + public void result(Any r) + { + set_result(r); + } + + /** + * Set the exception. + */ + public void except(Any exc) + { + set_exception(exc); + } +} diff --git a/libjava/classpath/gnu/CORBA/Poa/ORB_1_4.java b/libjava/classpath/gnu/CORBA/Poa/ORB_1_4.java new file mode 100644 index 000000000..360537e2c --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Poa/ORB_1_4.java @@ -0,0 +1,293 @@ +/* ORB_1_4.java -- + 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.CORBA.Poa; + +import gnu.CORBA.OrbFunctional; +import gnu.CORBA.IOR; +import gnu.CORBA.Connected_objects.cObject; +import gnu.CORBA.DynAn.gnuDynAnyFactory; +import gnu.CORBA.Interceptor.ClientRequestInterceptors; +import gnu.CORBA.Interceptor.IORInterceptors; +import gnu.CORBA.Interceptor.Registrator; +import gnu.CORBA.Interceptor.ServerRequestInterceptors; +import gnu.CORBA.Interceptor.gnuIcCurrent; +import gnu.CORBA.Interceptor.gnuIorInfo; + +import org.omg.CORBA.Any; +import org.omg.CORBA.BAD_OPERATION; +import org.omg.CORBA.BAD_PARAM; +import org.omg.CORBA.OBJECT_NOT_EXIST; +import org.omg.CORBA.ORB; +import org.omg.CORBA.Policy; +import org.omg.CORBA.PolicyError; +import org.omg.CORBA.portable.ObjectImpl; +import org.omg.PortableInterceptor.PolicyFactory; +import org.omg.PortableServer.Servant; +import org.omg.PortableServer.POAManagerPackage.State; +import org.omg.PortableServer.POAPackage.InvalidPolicy; + +import java.applet.Applet; +import java.util.Properties; + +/** + * The ORB, supporting POAs that are the feature of jdk 1.4. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class ORB_1_4 + extends OrbFunctional +{ + /** + * The root POA. + */ + public final gnuPOA rootPOA; + + /** + * Maps the active threads to the invocation data ("POA Current's"). + */ + public gnuPoaCurrent currents = new gnuPoaCurrent(); + + /** + * Maps the active threads to the interceptor data ("Interceptor Current's"). + */ + public gnuIcCurrent ic_current = new gnuIcCurrent(this); + + /** + * Creates dynamic anys. + */ + public gnuDynAnyFactory factory = new gnuDynAnyFactory(this); + + /** + * Calls the parent constructor and additionally puts the "RootPOA", + * "RootPOAManager", "POACurrent" and "DynAnyFactory" into initial references. + */ + public ORB_1_4() + { + super(); + try + { + rootPOA = new gnuPOA(null, "RootPOA", null, StandardPolicies.rootPoa(), this); + } + catch (InvalidPolicy ex) + { + // Invalid default policy set. + InternalError ierr = new InternalError(); + ierr.initCause(ex); + throw ierr; + } + initial_references.put("RootPOA", rootPOA); + initial_references.put("RootPOAManager", rootPOA.the_POAManager()); + initial_references.put("POACurrent", currents); + initial_references.put("DynAnyFactory", factory); + initial_references.put("PICurrent", ic_current); + } + + /** + * If the super method detects that the object is not connected to this ORB, + * try to find and activate the object. + */ + public String object_to_string(org.omg.CORBA.Object forObject) + { + try + { + return super.object_to_string(forObject); + } + catch (Exception ex) + { + try + { + AOM.Obj exists = rootPOA.findObject(forObject); + if (exists == null) + throw new OBJECT_NOT_EXIST(forObject == null ? "null" + : forObject.toString()); + else if (exists.poa instanceof gnuPOA) + ((gnuPOA) exists.poa).connect_to_orb(exists.key, forObject); + else + exists.poa.create_reference_with_id(exists.key, + ((ObjectImpl) exists.object)._ids()[0]); + } + catch (Exception bex) + { + BAD_PARAM bad = new BAD_PARAM("Unable to activate " + forObject); + bad.initCause(bex); + throw bad; + } + + return super.object_to_string(forObject); + } + } + + /** + * Destroy all poas and then call the superclass method. + */ + public void destroy() + { + // This will propagate through the whole POA tree. + rootPOA.destroy(true, false); + + super.destroy(); + } + + /** + * Do interceptor registration. + * + * @param properties the properties, between those names the agreed prefix + * "org.omg.PortableInterceptor.ORBInitializerClass." is searched. + * + * @param args the string array, passed to the ORB.init + */ + protected void registerInterceptors(Properties properties, String[] args) + { + Registrator registrator = new Registrator(this, properties, args); + + policyFactories = registrator.m_policyFactories; + + registrator.pre_init(); + initial_references.putAll(registrator.getRegisteredReferences()); + registrator.post_init(); + + if (registrator.hasIorInterceptors()) + iIor = new IORInterceptors(registrator); + + if (registrator.hasServerRequestInterceptors()) + iServer = new ServerRequestInterceptors(registrator); + + if (registrator.hasClientRequestInterceptors()) + iClient = new ClientRequestInterceptors(registrator); + + policyFactories = registrator.m_policyFactories; + } + + /** + * Create IOR and allow registered interceptors to add additional components. + */ + protected IOR createIOR(cObject ref) + throws BAD_OPERATION + { + IOR ior = super.createIOR(ref); + if (iIor != null) + { + AOM.Obj obj = rootPOA.findIorKey(ior.key); + + gnuPOA poa; + + // Null means that the object was connected to the ORB directly. + if (obj == null) + poa = rootPOA; + else + poa = obj.poa; + + gnuIorInfo info = new gnuIorInfo(this, poa, ior); + + // This may modify the ior. + iIor.establish_components(info); + iIor.components_established(info); + } + return ior; + } + + /** + * Create policy using the previously registered factory. + */ + public Policy create_policy(int type, Any value) + throws PolicyError + { + Integer policy = new Integer(type); + + PolicyFactory forge = (PolicyFactory) policyFactories.get(policy); + if (forge == null) + throw new PolicyError("No factory registered for policy " + type, + (short) type); + else + return forge.create_policy(type, value); + } + + /** + * Set the parameters and then register interceptors. + */ + protected void set_parameters(Applet app, Properties props) + { + super.set_parameters(app, props); + registerInterceptors(props, new String[0]); + } + + /** + * Set the parameters and then register interceptors. + */ + protected void set_parameters(String[] para, Properties props) + { + super.set_parameters(para, props); + registerInterceptors(props, para); + } + + /** + * This method is called by RMI-IIOP {@link javax.rmi.Tie#orb(ORB)}, passing + * this as parameter. The ORB will try to connect that tie as + * one of its objects, if it is not already connected. If the wrapper is an + * instance of Servant this method also activates the root poa (if not already + * active). + */ + public void set_delegate(java.lang.Object wrapper) + { + if (wrapper instanceof org.omg.CORBA.Object) + { + org.omg.CORBA.Object object = (org.omg.CORBA.Object) wrapper; + if (connected_objects.getKey(object) == null) + connect(object); + } + else if (wrapper instanceof Servant) + { + Servant s = (Servant) wrapper; + if (rootPOA.findServant(s) == null) + try + { + rootPOA.servant_to_reference(s); + if (rootPOA.the_POAManager().get_state().value() == State._HOLDING) + rootPOA.the_POAManager().activate(); + } + catch (Exception e) + { + BAD_OPERATION bad = new BAD_OPERATION("Unable to connect " + + wrapper + " to " + this); + throw bad; + } + } + } + +} diff --git a/libjava/classpath/gnu/CORBA/Poa/ServantDelegateImpl.java b/libjava/classpath/gnu/CORBA/Poa/ServantDelegateImpl.java new file mode 100644 index 000000000..2123a1c9c --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Poa/ServantDelegateImpl.java @@ -0,0 +1,232 @@ +/* ServantDelegateImpl.java -- + 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.CORBA.Poa; + +import gnu.CORBA.Unexpected; + +import org.omg.CORBA.NO_IMPLEMENT; +import org.omg.CORBA.ORB; +import org.omg.CORBA.ORBPackage.InvalidName; +import org.omg.CORBA.Object; +import org.omg.PortableServer.CurrentPackage.NoContext; +import org.omg.PortableServer.POA; +import org.omg.PortableServer.POAHelper; +import org.omg.PortableServer.Servant; +import org.omg.PortableServer.portable.Delegate; + +/** + * The implementation of the servant delegate for the locally existing + * servant.The associated servant that must also implement the + * {@link InvokeHandler} interface. Each servant requires a separate + * instance of this delegate and can serve a single object only. + * Hence the fields are final, but the delegate is typically reused + * unless the same servant is connected to different objects. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class ServantDelegateImpl + implements Delegate +{ + /** + * The servant, associated with this object. + */ + final Servant servant; + + /** + * The servant (not object) id. + */ + final byte[] servant_id; + + /** + * The POA, where the servant is connected. + */ + final gnuPOA poa; + + /** + * The object, exposed as an object, served by this servant. + */ + final gnuServantObject object; + + /** + * Create the delegat for the servant that will be connected to the + * given poa. The method is normally called from inside of gnuPOA. + * The constructor sets the newly created delegate as the delegate to this + * servant by calling Servant._set_delegate. + * + * @param a_poa the poa. + * @param a_servant the servant. + * @param a_servant_id the servant id. + */ + public ServantDelegateImpl(Servant a_servant, gnuPOA a_poa, byte[] a_servant_id) + { + poa = a_poa; + servant = a_servant; + servant_id = a_servant_id; + servant._set_delegate(this); + object = + new gnuServantObject(servant, servant_id, (ORB_1_4) servant._orb(), a_poa); + object._set_delegate(new LocalDelegate(object, poa, a_servant_id)); + } + + /** + * Check if this object could be named by the given repository id. + * @param idl_id the repository id to check. + * + * @return true if it is one of the possible repository ids of this + * object. + */ + public boolean is_a(Servant a_servant, String idl_id) + { + same(a_servant); + + String[] maybe = object.repository_ids; + if (maybe == null) + maybe = servant._all_interfaces(poa, object.Id); + for (int i = 0; i < maybe.length; i++) + { + if (maybe [ i ].equals(idl_id)) + return true; + } + return false; + } + + /** + * Return the ORB's default POA. + */ + public POA default_POA(Servant a_servant) + { + same(a_servant); + try + { + return POAHelper.narrow(orb(a_servant).resolve_initial_references("RootPOA")); + } + catch (InvalidName ex) + { + throw new Unexpected(ex); + } + } + + /** + * Get ORB. + */ + public ORB orb(Servant a_servant) + { + same(a_servant); + return poa.orb(); + } + + /** + * Get the object, exposing the servant. + */ + public Object this_object(Servant a_servant) + { + same(a_servant); + try + { + return poa.aom.get(poa.m_orb.currents.get_object_id()).object; + } + catch (NoContext ex) + { + return object; + } + } + + /** + * Not supported. + * + * @specnote Same as for Sun up till 1.5 inclusive. + */ + public Object get_interface_def(Servant a_servant) + { + same(a_servant); + throw new NO_IMPLEMENT(); + } + + /** + * Get the Id of the object being currently served. + */ + public byte[] object_id(Servant a_servant) + { + same(a_servant); + try + { + byte[] id = poa.m_orb.currents.get_object_id(); + return id; + } + catch (NoContext ex) + { + return object.Id; + } + } + + /** + * Always returns false; + */ + public boolean non_existent(Servant a_servant) + { + same(a_servant); + return false; + } + + /** + * Return the associated POA. + */ + public POA poa(Servant a_servant) + { + same(a_servant); + try + { + return poa.m_orb.currents.get_POA(); + } + catch (NoContext ex) + { + return poa; + } + } + + /** + * Checks if the passed servant is the same as the servant, associated with + * this delegate. This class requires a single servant per delegate. + */ + void same(Servant some_servant) + { + if (servant != some_servant) + throw new InternalError("Only one servant per delegate is supported."); + } +} diff --git a/libjava/classpath/gnu/CORBA/Poa/StandardPolicies.java b/libjava/classpath/gnu/CORBA/Poa/StandardPolicies.java new file mode 100644 index 000000000..6b84031f1 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Poa/StandardPolicies.java @@ -0,0 +1,128 @@ +/* StandardPolicies.java -- + 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.CORBA.Poa; + +import org.omg.CORBA.Policy; +import org.omg.PortableServer.IdAssignmentPolicyValue; +import org.omg.PortableServer.IdUniquenessPolicyValue; +import org.omg.PortableServer.ImplicitActivationPolicyValue; +import org.omg.PortableServer.LifespanPolicyValue; +import org.omg.PortableServer.RequestProcessingPolicyValue; +import org.omg.PortableServer.ServantRetentionPolicyValue; +import org.omg.PortableServer.ThreadPolicyValue; + +import java.util.ArrayList; + +/** + * Contains the frequently uset POA policy sets. The policy + * arrays are package private for security reasons, the cloned + * copies are returned. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class StandardPolicies +{ + /** + * The default policy set, as defined in OMG specs. This is also + * the policy set for the root POA. + */ + private static final AccessiblePolicy[] rootPOASet = + new AccessiblePolicy[] + { + new gnuThreadPolicy(ThreadPolicyValue.ORB_CTRL_MODEL), + new gnuLifespanPolicy(LifespanPolicyValue.TRANSIENT), + new gnuIdUniquenessPolicy(IdUniquenessPolicyValue.UNIQUE_ID), + new gnuIdAssignmentPolicy(IdAssignmentPolicyValue.SYSTEM_ID), + new gnuServantRetentionPolicy(ServantRetentionPolicyValue.RETAIN), + new gnuRequestProcessingPolicy(RequestProcessingPolicyValue.USE_ACTIVE_OBJECT_MAP_ONLY), + new gnuImplicitActivationPolicy(ImplicitActivationPolicyValue.IMPLICIT_ACTIVATION) + }; + + /** + * Return the policy set, applicable for the root POA, as defined + * in OMG specs. + */ + public static Policy[] rootPoa() + { + Policy[] p = new Policy[ rootPOASet.length ]; + System.arraycopy(rootPOASet, 0, p, 0, p.length); + return p; + } + + /** + * Convert the potentially incomplete policy array into array, containing + * the complete policy set. + * + * @param policies the policy list, may be incomplete (even zero size). + * + * @return the complete policy array. The missing, but needed policies + * are added with they default values. + */ + public static Policy[] withDefault(Policy[] policies) + { + ArrayList current = new ArrayList(rootPOASet.length); + Policy p_default; + boolean specified; + + for (int i = 0; i < rootPOASet.length; i++) + { + p_default = rootPOASet [ i ]; + specified = false; + ForThis: + for (int j = 0; j < policies.length; j++) + { + if (policies [ j ].policy_type() == p_default.policy_type()) + { + specified = true; + current.add(policies [ j ]); + break ForThis; + } + } + if (!specified) + current.add(p_default.copy()); + } + + Policy[] complete = new Policy[ current.size() ]; + for (int i = 0; i < complete.length; i++) + { + complete [ i ] = (Policy) current.get(i); + } + return complete; + } +} diff --git a/libjava/classpath/gnu/CORBA/Poa/gnuAdapterActivator.java b/libjava/classpath/gnu/CORBA/Poa/gnuAdapterActivator.java new file mode 100644 index 000000000..fc64e6bb1 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Poa/gnuAdapterActivator.java @@ -0,0 +1,81 @@ +/* gnuAdapterActivator.java -- + 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.CORBA.Poa; + +import org.omg.CORBA.LocalObject; +import org.omg.PortableServer.AdapterActivator; +import org.omg.PortableServer.POA; + +/** + * Defines a simple adapter activator. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class gnuAdapterActivator + extends LocalObject + implements AdapterActivator +{ + /** + * Create a new POA on the parent, using the parent policy set + * from the suitable parent of grandparend and with independent + * POA manager (passing null to the createPOA). + * + * @param parent a parent. Either this parent or one of its + * grandparents must be gnuAbstractPOA, able to provide a + * policy set. + * + * @param child_name the name of the child being created. + * + * @return true on success or false if no gnuAbstractPOA + * found till the root poa. + */ + public boolean unknown_adapter(POA parent, String child_name) + { + try + { + POA n = parent.create_POA(child_name, null, StandardPolicies.rootPoa()); + n.the_POAManager().activate(); + } + catch (Exception ex) + { + return false; + } + return true; + } +} diff --git a/libjava/classpath/gnu/CORBA/Poa/gnuForwardRequest.java b/libjava/classpath/gnu/CORBA/Poa/gnuForwardRequest.java new file mode 100644 index 000000000..01c6cccd5 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Poa/gnuForwardRequest.java @@ -0,0 +1,90 @@ +/* gnuForwardRequest.java -- + 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.CORBA.Poa; + +import gnu.CORBA.GIOP.ReplyHeader; + +import org.omg.CORBA.BAD_PARAM; +import org.omg.CORBA.portable.ObjectImpl; + +/** + * The class, indicating that the request should be forwarded to another + * target. We cannot use ForwardRequest because the exception is throws + * from methods that does not declare throwing it. Hence must be + * RuntimeException. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class gnuForwardRequest + extends RuntimeException +{ + /** + * Use serialVersionUID (v1.4) for interoperability. + */ + private static final long serialVersionUID = -1L; + + /** + * The object reference, indicating the new location of the invocation target. + */ + public ObjectImpl forward_reference; + + /** + * This information shows if we use LOCATION_FORWARD or + * LOCATION_FORWARD_PERM in request. By defalult, LOCATION_FORWARD + * is always used. To use LOCATION_FORWARD_PERM, this exception should + * be thrown from the servant manager instead of ForwardRequest, + * with this field set to ReplyHeader.LOCATION_FORWARD_PERM. + */ + public byte forwarding_code = ReplyHeader.LOCATION_FORWARD; + + /** + * Create the ForwardRequest with explaining message and + * initialising the object reference to the given value. + * + * @param why a string, explaining, why this exception has been thrown. + * @param a_forward_reference a value for forward_reference. + */ + public gnuForwardRequest(org.omg.CORBA.Object a_forward_reference) + { + if (a_forward_reference instanceof ObjectImpl) + this.forward_reference = (ObjectImpl) a_forward_reference; + else + throw new BAD_PARAM("ObjectImpl expected"); + } +} diff --git a/libjava/classpath/gnu/CORBA/Poa/gnuIdAssignmentPolicy.java b/libjava/classpath/gnu/CORBA/Poa/gnuIdAssignmentPolicy.java new file mode 100644 index 000000000..1234abce6 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Poa/gnuIdAssignmentPolicy.java @@ -0,0 +1,80 @@ +/* gnuIdAssignmentPolicy.java -- + 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.CORBA.Poa; + +import gnu.CORBA._PolicyImplBase; + +import org.omg.PortableServer.ID_ASSIGNMENT_POLICY_ID; +import org.omg.PortableServer.IdAssignmentPolicy; +import org.omg.PortableServer.IdAssignmentPolicyValue; + +/** + * Implementation of the id assignment policy. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class gnuIdAssignmentPolicy + extends _PolicyImplBase + implements IdAssignmentPolicy, AccessiblePolicy +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1L; + + /** + * Create the policy. + * + * @param v a value for the policy. + */ + public gnuIdAssignmentPolicy(IdAssignmentPolicyValue v) + { + super(ID_ASSIGNMENT_POLICY_ID.value, v, v.value(), + "IDL:org.omg/PortableServer/IdAssignmentPolicy:1.0" + ); + } + + /** + * Get the value for the policy that was passed in a constructor. + */ + public IdAssignmentPolicyValue value() + { + return (IdAssignmentPolicyValue) getValue(); + } +} diff --git a/libjava/classpath/gnu/CORBA/Poa/gnuIdUniquenessPolicy.java b/libjava/classpath/gnu/CORBA/Poa/gnuIdUniquenessPolicy.java new file mode 100644 index 000000000..21d8c54c4 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Poa/gnuIdUniquenessPolicy.java @@ -0,0 +1,80 @@ +/* gnuIdUniquenessPolicy.java -- + 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.CORBA.Poa; + +import gnu.CORBA._PolicyImplBase; + +import org.omg.PortableServer.ID_UNIQUENESS_POLICY_ID; +import org.omg.PortableServer.IdUniquenessPolicy; +import org.omg.PortableServer.IdUniquenessPolicyValue; + +/** + * Implementation of the id uniqueness policy. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class gnuIdUniquenessPolicy + extends _PolicyImplBase + implements IdUniquenessPolicy, AccessiblePolicy +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1L; + + /** + * Create the policy. + * + * @param v a value for the policy. + */ + public gnuIdUniquenessPolicy(IdUniquenessPolicyValue v) + { + super(ID_UNIQUENESS_POLICY_ID.value, v, v.value(), + "IDL:org.omg/PortableServer/IdUniquenessPolicy:1.0" + ); + } + + /** + * Get the value for the policy that was passed in a constructor. + */ + public IdUniquenessPolicyValue value() + { + return (IdUniquenessPolicyValue) getValue(); + } +} diff --git a/libjava/classpath/gnu/CORBA/Poa/gnuImplicitActivationPolicy.java b/libjava/classpath/gnu/CORBA/Poa/gnuImplicitActivationPolicy.java new file mode 100644 index 000000000..96ce42708 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Poa/gnuImplicitActivationPolicy.java @@ -0,0 +1,80 @@ +/* gnuImplicitActivationPolicy.java -- + 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.CORBA.Poa; + +import gnu.CORBA._PolicyImplBase; + +import org.omg.PortableServer.IMPLICIT_ACTIVATION_POLICY_ID; +import org.omg.PortableServer.ImplicitActivationPolicy; +import org.omg.PortableServer.ImplicitActivationPolicyValue; + +/** + * Implementation of the implicit activation policy. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class gnuImplicitActivationPolicy + extends _PolicyImplBase + implements ImplicitActivationPolicy, AccessiblePolicy +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1L; + + /** + * Create the policy. + * + * @param v a value for the policy. + */ + public gnuImplicitActivationPolicy(ImplicitActivationPolicyValue v) + { + super(IMPLICIT_ACTIVATION_POLICY_ID.value, v, v.value(), + "IDL:org.omg/PortableServer/ImplicitActivationPolicy:1.0" + ); + } + + /** + * Get the value for the policy that was passed in a constructor. + */ + public ImplicitActivationPolicyValue value() + { + return (ImplicitActivationPolicyValue) getValue(); + } +} diff --git a/libjava/classpath/gnu/CORBA/Poa/gnuLifespanPolicy.java b/libjava/classpath/gnu/CORBA/Poa/gnuLifespanPolicy.java new file mode 100644 index 000000000..6efb9d603 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Poa/gnuLifespanPolicy.java @@ -0,0 +1,80 @@ +/* gnuLifespanPolicy.java -- + 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.CORBA.Poa; + +import gnu.CORBA._PolicyImplBase; + +import org.omg.PortableServer.LIFESPAN_POLICY_ID; +import org.omg.PortableServer.LifespanPolicy; +import org.omg.PortableServer.LifespanPolicyValue; + +/** + * The implementation of the life span policy. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class gnuLifespanPolicy + extends _PolicyImplBase + implements LifespanPolicy, AccessiblePolicy +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1L; + + /** + * Create the policy. + * + * @param v a value for the policy. + */ + public gnuLifespanPolicy(LifespanPolicyValue v) + { + super(LIFESPAN_POLICY_ID.value, v, v.value(), + "IDL:org.omg/PortableServer/LifespanPolicy:1.0" + ); + } + + /** + * Get the value for the policy that was passed in a constructor. + */ + public LifespanPolicyValue value() + { + return (LifespanPolicyValue) getValue(); + } +} diff --git a/libjava/classpath/gnu/CORBA/Poa/gnuPOA.java b/libjava/classpath/gnu/CORBA/Poa/gnuPOA.java new file mode 100644 index 000000000..5d323305a --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Poa/gnuPOA.java @@ -0,0 +1,1817 @@ +/* gnuAbstractPOA.java -- + 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.CORBA.Poa; + +import gnu.java.lang.CPStringBuilder; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; + +import org.omg.CORBA.BAD_INV_ORDER; +import org.omg.CORBA.BAD_PARAM; +import org.omg.CORBA.CompletionStatus; +import org.omg.CORBA.LocalObject; +import org.omg.CORBA.NO_IMPLEMENT; +import org.omg.CORBA.OBJ_ADAPTER; +import org.omg.CORBA.ORB; +import org.omg.CORBA.Object; +import org.omg.CORBA.Policy; +import org.omg.CORBA.SetOverrideType; +import org.omg.CORBA.TRANSIENT; +import org.omg.CORBA.portable.ObjectImpl; +import org.omg.PortableInterceptor.NON_EXISTENT; +import org.omg.PortableInterceptor.ObjectReferenceFactory; +import org.omg.PortableInterceptor.ObjectReferenceTemplate; +import org.omg.PortableInterceptor.ObjectReferenceTemplateHelper; +import org.omg.PortableServer.AdapterActivator; +import org.omg.PortableServer.ForwardRequest; +import org.omg.PortableServer.IdAssignmentPolicy; +import org.omg.PortableServer.IdAssignmentPolicyValue; +import org.omg.PortableServer.IdUniquenessPolicy; +import org.omg.PortableServer.IdUniquenessPolicyValue; +import org.omg.PortableServer.ImplicitActivationPolicy; +import org.omg.PortableServer.ImplicitActivationPolicyValue; +import org.omg.PortableServer.LifespanPolicy; +import org.omg.PortableServer.LifespanPolicyValue; +import org.omg.PortableServer.POA; +import org.omg.PortableServer.POAManager; +import org.omg.PortableServer.RequestProcessingPolicy; +import org.omg.PortableServer.RequestProcessingPolicyValue; +import org.omg.PortableServer.SERVANT_RETENTION_POLICY_ID; +import org.omg.PortableServer.Servant; +import org.omg.PortableServer.ServantActivator; +import org.omg.PortableServer.ServantLocator; +import org.omg.PortableServer.ServantManager; +import org.omg.PortableServer.ServantRetentionPolicy; +import org.omg.PortableServer.ServantRetentionPolicyValue; +import org.omg.PortableServer.ThreadPolicy; +import org.omg.PortableServer.ThreadPolicyValue; +import org.omg.PortableServer.POAManagerPackage.State; +import org.omg.PortableServer.POAPackage.AdapterAlreadyExists; +import org.omg.PortableServer.POAPackage.AdapterNonExistent; +import org.omg.PortableServer.POAPackage.InvalidPolicy; +import org.omg.PortableServer.POAPackage.NoServant; +import org.omg.PortableServer.POAPackage.ObjectAlreadyActive; +import org.omg.PortableServer.POAPackage.ObjectNotActive; +import org.omg.PortableServer.POAPackage.ServantAlreadyActive; +import org.omg.PortableServer.POAPackage.ServantNotActive; +import org.omg.PortableServer.POAPackage.WrongAdapter; +import org.omg.PortableServer.POAPackage.WrongPolicy; + +import gnu.CORBA.OrbFunctional; +import gnu.CORBA.CDR.BufferredCdrInput; +import gnu.CORBA.CDR.BufferedCdrOutput; + +/** + * Our POA implementation. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class gnuPOA + extends LocalObject + implements POA, ObjectReferenceFactory +{ + /** + * The object reference template, associated with this POA. + * + * @since 1.5 + */ + class RefTemplate implements ObjectReferenceTemplate + { + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + RefTemplate() + { + // The adapter name is computed once. + ArrayList names = new ArrayList(); + names.add(the_name()); + + POA poa = the_parent(); + while (poa != null) + { + names.add(poa.the_name()); + poa = poa.the_parent(); + } + + // Fill in the string array in reverse (more natural) order, + // root POA first. + m_adapter_name = new String[names.size()]; + + for (int i = 0; i < m_adapter_name.length; i++) + m_adapter_name[i] = (String) names.get(m_adapter_name.length - i - 1); + } + + /** + * The adapter name + */ + final String[] m_adapter_name; + + /** + * Get the name of this POA. + */ + public String[] adapter_name() + { + return (String[]) m_adapter_name.clone(); + } + + /** + * Get the ORB id. + */ + public String orb_id() + { + return m_orb.orb_id; + } + + /** + * Get the server id. + */ + public String server_id() + { + return OrbFunctional.server_id; + } + + /** + * Create the object. + */ + public Object make_object(String repositoryId, byte[] objectId) + { + return create_reference_with_id(objectId, repositoryId); + } + + /** + * Get the array of truncatible repository ids. + */ + public String[] _truncatable_ids() + { + return ref_template_ids; + } + } + + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * The adapter reference template. + */ + ObjectReferenceTemplate refTemplate; + + /** + * The reference template repository ids. Defined outside the class as it + * cannot have static members. + */ + final static String[] ref_template_ids = + new String[] { ObjectReferenceTemplateHelper.id() }; + + /** + * The active object map, mapping between object keys, objects and servants. + */ + public final AOM aom = new AOM(); + + /** + * The children of this POA. + */ + final ArrayList children = new ArrayList(); + + /** + * The name of this POA. + */ + final String name; + + /** + * The parent of this POA (null for the root POA). + */ + final POA parent; + + /** + * The ior key signature, indicating, that the ior key is encoded using + * internal agreements of this implementation (0x'free'). + */ + static final int SIGNATURE = 0x66726565; + + /** + * The adapter activator for this POA, null if no activator is set. + */ + AdapterActivator m_activator; + + /** + * The POA manager for this POA. + */ + POAManager m_manager; + + /** + * The servant manager (servant activator) for this POA. + */ + ServantActivator servant_activator; + + /** + * The servant manager (servant locator) for this POA. + */ + ServantLocator servant_locator; + + /** + * The default servant, if on is in use. + */ + Servant default_servant; + + /** + * The cached poa id value, computed once. + */ + private byte[] m_poa_id; + + /** + * The all policy values that apply to this POA. + * The used policy values are singletons, unique between policies. + */ + private final HashSet m_policies; + + /** + * An array of the set policies. + */ + Policy[] s_policies; + + /** + * The ORB, where the POA is connected. + */ + final ORB_1_4 m_orb; + + /** + * When true, the POA is being destroyed or is destroyed. + */ + boolean m_inDestruction; + + /** + * True if the active object map is used by this POA. + * The value is moved into separate boolean value due + * necessity of the frequent checks. + */ + public final boolean retain_servant; + + /** + * The object reference factory, used to create the new object + * references. + */ + ObjectReferenceFactory m_object_factory = this; + + /** + * Create a new abstract POA. + * + * @param a_parent the parent of this POA. + * @param a_name a name for this POA. + * @param a_manager a manager for this POA. If null, a new + * {@link gnuPOAManager} will be instantiated. + * @param a_policies an array of policies that apply to this POA. + * @param an_orb an ORB for this POA. + */ + public gnuPOA(gnuPOA a_parent, String a_name, POAManager a_manager, + Policy[] a_policies, ORB_1_4 an_orb + ) + throws InvalidPolicy + { + // Add default policies. + Policy[] all_policies = StandardPolicies.withDefault(a_policies); + + name = a_name; + parent = a_parent; + m_orb = an_orb; + + if (a_manager != null) + m_manager = a_manager; + else + m_manager = new gnuPOAManager(); + + if (m_manager instanceof gnuPOAManager) + { + gnuPOAManager g = (gnuPOAManager) m_manager; + g.addPoa(this); + } + + m_policies = new HashSet(all_policies.length); + + s_policies = new Policy[ all_policies.length ]; + for (int i = 0; i < s_policies.length; i++) + { + s_policies [ i ] = all_policies [ i ].copy(); + m_policies.add(((AccessiblePolicy) s_policies [ i ]).getValue()); + } + + retain_servant = applies(ServantRetentionPolicyValue.RETAIN); + + validatePolicies(a_policies); + + refTemplate = new RefTemplate(); + } + + /** + * Wait while at least one of the threads in this POA is actively + * processing one of requests. + */ + public void waitWhileRunning() + { + // First pause. + long time = 1; + + // Maximal duration between checks. + long max = 500; + + boolean runs; + + do + { + runs = m_orb.currents.has(this); + + if (runs) + { + // Avoid taking CPU resources + // from the thread that is running. + try + { + Thread.sleep(time); + time = time * 2; + if (time > max) + time = max; + } + catch (InterruptedException ex) + { + } + } + } + while (runs); + } + + /** + * Etherealize all objects, associated with this POA. Invoked from the + * {@link gnuPOAManager} only if it is known that the servant_activator + * holds non-null value. + */ + protected void etherealizeAll() + { + if (servant_activator == null) + return; + + ArrayList keys = new ArrayList(); + keys.addAll(aom.keySet()); + + byte[] key; + AOM.Obj obj; + boolean last; + for (int i = 0; i < keys.size(); i++) + { + key = (byte[]) keys.get(i); + obj = aom.get(key); + + if (obj.poa == this) + { + aom.remove(key); + + if (!obj.isDeactiveted()) + { + // Check if the servant still stays under the other key. + last = aom.findServant(obj.servant) == null; + servant_activator.etherealize(obj.key, this, obj.servant, true, + last + ); + } + } + } + } + + /** + * Create an instance of the POA with the given features. + * This method is not responsible for duplicate checking + * or adding the returned instance to any possible table. + * + * @param child_name the name of the poa being created. + * @param a_manager the poa manager (never null). + * @param policies the array of policies. + * @param an_orb the ORB for this POA. + * + * @return the created POA. + * + * @throws InvalidPolicy for conflicting or otherwise invalid policies.| + */ + protected POA createPoaInstance(String child_name, POAManager a_manager, + Policy[] policies, ORB_1_4 an_orb + ) + throws InvalidPolicy + { + POAManager some_manager = + a_manager == null ? new gnuPOAManager() : a_manager; + + if (some_manager instanceof gnuPOAManager) + { + ((gnuPOAManager) some_manager).addPoa(this); + } + + return new gnuPOA(this, child_name, some_manager, policies, an_orb); + } + + /** + * Check if the given policy value applies to this POA. + * + * @param policy_value a policy value to check. The policy values are + * singletons and unique between the different policies, so the policy + * type is not passed. + * + * @return true if the policy value applies, false otherwise. + */ + public final boolean applies(java.lang.Object policy_value) + { + return m_policies.contains(policy_value); + } + + /** + * Check for the presence of the required policy. + * + * @param policy_value a policy value to check. + * + * @throws WrongPolicy if the required policy value is not applicable. + */ + public final void required(java.lang.Object policy_value) + throws WrongPolicy + { + if (!applies(policy_value)) + throw new WrongPolicy(policy_value + " policy required."); + } + + /** + * Check for the absence of the given policy. + * + * @param policy_value a policy value to check. + * + * @throws WrongPolicy if the passed policy value is applicable. + */ + public final void excluding(java.lang.Object policy_value) + throws WrongPolicy + { + if (applies(policy_value)) + throw new WrongPolicy(policy_value + " policy applies."); + } + + /** + * Find and optionally activate the child POA with the given name. + * + * @param poa_name the name of the POA to find. + * @param activate_it if the child with the specified name is not found + * or inactive and this parameter is true, the target POA activator is + * invoked to activate that child. If this succeeds, that child POA + * is returned. + * + * @throws AdapterNonExistent if no active child with the given name + * is found and one of the following is true: + * a) the target POA has no associated + * {@link AdapterActivator}. b) that activator fails to activate the + * child POA. c) activate_id = false. + */ + public POA find_POA(String poa_name, boolean activate_it) + throws AdapterNonExistent + { + POA child; + for (int i = 0; i < children.size(); i++) + { + child = (POA) children.get(i); + if (child.the_name().equals(poa_name)) + return child; + } + + if (activate_it && m_activator != null) + { + boolean activated = m_activator.unknown_adapter(this, poa_name); + if (!activated) + throw new AdapterNonExistent(poa_name + " activation failed."); + + // Tha activator should add the child to the childrent table. + for (int i = 0; i < children.size(); i++) + { + child = (POA) children.get(i); + if (child.the_name().equals(poa_name)) + return child; + } + throw new AdapterNonExistent(poa_name + " not created. "); + } + else + throw new AdapterNonExistent(poa_name); + } + + /** + * Generate the Object Id for the given servant and add the servant to the + * Active Object Map using this Id a a key. If the servant activator is set, + * its incarnate method will be called. + * + * @param a_servant a servant that would serve the object with the returned + * Object Id. If null is passed, under apporoprate policies the servant + * activator is invoked. + * + * @return the generated objert Id for the given servant. + * + * @throws ServantAlreadyActive if this servant is already in the Active + * Object Map and the UNIQUE_ID policy applies. + * + * @throws WrongPolicy if the required policies SYSTEM_ID and RETAIN do not + * apply to this POA. + */ + public byte[] activate_object(Servant a_servant) + throws ServantAlreadyActive, WrongPolicy + { + checkDiscarding(); + required(ServantRetentionPolicyValue.RETAIN); + required(IdAssignmentPolicyValue.SYSTEM_ID); + + AOM.Obj exists = aom.findServant(a_servant); + + if (exists != null) + { + if (exists.isDeactiveted()) + { + // If exists but deactivated, activate and return + // the existing key. + exists.setDeactivated(false); + incarnate(exists, exists.key, a_servant, false); + return exists.key; + } + else if (applies(IdUniquenessPolicyValue.UNIQUE_ID)) + throw new ServantAlreadyActive(); + + // It multiple ids are allowed, exit block allowing repetetive + // activations. + } + + byte[] object_key = AOM.getFreeId(); + ServantDelegateImpl delegate = new ServantDelegateImpl(a_servant, this, + object_key); + create_and_connect(object_key, + a_servant._all_interfaces(this, object_key)[0], delegate); + return object_key; + } + + /** + * Add the given servant to the Active Object Map as a servant for the object + * with the provided Object Id. If the servant activator is set, its incarnate + * method will be called. + * + * @param an_Object_Id an object id for the given object. + * @param a_servant a servant that will serve the object with the given Object + * Id. If null is passed, under apporoprate policies the servant activator is + * invoked. + * + * @throws ObjectAlreadyActive if the given object id is already in the Active + * Object Map. + * @throws ServantAlreadyActive if the UNIQUE_ID policy applies and this + * servant is already in use. + * @throws WrongPolicy if the required RETAIN policy does not apply to this + * POA. + * @throws BAD_PARAM if the passed object id is invalid due any reason. + */ + public void activate_object_with_id(byte[] an_Object_Id, Servant a_servant) + throws ServantAlreadyActive, ObjectAlreadyActive, + WrongPolicy + { + activate_object_with_id(an_Object_Id, a_servant, false); + } + + /** + * Same as activate_object_with_id, but permits gnuForwardRequest forwarding + * exception. This is used when the activation is called from the remote + * invocation context and we have possibility to return the forwarding + * message. + */ + public void activate_object_with_id(byte[] an_Object_Id, Servant a_servant, + boolean use_forwarding) + throws ServantAlreadyActive, ObjectAlreadyActive, WrongPolicy + { + checkDiscarding(); + required(ServantRetentionPolicyValue.RETAIN); + + // If the UNIQUE_ID applies, the servant being passed must not be + // already active. + if (applies(IdUniquenessPolicyValue.UNIQUE_ID)) + { + AOM.Obj sx = aom.findServant(a_servant, false); + if (sx != null) + throw new ServantAlreadyActive(); + } + + AOM.Obj exists = aom.get(an_Object_Id); + if (exists != null) + { + if (exists.servant == null) + { + locateServant(an_Object_Id, a_servant, exists, use_forwarding); + exists.setDeactivated(false); + } + else if (exists.isDeactiveted()) + { + exists.setDeactivated(false); + incarnate(exists, an_Object_Id, a_servant, use_forwarding); + } + else + throw new ObjectAlreadyActive(); + } + else + { + ServantDelegateImpl delegate = new ServantDelegateImpl(a_servant, this, + an_Object_Id); + create_and_connect(an_Object_Id, a_servant._all_interfaces(this, + an_Object_Id)[0], delegate); + } + } + + /** + * Locate the servant for this object Id and connect it to ORB. + * + * @param an_Object_Id the object id. + * @param a_servant the servant (may be null). + * @param exists an existing active object map entry. + * @param use_forwarding allow to throw the gnuForwardRequest if the activator + * throws ForwardRequest. + * + * @throws OBJ_ADAPTER minor 4 if the servant cannot be located (the required + * servant manager may be missing). + */ + private void locateServant(byte[] an_Object_Id, Servant a_servant, + AOM.Obj exists, boolean use_forwarding + ) + throws InternalError + { + // An object was created with create_reference. + gnuServantObject object = (gnuServantObject) exists.object; + if (servant_activator != null) + { + exists.setServant(incarnate(exists, an_Object_Id, a_servant, + use_forwarding + ) + ); + } + else if (default_servant != null) + { + exists.setServant(default_servant); + } + if (exists.servant == null) + { + exists.setServant(a_servant); + } + if (exists.servant == null) + { + throw new OBJ_ADAPTER("no servant", 4, CompletionStatus.COMPLETED_NO); + } + + ServantDelegateImpl delegate = + new ServantDelegateImpl(exists.servant, this, an_Object_Id); + exists.servant._set_delegate(delegate); + object.setServant(exists.servant); + connect_to_orb(an_Object_Id, delegate.object); + } + + /** + * Deactivate object with the given id. + * + * The deactivated object will continue to process requests that arrived + * before decativation. If this POA has the associated + * servant manager, a {@link ServantActivatorOperations#etherealize} is + * immediately invoked on the passed id. + * + * @throws WrongPolicy if the required RETAIN policy does not apply to + * this POA. + */ + public void deactivate_object(byte[] the_Object_Id) + throws ObjectNotActive, WrongPolicy + { + required(ServantRetentionPolicyValue.RETAIN); + + AOM.Obj exists = aom.get(the_Object_Id); + + if (exists == null || exists.isDeactiveted()) + throw new ObjectNotActive(); + + exists.setDeactivated(true); + + // Check if this servant is serving something else. + aom.remove(the_Object_Id); + + AOM.Obj other = aom.findServant(exists.servant, false); + + boolean remaining = other != null; + + aom.put(exists); + + if (servant_activator != null) + servant_activator.etherealize(the_Object_Id, this, exists.servant, false, + remaining + ); + } + + /** + * Create the object reference, encapsulating the given repository Id and + * the Object Id, generated by this POA. The returned object will not be + * activated by default and may be activated on the first invocation by + * the servant manager (if it is set and if policies are applicable). + * + * @param a_repository_id the repository id for the given object, can + * be null if to be requested from the servant later. + * + * @throws WrongPolicy if the required SYSTEM_ID policy does not apply to + * this POA. + */ + public org.omg.CORBA.Object create_reference(String a_repository_id) + throws WrongPolicy + { + required(IdAssignmentPolicyValue.SYSTEM_ID); + return create_reference_with_id(AOM.getFreeId(), a_repository_id); + } + + /** + *

+ * Create the object reference, encapsulating the given repository Id and + * the given Object Id. The returned object will not be + * activated by default and may be activated on the first invocation by + * the servant manager (if the IMPLICIT_ACTIVATION policy applies). + * + * @param an_object_id the object id for the object being created. If this + * POA uses the SYSTEM_ID policy, the portable application should only + * pass the ids, generated by this POA. + * + * @param a_repository_id the repository id for the object being created, + * can be null if this information should be later requested from the + * servant. + */ + public org.omg.CORBA.Object create_reference_with_id(byte[] an_object_id, + String a_repository_id + ) + { + String[] ids; + if (a_repository_id == null) + ids = null; + else + ids = new String[] { a_repository_id }; + + // Check maybe such object is already activated. + AOM.Obj e = aom.get(an_object_id); + + Servant servant; + if (e == null) + { + servant = null; + } + else + { + servant = e.servant; + e.setDeactivated(false); + } + + gnuServantObject object = + new gnuServantObject(ids, an_object_id, this, m_orb); + object._set_delegate(new LocalDelegate(object, this, an_object_id)); + aom.add(object.Id, object, servant, this); + connect_to_orb(an_object_id, object); + + return object; + } + + /** + * Creates a new POA as a child of the target POA. + * + * @param child_name the name of the child POA being created. + * @param manager the manager that will control the new POA. If this parameter + * is null, a new POA manager is created and associated with the new POA. + * + * @param policies the policies, applicable for the parent POA. Policies + * are not inherited from the parent POA. + * + * @return an newly created POA. The POA will be intially in the holding + * state and must be activated to start processing requests. + * + * @throws AdapterAlreadyExists if the child with the given child_name + * already exists for the current POA. + * @throws InvalidPolicy if the policies conflict with each other or are + * otherwise inappropriate. + * + * @see #the_children() + */ + public POA create_POA(String child_name, POAManager manager, Policy[] policies) + throws AdapterAlreadyExists, InvalidPolicy + { + POA child; + for (int i = 0; i < children.size(); i++) + { + child = (POA) children.get(i); + if (child.the_name().equals(child_name)) + throw new AdapterAlreadyExists(name + "/" + child_name); + } + + POA poa = createPoaInstance(child_name, manager, policies, m_orb); + children.add(poa); + return poa; + } + + /** + * Returns a default servant for this POA. + * + * @return a servant that will be used for requests for + * which no servant is found in the Active Object Map. + * + * @throws NoServant if there is no default servant associated with this POA. + * @throws WrongPolicy if the USE_DEFAULT_SERVANT policy is not active. + */ + public Servant get_servant() + throws NoServant, WrongPolicy + { + required(RequestProcessingPolicyValue.USE_DEFAULT_SERVANT); + if (default_servant == null) + throw new NoServant(); + return default_servant; + } + + /** + * Sets the default servant for this POA. + * + * @param a_servant a servant that will be used for requests for + * which no servant is found in the Active Object Map. + * + * @throws WrongPolicy if the USE_DEFAULT_SERVANT policy is not active. + */ + public void set_servant(Servant a_servant) + throws WrongPolicy + { + required(RequestProcessingPolicyValue.USE_DEFAULT_SERVANT); + default_servant = a_servant; + } + + /** + * Set a servant manager for this POA. + * + * @param a servant manager being set. If the RETAIN policy applies, the + * manager must implement a {@link ServantActivator}. If the NON_RETAIN + * policy applies, the manager must implement a {@link ServantLocator}. + * + * @throws WrongPolicy if the required USE_SERVANT_MANAGER policy does not + * apply to this POA. + * + * @throws OBJ_ADAPTER minor code 4 if the passed manager does not + * implement the required interface ({@link ServantActivator}, + * {@link ServantLocator}). The POA, that has the RETAIN policy uses + * servant managers that are ServantActivators. When the POA has the + * NON_RETAIN policy it uses servant managers that are ServantLoacators. + * + * @throws BAD_INV_ORDER minor code 6 if the method is called more than once + * on the same POA. The manager can be set only once. + */ + public void set_servant_manager(ServantManager a_manager) + throws WrongPolicy + { + required(RequestProcessingPolicyValue.USE_SERVANT_MANAGER); + if (servant_activator != null || servant_locator != null) + throw new BAD_INV_ORDER("Setting manager twice for " + name, 6, + CompletionStatus.COMPLETED_NO + ); + + if (applies(ServantRetentionPolicyValue.RETAIN)) + { + if (a_manager instanceof ServantActivator) + servant_activator = (ServantActivator) a_manager; + else + throw new OBJ_ADAPTER("RETAIN requires ServantActivator", 4, + CompletionStatus.COMPLETED_NO + ); + } + else if (applies(ServantRetentionPolicyValue.NON_RETAIN)) + { + if (a_manager instanceof ServantLocator) + servant_locator = (ServantLocator) a_manager; + else + throw new OBJ_ADAPTER("NON_RETAIN requires ServantLocator", 4, + CompletionStatus.COMPLETED_NO + ); + } + else + throw new WrongPolicy("No servant retention policy is specified."); + } + + /** + * Get the servant manager, associated with this POA. + * + * @return the associated servant manager or null if it has + * been previously set. + * + * @throws WrongPolicy if the required USE_SERVANT_MANAGER policy does not + * apply to this POA. + */ + public ServantManager get_servant_manager() + throws WrongPolicy + { + required(RequestProcessingPolicyValue.USE_SERVANT_MANAGER); + + if (servant_activator != null) + return servant_activator; + else + return servant_locator; + } + + /** + * Get the unique Id of the POA in the process in which it is created. + * This Id is needed by portable interceptors. The id is unique + * for the life span of the POA in the process. For persistent + * POAs, if a POA is created in the same path with the same name as + * another POA, these POAs are identical have the same id. All transient + * POAs are assumed unique. + */ + public byte[] id() + { + if (m_poa_id != null) + return m_poa_id; + else + { + BufferedCdrOutput buffer = new BufferedCdrOutput(); + POA p = this; + while (p != null) + { + buffer.write_string(p.the_name()); + p = p.the_parent(); + } + m_poa_id = buffer.buffer.toByteArray(); + return m_poa_id; + } + } + + /** + * Returns the reference to the active object with the given Id. + * + * @param the_Object_Id the object id. + * + * @throws ObjectNotActive if there is no active object with such Id + * in the scope of this POA. + * @throws WrongPolicy if the required RETAIN policy does not apply to + * this POA. + */ + public org.omg.CORBA.Object id_to_reference(byte[] the_Object_Id) + throws ObjectNotActive, WrongPolicy + { + required(ServantRetentionPolicyValue.RETAIN); + + AOM.Obj ref = aom.get(the_Object_Id); + if (ref == null) + throw new ObjectNotActive(); + else + return ref.object; + } + + /** + * Returns the servant that serves the active object with the given Id. + * + * @param the_Object_Id the object id. + * + * @throws ObjectNotActive if there is no active object with such Id or + * it is not currently active. + * @throws WrongPolicy. This method requires either RETAIN or + * USE_DEFAULT_SERVANT policies and reaises the WrongPolicy if none of them + * apply to this POA. + */ + public Servant id_to_servant(byte[] the_Object_Id) + throws ObjectNotActive, WrongPolicy + { + if (applies(ServantRetentionPolicyValue.RETAIN)) + { + AOM.Obj ref = aom.get(the_Object_Id); + if (ref == null || ref.isDeactiveted()) + { + if (default_servant != null) + return default_servant; + else + throw new ObjectNotActive(); + } + else if (ref.servant != null) + return ref.servant; + else if (default_servant != null) + return default_servant; + else + throw new ObjectNotActive(); + } + else if (default_servant != null) + { + return default_servant; + } + else + throw new WrongPolicy("Either RETAIN or USE_DEFAULT_SERVANT required."); + } + + /** + * Returns the Object Id, encapsulated in the given object reference. + * + * @param the_Object the object that has been previously created with this + * POA. It need not be active. + * + * @throws WrongAdapter if the passed object is not known for this POA. + * @throws WrongPolicy never (declared for the future extensions only). + */ + public byte[] reference_to_id(org.omg.CORBA.Object the_Object) + throws WrongAdapter, WrongPolicy + { + AOM.Obj ref = aom.findObject(the_Object); + if (ref == null) + throw new WrongAdapter(); + return ref.key; + } + + /** + * Returns the servant that is serving this object. + * + * @return if the RETAIN policy applies and the object is in the Active Object + * Map, the method returns the servant, associated with this object. + * Otherwise, if the USE_DEFAULT_SERVANT policy applies, the method returns + * the default servant (if one was set). + * + * @throws ObjectNotActive if none of the conditions above are satisfied. + * @throws WrongAdapter if the object reference was not created with this POA. + * @throws WrongPolicy. This method requires either RETAIN or + * USE_DEFAULT_SERVANT policies and reaises the WrongPolicy if none of them + * apply to this POA. + */ + public Servant reference_to_servant(org.omg.CORBA.Object the_Object) + throws ObjectNotActive, WrongPolicy, WrongAdapter + { + if (applies(ServantRetentionPolicyValue.RETAIN)) + { + AOM.Obj ref = aom.findObject(the_Object); + if (ref == null) + { + String object; + if (the_Object == null) + object = "null passed"; + else if (the_Object instanceof gnuServantObject) + { + gnuServantObject gs = (gnuServantObject) the_Object; + object = "Wrong owner POA " + gs.poa.the_name(); + } + else + object = "Unknown " + the_Object.getClass().getName(); + + throw new WrongAdapter(object + " for '" + the_name() + "'"); + } + else if (ref.isDeactiveted() || ref.servant == null) + { + if (default_servant != null) + return default_servant; + else + throw new ObjectNotActive(); + } + else + return ref.servant; + } + else if (default_servant != null) + { + return default_servant; + } + else + throw new WrongPolicy("Either RETAIN or USE_DEFAULT_SERVANT required."); + } + + /** + * Returns the id of the object, served by the given servant (assuming that + * the servant serves only one object). The id is found in one of the + * following ways. + *

+ * + * @throws ServantNotActive in all cases, not listed in the list above. + * @throws WrongPolicy The method requres USE_DEFAULT_SERVANT policy or a + * combination of the RETAIN policy and either the UNIQUE_ID or + * IMPLICIT_ACTIVATION policies and throws the WrongPolicy if these conditions + * are not satisfied. + */ + public byte[] servant_to_id(Servant the_Servant) + throws ServantNotActive, WrongPolicy + { + if (applies(RequestProcessingPolicyValue.USE_DEFAULT_SERVANT) || + applies(ServantRetentionPolicyValue.RETAIN) && + ( + applies(IdUniquenessPolicyValue.UNIQUE_ID) || + applies(ImplicitActivationPolicyValue.IMPLICIT_ACTIVATION) + ) + ) + { + AOM.Obj ref = null; + if (!applies(IdUniquenessPolicyValue.MULTIPLE_ID)) + ref = aom.findServant(the_Servant); + if (ref == null && + applies(ImplicitActivationPolicyValue.IMPLICIT_ACTIVATION) + ) + { + // Try to activate. + try + { + return activate_object(the_Servant); + } + catch (ServantAlreadyActive ex) + { + // Either it shuld not be or the policy allows multiple ids. + throw new InternalError(); + } + } + if (ref == null) + throw new ServantNotActive(); + else + return ref.key; + } + else + throw new WrongPolicy("(RETAIN and UNIQUE ID) " + + "or USE_DEFAULT_SERVANT required." + ); + } + + /** + *

+ * Converts the given servant to the object reference. The servant will serve + * all methods, invoked on the returned object. The returned object reference + * can be passed to the remote client, enabling remote invocations. + *

+ *

+ * If the specified servant is active, it is returned. Otherwise, if the POA + * has the IMPLICIT_ACTIVATION policy the method activates the servant. In + * this case, if the servant activator is set, the + * {@link ServantActivatorOperations#incarnate} method will be called. + *

+ * + * @throws ServantNotActive if the servant is inactive and no + * IMPLICIT_ACTIVATION policy applies. + * @throws WrongPolicy This method needs the RETAIN policy and either the + * UNIQUE_ID or IMPLICIT_ACTIVATION policies. + * + * @return the object, exposing the given servant in the context of this POA. + */ + public org.omg.CORBA.Object servant_to_reference(Servant the_Servant) + throws ServantNotActive, WrongPolicy + { + required(ServantRetentionPolicyValue.RETAIN); + + AOM.Obj exists = null; + + if (!applies(IdUniquenessPolicyValue.MULTIPLE_ID)) + exists = aom.findServant(the_Servant); + + if (exists != null) + { + if (exists.isDeactiveted()) + { + if (applies(ImplicitActivationPolicyValue.IMPLICIT_ACTIVATION)) + { + checkDiscarding(); + exists.setDeactivated(false); + incarnate(exists, exists.key, the_Servant, false); + } + else + throw new ServantNotActive(); + } + else + return exists.object; + } + if (exists == null + && applies(ImplicitActivationPolicyValue.IMPLICIT_ACTIVATION)) + { + checkDiscarding(); + + byte[] object_key = AOM.getFreeId(); + + ServantDelegateImpl delegate = new ServantDelegateImpl(the_Servant, + this, object_key); + create_and_connect(object_key, the_Servant._all_interfaces(this, + object_key)[0], delegate); + + return delegate.object; + } + else + throw new ServantNotActive(); + } + + /** + * Incarnate in cases when request forwarding is not expected because the + * servant must be provided by the servant activator. + * + * @param x the aom entry, where the object is replaced by value, returned by + * servant activator (if not null). + * + * @param object_key the object key. + * + * @param a_servant the servant that was passed as a parameter in the + * activation method. + * + * @param use_forwarding if true, the gnuForwardRequest is throw under the + * forwarding exception (for remote client). Otherwise, the request is + * internally redirected (for local invocation). + */ + private Servant incarnate(AOM.Obj x, byte[] object_key, + Servant a_servant, boolean use_forwarding + ) + { + if (servant_activator != null) + { + Servant servant; + try + { + servant = servant_activator.incarnate(object_key, this); + } + catch (ForwardRequest ex) + { + if (use_forwarding) + throw new gnuForwardRequest(ex.forward_reference); + else + servant = + ForwardedServant.create((ObjectImpl) ex.forward_reference); + } + if (servant != null && x != null) + x.setServant(servant); + if (servant == null && x != null) + servant = x.servant; + return servant; + } + else if (a_servant != null) + { + x.setServant(a_servant); + return a_servant; + } + else if (x.servant != null) + { + return x.servant; + } + else if (default_servant != null) + { + x.setServant(default_servant); + return x.servant; + } + else + throw new BAD_INV_ORDER("No servant given and the servant activator not set"); + } + + /** + * Return the POA manager, associated with this POA. + * + * @return the associated POA manager (always available). + */ + public POAManager the_POAManager() + { + return m_manager; + } + + /** + * Returns the adapter activator, associated with this POA. + * The newly created POA has no activator (null would be + * returned). The ORB root POA also initially has no activator. + * + * @return tha adapter activator or null if this POA has no + * associated adapter activator. + */ + public AdapterActivator the_activator() + { + return m_activator; + } + + /** + * Set the adapter activator for this POA. + * + * @param an_activator the activator being set. + */ + public void the_activator(AdapterActivator an_activator) + { + m_activator = an_activator; + } + + /** + * The children of this POA. + * + * @return the array of all childs for this POA. + */ + public POA[] the_children() + { + POA[] poas = new POA[ children.size() ]; + for (int i = 0; i < poas.length; i++) + { + poas [ i ] = (POA) children.get(i); + } + return poas; + } + + /** + * Return the name of this POA. + * + * @return the name of POA, relative to its parent. + */ + public String the_name() + { + return name; + } + + /** + * Return the parent of this POA. + * + * @return the parent POA or null if this is a root POA. + */ + public POA the_parent() + { + return parent; + } + + /** {@inheritDoc} */ + public IdAssignmentPolicy create_id_assignment_policy(IdAssignmentPolicyValue a_value) + { + return new gnuIdAssignmentPolicy(a_value); + } + + /** {@inheritDoc} */ + public IdUniquenessPolicy create_id_uniqueness_policy(IdUniquenessPolicyValue a_value) + { + return new gnuIdUniquenessPolicy(a_value); + } + + /** {@inheritDoc} */ + public ImplicitActivationPolicy create_implicit_activation_policy(ImplicitActivationPolicyValue a_value) + { + return new gnuImplicitActivationPolicy(a_value); + } + + /** {@inheritDoc} */ + public LifespanPolicy create_lifespan_policy(LifespanPolicyValue a_value) + { + return new gnuLifespanPolicy(a_value); + } + + /** {@inheritDoc} */ + public RequestProcessingPolicy create_request_processing_policy(RequestProcessingPolicyValue a_value) + { + return new gnuRequestProcessingPolicy(a_value); + } + + /** {@inheritDoc} */ + public ServantRetentionPolicy create_servant_retention_policy(ServantRetentionPolicyValue a_value) + { + return new gnuServantRetentionPolicy(a_value); + } + + /** {@inheritDoc} */ + public ThreadPolicy create_thread_policy(ThreadPolicyValue a_value) + { + return new gnuThreadPolicy(a_value); + } + + /** + *

+ * Destroy this POA and all descendant POAs. The destroyed POAs can be later + * re-created via {@link AdapterActivator} or by invoking {@link #create_POA}. + * This differs from {@link PoaManagerOperations#deactivate} that does not + * allow recreation of the deactivated POAs. After deactivation, recreation is + * only possible if the POAs were later destroyed. + *

+ *

+ * The remote invocation on the target, belonging to the POA that is currently + * destroyed return the remote exception ({@link TRANSIENT}, minor code 4). + *

+ * + * @param etherealize_objects if true, and POA has RETAIN policy, and the + * servant manager is available, the servant manager method + * {@link ServantActivatorOperations#etherealize} is called for each active + * object in the Active Object Map. This method should not try to access POA + * being destroyed. If destroy is called multiple times before + * the destruction completes, the etherialization should be invoked only once. + * + * @param wait_for_completion if true, the method waits till the POA being + * destroyed completes all current requests and etherialization. If false, the + * method returns immediately. + */ + public void destroy(boolean etherealize_objects, boolean wait_for_completion) + { + // Notify the IOR interceptors about that the POA is destroyed. + if (m_orb.iIor != null) + m_orb.iIor.adapter_state_changed( + new ObjectReferenceTemplate[] { getReferenceTemplate() }, + NON_EXISTENT.value); + + if (wait_for_completion) + waitWhileRunning(); + + // Nofify the IOR interceptors that the POA is destroyed. + if (m_manager instanceof gnuPOAManager) + { + ((gnuPOAManager) m_manager).poaDestroyed(this); + } + + // Put the brake instead of manager, preventing the subsequent + // requests. + gnuPOAManager g = new gnuPOAManager(); + g.state = State.INACTIVE; + m_manager = g; + + // Disconnect from parent. + if (parent instanceof gnuPOA) + { + ((gnuPOA) parent).children.remove(this); + } + + unregisterFromManager(); + + // Disconnect from the ORB all objects, registered with this POA. + ArrayList keys = new ArrayList(); + keys.addAll(aom.keySet()); + + byte[] key; + AOM.Obj obj; + for (int i = 0; i < keys.size(); i++) + { + key = (byte[]) keys.get(i); + obj = aom.get(key); + if (obj.poa == this) + m_orb.disconnect(obj.object); + } + + m_orb.identityDestroyed(this); + + if (etherealize_objects && servant_activator != null && !m_inDestruction) + { + etherealizeAll(); + } + m_inDestruction = true; + + POA[] ch = the_children(); + for (int i = 0; i < ch.length; i++) + { + ch[i].destroy(etherealize_objects, wait_for_completion); + } + } + + /** + * Destroy this POA if it has not been destroyed, destroys it. + */ + protected void finalize() + throws java.lang.Throwable + { + if (!m_inDestruction) + destroy(false, false); + } + + /** + * Remove self from the manager list. + */ + private void unregisterFromManager() + { + if (m_manager instanceof gnuPOAManager) + { + gnuPOAManager p = (gnuPOAManager) m_manager; + p.removePOA(this); + } + } + + /** + * Get the policy of the given type, associated with this POA. + * + * @param a_policy_type a type of the requested policy. + * @return a policy of the given type, applyting to this POA. + * + * @throws org.omg.CORBA.BAD_PARAM if the policy of this type has not + * been specified for this POA. + */ + public Policy _get_policy(int a_policy_type) + throws org.omg.CORBA.BAD_PARAM + { + for (int i = 0; i < s_policies.length; i++) + { + if (s_policies [ i ].policy_type() == a_policy_type) + return s_policies [ i ].copy(); + } + throw new BAD_PARAM("No policy type " + a_policy_type); + } + + /** + * Get the copy of the policy array. + */ + public Policy[] getPolicyArray() + { + Policy[] r = new Policy[ s_policies.length ]; + for (int i = 0; i < s_policies.length; i++) + { + r [ i ] = s_policies [ i ].copy(); + } + return r; + } + + /** + * The POAs cannot be created by this method. + * + * @specnote this is also not possible in Suns jdk at least till 1.4. + * + * @throws NO_IMPLEMENT always. + */ + public org.omg.CORBA.Object _set_policy_override(Policy[] policies, + SetOverrideType how + ) + { + throw new NO_IMPLEMENT("Use createPOA instead."); + } + + /** + * Get the ORB, where this POA is connected. + */ + public ORB orb() + { + return m_orb; + } + + /** + * Connect the given delegate under the given key, also calling incarnate. + */ + private void create_and_connect(byte[] object_key, String repository_id, + ServantDelegateImpl delegate) + { + aom.add(delegate); + connect_to_orb(object_key, getReferenceFactory().make_object(repository_id, + object_key)); + if (servant_activator != null) + incarnate(null, object_key, delegate.servant, false); + } + + /** + * Check if the POA is not in a discarding mode. The activation + * operations are forbidded in discarding mode. + * + * @throws TRANSIENT if the POA is in discarding mode. + */ + void checkDiscarding() + throws TRANSIENT + { + if (m_manager.get_state() == State.DISCARDING) + throw new TRANSIENT("Discarding mode", 1, CompletionStatus.COMPLETED_MAYBE); + } + + /** + * Connect the given delegate object to orb. + */ + protected void connect_to_orb(byte[] an_Object_Id, org.omg.CORBA.Object object) + { + if (applies(ThreadPolicyValue.SINGLE_THREAD_MODEL)) + m_orb.connect_1_thread(object, toIORKey(an_Object_Id), this); + else + m_orb.connect(object, toIORKey(an_Object_Id)); + } + + /** + * Returns the representation of this POA tree. + */ + public String toString() + { + CPStringBuilder b = new CPStringBuilder(name); + + if (children.size() != 0) + { + b.append(" ("); + + for (int i = 0; i < children.size(); i++) + { + b.append(children.get(i)); + if (i < children.size() - 2) + b.append(", "); + } + b.append(")"); + } + return b.toString(); + } + + /** + * Check if the policy set is valid. + */ + protected boolean validatePolicies(Policy[] a) + throws InvalidPolicy + { + if (applies(ServantRetentionPolicyValue.NON_RETAIN)) + { + if (!applies(RequestProcessingPolicyValue.USE_DEFAULT_SERVANT) && + !applies(RequestProcessingPolicyValue.USE_SERVANT_MANAGER) + ) + { + short p = 0; + for (short i = 0; i < a.length; i++) + { + if (a [ i ].policy_type() == SERVANT_RETENTION_POLICY_ID.value) + p = i; + } + throw new InvalidPolicy("NON_RETAIN requires either " + + "USE_DEFAULT_SERVANT or USE_SERVANT_MANAGER", + p + ); + } + } + return true; + } + + /** + * Recursively searches for the given object in the POA tree. + */ + public AOM.Obj findObject(org.omg.CORBA.Object object) + { + AOM.Obj h = aom.findObject(object); + if (h != null) + return h; + else + { + for (int i = 0; i < children.size(); i++) + { + h = ((gnuPOA) children.get(i)).findObject(object); + if (h != null) + return h; + } + } + return h; + } + + /** + * Recursively searches for the given key in the POA tree. + * @param ior_key the key, ecapsulating both object + * and poa ids. + * @return + */ + public AOM.Obj findKey(byte[] object_id, byte[] poa_id) + { + AOM.Obj h = null; + if (Arrays.equals(poa_id, id())) + h = aom.get(object_id); + if (h != null) + return h; + else + { + for (int i = 0; i < children.size(); i++) + { + h = ((gnuPOA) children.get(i)).findKey(object_id, poa_id); + if (h != null) + return h; + } + } + return h; + } + + /** + * Parses the given key, extracts poa and object id and searches + * for such reference. + */ + public AOM.Obj findIorKey(byte[] ior_key) + { + BufferredCdrInput in = new BufferredCdrInput(ior_key); + int signature = in.read_long(); + if (signature != SIGNATURE) + return null; + + byte[] id = in.read_sequence(); + byte[] poa = in.read_sequence(); + return findKey(id, poa); + } + + /** + * Converts the object Id into the IOR key. IOR key must be + * unique in the scope of the ORB, and Ids only in the scope of POA. + * Hence the IOR key includes the POA identifiers. + */ + public byte[] toIORKey(byte[] object_id) + { + BufferedCdrOutput buffer = new BufferedCdrOutput(); + buffer.write_long(SIGNATURE); + buffer.write_sequence(object_id); + buffer.write_sequence(id()); + return buffer.buffer.toByteArray(); + } + + /** + * Extracts the object id from the ior key. + * + * @param ior_key + * + * @return the encapsulated object ior key or null if + * this ior key either refers a different POA or encoding signature + * mismatch. + */ + public byte[] idFormIor(byte[] ior_key) + { + BufferredCdrInput in = new BufferredCdrInput(ior_key); + int signature = in.read_long(); + if (signature != SIGNATURE) + return null; + + byte[] object_id = in.read_sequence(); + byte[] poa_id = in.read_sequence(); + if (Arrays.equals(poa_id, id())) + return object_id; + else + return null; + } + + /** + * Recursively searches for the given servant in the POA tree. + */ + public AOM.Obj findServant(Servant servant) + { + AOM.Obj h = aom.findServant(servant); + if (h != null) + return h; + else + { + for (int i = 0; i < children.size(); i++) + { + h = ((gnuPOA) children.get(i)).findServant(servant); + if (h != null) + return h; + } + } + return h; + } + + /** + * Get the object reference template of this POA. + * Instantiate a singleton instance, if required. + */ + public ObjectReferenceTemplate getReferenceTemplate() + { + if (refTemplate == null) + refTemplate = new RefTemplate(); + + return refTemplate; + } + + public ObjectReferenceFactory getReferenceFactory() + { + return m_object_factory; + } + + public void setReferenceFactory(ObjectReferenceFactory factory) + { + m_object_factory = factory; + } + + /** + * Create the object (needed by the factory interface). + */ + public Object make_object(String a_repository_id, byte[] an_object_id) + { + AOM.Obj existing = aom.get(an_object_id); + // The object may already exist. In this case, it is just returned. + if (existing != null && existing.object != null) + return existing.object; + else + { + return new gnuServantObject(new String[] { a_repository_id }, + an_object_id, this, m_orb); + } + } + + /** + * Required by object reference factory ops. + */ + public String[] _truncatable_ids() + { + return ref_template_ids; + } +} diff --git a/libjava/classpath/gnu/CORBA/Poa/gnuPOAManager.java b/libjava/classpath/gnu/CORBA/Poa/gnuPOAManager.java new file mode 100644 index 000000000..db43751a7 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Poa/gnuPOAManager.java @@ -0,0 +1,272 @@ +/* gnuPOAManager.java -- + 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.CORBA.Poa; + +import org.omg.CORBA.BAD_INV_ORDER; +import org.omg.CORBA.LocalObject; +import org.omg.PortableInterceptor.NON_EXISTENT; +import org.omg.PortableServer.POAManager; +import org.omg.PortableServer.POAManagerPackage.AdapterInactive; +import org.omg.PortableServer.POAManagerPackage.State; + +import java.util.HashSet; +import java.util.Iterator; + +/** + * The implementation of the POA manager. The manager is a controlled + * switch that can change its states in response to the method calls + * and throw exceptions if the requested change is invalid. It is possible + * to check the state this switch. It does not do anything else. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class gnuPOAManager + extends LocalObject + implements POAManager +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * The POAs, controlled by this manager. + */ + private HashSet POAs = new HashSet(); + + /** + * The state of the manager. The newly created manager is always + * in the holding state. + */ + State state = State.HOLDING; + + /** + * Get the state of the POA manager. + */ + public State get_state() + { + return state; + } + + /** + * Turns the associated POAs into active state, allowing them to receive + * and process requests. + * + * @throws AdapterInactive if the POAs are in the inactive state. + * If once inactivated, the POA cannot be activated again. This + * method can only be called to leave the holding or discarding state. + */ + public void activate() + throws AdapterInactive + { + if (state != State.INACTIVE) + state = State.ACTIVE; + else + throw new AdapterInactive(); + + notifyInterceptors(state.value()); + } + + /** + * Turns the associated POAs into holding state. In this state, the POAs + * queue incoming requests but do not process them. + * + * @param wait_for_completion if true, the method call suspends the current + * thread till POAs complete the requests they are currently processing. If + * false, the method returns immediately. + + * @throws AdapterInactive if the POAs are in the inactive state. + */ + public void hold_requests(boolean wait_for_completion) + throws AdapterInactive + { + if (state != State.INACTIVE) + state = State.HOLDING; + else + throw new AdapterInactive(); + + notifyInterceptors(state.value()); + + if (wait_for_completion) + waitForIdle(); + } + + /** + * + * Turns the asociated POAs into inactive state. The POAs in the incative + * state will reject new requests. If the POA is once inactivated, it + * cannot be activated again. The operation is used when + * the associated POAs are to be shut down. + * + * @param etherealize_objects if true, the servant managers of the + * associated POAs, having RETAIN and USE_SERVANT_MANAGER policies, + * will receive a call of {@link ServantActivatorOperations#etherealize}. + * + * @param wait_for_completion if true, the method call suspends the current + * thread till POAs complete the requests they are currently processing. If + * false, the method returns immediately. + * + * @throws AdapterInactive if the POAs are already in the inactive state. + * + * @see POAOperations#destroy + */ + public void deactivate(boolean etherealize_objects, + boolean wait_for_completion + ) + throws AdapterInactive + { + if (state == State.INACTIVE) + throw new AdapterInactive("Repetetive inactivation"); + state = State.INACTIVE; + + notifyInterceptors(state.value()); + + if (wait_for_completion) + waitForIdle(); + + Iterator iter = POAs.iterator(); + while (iter.hasNext()) + { + gnuPOA poa = (gnuPOA) iter.next(); + + // If the servant activator is non null, this means it has been + // set - hence the policies are appropriate. + if (poa.servant_activator != null) + poa.etherealizeAll(); + } + } + + /** + * Turns the associated POAs into discaring state. In this state, the POAs + * discard the incoming requests. This mode is used in situations when + * the server is flooded with requests. The client receives remote exception + * ({@link org.omg.CORBA.TRANSIENT}, minor code 1). + * + * @param wait_for_completion if true, the method call suspends the current + * thread till POAs complete the requests they are currently processing. If + * false, the method returns immediately. + + * @throws AdapterInactive if the POAs are in the inactive state. + */ + public void discard_requests(boolean wait_for_completion) + throws AdapterInactive + { + if (state != State.INACTIVE) + state = State.DISCARDING; + else + throw new AdapterInactive(); + + notifyInterceptors(state.value()); + + if (wait_for_completion) + waitForIdle(); + } + + /** + * Suspend the current thread while at least one of the associated POA is + * actively processing some requests. The method assumes that the POAs + * are not accepting the new requests due manager state. + * + * @throws BAD_INV_ORDER if the POAs are in the active state. + */ + public void waitForIdle() + { + if (state == State.ACTIVE) + throw new BAD_INV_ORDER("The state is active"); + + gnuPOA poa; + Iterator iter = POAs.iterator(); + + while (iter.hasNext()) + { + poa = (gnuPOA) iter.next(); + poa.waitWhileRunning(); + } + } + + /** + * Add the POA that will be controlled by this manager. + * + * @param poa the POA. + */ + public void addPoa(gnuPOA poa) + { + POAs.add(poa); + } + + /** + * Remove the POA, releasing it from the control of this manager. + * Called in POA finaliser. + * + * @param poa the POA to remove. + */ + public void removePOA(gnuPOA poa) + { + POAs.remove(poa); + } + + /** + * This method is called when POA is destryed. The interceptors are + * notified. + */ + public void poaDestroyed(gnuPOA poa) + { + notifyInterceptors(NON_EXISTENT.value); + } + + /** + * Notify CORBA 3.0 interceptors about the status change. + */ + public synchronized void notifyInterceptors(int new_state) + { + gnuPOA poa; + Iterator iter = POAs.iterator(); + + // The System.identityHashCode is also called in gnuIorInfo. + while (iter.hasNext()) + { + poa = (gnuPOA) iter.next(); + if (poa.m_orb.iIor != null) + { + poa.m_orb.iIor.adapter_manager_state_changed( + System.identityHashCode(this), (short) new_state); + } + } + } +} diff --git a/libjava/classpath/gnu/CORBA/Poa/gnuPoaCurrent.java b/libjava/classpath/gnu/CORBA/Poa/gnuPoaCurrent.java new file mode 100644 index 000000000..d489d0e83 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Poa/gnuPoaCurrent.java @@ -0,0 +1,179 @@ +/* gnuPoaCurrent.java -- + 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.CORBA.Poa; + +import org.omg.CORBA.CurrentHelper; +import org.omg.CORBA.portable.ObjectImpl; +import org.omg.PortableServer.Current; +import org.omg.PortableServer.CurrentOperations; +import org.omg.PortableServer.CurrentPackage.NoContext; +import org.omg.PortableServer.POA; + +import java.util.Iterator; +import java.util.Map; +import java.util.TreeMap; + +/** + * Supports the "Poa current" concept, providing the id and poa of + * the object currently being served. There is only one instance + * of this class per ORB. It maintains a thread to information map. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class gnuPoaCurrent + extends ObjectImpl + implements Current +{ + /** + * The table, mapping threads to records. + */ + private TreeMap threads = new TreeMap(); + + /** + * Get the array of POA current repository ids. + * + * @return a single member array, containing value, returned + * by the {@link CurrentHelper#id}, normally + * "IDL:omg.org/PortableServer/Current:2.3". + */ + public String[] _ids() + { + return new String[] { CurrentHelper.id() }; + } + + /** + * Get the object id, associated with the thread currently being served. + * + * @throws NoContext if the current thread is not associated with any + * object. + */ + public byte[] get_object_id() + throws NoContext + { + CurrentOperations r; + synchronized (threads) + { + r = (CurrentOperations) threads.get(Thread.currentThread().getName()); + } + if (r != null) + return r.get_object_id(); + else + throw new NoContext(Thread.currentThread().getName()); + } + + /** + * Get the object POA, associated with the thread currently being served. + * + * @throws NoContext if the current thread is not associated with any + * object. + */ + public POA get_POA() + throws NoContext + { + CurrentOperations r; + synchronized (threads) + { + r = (CurrentOperations) threads.get(Thread.currentThread().getName()); + } + if (r != null) + return r.get_POA(); + else + throw new NoContext(Thread.currentThread().getName()); + } + + /** + * Add the entry to the map. + */ + public void put(Thread t, CurrentOperations record) + { + synchronized (threads) + { + threads.put(t.getName(), record); + } + } + + /** + * Check if this Poa has some running threads. + */ + public boolean has(POA poa) + { + synchronized (threads) + { + Iterator iter = threads.entrySet().iterator(); + while (iter.hasNext()) + { + Map.Entry item = (Map.Entry) iter.next(); + try + { + if (((CurrentOperations) item.getValue()).get_POA() == poa) + { + return true; + } + } + catch (NoContext ex) + { + throw new InternalError(); + } + } + } + return false; + } + + /** + * Check if this thread is registered. + */ + public boolean has(Thread t) + { + synchronized (threads) + { + return threads.containsKey(t.getName()); + } + } + + /** + * Remove the entry from the map. + */ + public void remove(Thread t) + { + synchronized (threads) + { + threads.remove(t.getName()); + } + } +} diff --git a/libjava/classpath/gnu/CORBA/Poa/gnuRequestProcessingPolicy.java b/libjava/classpath/gnu/CORBA/Poa/gnuRequestProcessingPolicy.java new file mode 100644 index 000000000..4e322e5e2 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Poa/gnuRequestProcessingPolicy.java @@ -0,0 +1,80 @@ +/* gnuRequestProcessingPolicy.java -- + 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.CORBA.Poa; + +import gnu.CORBA._PolicyImplBase; + +import org.omg.PortableServer.REQUEST_PROCESSING_POLICY_ID; +import org.omg.PortableServer.RequestProcessingPolicy; +import org.omg.PortableServer.RequestProcessingPolicyValue; + +/** + * The implementation of the request processing policy. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class gnuRequestProcessingPolicy + extends _PolicyImplBase + implements RequestProcessingPolicy, AccessiblePolicy +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1L; + + /** + * Create the policy. + * + * @param v a value for the policy. + */ + public gnuRequestProcessingPolicy(RequestProcessingPolicyValue v) + { + super(REQUEST_PROCESSING_POLICY_ID.value, v, v.value(), + "IDL:org.omg/PortableServer/RequestProcessingPolicy:1.0" + ); + } + + /** + * Get the value for the policy that was passed in a constructor. + */ + public RequestProcessingPolicyValue value() + { + return (RequestProcessingPolicyValue) getValue(); + } +} diff --git a/libjava/classpath/gnu/CORBA/Poa/gnuServantObject.java b/libjava/classpath/gnu/CORBA/Poa/gnuServantObject.java new file mode 100644 index 000000000..17ef452a7 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Poa/gnuServantObject.java @@ -0,0 +1,825 @@ +/* gnuServantObject.java -- + 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.CORBA.Poa; + +import gnu.CORBA.GIOP.ReplyHeader; +import gnu.CORBA.IorDelegate; +import gnu.CORBA.IorObject; +import gnu.CORBA.Interceptor.gnuServerRequestInfo; +import gnu.CORBA.typecodes.RecordTypeCode; +import gnu.CORBA.IOR; +import gnu.CORBA.IorProvider; +import gnu.CORBA.Minor; +import gnu.CORBA.ObjectCreator; +import gnu.CORBA.Unexpected; +import gnu.CORBA.ResponseHandlerImpl; +import gnu.CORBA.StreamHolder; + +import gnu.java.lang.CPStringBuilder; + +import org.omg.CORBA.Any; +import org.omg.CORBA.BAD_OPERATION; +import org.omg.CORBA.BAD_PARAM; +import org.omg.CORBA.CompletionStatus; +import org.omg.CORBA.OBJECT_NOT_EXIST; +import org.omg.CORBA.OBJ_ADAPTER; +import org.omg.CORBA.ORB; +import org.omg.CORBA.SystemException; +import org.omg.CORBA.TCKind; +import org.omg.CORBA.TRANSIENT; +import org.omg.CORBA.UserException; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.InvokeHandler; +import org.omg.CORBA.portable.ObjectImpl; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.ResponseHandler; +import org.omg.PortableInterceptor.ForwardRequest; +import org.omg.PortableInterceptor.ServerRequestInterceptorOperations; +import org.omg.PortableServer.CurrentOperations; +import org.omg.PortableServer.DynamicImplementation; +import org.omg.PortableServer.ImplicitActivationPolicyValue; +import org.omg.PortableServer.POA; +import org.omg.PortableServer.POAManager; +import org.omg.PortableServer.POAManagerPackage.State; +import org.omg.PortableServer.Servant; +import org.omg.PortableServer.ServantLocatorPackage.CookieHolder; +import org.omg.PortableServer.ServantRetentionPolicyValue; +import org.omg.PortableServer.portable.Delegate; + +import java.io.IOException; + +import java.util.Arrays; + +/** + * Represents a CORBA object, being locally served by the associated servant. + * The calls to the object are forwarded to the calls to the servant. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class gnuServantObject extends ObjectImpl + implements org.omg.CORBA.Object, + InvokeHandler, + CurrentOperations, + IorProvider +{ + /** + * The associated servant that must also implement the {@link InvokeHandler} + * interface. This value can be temporary null if the object was created using + * POA.create_reference or POA.create_reference_with_id, private to force + * always to use {@link setServant}. + */ + private Servant servant; + + /** + * The Id of this object. + */ + public final byte[] Id; + + /** + * The poa that takes care about this object. + */ + public final gnuPOA poa; + + /** + * The POA manager, used to control the work of this object. + */ + public final POAManager manager; + + /** + * The orb. + */ + public final ORB_1_4 orb; + + /** + * The object repository ids, if they were specified separately. Normally, the + * ids are requested from the servant. + */ + public final String[] repository_ids; + + /** + * True indicates that the NO_RETAIN policy applies for the servant. + * The servant must be discarded after the each call. + */ + boolean noRetain; + + /** + * Create an object with no connected servant. The servant must be set later. + * + * @param a_repository_ids an array of repository ids, can be null (then ids + * will be requested from the servant). + * @param an_id the object id. + * @param a_poa the POA. + */ + public gnuServantObject(String[] a_repository_ids, byte[] an_id, + gnuPOA a_poa, ORB_1_4 an_orb + ) + { + repository_ids = a_repository_ids; + Id = an_id; + manager = a_poa.the_POAManager(); + poa = a_poa; + orb = an_orb; + + noRetain = poa.applies(ServantRetentionPolicyValue.NON_RETAIN); + } + + /** + * Get the IOR as it would be for this object. + */ + public IOR getIor() + { + return orb.getLocalIor(this); + } + + /** + * Create a servant object, associated with the passed servant. + * + * @param a_servant a servant, serving this object. + * @param an_id an Object Id for this object. + * + * @throws BAD_PARAM if the passed servant is not an {@link InvokeHandler}. + */ + public gnuServantObject(Servant a_servant, byte[] an_id, ORB_1_4 an_orb, + gnuPOA a_poa + ) + { + Id = an_id; + setServant(a_servant); + poa = a_poa; + if (poa != null) + { + manager = poa.the_POAManager(); + } + else + { + manager = null; + } + repository_ids = null; + orb = an_orb; + + noRetain = poa != null && poa.applies(ServantRetentionPolicyValue.NON_RETAIN); + } + + /** + * Set a servant, if it has not been previously set. + * + * @param a_servant a servant to set, can be null to indicate the necessity + * for the subsequent activation. + * + * @throws BAD_PARAM if the passed servant is not an {@link InvokeHandler} or + * {@link DynamicImplementation} and also not null. + */ + public void setServant(Servant a_servant) + { + if (a_servant != null && + !(a_servant instanceof InvokeHandler) && + !(a_servant instanceof DynamicImplementation) + ) + { + throw new BAD_PARAM("Must be either InvokeHandler or " + + "DynamicImplementation, but is " + a_servant + ); + } + servant = a_servant; + } + + /** + * Returns the associated servant. + */ + public Servant getServant() + { + return servant; + } + + /** + * Return the associated invocation handler. + */ + public InvokeHandler getHandler(String operation, CookieHolder cookie, + boolean forwarding_allowed + ) throws gnuForwardRequest + { + if (servant != null && !noRetain) + { + return servantToHandler(servant); + } + else + { + // Use servant locator to locate the servant. + if (poa.servant_locator != null) + { + try + { + servant = + poa.servant_locator.preinvoke(Id, poa, operation, cookie); + return servantToHandler(servant); + } + catch (org.omg.PortableServer.ForwardRequest forw_ex) + { + if (forwarding_allowed) + { + throw new gnuForwardRequest(forw_ex.forward_reference); + } + else + { + servant = + ForwardedServant.create(forw_ex.forward_reference); + return servantToHandler(servant); + } + } + } + else + // Use servant activator to locate the servant. + if (poa.applies(ImplicitActivationPolicyValue.IMPLICIT_ACTIVATION) && + poa.applies(ServantRetentionPolicyValue.RETAIN) + ) + { + try + { + poa.activate_object_with_id(Id, servant, forwarding_allowed); + servant = poa.id_to_servant(Id); + return servantToHandler(servant); + } + catch (gnuForwardRequest forwarded) + { + throw forwarded; + } + catch (Exception ex) + { + BAD_OPERATION bad = + new BAD_OPERATION("Unable to activate", Minor.Activation, + CompletionStatus.COMPLETED_NO + ); + bad.initCause(ex); + throw bad; + } + } + else if (poa.default_servant != null) + { + servant = poa.default_servant; + return servantToHandler(servant); + } + + // No servant and no servant manager - throw exception. + else + { + throw new BAD_OPERATION("Unable to activate", Minor.Activation, + CompletionStatus.COMPLETED_NO + ); + } + } + } + + /** + * Convert the servant to invocation handler. + */ + public InvokeHandler servantToHandler(Servant a_servant) + { + if (a_servant instanceof InvokeHandler) + { + return (InvokeHandler) a_servant; + } + else if (a_servant instanceof DynamicImplementation) + { + return new DynamicImpHandler((DynamicImplementation) a_servant); + } + else + { + throw new BAD_OPERATION(a_servant + + " must be either InvokeHandler or " + "POA DynamicImplementation" + ); + } + } + + /** + * Create a servant object, associated with the passed servant. Requests the + * object id from the servant. Depending on the policies of the servants POA, + * the calls are eithe not synchronized or synchronized on POA or ORB. + * + * @param a_servant a servant, serving this object. + * @param an_id an Object Id for this object. + */ + public gnuServantObject(Servant a_servant, gnuPOA a_poa) + { + this(a_servant, a_servant._object_id(), (ORB_1_4) a_servant._orb(), a_poa); + } + + /** + * Delegates call to servant, passing the poa and Id. + */ + public String[] _ids() + { + if (repository_ids == null) + { + return getServant()._all_interfaces(poa, Id); + } + else + { + return repository_ids; + } + } + + /** + * Gets a string representation. + */ + public String toString() + { + CPStringBuilder b = new CPStringBuilder("Servant object ("); + for (int i = 0; i < Id.length; i++) + { + b.append(Integer.toHexString(Id [ i ] & 0xFF)); + b.append(' '); + } + b.append(')'); + return b.toString(); + } + + /** + * Always returns true. + */ + public boolean _is_local() + { + return true; + } + + /** + * Check if this object could be named by the given repository id. + * + * @param idl_id the repository id to check. + * + * @return true if it is one of the possible repository ids of this object. + */ + public boolean _is_a(String idl_id) + { + String[] maybe = _ids(); + for (int i = 0; i < maybe.length; i++) + { + if (maybe [ i ].equals(idl_id)) + { + return true; + } + } + return false; + } + + /** + * Get an ORB, associated with the servant of this object. + * + * @return + */ + public ORB _orb() + { + return getServant()._orb(); + } + + /** + * Handle the invocation (delegates to servant). + * + * @throws TRANSIENT minor 0x535503e9 if the POA is in discarding mode. + * @throws OBJ_ADAPTER minor 0x535503ea if the POA is inactivated. + * @throws OBJECT_NOT_EXISTS minor 0x535503ec if this object is inactivated. + * + * @specnote see {@link POAManagerOperations} for specnotes about the minor + * codes. + */ + public OutputStream _invoke(String method, InputStream input, + ResponseHandler r_handler + ) throws SystemException + { + boolean intercept = false; + ServerRequestInterceptorOperations interceptor = null; + gnuServerRequestInfo info = null; + ResponseHandlerImpl i_handler = null; + + try + { + if (orb.iServer != null && + r_handler instanceof ResponseHandlerImpl + ) + { + interceptor = orb.iServer; + + i_handler = (ResponseHandlerImpl) r_handler; + + info = + new gnuServerRequestInfo(this, i_handler.request_header, + i_handler.reply_header + ); + intercept = true; + + interceptor.receive_request_service_contexts(info); + } + + try + { + CookieHolder cookie = null; + AOM.Obj self = poa.aom.get(Id); + + if (poa.servant_locator != null) + { + // If the servant locator is in use, it is always responsible + // for providing the servant. + self.servant = servant = null; + cookie = new CookieHolder(); + } + else if (self != null && self.isDeactiveted()) + { + if (poa.applies( + ImplicitActivationPolicyValue.IMPLICIT_ACTIVATION + ) && + poa.servant_activator != null + ) + { + // Reset the servant, forcing the subsequent activation. + servant = null; + } + else + { + throw new OBJECT_NOT_EXIST("Object deactivated", + 0x535503ec, CompletionStatus.COMPLETED_NO + ); + } + } + + InvokeHandler handler = getHandler(method, cookie, true); + + Delegate d = null; + + try + { + d = servant._get_delegate(); + orb.currents.put(Thread.currentThread(), this); + } + catch (Exception ex) + { + // In some cases exception is thrown if the delegate is not set. + } + if (d instanceof ServantDelegateImpl) + { + // If the delegate is already set, check maybe we can + // reuse the existing instance. + if (((ServantDelegateImpl) d).object != this) + { + servant._set_delegate(new ServantDelegateImpl(servant, poa, Id)); + } + } + else + { + servant._set_delegate(new ServantDelegateImpl(servant, poa, Id)); + } + + try + { + switch (manager.get_state().value()) + { + case State._ACTIVE : + + OutputStream rt; + try + { + if (intercept) + { + interceptor.receive_request(info); + } + + rt = handler._invoke(method, input, r_handler); + + if (intercept) + { + // Handler is casted into i_handler. + if (i_handler.isExceptionReply()) + { + info.m_reply_header.reply_status = + ReplyHeader.USER_EXCEPTION; + + // Make Any, holding the user exception. + Any a = orb.create_any(); + OutputStream buf = i_handler.getBuffer(); + InputStream in = buf.create_input_stream(); + String uex_idl = "unknown"; + try + { + in.mark(Integer.MAX_VALUE); + uex_idl = in.read_string(); + in.reset(); + } + catch (IOException e) + { + throw new Unexpected(e); + } + + try + { + UserException exception = + ObjectCreator.readUserException(uex_idl, + in + ); + + ObjectCreator.insertWithHelper(a, + exception + ); + } + catch (Exception e) + { + // Failed due any reason, insert without + // helper. + a.insert_Streamable(new StreamHolder( + buf.create_input_stream() + ) + ); + + RecordTypeCode r = + new RecordTypeCode(TCKind.tk_except); + r.setId(uex_idl); + r.setName(ObjectCreator.getDefaultName( + uex_idl + ) + ); + } + + info.m_usr_exception = a; + interceptor.send_exception(info); + } + else + { + info.m_reply_header.reply_status = + ReplyHeader.NO_EXCEPTION; + interceptor.send_reply(info); + } + } + } + catch (SystemException sys_ex) + { + if (intercept) + { + info.m_reply_header.reply_status = + ReplyHeader.SYSTEM_EXCEPTION; + info.m_sys_exception = sys_ex; + interceptor.send_exception(info); + } + throw sys_ex; + } + + return rt; + + case State._HOLDING : + + // The holding mode is implemented + // relying on the holding capabilites of the network + // support (if any). + // TODO FIXME in more recent CORBA applications, the + // client + // ORB can free the connection and wait for a server side + // notification about the completed request. Implement + // this + // as soon as JDK specification would allow bidirectional + // policy. + int sleep = 5; + int max = 500; + + // Wait till the state will be switched into some other + // mode. + while (manager.get_state().value() == State._HOLDING) + { + try + { + Thread.sleep(sleep); + if (sleep < max) + { + sleep = max; + } + } + catch (InterruptedException ex) + { + } + } + + // Handle another mode. + return _invoke(method, input, r_handler); + + case State._DISCARDING : + throw new TRANSIENT("Discarding mode", 0x535503e9, + CompletionStatus.COMPLETED_NO + ); + + case State._INACTIVE : + throw new OBJ_ADAPTER("POA deactivated", 0x535503ea, + CompletionStatus.COMPLETED_NO + ); + + default : + throw new InternalError(); // No more states. + } + } + finally + { + if (poa.servant_locator != null) + { + poa.servant_locator.postinvoke(Id, poa, method, + cookie.value, servant + ); + } + } + } + finally + { + orb.currents.remove(Thread.currentThread()); + if (noRetain) + servant = null; + } + } + catch (ForwardRequest fex) + { + // May be thrown by interceptor. + if (intercept) + { + Forwarding: + while (true) + { + info.m_reply_header.reply_status = + ReplyHeader.LOCATION_FORWARD; + info.m_forward_reference = fex.forward; + try + { + interceptor.send_other(info); + break Forwarding; + } + catch (ForwardRequest fex2) + { + info.m_forward_reference = fex2.forward; + fex.forward = info.m_forward_reference; + } + } + } + throw new gnuForwardRequest(fex.forward); + } + catch (gnuForwardRequest fex) + { + // May be thrown during activation. + if (intercept) + { + Forwarding: + while (true) + { + info.m_reply_header.reply_status = + ReplyHeader.LOCATION_FORWARD; + info.m_forward_reference = fex.forward_reference; + try + { + interceptor.send_other(info); + break Forwarding; + } + catch (ForwardRequest fex2) + { + info.m_forward_reference = fex2.forward; + fex.forward_reference = (ObjectImpl) fex2.forward; + } + } + } + throw fex; + } + } + + /** + * Compare with another object for equality, comparing the object keys. + */ + public boolean equals(java.lang.Object other) + { + if (other instanceof gnuServantObject) + { + gnuServantObject o = (gnuServantObject) other; + + return Arrays.equals(o.Id, Id); + } + else + { + return false; + } + } + + /** + * Get the hash code, based on the object key. + */ + public int hashCode() + { + long s = 0; + int v = 1; + for (int i = 0; i < Id.length; i++) + { + s += Id [ i ] * v; + if (s > Integer.MAX_VALUE) + { + s = s % Integer.MAX_VALUE; + v = 1; + } + v = v * 8; + } + return (int) (s % Integer.MAX_VALUE); + } + + /** + * Get the object id. + */ + public byte[] get_object_id() + { + return Id; + } + + /** + * Get POA. + */ + public POA get_POA() + { + return poa; + } + + /** + * Returns without action. + */ + public void _release() + { + } + + /** + * Returns without action. + */ + public void _releaseReply(InputStream stream) + { + } + + /** + * Checks if this object is equivalent to another instance. These objects are + * assumed equal if they are connected to the same orb and poa under the same + * Id, regardless of they delegates. + * + * @param other instance to check. + * @return + */ + public boolean _is_equivalent(org.omg.CORBA.Object other) + { + if (other instanceof gnuServantObject) + { + gnuServantObject g = (gnuServantObject) other; + return orb == g.orb && poa == g.poa && Arrays.equals(Id, g.Id); + } + else if (other instanceof IorObject) + { + IorObject ir = ((IorObject) other); + try + { + IorDelegate ird = (IorDelegate) ir._get_delegate(); + byte[] ior_id = poa.idFormIor(ird.getIor().key); + if (ior_id != null && Arrays.equals(ior_id, Id)) + { + return true; + } + else + { + return false; + } + } + catch (Exception ex) + { + // Non - typical delegate or very specific subclass of + // IOR_constructed_object. + return super._is_equivalent(other); + } + } + return super._is_equivalent(other); + } +} diff --git a/libjava/classpath/gnu/CORBA/Poa/gnuServantRetentionPolicy.java b/libjava/classpath/gnu/CORBA/Poa/gnuServantRetentionPolicy.java new file mode 100644 index 000000000..95958d299 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Poa/gnuServantRetentionPolicy.java @@ -0,0 +1,80 @@ +/* gnuServantRetentionPolicy.java -- + 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.CORBA.Poa; + +import gnu.CORBA._PolicyImplBase; + +import org.omg.PortableServer.SERVANT_RETENTION_POLICY_ID; +import org.omg.PortableServer.ServantRetentionPolicy; +import org.omg.PortableServer.ServantRetentionPolicyValue; + +/** + * The implementation of the servant retention policy. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class gnuServantRetentionPolicy + extends _PolicyImplBase + implements ServantRetentionPolicy, AccessiblePolicy +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1L; + + /** + * Create the policy. + * + * @param v a value for the policy. + */ + public gnuServantRetentionPolicy(ServantRetentionPolicyValue v) + { + super(SERVANT_RETENTION_POLICY_ID.value, v, v.value(), + "IDL:org.omg/PortableServer/ServantRetentionPolicy:1.0" + ); + } + + /** + * Get the value for the policy that was passed in a constructor. + */ + public ServantRetentionPolicyValue value() + { + return (ServantRetentionPolicyValue) getValue(); + } +} diff --git a/libjava/classpath/gnu/CORBA/Poa/gnuThreadPolicy.java b/libjava/classpath/gnu/CORBA/Poa/gnuThreadPolicy.java new file mode 100644 index 000000000..e7dac0f6a --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Poa/gnuThreadPolicy.java @@ -0,0 +1,80 @@ +/* gnuThreadPolicy.java -- + 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.CORBA.Poa; + +import gnu.CORBA._PolicyImplBase; + +import org.omg.PortableServer.THREAD_POLICY_ID; +import org.omg.PortableServer.ThreadPolicy; +import org.omg.PortableServer.ThreadPolicyValue; + +/** + * The implementation of the thread policy. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class gnuThreadPolicy + extends _PolicyImplBase + implements ThreadPolicy, AccessiblePolicy +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1L; + + /** + * Create the policy. + * + * @param v a value for the policy. + */ + public gnuThreadPolicy(ThreadPolicyValue v) + { + super(THREAD_POLICY_ID.value, v, v.value(), + "IDL:org.omg/PortableServer/ThreadPolicy:1.0" + ); + } + + /** + * Get the value for the policy that was passed in a constructor. + */ + public ThreadPolicyValue value() + { + return (ThreadPolicyValue) getValue(); + } +} diff --git a/libjava/classpath/gnu/CORBA/RawReply.java b/libjava/classpath/gnu/CORBA/RawReply.java new file mode 100644 index 000000000..a36f4b4b2 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/RawReply.java @@ -0,0 +1,95 @@ +/* RawReply.java -- + 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.CORBA; + +import gnu.CORBA.CDR.BufferredCdrInput; +import gnu.CORBA.GIOP.MessageHeader; + +import org.omg.CORBA.ORB; + +/** + * The remote object reply in the binary form, holding + * the message header and the following binary data. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +class RawReply +{ + /** + * The message header. + */ + final MessageHeader header; + + /** + * The associated orb. + */ + final ORB orb; + + /** + * The message data. + */ + final byte[] data; + + /** + * Create the binary reply. + * + * @param an_header the message header + * @param a_data the message data. + */ + RawReply(ORB an_orb, MessageHeader an_header, byte[] a_data) + { + orb = an_orb; + header = an_header; + data = a_data; + } + + /** + * Get the CDR input stream with the correctly set alignment. + * + * @return the CDR stream to read the message data. + */ + BufferredCdrInput getStream() + { + BufferredCdrInput in = new BufferredCdrInput(data); + in.setOffset(header.getHeaderSize()); + in.setVersion(header.version); + in.setOrb(orb); + in.setBigEndian(header.isBigEndian()); + return in; + } +} diff --git a/libjava/classpath/gnu/CORBA/ResponseHandlerImpl.java b/libjava/classpath/gnu/CORBA/ResponseHandlerImpl.java new file mode 100644 index 000000000..4d509cc52 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/ResponseHandlerImpl.java @@ -0,0 +1,189 @@ +/* ResponseHandlerImpl.java -- + 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.CORBA; + +import gnu.CORBA.CDR.BufferedCdrOutput; +import gnu.CORBA.GIOP.MessageHeader; +import gnu.CORBA.GIOP.ReplyHeader; +import gnu.CORBA.GIOP.RequestHeader; +import gnu.CORBA.GIOP.CodeSetServiceContext; + +import org.omg.CORBA.ORB; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.ResponseHandler; + +/** + * Provides the CDR output streams for writing the response to the given buffer. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class ResponseHandlerImpl + implements ResponseHandler +{ + /** + * The message header. This field is used to compute the size and alignments. + * It is, however, never directly written to the buffer stream. + */ + public final MessageHeader message_header; + + /** + * The associated orb. + */ + public final ORB orb; + + /** + * The reply header. + */ + public final ReplyHeader reply_header; + + /** + * The request header. + */ + public final RequestHeader request_header; + + /** + * True if the stream was obtained by invoking {@link #createExceptionReply()}, + * false otherwise. + */ + private boolean exceptionReply; + + /** + * The buffer to write into. + */ + private BufferedCdrOutput buffer; + + /** + * Create a new buffered response handler that uses the given message headers. + * The headers are used to compute sizes and check the versions. They are not + * written into a stream inside this class. + * + * @param m_header a message header. + * @param r_header a reply header. + */ + ResponseHandlerImpl(ORB an_orb, MessageHeader m_header, + ReplyHeader r_header, RequestHeader rq_header) + { + message_header = m_header; + reply_header = r_header; + request_header = rq_header; + orb = an_orb; + prepareStream(); + } + + /** + * Get an output stream for providing details about the exception. Before + * returning the stream, the handler automatically writes the message header + * and the reply about exception header, but not the message header. + * + * @return the stream to write exception details into. + */ + public OutputStream createExceptionReply() + { + exceptionReply = true; + prepareStream(); + return buffer; + } + + /** + * Get an output stream for writing a regular reply (not an exception). + * + * Before returning the stream, the handler automatically writes the regular + * reply header, but not the message header. + * + * @return the output stream for writing a regular reply. + */ + public OutputStream createReply() + { + exceptionReply = false; + prepareStream(); + reply_header.reply_status = ReplyHeader.NO_EXCEPTION; + return buffer; + } + + /** + * Get the buffer, normally containing the written reply. The reply includes + * the reply header (or the exception header) but does not include the message + * header. + * + * The stream buffer can also be empty if no data have been written into + * streams, returned by {@link #createReply()} or + * {@link #createExceptionReply()}. + * + * @return the CDR output stream, containing the written output. + */ + public BufferedCdrOutput getBuffer() + { + return buffer; + } + + /** + * True if the stream was obtained by invoking {@link #createExceptionReply()}, + * false otherwise (usually no-exception reply). + */ + public boolean isExceptionReply() + { + return exceptionReply; + } + + /** + * Compute the header offset, set the correct version number and codeset. + */ + private void prepareStream() + { + buffer = new BufferedCdrOutput(); + buffer.setOrb(orb); + buffer.setVersion(message_header.version); + buffer.setCodeSet(CodeSetServiceContext.find(reply_header.service_context)); + + // Since 1.2, the data section is always aligned on the 8 byte boundary. + // In older versions, it is necessary to set the offset correctly. + if (message_header.version.until_inclusive(1, 1)) + { + buffer.setOffset(message_header.getHeaderSize()); + + // Get the position after the reply header would be written. + reply_header.write(buffer); + + int new_offset = message_header.getHeaderSize() + buffer.buffer.size(); + + buffer.buffer.reset(); + buffer.setOffset(new_offset); + } + } +} diff --git a/libjava/classpath/gnu/CORBA/SafeForDirectCalls.java b/libjava/classpath/gnu/CORBA/SafeForDirectCalls.java new file mode 100644 index 000000000..f3efb6677 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/SafeForDirectCalls.java @@ -0,0 +1,50 @@ +/* SafeForDirectCalls.java -- FIXME: briefly describe file purpose + 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.CORBA; + +/** + * This interface marks that the object does not modify the passed read only + * parameters and hence, if it is local, it is safe to call the methods + * directly, without cloning such parameters. Otherwise such parameters should + * be cloned. + */ +public interface SafeForDirectCalls +{ + +} diff --git a/libjava/classpath/gnu/CORBA/ServiceDetailHolder.java b/libjava/classpath/gnu/CORBA/ServiceDetailHolder.java new file mode 100644 index 000000000..e8786374a --- /dev/null +++ b/libjava/classpath/gnu/CORBA/ServiceDetailHolder.java @@ -0,0 +1,91 @@ +/* ServiceDetailHolder.java -- + 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.CORBA; + +import org.omg.CORBA.ServiceDetail; +import org.omg.CORBA.ServiceDetailHelper; + + +/** + * The service detail holder. This class is not included in the original + * API specification, so we place it outside the org.omg namespace. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class ServiceDetailHolder + implements org.omg.CORBA.portable.Streamable +{ + /** + * The stored value. + */ + public ServiceDetail value; + + /** + * Create the initialised instance. + * @param initialValue + */ + public ServiceDetailHolder(ServiceDetail initialValue) + { + value = initialValue; + } + + /** + * Read from the CDR stream. + */ + public void _read(org.omg.CORBA.portable.InputStream in) + { + value = ServiceDetailHelper.read(in); + } + + /** + * Get the typecode. + */ + public org.omg.CORBA.TypeCode _type() + { + return ServiceDetailHelper.type(); + } + + /** + * Write into the CDR stream. + */ + public void _write(org.omg.CORBA.portable.OutputStream out) + { + ServiceDetailHelper.write(out, value); + } +} diff --git a/libjava/classpath/gnu/CORBA/ServiceRequestAdapter.java b/libjava/classpath/gnu/CORBA/ServiceRequestAdapter.java new file mode 100644 index 000000000..0c21f6f45 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/ServiceRequestAdapter.java @@ -0,0 +1,167 @@ +/* ServiceRequestConverter.java -- + 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.CORBA; + +import gnu.CORBA.CDR.BufferedCdrOutput; + +import org.omg.CORBA.ARG_IN; +import org.omg.CORBA.ARG_OUT; +import org.omg.CORBA.Any; +import org.omg.CORBA.Bounds; +import org.omg.CORBA.ServerRequest; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.InvokeHandler; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.ResponseHandler; +import org.omg.CORBA.portable.Streamable; + +/** + * This class supports invocation using ServerRequest. When possible, + * it is better to use the {@link ObjectImpl#_invoke} rather than + * working via ServerRequest. However since 1.4 the ServerRequest is + * involved into POA machinery making this type of call is sometimes + * inavoidable. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class ServiceRequestAdapter + implements ResponseHandler +{ + /** + * A buffer for writing the response. + */ + BufferedCdrOutput reply = new BufferedCdrOutput(); + + /** + * If set to true, an exception has been thrown during the invocation. + */ + boolean isException; + + public OutputStream createExceptionReply() + { + isException = true; + return reply; + } + + public OutputStream createReply() + { + isException = false; + return reply; + } + + /** + * Make an invocation. + * + * @param request a server request, containg the invocation information. + * @param target the invocation target + * @param result the result holder with the set suitable streamable. + * Using this parameter only increase the performance. It can be + * null if the return type is void or unknown. + */ + public static void invoke(ServerRequest request, InvokeHandler target, + Streamable result + ) + { + try + { + int IN = ARG_IN.value; + int OUT = ARG_OUT.value; + + // Write all arguments to the buffer output stream. + BufferedCdrOutput buffer = new BufferedCdrOutput(); + gnuNVList args = new gnuNVList(); + request.arguments(args); + + for (int i = 0; i < args.count(); i++) + { + if ((args.item(i).flags() & IN) != 0) + { + args.item(i).value().write_value(buffer); + } + } + + ServiceRequestAdapter h = new ServiceRequestAdapter(); + + target._invoke(request.operation(), buffer.create_input_stream(), h); + + InputStream in = h.reply.create_input_stream(); + + if (h.isException) + { + // Write the exception information + gnuAny exc = new gnuAny(); + GeneralHolder uku = new GeneralHolder(h.reply); + exc.insert_Streamable(uku); + request.set_exception(exc); + } + else + { + if (result != null) + { + // Use the holder for the return value, if provided. + result._read(in); + + gnuAny r = new gnuAny(); + r.insert_Streamable(result); + request.set_result(r); + } + else + { + // Use the universal holder otherwise. + gnuAny r = new gnuAny(); + r.insert_Streamable(new StreamHolder(in)); + } + + // Unpack the arguments + for (int i = 0; i < args.count(); i++) + { + if ((args.item(i).flags() & OUT) != 0) + { + Any a = args.item(i).value(); + a.read_value(in, a.type()); + } + } + } + } + catch (Bounds ex) + { + throw new InternalError(); + } + } +} diff --git a/libjava/classpath/gnu/CORBA/SetOverrideTypeHolder.java b/libjava/classpath/gnu/CORBA/SetOverrideTypeHolder.java new file mode 100644 index 000000000..478ec3f70 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/SetOverrideTypeHolder.java @@ -0,0 +1,90 @@ +/* SetOverrideTypeHolder.java -- + 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.CORBA; + +import org.omg.CORBA.SetOverrideType; +import org.omg.CORBA.SetOverrideTypeHelper; + +/** + * The holder for SetOverrideType. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class SetOverrideTypeHolder + implements org.omg.CORBA.portable.Streamable +{ + /** + * The stored SetOverrideType value. + */ + public SetOverrideType value; + + /** + * Create the initialised instance. + * + * @param initialValue the initial value. + */ + public SetOverrideTypeHolder(SetOverrideType initialValue) + { + value = initialValue; + } + + /** + * Fill in the {@link value} by data from the CDR stream. + */ + public void _read(org.omg.CORBA.portable.InputStream in) + { + value = SetOverrideTypeHelper.read(in); + } + + /** + * Get the typecode of the SetOverrideType. + */ + public org.omg.CORBA.TypeCode _type() + { + return SetOverrideTypeHelper.type(); + } + + /** + * Write the stored value into the CDR stream. + */ + public void _write(org.omg.CORBA.portable.OutputStream out) + { + SetOverrideTypeHelper.write(out, value); + } +} diff --git a/libjava/classpath/gnu/CORBA/SimpleDelegate.java b/libjava/classpath/gnu/CORBA/SimpleDelegate.java new file mode 100644 index 000000000..d1c6ab407 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/SimpleDelegate.java @@ -0,0 +1,318 @@ +/* Local_delegate.java -- + 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.CORBA; + +import org.omg.CORBA.Context; +import org.omg.CORBA.ContextList; +import org.omg.CORBA.ExceptionList; +import org.omg.CORBA.NO_IMPLEMENT; +import org.omg.CORBA.NVList; +import org.omg.CORBA.NamedValue; +import org.omg.CORBA.ORB; +import org.omg.CORBA.Request; +import org.omg.CORBA.portable.Delegate; +import org.omg.CORBA.portable.ObjectImpl; + +/** + * The delegate, implementing the basic functionality only. This delegate + * is set in {@link ORG.connect(org.omg.CORBA.Object)} if ORB + * determines that the object is an instance of the + * {@link org.omg.CORBA.portable.ObjectImpl} and no other delegate is set. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class SimpleDelegate + extends Delegate + implements IorProvider +{ + /** + * The orb. + */ + protected final ORB orb; + + /** + * The ior. + */ + protected IOR ior; + + public SimpleDelegate(ORB an_orb, IOR an_ior) + { + orb = an_orb; + ior = an_ior; + } + + /** + * Set the IOR of this object. The IOR must be newly set if + * the server reports that the object has permanently moved to a new + * location. + * + * @param an_ior the new IOR. + */ + public void setIor(IOR an_ior) + { + this.ior = an_ior; + } + + /** + * Get the IOR of this object. + */ + public IOR getIor() + { + return ior; + } + + /** + * Create the request for the local call + */ + public Request create_request(org.omg.CORBA.Object target, Context context, + String operation, NVList parameters, + NamedValue returns + ) + { + if (orb instanceof OrbFunctional) + { + ((OrbFunctional) orb).ensureRunning(); + } + gnuRequest g = new gnuRequest(); + g.setORB(orb); + g.setOperation(operation); + g.setIor(ior); + g.m_target = target; + g.ctx(context); + g.set_args(parameters); + if (returns != null) + g.set_result(returns); + return g; + } + + /** + * Create the request for the local call. + */ + public Request create_request(org.omg.CORBA.Object target, Context context, + String operation, NVList parameters, + NamedValue returns, ExceptionList exceptions, + ContextList ctx_list + ) + { + if (orb instanceof OrbFunctional) + { + ((OrbFunctional) orb).ensureRunning(); + } + gnuRequest g = new gnuRequest(); + g.setORB(orb); + g.setOperation(operation); + g.setIor(ior); + g.m_target = target; + g.ctx(context); + g.set_args(parameters); + g.set_exceptions(exceptions); + g.set_context_list(ctx_list); + if (returns != null) + g.set_result(returns); + return g; + } + + /** + * Not implemented. + * + * @throws NO_IMPLEMENT, always. + */ + public org.omg.CORBA.Object duplicate(org.omg.CORBA.Object target) + { + throw new NO_IMPLEMENT(); + } + + /** + * Performs direct comparison ('=='). + */ + public boolean equals(org.omg.CORBA.Object self, org.omg.CORBA.Object other) + { + return self == other; + } + + /** + * Not implemented. + * + * @throws NO_IMPLEMENT, always. + */ + public org.omg.CORBA.Object get_interface_def(org.omg.CORBA.Object target) + { + throw new NO_IMPLEMENT(); + } + + /** + * Return the hashcode (0 <= hashcode < maximum). + */ + public int hash(org.omg.CORBA.Object target, int maximum) + { + return target == null ? 0 : target.hashCode() % maximum; + } + + /** + * Delegates functionality to java.lang.Object.hashCode(); + */ + public int hashCode(org.omg.CORBA.Object target) + { + return target == null ? 0 : target.hashCode(); + } + + /** + * Check if this object can be referenced by the given repository id. + * + * @param target the CORBA object, must be an instance of + * {@link org.omg.CORBA.portable.ObjectImpl}. + * + * @param repositoryIdentifer the repository id. + * + * @return true if the passed parameter is a repository id of this + * CORBA object. + */ + public boolean is_a(org.omg.CORBA.Object target, String repositoryIdentifer) + { + if (!(target instanceof ObjectImpl)) + throw new NO_IMPLEMENT("Supported only for org.omg.CORBA.portable.ObjectImpl"); + + ObjectImpl imp = (ObjectImpl) target; + String[] ids = imp._ids(); + + for (int i = 0; i < ids.length; i++) + { + if (ids [ i ].equals(repositoryIdentifer)) + return true; + } + return false; + } + + /** + * Returns true if the objects are the same or have the same delegate set. All + * objects in this implementation have a separate delegate. + */ + public boolean is_equivalent(org.omg.CORBA.Object target, + org.omg.CORBA.Object other) + { + if (target == other) + return true; + if ((target instanceof ObjectImpl) && other instanceof ObjectImpl) + { + try + { + org.omg.CORBA.portable.Delegate a = ((ObjectImpl) target)._get_delegate(); + org.omg.CORBA.portable.Delegate b = ((ObjectImpl) other)._get_delegate(); + if (a == b) + { + return true; + } + else + { + // We compere the IOR's in this case. + if (a instanceof IorProvider && b instanceof IorProvider) + { + IOR ia = ((IorProvider) a).getIor(); + IOR ib = ((IorProvider) b).getIor(); + + if (ia != null && ib != null) + return (ia.equals(ib)); + else + return ia == ib; + } + } + if (a != null && b != null) + { + return a.equals(b); + } + } + catch (Exception ex) + { + // Unable to get one of the delegates. + return false; + } + } + return false; + } + + /** + * Returns true by default. + */ + public boolean is_local(org.omg.CORBA.Object self) + { + return true; + } + + /** + * Returns true if the target is null. + */ + public boolean non_existent(org.omg.CORBA.Object target) + { + return target == null; + } + + /** + * Returns the ORB, passed in constructor, + * regardless of the argument. This class requires a single instance + * per each object. + */ + public ORB orb(org.omg.CORBA.Object target) + { + return orb; + } + + /** + * Returns without action. + */ + public void release(org.omg.CORBA.Object target) + { + } + + /** + * This method assumes that the target is local and connected to the ORB. + */ + public Request request(org.omg.CORBA.Object target, String operation) + { + if (orb instanceof OrbFunctional) + { + ((OrbFunctional) orb).ensureRunning(); + } + gnuRequest g = new gnuRequest(); + g.setORB(orb); + g.setOperation(operation); + g.setIor(ior); + g.m_target = target; + return g; + } +} diff --git a/libjava/classpath/gnu/CORBA/SocketRepository.java b/libjava/classpath/gnu/CORBA/SocketRepository.java new file mode 100644 index 000000000..71e073adb --- /dev/null +++ b/libjava/classpath/gnu/CORBA/SocketRepository.java @@ -0,0 +1,148 @@ +/* SocketRepository.java -- + 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.CORBA; + +import java.net.Socket; +import java.net.SocketException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * This class caches the opened sockets that are reused during the + * frequent calls. Otherwise, some CORBA applications may spend + * up to 90 % of the working time just for closing and opening the sockets. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class SocketRepository +{ + /** + * The socket map. + */ + private static HashMap sockets = new HashMap(); + + /** + * Put a socket. This method also discards all not reusable sockets from + * the map. + * + * @param key as socket key. + * + * @param s a socket. + */ + public static void put_socket(Object key, Socket s) + { + synchronized (sockets) + { + sockets.put(key, s); + gc(); + } + } + + /** + * Removes all non reusable sockets. As it is private, + * we know we call from the synchronized code already. + */ + private static void gc() + { + Iterator iter = sockets.entrySet().iterator(); + + Map.Entry e; + Socket sx; + + while (iter.hasNext()) + { + e = (Map.Entry) iter.next(); + sx = (Socket) e.getValue(); + + if (not_reusable(sx)) + iter.remove(); + } + } + + /** + * Return true if the socket is no longer reusable. + */ + static boolean not_reusable(Socket s) + { + return (s.isClosed() || !s.isBound() || !s.isConnected() || + s.isInputShutdown() || s.isOutputShutdown()); + } + + /** + * Get a socket. + * + * @param key a socket key. + * + * @return an opened socket for reuse, null if no such available or it is + * closed, its input or output has been shutown or otherwise the socket is not + * reuseable. + */ + public static Socket get_socket(Object key) + { + synchronized (sockets) + { + Socket s = (Socket) sockets.get(key); + if (s == null) + return null; + + // Ensure that the socket is fully reusable. + else if (not_reusable(s)) + { + sockets.remove(key); + return null; + } + else + { + try + { + // Set one minute time out that will be changed later. + s.setSoTimeout(60 * 1000); + } + catch (SocketException e) + { + s = null; + } + + sockets.remove(key); + return s; + } + } + } +} diff --git a/libjava/classpath/gnu/CORBA/StreamBasedRequest.java b/libjava/classpath/gnu/CORBA/StreamBasedRequest.java new file mode 100644 index 000000000..66796d653 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/StreamBasedRequest.java @@ -0,0 +1,60 @@ +/* gnuStreamRequest.java -- + 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.CORBA; + +import gnu.CORBA.CDR.BufferedCdrOutput; + +/** + * A stream, additionally holding the gnu request. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class StreamBasedRequest + extends BufferedCdrOutput +{ + /** + * The enclosed request. + */ + public gnuRequest request; + + /** + * True if the response is expected. + */ + public boolean response_expected = true; +} diff --git a/libjava/classpath/gnu/CORBA/StreamHolder.java b/libjava/classpath/gnu/CORBA/StreamHolder.java new file mode 100644 index 000000000..992b4af21 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/StreamHolder.java @@ -0,0 +1,123 @@ +/* StreamHolder.java -- + 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.CORBA; + +import org.omg.CORBA.MARSHAL; +import org.omg.CORBA.NO_IMPLEMENT; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.Streamable; + +import java.io.IOException; + +/** + * A holder that stores the input stream, from that the holder data + * can be read. There is no way to write the data into this holder. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class StreamHolder + implements Streamable +{ + /** + * The stream, holding the data for this holder. + */ + protected final InputStream stream; + + /** + * Create a holder that will read from the given stream. + * + * @param a_stream a stream. + */ + public StreamHolder(InputStream a_stream) + { + stream = a_stream; + } + + /** + * This method is not in use, should never be called. + */ + public TypeCode _type() + { + throw new NO_IMPLEMENT(); + } + + /** + * Writes the data from the stored stream into the provided + * output stream till the end of the input stream is reached. + * + * @throws MARSHAL if the IOException is thrown during operation. + */ + public void _write(OutputStream output) + { + try + { + int d = stream.read(); + + while (d >= 0) + { + output.write(d); + d = stream.read(); + } + } + catch (IOException ex) + { + MARSHAL m = new MARSHAL(); + m.initCause(ex); + m.minor = Minor.CDR; + throw m; + } + } + + /** + * This method is not in use, should never be called. + */ + public void _read(InputStream input) + { + throw new NO_IMPLEMENT(); + } + + /** + * Get the input stream that has been passed in constructor. + */ + InputStream getInputStream() + { + return stream; + } +} diff --git a/libjava/classpath/gnu/CORBA/StubLocator.java b/libjava/classpath/gnu/CORBA/StubLocator.java new file mode 100644 index 000000000..d9e5ee471 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/StubLocator.java @@ -0,0 +1,110 @@ +/* StubLocator.java -- + 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.CORBA; + +import org.omg.CORBA.ORB; +import org.omg.CORBA.portable.ObjectImpl; + +/** + * Finds a stub class like "_HelloStub" that can be instantiated + * from IOR reference. The returned object can be casted to the + * used type like "Hello" without using the helper .narrow method, + * and the object is not unnsecessarily re - instantiated if + * the .narrow method is used anyway. If no stub, matching the naming + * conventions, is available, the returned stub replacement can still be used + * to get the valid request, add parameter and invoke the method by name. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class StubLocator +{ + /** + * Search for the possibly available default stub. + * + * @param orb the current ORB. It is not required to find the binding + * classes, but is needed to instantiate the default implementation + * if no binding classes are found. + * + * @param ior the IOR, possibly containing the information about the + * correct implementation class. + */ + public static ObjectImpl search(ORB orb, IOR ior) + { + try + { + int a = ior.Id.indexOf(':'); + int b = ior.Id.lastIndexOf(':'); + + String s = ior.Id.substring(a + 1, b).replace('/', '.'); + + String path; + + b = s.lastIndexOf('.'); + if (b > 0) + path = s.substring(0, b + 1); + else + path = ""; + + String stub = "_" + s.substring(b + 1) + "Stub"; + + Class stubClass = ObjectCreator.forName(path + stub); + + return (ObjectImpl) stubClass.newInstance(); + } + catch (Exception failed) + { + // Various exceptions can be thrown if the Id cannot be parsed, + // the class is missing, cannot be instantiated or is not an + // instance of the ObjectImpl. + return createDefaultStub(orb, ior); + } + } + + /** + * Return the default stub for the case when the client binding classes + * are not locally available. The returned stub can still be used + * to get the valid request, add parameter and invoke the method by name. + * + * @return the default implementation. + */ + protected static ObjectImpl createDefaultStub(ORB orb, IOR ior) + { + return new IorObject(orb, ior); + } +} diff --git a/libjava/classpath/gnu/CORBA/TypeCodeHelper.java b/libjava/classpath/gnu/CORBA/TypeCodeHelper.java new file mode 100644 index 000000000..46831e8d2 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/TypeCodeHelper.java @@ -0,0 +1,304 @@ +/* TypeCodeHelper.java -- + 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.CORBA; + +import gnu.CORBA.typecodes.FixedTypeCode; +import gnu.CORBA.typecodes.GeneralTypeCode; +import gnu.CORBA.typecodes.ArrayTypeCode; +import gnu.CORBA.typecodes.PrimitiveTypeCode; +import gnu.CORBA.typecodes.RecordTypeCode; +import gnu.CORBA.typecodes.StringTypeCode; + +import org.omg.CORBA.TCKind; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.TypeCodePackage.BadKind; +import org.omg.CORBA.TypeCodePackage.Bounds; + +/** + * Reads and writes the TypeCodes usind common data representation. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class TypeCodeHelper +{ + /** + * Read the CORBA {@link TypeCode}. First, the TypeCode kind + * is read as four byte long. Then, if needed, the additional + * parameters are loaded following CORBA specification. + * + * @param in a stream to read from. + */ + public static TypeCode read(org.omg.CORBA.portable.InputStream in) + throws BadKind, Bounds + { + TCKind kind = TCKind.from_int(in.read_long()); + TypeCode rt; + GeneralTypeCode g; + RecordTypeCode r; + RecordTypeCode.Field f; + StringTypeCode s; + int n; + + switch (kind.value()) + { + case TCKind._tk_sequence : + case TCKind._tk_array : + + ArrayTypeCode p = new ArrayTypeCode(kind); + p.setLength(in.read_long()); + rt = p; + break; + + case TCKind._tk_string : + case TCKind._tk_wstring : + s = new StringTypeCode(kind); + s.setLength(in.read_long()); + rt = s; + break; + + case TCKind._tk_fixed : + + FixedTypeCode fx = new FixedTypeCode(); + fx.setDigits(in.read_short()); + fx.setScale(in.read_short()); + rt = fx; + break; + + case TCKind._tk_objref : + case TCKind._tk_native : + case TCKind._tk_abstract_interface : + g = new GeneralTypeCode(kind); + g.setId(in.read_string()); + g.setName(in.read_string()); + rt = g; + break; + + case TCKind._tk_alias : + case TCKind._tk_value_box : + g = new GeneralTypeCode(kind); + g.setId(in.read_string()); + g.setName(in.read_string()); + g.setContentType(in.read_TypeCode()); + rt = g; + break; + + case TCKind._tk_struct : + case TCKind._tk_except : + r = new RecordTypeCode(kind); + r.setId(in.read_string()); + r.setName(in.read_string()); + + n = in.read_long(); + + for (int i = 0; i < n; i++) + { + f = r.field(); + f.name = in.read_string(); + f.type = in.read_TypeCode(); + } + rt = r; + break; + + case TCKind._tk_enum : + r = new RecordTypeCode(kind); + r.setId(in.read_string()); + r.setName(in.read_string()); + + n = in.read_long(); + + for (int i = 0; i < n; i++) + { + f = r.field(); + f.name = in.read_string(); + } + rt = r; + break; + + case TCKind._tk_union : + r = new RecordTypeCode(kind); + r.setId(in.read_string()); + r.setName(in.read_string()); + r.setDiscriminator_type(in.read_TypeCode()); + r.setDefaultIndex(in.read_long()); + + n = in.read_long(); + + for (int i = 0; i < n; i++) + { + f = r.field(); + f.label = in.read_any(); + f.name = in.read_string(); + f.type = in.read_TypeCode(); + } + rt = r; + + break; + + case TCKind._tk_value : + r = new RecordTypeCode(kind); + r.setId(in.read_string()); + r.setName(in.read_string()); + r.setTypeModifier(in.read_short()); + r.setConcreteBase_type(in.read_TypeCode()); + + n = in.read_long(); + + for (int i = 0; i < n; i++) + { + f = r.field(); + f.name = in.read_string(); + f.type = in.read_TypeCode(); + f.visibility = in.read_short(); + } + rt = r; + break; + + default : + rt = new PrimitiveTypeCode(kind); + } + return rt; + } + + /** + * Write the CORBA {@link TypeCode}. First, the TypeCode kind + * is written as four byte long. Then, if needed, the additional + * parameters are stored following CORBA specification. + * + * @param out a stream to write into. + * @param x a {@link TypeCode} to write. + */ + public static void write(org.omg.CORBA.portable.OutputStream out, TypeCode x) + throws BadKind, Bounds + { + out.write_long(x.kind().value()); + + switch (x.kind().value()) + { + case TCKind._tk_string : + case TCKind._tk_wstring : + out.write_long(x.length()); + break; + + case TCKind._tk_sequence : + case TCKind._tk_array : + write(out, x.content_type()); + out.write_long(x.length()); + break; + + case TCKind._tk_fixed : + out.write_short(x.fixed_digits()); + out.write_short(x.fixed_scale()); + break; + + case TCKind._tk_objref : + case TCKind._tk_native : + case TCKind._tk_abstract_interface : + out.write_string(x.id()); + out.write_string(x.name()); + break; + + case TCKind._tk_alias : + case TCKind._tk_value_box : + out.write_string(x.id()); + out.write_string(x.name()); + write(out, x.content_type()); + break; + + case TCKind._tk_struct : + case TCKind._tk_except : + out.write_string(x.id()); + out.write_string(x.name()); + + out.write_long(x.member_count()); + + for (int i = 0; i < x.member_count(); i++) + { + out.write_string(x.member_name(i)); + write(out, x.member_type(i)); + } + break; + + case TCKind._tk_enum : + out.write_string(x.id()); + out.write_string(x.name()); + + out.write_long(x.member_count()); + + for (int i = 0; i < x.member_count(); i++) + { + out.write_string(x.member_name(i)); + } + break; + + case TCKind._tk_union : + out.write_string(x.id()); + out.write_string(x.name()); + + write(out, x.discriminator_type()); + out.write_long(x.default_index()); + + out.write_long(x.member_count()); + + for (int i = 0; i < x.member_count(); i++) + { + out.write_any(x.member_label(i)); + out.write_string(x.member_name(i)); + write(out, x.member_type(i)); + } + break; + + case TCKind._tk_value : + out.write_string(x.id()); + out.write_string(x.name()); + out.write_short(x.type_modifier()); + write(out, x.concrete_base_type()); + + out.write_long(x.member_count()); + + for (int i = 0; i < x.member_count(); i++) + { + out.write_string(x.member_name(i)); + write(out, x.member_type(i)); + out.write_short(x.member_visibility(i)); + } + break; + + default :} + } +} diff --git a/libjava/classpath/gnu/CORBA/TypeKindNamer.java b/libjava/classpath/gnu/CORBA/TypeKindNamer.java new file mode 100644 index 000000000..464fd98a1 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/TypeKindNamer.java @@ -0,0 +1,183 @@ +/* primitiveTypes.java -- + 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.CORBA; + +import gnu.CORBA.typecodes.PrimitiveTypeCode; +import gnu.CORBA.typecodes.RecordTypeCode; + +import org.omg.CORBA.TCKind; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.TypeCodePackage.BadKind; + +/** + * A conveniency method for naming the built-in types. + * This is used in error reporting that is part of the user interface. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class TypeKindNamer +{ + /** + * Names of the primitve types. + */ + protected static final String[] tk = + new String[] + { + "null", "void", "short", "long", "ushort", "ulong", "float", "double", + "boolean", "char", "octet", "any", "TypeCode", "Principal", "objref", + "struct", "union", "enum", "string", "sequence", "array", "alias", + "exception", "longlong", "ulonglong", "longdouble", "wchar", "wstring", + "fixed", "value", "value_box", "native", "abstract_interface" + }; + + /** + * Primitve TypeCodes. + */ + protected static final TypeCode[] primitveCodes = + new TypeCode[] + { + new PrimitiveTypeCode(TCKind.tk_null), + new PrimitiveTypeCode(TCKind.tk_void), + new PrimitiveTypeCode(TCKind.tk_short), + new PrimitiveTypeCode(TCKind.tk_long), + new PrimitiveTypeCode(TCKind.tk_ushort), + new PrimitiveTypeCode(TCKind.tk_ulong), + new PrimitiveTypeCode(TCKind.tk_float), + new PrimitiveTypeCode(TCKind.tk_double), + new PrimitiveTypeCode(TCKind.tk_boolean), + new PrimitiveTypeCode(TCKind.tk_char), + new PrimitiveTypeCode(TCKind.tk_octet), + new PrimitiveTypeCode(TCKind.tk_any), + new PrimitiveTypeCode(TCKind.tk_TypeCode), + new PrimitiveTypeCode(TCKind.tk_Principal), + new RecordTypeCode(TCKind.tk_objref), + new PrimitiveTypeCode(TCKind.tk_struct), + new PrimitiveTypeCode(TCKind.tk_union), + new PrimitiveTypeCode(TCKind.tk_enum), + new PrimitiveTypeCode(TCKind.tk_string), + new PrimitiveTypeCode(TCKind.tk_sequence), + new PrimitiveTypeCode(TCKind.tk_array), + new PrimitiveTypeCode(TCKind.tk_alias), + new PrimitiveTypeCode(TCKind.tk_except), + new PrimitiveTypeCode(TCKind.tk_longlong), + new PrimitiveTypeCode(TCKind.tk_ulonglong), + new PrimitiveTypeCode(TCKind.tk_longdouble), + new PrimitiveTypeCode(TCKind.tk_wchar), + new PrimitiveTypeCode(TCKind.tk_wstring), + new PrimitiveTypeCode(TCKind.tk_fixed), + new PrimitiveTypeCode(TCKind.tk_value), + new PrimitiveTypeCode(TCKind.tk_value_box), + new PrimitiveTypeCode(TCKind.tk_native), + new PrimitiveTypeCode(TCKind.tk_abstract_interface) + }; + + static + { + // The Id of the "abstract object" is defined as empty string. + RecordTypeCode object = + (RecordTypeCode) primitveCodes [ TCKind._tk_objref ]; + object.setId(""); + object.setName("Object"); + } + + /** + * Get the primitive type code. + * + * @return the primitve type code, corresponding the passed value. + * + * @throws BadKind if this is not a primitive type code. + */ + public static TypeCode getPrimitveTC(TCKind tc) + throws BadKind + { + try + { + return primitveCodes [ tc.value() ]; + } + catch (ArrayIndexOutOfBoundsException ex) + { + throw new BadKind(tc.value() + " is not a primitve type."); + } + } + + /** + * Get the string name of the passed primitive type. + * + * @param kind the kind of the primitive type the must be defined + * in {@link omg.org.CORBA.TCKind}. + * + * @return the short string name, used in error reporting, etc. + */ + public static String nameIt(int kind) + { + try + { + return tk [ kind ]; + } + catch (ArrayIndexOutOfBoundsException ex) + { + return "type of kind '" + kind + "'"; + } + } + + /** + * Get the string name of the passed primitive type. + * + * @param kind the kind of the primitive type the must be defined + * in {@link omg.org.CORBA.TCKind}. + * + * @return the short string name, used in error reporting, etc. + */ + public static String nameIt(TypeCode type) + { + try + { + if (type.kind().value() == TCKind._tk_array) + return "array of " + nameIt(type.content_type()); + else if (type.kind().value() == TCKind._tk_sequence) + return "sequence of " + nameIt(type.content_type()); + else + return nameIt(type.kind().value()); + } + catch (Exception ex) + { + return "type of kind '" + type.kind().value() + "'"; + } + } +} diff --git a/libjava/classpath/gnu/CORBA/Unexpected.java b/libjava/classpath/gnu/CORBA/Unexpected.java new file mode 100644 index 000000000..89fb7e7b9 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Unexpected.java @@ -0,0 +1,128 @@ +/* DNW.java -- + 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.CORBA; + + +/** + * Contains the static method to throw an error in the case + * when the execution should never get into the current point. + * + * The error message contains the text, suggesting to check + * the user code first and then report a bug. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class Unexpected + extends InternalError +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * The default message for the CORBA assertion error. + */ + public static final String SHARED_MESSAGE = + "CORBA assertion error. Please check your code. " + + "If you think it is Classpath problem, please report " + + "this bug providing as much information as possible."; + + /** + * Create an instance with explaining message and enclosing + * exception. + */ + public Unexpected(String msg, Exception why) + { + super(msg + ". " + SHARED_MESSAGE); + if (why != null) + initCause(why); + } + + /** + * Create an instance with enclosing exception. + */ + public Unexpected(Exception why) + { + super(SHARED_MESSAGE); + if (why != null) + initCause(why); + } + + /** + * Create an instance. + */ + public Unexpected() + { + super(SHARED_MESSAGE); + } + + /** + * Throws an error with the custom explaining message and + * the appended share message. + * + * @param msg the error message + * @param why the enclosing exception. + */ + public static void error(String msg, Exception why) + { + throw new Unexpected(msg, why); + } + + /** + * Throws an error with the shared explaining message. + * + * @param why the enclosing exception. + * @throws Error, always. + */ + public static void error(Exception why) + { + throw new Unexpected(why); + } + + /** + * Throws an error with the shared explaining message. + * + * @throws Error, always. + */ + public static void error() + { + throw new Unexpected(); + } +} diff --git a/libjava/classpath/gnu/CORBA/Version.java b/libjava/classpath/gnu/CORBA/Version.java new file mode 100644 index 000000000..20449a389 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/Version.java @@ -0,0 +1,222 @@ +/* Version.java -- + 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.CORBA; + +import java.io.IOException; +import java.io.Serializable; + +import org.omg.CORBA.MARSHAL; + +/** + * A version number, represented by the major version number + * and the minor version number. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class Version + implements Serializable +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * Major number (0..256, so the byte cannot be used). + */ + public final int major; + + /** + * Minor number. + */ + public final int minor; + + /** + * Create the version with the given version numbers. + * + * @param _major major number (0..255) + * @param _minor minor number (0..255) + */ + public Version(int _major, int _minor) + { + major = (byte) _major; + minor = (byte) _minor; + } + + /** + * Returns true if the versions are equal. + * @param other the other version to compare. + * + * @return true if the versions are equal + */ + public boolean equals(java.lang.Object other) + { + if (other == this) + { + return true; + } + if (!(other instanceof Version)) + { + return false; + } + + Version that = (Version) other; + return same(that); + } + + /** + * Get the hashcode, higher 8 bits being the major version and lower 8 bits + * the minor version. + */ + public int hashCode() + { + return major << 8 | minor; + } + + /** + * Read from the input stream, major number first. + * @param in a stream to read from. + */ + public static Version read_version(java.io.InputStream in) + { + try + { + int major = in.read() & 0xFF; + int minor = in.read() & 0xFF; + return new Version(major, minor); + } + catch (IOException ex) + { + MARSHAL m = new MARSHAL("IOException while reading message header"); + m.initCause(ex); + m.minor = Minor.Header; + throw m; + } + } + + /** + * Returns true if the versions are the same. + * + * @param that the other version to compare. + * + * @return true if the versions are the same. + */ + public boolean same(Version that) + { + return major == that.major && minor == that.minor; + } + + /** + * Returns true if the given version is higher than + * or equals to the version, supplied as parameter + * in the form of two integers. + * + * @param a_major major number of the version to compare. + * @param a_minor minor number of the version to compare. + * + * @return true if this version is higher than or equals to + * the version v. + */ + public boolean since_inclusive(int a_major, int a_minor) + { + if (major > a_major) + return true; + else if (major < a_major) + return false; + else + + // Major numbers are equal. + return minor >= a_minor; + } + + /** + * Return the string representation, in the form + * major.minor. + */ + public String toString() + { + return major + "." + minor; + } + + /** + * Returs true if the given version is lower or equal to the + * version, specified by the provided minor and major version + * number. This means, the version, specified by these two numbers, + * should be supported by the current version. + * + * @param a_major a major version number. + * @param a_minor a minor version number. + * + * @return true if the current version should be supported by the + * version, specified by the two passed numbers. + */ + public boolean until_inclusive(int a_major, int a_minor) + { + if (major < a_major) + return true; + else if (major > a_major) + return false; + else + + // Major numbers are equal. + return minor <= a_minor; + } + + /** + * Write into the output stream, major number first. + * + * @param out a stream to write into. + */ + public void write(java.io.OutputStream out) + { + try + { + out.write(major & 0xFF); + out.write(minor & 0xFF); + } + catch (IOException ex) + { + MARSHAL m = new MARSHAL("IOException while writing message header"); + m.minor = Minor.Header; + m.initCause(ex); + throw m; + } + } + +} diff --git a/libjava/classpath/gnu/CORBA/WCharHolder.java b/libjava/classpath/gnu/CORBA/WCharHolder.java new file mode 100644 index 000000000..3c6a87fbe --- /dev/null +++ b/libjava/classpath/gnu/CORBA/WCharHolder.java @@ -0,0 +1,128 @@ +/* WCharHolder.java -- + 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.CORBA; + +import gnu.CORBA.typecodes.PrimitiveTypeCode; + +import org.omg.CORBA.TCKind; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.Streamable; + +/** + * A holder for CORBA char that is mapped into + * java char. + * + * The holders have several application areas. The end user usually + * sees them implementing CORBA methods where the primitive type + * is passed by reference. While CORBA (or, for example, C) supports + * this, the java does not and a wrapper class is required. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public final class WCharHolder + implements Streamable +{ + /** + * The default type code for this holder. + */ + private static final TypeCode t_char = new PrimitiveTypeCode(TCKind.tk_wchar); + + /** + * The char (CORBA wchar) value, + * held by this WCharHolder. + */ + public char value; + + /** + * Constructs an instance of WCharHolder, + * initializing {@link #value} to 0 . + */ + public WCharHolder() + { + } + + /** + * Constructs an instance of WCharHolder, + * initializing {@link #value} to the given char. + * + * @param initial_value a value that will be assigned to the + * {@link #value} field. + */ + public WCharHolder(char initial_value) + { + value = initial_value; + } + + /** + * Fill in the {@link value } field by reading the required data + * from the given stream. For char, the functionality + * is delegated to + * {@link org.omg.CORBA.portable.InputStream#read_wchar}. + * + * @param input the input stream to read from. + */ + public void _read(InputStream input) + { + value = input.read_wchar(); + } + + /** + * Returns the TypeCode, corresponding the CORBA type that is stored + * using this holder. + */ + public TypeCode _type() + { + return t_char; + } + + /** + * Write the {@link value } field to the given stream. + * For char, the functionality + * is delegated to + * {@link org.omg.CORBA.portable.OutputStream#write_wchar(char) }. + * + * @param output the output stream to write into. + */ + public void _write(OutputStream output) + { + output.write_wchar(value); + } +} diff --git a/libjava/classpath/gnu/CORBA/WStringHolder.java b/libjava/classpath/gnu/CORBA/WStringHolder.java new file mode 100644 index 000000000..7f18791df --- /dev/null +++ b/libjava/classpath/gnu/CORBA/WStringHolder.java @@ -0,0 +1,131 @@ +/* WStringHolder.java -- + 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.CORBA; + +import gnu.CORBA.typecodes.StringTypeCode; + +import org.omg.CORBA.TCKind; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.Streamable; + +/** + * A holder for CORBA wstring that is mapped into + * java String. This holder writes and reads differently + * from the StringHolder. + * + * The holders have several application areas. The end user usually + * sees them implementing CORBA methods where the primitive type + * is passed by reference. While CORBA (or, for example, C) supports + * this, the java does not and a wrapper class is required. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class WStringHolder + implements Streamable +{ + /** + * The default type code for this holder. + */ + private static final StringTypeCode t_string = + new StringTypeCode(TCKind.tk_wstring); + + /** + * The String (CORBA string) value, + * held by this WStringHolder. + */ + public String value; + + /** + * Constructs an instance of WStringHolder, + * initializing {@link #value} to null. + */ + public WStringHolder() + { + } + + /** + * Constructs an instance of WStringHolder, + * initializing {@link #value} to the given String. + * + * @param initial_value a value that will be assigned to the + * {@link #value} field. + */ + public WStringHolder(String initial_value) + { + value = initial_value; + } + + /** + * Fill in the {@link #value } field by reading the required data + * from the given stream. For string, the functionality + * is delegated to + * {@link org.omg.CORBA.portable.InputStream#read_wstring}. + * + * @param input the input stream to read from. + */ + public void _read(InputStream input) + { + value = input.read_wstring(); + } + + /** + * Returns the TypeCode, corresponding the CORBA type that is stored + * using this holder. The {@link TypeCode#length()} method of the + * returned typecode always returns 0. + */ + public TypeCode _type() + { + return t_string; + } + + /** + * Write the {@link #value } field to the given stream. + * For string, the functionality + * is delegated to + * {@link org.omg.CORBA.portable.OutputStream#write_wstring(String) }. + * + * @param output the output stream to write into. + */ + public void _write(OutputStream output) + { + output.write_wstring(value); + } +} diff --git a/libjava/classpath/gnu/CORBA/_PolicyImplBase.java b/libjava/classpath/gnu/CORBA/_PolicyImplBase.java new file mode 100644 index 000000000..a235080c1 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/_PolicyImplBase.java @@ -0,0 +1,232 @@ +/* _PolicyImplBase.java -- + 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.CORBA; + +import org.omg.CORBA.BAD_OPERATION; +import org.omg.CORBA.CompletionStatus; +import org.omg.CORBA.Policy; +import org.omg.CORBA.PolicyHelper; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.InvokeHandler; +import org.omg.CORBA.portable.ObjectImpl; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.ResponseHandler; + +/** + * The server side implementation base for the {@link Policy}. + * + * @specnote The java 1.4 API does not define the server side policy + * implementation base, but it defines the policy client side stub. + * As these two classes always work together, and even no separate testing is + * possible, the required implementation base is provided in gnu.CORBA + * namespace. Sun will probably include they base in the future java APIs. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public abstract class _PolicyImplBase + extends ObjectImpl + implements Policy, InvokeHandler +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * The policy repository ids. + */ + private final String[] ids; + + /** + * The type of this policy. + */ + private final int type; + + /** + * The value of this policy. The value object is never the same + * for different policies. + */ + private final java.lang.Object value; + + /** + * The policy integer code, written in request to write + * the policy value. + */ + private final int policyCode; + + /** + * Create the new policy of the given type, having the given value. + * For security reasons, the method is kept package private. + * + * @param p_type the type of this policy. + * @param p_value the value of this policy. + * @param p_code the integer code of this policy. + * @param p_idl the policy IDL type string. The {@link #_ids()} + * will return array, first line being this string and another + * being PolicyHelper.id(). + */ + public _PolicyImplBase(int p_type, java.lang.Object p_value, int p_code, + String p_idl + ) + { + type = p_type; + value = p_value; + policyCode = p_code; + ids = new String[] { p_idl, PolicyHelper.id() }; + } + + /** + * Get the integer code of the type of this policy. + */ + public final int policy_type() + { + return type; + } + + /** + * Return the list of repository ids. + */ + public final String[] _ids() + { + return ids; + } + + /** + * Call the required method. + */ + public final OutputStream _invoke(String method, InputStream input, + ResponseHandler rh + ) + { + OutputStream output = null; + + if (method.equals("destroy")) + { + // The "destroy" has been invoked. + destroy(); + output = rh.createReply(); + } + else if (method.equals("copy")) + { + // The "copy" has been invoked. + org.omg.CORBA.Object returns = copy(); + output = rh.createReply(); + output.write_Object(this); + } + else if (method.equals("policy_type")) + { + // The "policy_type" has been invoked. + int returns = policy_type(); + output = rh.createReply(); + output.write_long(returns); + } + else if (method.equals("value")) + { + // The "value" can be invoked on the children types + // and must return an integer, representing the policy value + // (CORBA enumeration). + output = rh.createReply(); + output.write_long(policyCode); + } + else + throw new BAD_OPERATION(method, Minor.Method, + CompletionStatus.COMPLETED_MAYBE); + + return output; + } + + /** + * Get the value of this policy + */ + public final java.lang.Object getValue() + { + return value; + } + + /** + * Get the integer code of this policy value. + */ + public final int getCode() + { + return policyCode; + } + + /** + * Returns without action. It is a work of garbage collector + * to remove the unused objects. + */ + public final void destroy() + { + } + + /** + * Returns the string representation of the given policy. + */ + public final String toString() + { + return value.toString(); + } + + /** + * Create a copy of this policy. The object is not mutable, so + * this can be returned. + * + * @return this + */ + public Policy copy() + { + return this; + } + + /** + * Use the value to get a hash code. + */ + public int hashCode() + { + return getValue().hashCode(); + } + + /** + * Check the values for equality. + */ + public boolean equals(Object x) + { + return x == null ? false : getValue().equals(x); + } +} diff --git a/libjava/classpath/gnu/CORBA/gnuAny.java b/libjava/classpath/gnu/CORBA/gnuAny.java new file mode 100644 index 000000000..6692d623e --- /dev/null +++ b/libjava/classpath/gnu/CORBA/gnuAny.java @@ -0,0 +1,907 @@ +/* gnuAny.java -- + 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.CORBA; + +import gnu.CORBA.CDR.Vio; +import gnu.CORBA.CDR.BufferredCdrInput; +import gnu.CORBA.CDR.BufferedCdrOutput; +import gnu.CORBA.typecodes.PrimitiveTypeCode; +import gnu.CORBA.typecodes.StringTypeCode; + +import org.omg.CORBA.Any; +import org.omg.CORBA.AnyHolder; +import org.omg.CORBA.BAD_OPERATION; +import org.omg.CORBA.BooleanHolder; +import org.omg.CORBA.CharHolder; +import org.omg.CORBA.DoubleHolder; +import org.omg.CORBA.FixedHolder; +import org.omg.CORBA.FloatHolder; +import org.omg.CORBA.IntHolder; +import org.omg.CORBA.LongHolder; +import org.omg.CORBA.MARSHAL; +import org.omg.CORBA.ORB; +import org.omg.CORBA.ObjectHolder; +import org.omg.CORBA.Principal; +import org.omg.CORBA.PrincipalHolder; +import org.omg.CORBA.ShortHolder; +import org.omg.CORBA.StringHolder; +import org.omg.CORBA.TCKind; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.TypeCodeHolder; +import org.omg.CORBA.ValueBaseHolder; +import org.omg.CORBA.portable.Streamable; + +import java.io.Serializable; +import java.lang.reflect.Field; +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.zip.Adler32; + +/** + * The implementation of {@link Any}. + * + * For performance reasonse, the inserted values are not cloned. + * If the value object allows modifications (like {@link Streamable}), + * these subsequent alterations are reflected by the instance of + * this gnuAny, and the gnuAny alterations are reflected by the + * returned value. If it is required to have the uncoupled value, + * it must be requested from the copy of the current instance. + * The {@link gnuAny} can be simply cloned by the provided + * {@link Clone()} method. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class gnuAny + extends Any +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * The value, returned by {@link #type()} if the value has been + * not intialized. + */ + protected static final TypeCode nullType = + new PrimitiveTypeCode(TCKind.tk_null); + + /** + * The Streamable, representing the value, held by this gnuAny. + */ + protected Streamable has; + + /** + * The complete typecode of the Streamable, if explicitly set. + */ + protected TypeCode typecode; + + /** + * The typecode kind of the Streamable, if explicitly set. + */ + protected int xKind = -1; + + /** + * The associated ORB. + */ + private ORB orb; + + /** + * Set the associated orb. + */ + public void setOrb(ORB an_orb) + { + orb = an_orb; + } + + /** + * Creates a deep copy of this gnuAny, writing to and subsequently + * reading from from the byte buffer. + * + * @return the uncoupled gnuAny with all fields set to identical + * values. + */ + public gnuAny Clone() + { + BufferedCdrOutput out = new BufferedCdrOutput(); + out.setOrb(orb); + out.write_any(this); + + BufferredCdrInput in = new BufferredCdrInput(out.buffer.toByteArray()); + in.setOrb(orb); + return (gnuAny) in.read_any(); + } + + /** + * Create the buffered CDR input stream, containing the + * value, stored inside of this {@link Any}. + */ + public org.omg.CORBA.portable.InputStream create_input_stream() + { + if (has instanceof GeneralHolder) + { + GeneralHolder u = (GeneralHolder) has; + return u.getInputStream(); + } + else + { + BufferedCdrOutput out = new BufferedCdrOutput(); + out.setOrb(orb); + write_value(out); + + BufferredCdrInput in = new BufferredCdrInput(out.buffer.toByteArray()); + in.setOrb(orb); + return in; + } + } + + /** + * Create the buffered CDR output stream (empty). + */ + public org.omg.CORBA.portable.OutputStream create_output_stream() + { + BufferedCdrOutput stream = new BufferedCdrOutput(); + stream.setOrb(orb); + return stream; + } + + /** + * Compare two Any's for equality. + * @param other the other Any to compare. + */ + public boolean equal(Any other) + { + if (other == this) + return true; + if (type().kind() != other.type().kind()) + return false; + + if (has != null && other instanceof gnuAny) + if (has.equals(((gnuAny) other).has)) + return true; + + BufferedCdrOutput a = new BufferedCdrOutput(); + a.setOrb(orb); + write_value(a); + + BufferedCdrOutput b = new BufferedCdrOutput(); + b.setOrb(orb); + other.write_value(b); + + byte[] ba = a.buffer.toByteArray(); + byte[] bb = b.buffer.toByteArray(); + + return Arrays.equals(ba, bb); + } + + /** + * Get the content - dependent hashcode. + */ + public int hashCode() + { + if (has == null) + return type().kind().value(); + else + { + Adler32 adler = new Adler32(); + + BufferedCdrOutput a = new BufferedCdrOutput(); + a.setOrb(orb); + write_value(a); + + adler.update(a.buffer.toByteArray()); + adler.update(type().kind().value()); + + return (int) adler.getValue() & Integer.MAX_VALUE; + } + } + + /** + * Delegates functionality to {@link #equal(Any)}. + */ + public boolean equals(java.lang.Object other) + { + if (other == this) + return true; + if (!(other instanceof Any)) + return false; + + return equal((Any) other); + } + + /** + * Extract the previously stored object. + */ + public org.omg.CORBA.Object extract_Object() + { + try + { + return ((ObjectHolder) has).value; + } + catch (ClassCastException ex) + { + BAD_OPERATION bad = new BAD_OPERATION(); + bad.initCause(ex); + bad.minor = Minor.Any; + throw bad; + } + } + + /** + * Extract the previously inserted CORBA Principal/ + * @return the previously inserted value. + * + * @throws org.omg.CORBA.BAD_OPERATION if the holder contains something + * else than Principal. + * + * @deprecated by CORBA 2.2. + */ + public Principal extract_Principal() + { + check(TCKind._tk_Principal); + return ((PrincipalHolder) has).value; + } + + /** + * Return the value, encapsulated in a suitable holder. + * This implementation returns the direct reference, + * so the alterations on the returned streamable are + * directly reflected to the content of this {@link Any}. + */ + public Streamable extract_Streamable() + { + return has; + } + + public TypeCode extract_TypeCode() + throws BAD_OPERATION + { + check(TCKind._tk_TypeCode); + return ((TypeCodeHolder) has).value; + } + + /** + * Extract the stored value type. + * + * @return the previously stored value type. + * + * @throws BAD_OPERATION if the Any contains something different. + * + * @see org.omg.CORBA.portable.ValueBase + */ + public Serializable extract_Value() + throws BAD_OPERATION + { + try + { + if (has instanceof ValueBaseHolder) + return ((ValueBaseHolder) has).value; + else + { + // Normally, ValueBase holder must be an instance of the + // ValueBaseHolder. However some IDL compilers probably + // have a bug, do not deriving this way. The the only + // way to access the wrapped value is via reflection. + Field f = has.getClass().getField("value"); + return (Serializable) f.get(has); + } + } + catch (Exception ex) + { + BAD_OPERATION bad = new BAD_OPERATION("Value type expected"); + bad.minor = Minor.Any; + bad.initCause(ex); + throw bad; + } + } + + /** {@inheritDoc} */ + public Any extract_any() + throws BAD_OPERATION + { + check(TCKind._tk_any); + return ((AnyHolder) has).value; + } + + /** {@inheritDoc} */ + public boolean extract_boolean() + throws BAD_OPERATION + { + check(TCKind._tk_boolean); + return ((BooleanHolder) has).value; + } + + /** {@inheritDoc} */ + public char extract_char() + throws BAD_OPERATION + { + check(TCKind._tk_char); + return ((CharHolder) has).value; + } + + /** {@inheritDoc} */ + public double extract_double() + throws BAD_OPERATION + { + check(TCKind._tk_double); + return ((DoubleHolder) has).value; + } + + /** + * Extract the previously inserted CORBA fixed/ + * @return the previously inserted value. + * + * @throws org.omg.CORBA.BAD_OPERATION if the holder contains something + * else than BigDecimal. + */ + public BigDecimal extract_fixed() + throws org.omg.CORBA.BAD_OPERATION + { + check(TCKind._tk_fixed); + return ((FixedHolder) has).value; + } + + /** {@inheritDoc} */ + public float extract_float() + throws BAD_OPERATION + { + check(TCKind._tk_float); + return ((FloatHolder) has).value; + } + + /** {@inheritDoc} */ + public int extract_long() + throws BAD_OPERATION + { + // CORBA long = java int. + check(TCKind._tk_long); + return ((IntHolder) has).value; + } + + /** {@inheritDoc} */ + public long extract_longlong() + throws BAD_OPERATION + { + check(TCKind._tk_longlong); + return ((LongHolder) has).value; + } + + /** {@inheritDoc} */ + public byte extract_octet() + throws BAD_OPERATION + { + // ShortHolder holds also octets. + check(TCKind._tk_octet); + return (byte) ((OctetHolder) has).value; + } + + /** {@inheritDoc} */ + public short extract_short() + throws BAD_OPERATION + { + check(TCKind._tk_short); + return ((ShortHolder) has).value; + } + + /** {@inheritDoc} */ + public String extract_string() + throws BAD_OPERATION + { + check(TCKind._tk_string); + return ((StringHolder) has).value; + } + + /** {@inheritDoc} */ + public int extract_ulong() + throws BAD_OPERATION + { + // IntHolder also holds ulongs. + check(TCKind._tk_ulong); + return ((IntHolder) has).value; + } + + /** {@inheritDoc} */ + public long extract_ulonglong() + throws BAD_OPERATION + { + // LongHolder also holds ulonglong + check(TCKind._tk_ulonglong); + return ((LongHolder) has).value; + } + + /** {@inheritDoc} */ + public short extract_ushort() + throws BAD_OPERATION + { + // ShortHolder also holds ushorts. + check(TCKind._tk_ushort); + return ((ShortHolder) has).value; + } + + /** {@inheritDoc} */ + public char extract_wchar() + throws BAD_OPERATION + { + check(TCKind._tk_wchar); + return ((WCharHolder) has).value; + } + + /** {@inheritDoc} */ + public String extract_wstring() + throws BAD_OPERATION + { + // StringHolder also holds wstrings. + check(TCKind._tk_wstring); + return ((WStringHolder) has).value; + } + + /** + * Inserts the CORBA object and sets the typecode to the given type. + */ + public void insert_Object(org.omg.CORBA.Object x, TypeCode typecode) + { + has = new ObjectHolder(x); + type(typecode); + } + + /** + * Inserts the CORBA object. + */ + public void insert_Object(org.omg.CORBA.Object x) + { + has = new ObjectHolder(x); + } + + /** + * Insert the CORBA Principal. + * This implementation uses direct assignment, so the later + * alterations of that BigDecimal are reflected on the + * content of this {@link Any}. + * + * @deprecated by CORBA 2.2. + */ + public void insert_Principal(Principal x) + { + resetTypes(); + if (has instanceof PrincipalHolder) + ((PrincipalHolder) has).value = x; + else + has = new PrincipalHolder(x); + } + + /** + * Sets the value to the value, encapsulated in this holder. + * This implementation uses direct assignment, so the later + * alterations of that streamable are reflected on the + * content of this {@link Any}. + */ + public void insert_Streamable(Streamable x) + { + resetTypes(); + has = x; + } + + /** + * Insert the typecode into this Any + * @param typecode the typecode to insert. + */ + public void insert_TypeCode(TypeCode typecode) + { + resetTypes(); + if (has instanceof TypeCodeHolder) + ((TypeCodeHolder) has).value = typecode; + else + has = new TypeCodeHolder(typecode); + } + + /** {@inheritDoc} */ + public void insert_Value(Serializable x, TypeCode c_typecode) + { + if (typecode != null && typecode.kind() == TCKind.tk_value_box) + { + has = new gnuValueHolder(x, typecode); + } + else + { + type(typecode); + insert_Value(x); + } + } + + /** {@inheritDoc} */ + public void insert_Value(Serializable x) + { + if (typecode != null && typecode.kind() == TCKind.tk_value_box) + { + has = new gnuValueHolder(x, typecode); + } + else + { + if (has instanceof ValueBaseHolder) + ((ValueBaseHolder) has).value = x; + else + has = new ValueBaseHolder(x); + } + } + + /** + * Insert another {@link Any} into this {@link Any}. + * This implementation uses direct assignment, so the later + * alterations of that {@link Any} are reflected on the + * content of this {@link Any}. + */ + public void insert_any(Any an_any) + { + resetTypes(); + if (has instanceof AnyHolder) + ((AnyHolder) has).value = an_any; + else + has = new AnyHolder(an_any); + } + + /** {@inheritDoc} */ + public void insert_boolean(boolean x) + { + resetTypes(); + if (has instanceof BooleanHolder) + ((BooleanHolder) has).value = x; + else + has = new BooleanHolder(x); + } + + /** {@inheritDoc} */ + public void insert_char(char x) + { + resetTypes(); + if (has instanceof CharHolder) + ((CharHolder) has).value = x; + else + has = new CharHolder(x); + } + + /** {@inheritDoc} */ + public void insert_double(double x) + { + resetTypes(); + if (has instanceof DoubleHolder) + ((DoubleHolder) has).value = x; + else + has = new DoubleHolder(x); + } + + /** + * Inserts the CORBA fixed, setting the typecode + * explicitly. + * This implementation uses direct assignment, so the later + * alterations of that BigDecimal are reflected on the + * content of this {@link Any}. + */ + public void insert_fixed(BigDecimal x, TypeCode x_typecode) + { + resetTypes(); + insert_fixed(x); + typecode = x_typecode; + } + + /** + * Inserts the CORBA fixed, setting the typecode + * by example of the currently passed value. + * This implementation uses direct assignment, so the later + * alterations of that BigDecimal are reflected on the + * content of this {@link Any}, including the typecode. + */ + public void insert_fixed(BigDecimal x) + { + resetTypes(); + if (has instanceof FixedHolder) + ((FixedHolder) has).value = x; + else + has = new FixedHolder(x); + } + + /** {@inheritDoc} */ + public void insert_float(float x) + { + resetTypes(); + if (has instanceof FloatHolder) + ((FloatHolder) has).value = x; + else + has = new FloatHolder(x); + } + + /** {@inheritDoc} */ + public void insert_long(int x) + { + resetTypes(); + if (has instanceof IntHolder) + ((IntHolder) has).value = x; + else + has = new IntHolder(x); + } + + /** {@inheritDoc} */ + public void insert_longlong(long x) + { + resetTypes(); + if (has instanceof LongHolder) + ((LongHolder) has).value = x; + else + has = new LongHolder(x); + } + + /** {@inheritDoc} */ + public void insert_octet(byte x) + { + resetTypes(); + if (has instanceof OctetHolder) + ((OctetHolder) has).value = x; + else + has = new OctetHolder(x); + } + + /** {@inheritDoc} */ + public void insert_short(short x) + { + resetTypes(); + if (has instanceof ShortHolder) + ((ShortHolder) has).value = x; + else + has = new ShortHolder(x); + } + + /** {@inheritDoc} */ + public void insert_string(String x) + { + resetTypes(); + if (has instanceof StringHolder) + ((StringHolder) has).value = x; + else + has = new StringHolder(x); + + typecode = new StringTypeCode(TCKind.tk_string); + } + + /** {@inheritDoc} */ + public void insert_ulong(int x) + { + resetTypes(); + if (has instanceof IntHolder) + ((IntHolder) has).value = x; + else + has = new IntHolder(x); + xKind = TCKind._tk_ulong; + } + + /** {@inheritDoc} */ + public void insert_ulonglong(long x) + { + resetTypes(); + if (has instanceof LongHolder) + ((LongHolder) has).value = x; + else + has = new LongHolder(x); + xKind = TCKind._tk_ulonglong; + } + + /** {@inheritDoc} */ + public void insert_ushort(short x) + { + resetTypes(); + if (has instanceof ShortHolder) + ((ShortHolder) has).value = x; + else + has = new ShortHolder(x); + xKind = TCKind._tk_ushort; + } + + /** {@inheritDoc} */ + public void insert_wchar(char x) + { + resetTypes(); + if (has instanceof WCharHolder) + ((WCharHolder) has).value = x; + else + has = new WCharHolder(x); + } + + /** {@inheritDoc} */ + public void insert_wstring(String x) + { + resetTypes(); + if (has instanceof WStringHolder) + ((WStringHolder) has).value = x; + else + has = new WStringHolder(x); + } + + /** + * Return the associated orb. + */ + public ORB orb() + { + return orb; + } + + /** + * Read the value of the given type from the given stream. + * + * @param input a stream to read from. + * @param a_type a typecode of the value to read. + */ + public void read_value(org.omg.CORBA.portable.InputStream input, + TypeCode a_type + ) + throws MARSHAL + { + try + { + int kind = a_type.kind().value(); + + // Fixed needs special handling. + if (kind == TCKind._tk_fixed) + { + BigDecimal dec = BigDecimalHelper.read(input, a_type.fixed_scale()); + has = new FixedHolder(dec); + } + else + { + has = HolderLocator.createHolder(a_type); + if (has == null) + { + // Use the Universal Holder that reads till the end of stream. + // This works with the extract/insert pair of the typical + // Helper. + BufferedCdrOutput buffer = new BufferedCdrOutput(); + buffer.setOrb(orb); + has = new GeneralHolder(buffer); + } + } + type(a_type); + + if (!(has instanceof GeneralHolder) && + (kind == TCKind._tk_value_box)) + { + // The streamable only contains operations for + // reading the value, not the value header. + Field vField = has.getClass().getField("value"); + + Object content = Vio.read(input, a_type.id()); + vField.set(has, content); + } + else + has._read(input); + } + catch (Exception ex) + { + MARSHAL m = new MARSHAL(); + m.minor = Minor.Any; + m.initCause(ex); + throw m; + } + } + + /** {@inheritDoc} */ + public TypeCode type() + { + if (typecode != null) + return typecode; + else if (xKind >= 0) + { + typecode = new PrimitiveTypeCode(TCKind.from_int(xKind)); + return typecode; + } + else + return has != null ? has._type() : nullType; + } + + /** + * Explicitly set the typecode of the value to the given type. + * + * @param valueTypeCode the typecode of the value. + */ + public void type(TypeCode valueTypeCode) + { + xKind = valueTypeCode.kind().value(); + typecode = valueTypeCode; + } + + /** {@inheritDoc} */ + public void write_value(org.omg.CORBA.portable.OutputStream output) + { + if (has != null) + has._write(output); + else + // These kinds support null. + if (xKind == TCKind._tk_null || xKind == TCKind._tk_objref || + xKind == TCKind._tk_value || xKind == TCKind._tk_value_box + ) + output.write_long(0); + } + + /** + * Check if the current value if the value of the given kind. + * + * @param kind a kind to check. + * @throws BAD_OPERATION if the value is not set of is different kind. + */ + protected void check(int kind) + throws BAD_OPERATION + { + if (has == null) + { + BAD_OPERATION bad = new BAD_OPERATION("value not set"); + bad.minor = Minor.Any; + throw bad; + } + + if (xKind >= 0) + { + if (xKind != kind) + if (!(xKind == TCKind._tk_alias && has._type().kind().value() == kind)) + { + BAD_OPERATION bad = new BAD_OPERATION("Extracting " + + TypeKindNamer.nameIt(kind) + " when stored " + + TypeKindNamer.nameIt(xKind)); + bad.minor = Minor.Any; + throw bad; + } + } + else + { + if (type().kind().value() != kind) + if (!(type().kind().value() == TCKind._tk_alias && has._type().kind().value() == kind)) + { + BAD_OPERATION bad = new BAD_OPERATION("Extracting " + + TypeKindNamer.nameIt(kind) + " stored " + + TypeKindNamer.nameIt(type())); + bad.minor = Minor.Any; + throw bad; + } + } + } + + /** + * Clear the additional type information before reusing this instance. + */ + private final void resetTypes() + { + typecode = null; + xKind = -1; + } +} diff --git a/libjava/classpath/gnu/CORBA/gnuCodecFactory.java b/libjava/classpath/gnu/CORBA/gnuCodecFactory.java new file mode 100644 index 000000000..5dfd56df1 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/gnuCodecFactory.java @@ -0,0 +1,90 @@ +/* gnuCodecFactory.java -- + 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.CORBA; + +import org.omg.CORBA.LocalObject; +import org.omg.CORBA.ORB; +import org.omg.IOP.Codec; +import org.omg.IOP.CodecFactory; +import org.omg.IOP.CodecFactoryPackage.UnknownEncoding; +import org.omg.IOP.ENCODING_CDR_ENCAPS; +import org.omg.IOP.Encoding; + +/** + * A simple implementation of the Codec factory, able to return the + * standard Codec's. Only ENCODING_CDR_ENCAPS encoding is supported. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class gnuCodecFactory extends LocalObject implements CodecFactory +{ + /** + * The associated ORB. + */ + private final ORB orb; + + /** + * Create a new instance of the this factory, associated with the given ORB. + */ + public gnuCodecFactory(ORB an_orb) + { + orb = an_orb; + } + + /** + * Creates the Codec for the given encoding. + * + * @param for_encoding the encoding for that the Codec must be created. + * + * @return the suitable Codec. + * + * @throws UnknownEncoding if the encoding is not a ENCODING_CDR_ENCAPS. + */ + public Codec create_codec(Encoding for_encoding) throws UnknownEncoding + { + if (for_encoding.format != ENCODING_CDR_ENCAPS.value) + throw new UnknownEncoding("Only ENCODING_CDR_ENCAPS is " + + "supported by this factory." + ); + + return new CdrEncapsCodecImpl(orb, + new Version(for_encoding.major_version, for_encoding.minor_version) + ); + } +} diff --git a/libjava/classpath/gnu/CORBA/gnuContext.java b/libjava/classpath/gnu/CORBA/gnuContext.java new file mode 100644 index 000000000..baa9fc804 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/gnuContext.java @@ -0,0 +1,202 @@ +/* gnuContext.java -- + 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.CORBA; + +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import org.omg.CORBA.Any; +import org.omg.CORBA.Bounds; +import org.omg.CORBA.CTX_RESTRICT_SCOPE; +import org.omg.CORBA.Context; +import org.omg.CORBA.NVList; + +/** + * The working implementation of the {@link org.omg.CORBA.Context}. + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class gnuContext + extends Context +{ + /** + * The parent context. + */ + Context parent; + + /** + * The collection to store the context properties. + */ + Map properties = new Hashtable(); + + /** + * The name of this context. + */ + String name; + + /** + * Creates the new context with the given name and parent. + * + * @param a_name a name of the new context. + * @param a_parent a parent, used to resolve the missing references. + */ + public gnuContext(String a_name, Context a_parent) + { + name = a_name; + parent = a_parent; + } + + /** {@inheritDoc} */ + public String context_name() + { + return name; + } + + /** {@inheritDoc} */ + public Context create_child(String child) + { + return new gnuContext(child, this); + } + + /** {@inheritDoc} */ + public void delete_values(String property) + { + boolean starts = false; + if (property.endsWith("*")) + { + starts = true; + property = property.substring(0, property.length() - 1); + } + + Set keys = properties.keySet(); + + Iterator iter = keys.iterator(); + while (iter.hasNext()) + { + String key = (String) iter.next(); + if ((starts && key.startsWith(property)) || + (!starts && key.equals(property)) + ) + iter.remove(); + } + } + + /** {@inheritDoc} */ + public NVList get_values(String start_scope, int flags, String pattern) + { + if (start_scope != null) + { + Context c = this; + while (c != null && !c.context_name().equals(start_scope)) + c = c.parent(); + if (c == null) + return new gnuNVList(); + } + + try + { + gnuNVList rt = new gnuNVList(); + + boolean starts = false; + if (pattern.endsWith("*")) + { + starts = true; + pattern = pattern.substring(0, pattern.length() - 1); + } + + Set keys = properties.keySet(); + + Iterator iter = keys.iterator(); + while (iter.hasNext()) + { + String key = (String) iter.next(); + if ((starts && key.startsWith(pattern)) || + (!starts && key.equals(pattern)) + ) + { + rt.add_value(key, (Any) properties.get(key), 0); + } + } + + if ((flags & CTX_RESTRICT_SCOPE.value) == 0 && parent != null) + { + NVList par = parent.get_values(start_scope, flags, pattern); + for (int i = 0; i < par.count(); i++) + { + rt.list.add(par.item(i)); + } + } + + return rt; + } + catch (Bounds ex) + { + throw new Error("Report this bug."); + } + } + + /** {@inheritDoc} */ + public Context parent() + { + return parent; + } + + /** {@inheritDoc} */ + public void set_one_value(String name, Any value) + { + properties.put(name, value); + } + + /** {@inheritDoc} */ + public void set_values(NVList values) + { + try + { + for (int i = 0; i < values.count(); i++) + { + properties.put(values.item(i).name(), values.item(i).value()); + } + } + catch (Bounds ex) + { + throw new Error("Please report this bug."); + } + } +} diff --git a/libjava/classpath/gnu/CORBA/gnuContextList.java b/libjava/classpath/gnu/CORBA/gnuContextList.java new file mode 100644 index 000000000..592eb2c2c --- /dev/null +++ b/libjava/classpath/gnu/CORBA/gnuContextList.java @@ -0,0 +1,81 @@ +/* gnuContextList.java -- + 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.CORBA; + +import org.omg.CORBA.Bounds; +import org.omg.CORBA.ContextList; + +/** + * The working implementation of the {@link org.omg.CORBA.ContextList}. + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class gnuContextList + extends ContextList +{ + /** + * The collection, holding the actual list of strings. + */ + CorbaList strings = new CorbaList(); + + /** {@inheritDoc} */ + public void add(String name) + { + strings.add(name); + } + + /** {@inheritDoc} */ + public int count() + { + return strings.size(); + } + + /** {@inheritDoc} */ + public String item(int at) + throws Bounds + { + return (String) strings.item(at); + } + + /** {@inheritDoc} */ + public void remove(int at) + throws Bounds + { + strings.drop(at); + } +} diff --git a/libjava/classpath/gnu/CORBA/gnuEnvironment.java b/libjava/classpath/gnu/CORBA/gnuEnvironment.java new file mode 100644 index 000000000..beb805e6f --- /dev/null +++ b/libjava/classpath/gnu/CORBA/gnuEnvironment.java @@ -0,0 +1,72 @@ +/* gnuEnvironment.java -- + 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.CORBA; + +import org.omg.CORBA.Environment; + +/** + * The implementation of the exception container ("Environment"). + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class gnuEnvironment + extends Environment +{ + /** + * The stored exception. + */ + protected Exception exception; + + /** {@inheritDoc} */ + public void clear() + { + exception = null; + } + + /** {@inheritDoc} */ + public void exception(Exception except) + { + exception = except; + } + + /** {@inheritDoc} */ + public Exception exception() + { + return exception; + } +} diff --git a/libjava/classpath/gnu/CORBA/gnuExceptionList.java b/libjava/classpath/gnu/CORBA/gnuExceptionList.java new file mode 100644 index 000000000..06ddf8d71 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/gnuExceptionList.java @@ -0,0 +1,82 @@ +/* gnuExceptionList.java -- + 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.CORBA; + +import org.omg.CORBA.Bounds; +import org.omg.CORBA.ExceptionList; +import org.omg.CORBA.TypeCode; + +/** + * The implementation of the list of type codes for exceptions. + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org). + */ +public class gnuExceptionList + extends ExceptionList +{ + /** + * A list to store the objects. + */ + protected CorbaList list = new CorbaList(); + + /** {@inheritDoc} */ + public void add(TypeCode an_exception) + { + list.add(an_exception); + } + + /** {@inheritDoc} */ + public int count() + { + return list.size(); + } + + /** {@inheritDoc} */ + public TypeCode item(int at) + throws Bounds + { + return (TypeCode) list.item(at); + } + + /** {@inheritDoc} */ + public void remove(int at) + throws Bounds + { + list.drop(at); + } +} diff --git a/libjava/classpath/gnu/CORBA/gnuNVList.java b/libjava/classpath/gnu/CORBA/gnuNVList.java new file mode 100644 index 000000000..3645a3e8d --- /dev/null +++ b/libjava/classpath/gnu/CORBA/gnuNVList.java @@ -0,0 +1,127 @@ +/* gnuNVList.java -- + 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.CORBA; + +import org.omg.CORBA.Any; +import org.omg.CORBA.Bounds; +import org.omg.CORBA.NVList; +import org.omg.CORBA.NamedValue; + +/** + * The implementation of {@link NVList}. + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class gnuNVList + extends NVList +{ + /** + * The list of the named values. + */ + protected CorbaList list; + + /** + * Creates the list with the default initial size. + */ + public gnuNVList() + { + list = new CorbaList(); + } + + /** + * Creates the list with the given initial size. + */ + public gnuNVList(int initial_size) + { + list = new CorbaList(initial_size); + } + + /** {@inheritDoc} */ + public NamedValue add(int a_flags) + { + return add_value(null, new gnuAny(), a_flags); + } + + /** {@inheritDoc} */ + public NamedValue add_item(String a_name, int a_flags) + { + return add_value(a_name, new gnuAny(), a_flags); + } + + /** {@inheritDoc} */ + public NamedValue add_value(String a_name, Any a_value, int a_flags) + { + gnuNamedValue n = new gnuNamedValue(); + n.setName(a_name); + n.setValue(a_value); + n.setFlags(a_flags); + list.add(n); + return n; + } + + /** + * Add the given named value to the list directly. + * + * @param value the named vaue to add. + */ + public void add(NamedValue value) + { + list.add(value); + } + + + /** {@inheritDoc} */ + public int count() + { + return list.size(); + } + + /** {@inheritDoc} */ + public NamedValue item(int at) + throws Bounds + { + return (NamedValue) list.item(at); + } + + /** {@inheritDoc} */ + public void remove(int at) + throws Bounds + { + list.drop(at); + } +} diff --git a/libjava/classpath/gnu/CORBA/gnuNamedValue.java b/libjava/classpath/gnu/CORBA/gnuNamedValue.java new file mode 100644 index 000000000..6e3c271c9 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/gnuNamedValue.java @@ -0,0 +1,112 @@ +/* gnuNamedValue.java -- + 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.CORBA; + +import org.omg.CORBA.Any; +import org.omg.CORBA.NamedValue; + +/** + * The implementation of the named value. + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class gnuNamedValue + extends NamedValue +{ + /** + * The named value value. + */ + private Any m_value = new gnuAny(); + + /** + * The named value name. + */ + private String m_name; + + /** + * The named value flags. + */ + private int m_flags; + + /** + * Set the flags, the normally expected values are + * {@link org.omg.CORBA.ARG_IN#value}, + * {@link org.omg.CORBA.ARG_OUT#value} and + * {@link org.omg.CORBA.ARG_INOUT#value}. + */ + public void setFlags(int flags) + { + m_flags = flags; + } + + /** + * Set the name of the value. + * @param name the name of this value + */ + public void setName(String name) + { + m_name = name; + } + + /** + * Set the value of the value. + * @param value the value of this object. + */ + public void setValue(Any value) + { + m_value = value; + } + + /** {@inheritDoc} */ + public int flags() + { + return m_flags; + } + + /** {@inheritDoc} */ + public String name() + { + return m_name; + } + + /** {@inheritDoc} */ + public Any value() + { + return m_value; + } +} diff --git a/libjava/classpath/gnu/CORBA/gnuRequest.java b/libjava/classpath/gnu/CORBA/gnuRequest.java new file mode 100644 index 000000000..56c9dbb1f --- /dev/null +++ b/libjava/classpath/gnu/CORBA/gnuRequest.java @@ -0,0 +1,1423 @@ +/* gnuRequest.java -- + 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.CORBA; + +import gnu.CORBA.CDR.BufferredCdrInput; +import gnu.CORBA.CDR.BufferedCdrOutput; +import gnu.CORBA.GIOP.MessageHeader; +import gnu.CORBA.GIOP.ReplyHeader; +import gnu.CORBA.GIOP.RequestHeader; +import gnu.CORBA.GIOP.CodeSetServiceContext; +import gnu.CORBA.Interceptor.gnuClientRequestInfo; +import gnu.CORBA.Poa.ORB_1_4; + +import org.omg.CORBA.ARG_IN; +import org.omg.CORBA.ARG_INOUT; +import org.omg.CORBA.ARG_OUT; +import org.omg.CORBA.Any; +import org.omg.CORBA.BAD_INV_ORDER; +import org.omg.CORBA.BAD_PARAM; +import org.omg.CORBA.Bounds; +import org.omg.CORBA.COMM_FAILURE; +import org.omg.CORBA.CompletionStatus; +import org.omg.CORBA.Context; +import org.omg.CORBA.ContextList; +import org.omg.CORBA.Environment; +import org.omg.CORBA.ExceptionList; +import org.omg.CORBA.INV_POLICY; +import org.omg.CORBA.MARSHAL; +import org.omg.CORBA.NO_IMPLEMENT; +import org.omg.CORBA.NO_RESOURCES; +import org.omg.CORBA.NVList; +import org.omg.CORBA.NamedValue; +import org.omg.CORBA.ORB; +import org.omg.CORBA.Policy; +import org.omg.CORBA.Request; +import org.omg.CORBA.SystemException; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.UnknownUserException; +import org.omg.CORBA.portable.ObjectImpl; +import org.omg.IOP.ServiceContext; +import org.omg.IOP.TAG_CODE_SETS; +import org.omg.IOP.TAG_INTERNET_IOP; +import org.omg.IOP.TaggedComponent; +import org.omg.IOP.TaggedProfile; +import org.omg.PortableInterceptor.ClientRequestInfo; +import org.omg.PortableInterceptor.ClientRequestInterceptorOperations; +import org.omg.PortableInterceptor.ForwardRequest; +import org.omg.PortableInterceptor.InvalidSlot; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import java.net.Socket; + +import java.util.ArrayList; + +/** + * The implementation of the CORBA request. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class gnuRequest extends Request implements Cloneable +{ + /** + * The maximal supported GIOP version. + */ + public static Version MAX_SUPPORTED = new Version(1, 2); + + /** + * The initial pause that the Request makes when the required port is not + * available. + */ + public static int PAUSE_INITIAL = 50; + + /** + * The number of repretetive attempts to get a required port, if it is not + * immediately available. + */ + public static int PAUSE_STEPS = 12; + + /** + * The maximal pausing interval between two repetetive attempts. The interval + * doubles after each unsuccessful attempt, but will not exceed this value. + */ + public static int PAUSE_MAX = 1000; + + /** + * The interceptor, listening the major request submission points. + */ + ClientRequestInterceptorOperations m_interceptor; + + /** + * The request info, used by interceptor. + */ + ClientRequestInfo m_info = new gnuClientRequestInfo(this); + + /** + * The empty byte array. + */ + private static final RawReply EMPTY = + new RawReply(null, new MessageHeader(), new byte[ 0 ]); + + /** + * The context holder for methods ctx(Context) and ctx(). + */ + protected Context m_context; + + /** + * The context list for method contexts(). + */ + protected ContextList m_context_list; + + /** + * The request environment for holding the exception the has possibly been + * thrown by the method being invoked. + */ + protected Environment m_environment = new gnuEnvironment(); + + /** + * The list of all exceptions that can be thrown by the method being invoked. + */ + protected ExceptionList m_exceptions = new gnuExceptionList(); + + /** + * The result, returned by the invoked method (function). + */ + protected NamedValue m_result = new gnuNamedValue(); + + /** + * The exception id, received from the server, null if none. + */ + protected String m_exception_id; + + /** + * The thrown system exception. + */ + protected SystemException m_sys_ex; + + /** + * The invocation target. + */ + protected org.omg.CORBA.Object m_target; + + /** + * The name of the method being invoked. + */ + protected String m_operation; + + /** + * This field temporary remembers the value of the forwarded ior reference. If + * it is not null, the request was forwarded and the effective target is not + * the same as the default target. + */ + public IOR m_forward_ior; + + /** + * Is set when object, and not IOR is directly available. + */ + public org.omg.CORBA.Object m_forwarding_target; + + /** + * The flag, indicating that the request has been sent and the result is + * already received. + */ + protected boolean complete; + + /** + * The flag, indicating that the response to this request must be ignored + * (used with {@link #send_oneway()}). + */ + protected boolean oneWay; + + /** + * The flag, indicating that the request has been sent and no result is yet + * received. + */ + protected boolean running; + + /** + * The request arguments. + */ + protected gnuNVList m_args = new gnuNVList(); + + /** + * The request arguments in the case when they are directly written into the + * parameter buffer. + */ + protected StreamBasedRequest m_parameter_buffer; + + /** + * The array of slots. + */ + protected Any[] m_slots; + + /** + * The request header currently in use. + */ + protected RequestHeader m_rqh; + + /** + * The reply header currently in use. + */ + protected ReplyHeader m_rph; + + /** + * The IOR of the target. + */ + private IOR ior; + + /** + * The ORB of the target. + */ + private ORB orb; + + /** + * The encoding, used to send the message. + * + * The default encoding is inherited from the set IOR (that string reference + * can be encoded in either Big or Little endian). If the IOR encoding is not + * known (for example, by obtaining the reference from the naming service), + * the Big Endian is used. + */ + private boolean Big_endian = true; + + /** + * Set the IOR data, sufficient to find the invocation target. This also sets + * default endian encoding for invocations. + * + * @see IOR.parse(String) + */ + public void setIor(IOR an_ior) + { + ior = an_ior; + setBigEndian(ior.Big_Endian); + } + + /** + * Used when redirecting request to another target. + */ + gnuRequest redirected; + + /** + * Get the IOR data, sufficient to find the invocation target. + * + * @return the IOR data. + */ + public IOR getIor() + { + return ior; + } + + /** + * Set the ORB, related to the invocation target. + */ + public void setORB(ORB an_orb) + { + orb = an_orb; + + // Take the interceptor from the ORB. + if (orb instanceof OrbRestricted) + m_interceptor = ((OrbRestricted) orb).iClient; + + if (m_interceptor != null && orb instanceof ORB_1_4) + { + m_slots = ((ORB_1_4) orb).ic_current.clone_slots(); + } + } + + /** + * Set the encoding that will be used to send the message. The default + * encoding is inherited from the set IOR (that string reference can be + * encoded in either Big or Little endian). If the IOR encoding is not known + * (for example, by obtaining the reference from the naming service), the Big + * Endian is used. + * + * @param use_big_endian true to use the Big Endian, false to use the Little + * Endian encoding. + */ + public void setBigEndian(boolean use_big_endian) + { + Big_endian = use_big_endian; + } + + /** + * The the method name to invoke. + * + * @param operation the method name. + */ + public void setOperation(String operation) + { + m_operation = operation; + } + + /** + * Get the parameter stream, where the invocation arguments should be written + * if they are written into the stream directly. + */ + public StreamBasedRequest getParameterStream() + { + m_parameter_buffer = new StreamBasedRequest(); + m_parameter_buffer.request = this; + m_parameter_buffer.setVersion(ior.Internet.version); + m_parameter_buffer.setCodeSet(CodeSetServiceContext.negotiate(ior.Internet.CodeSets)); + m_parameter_buffer.setOrb(orb); + m_parameter_buffer.setBigEndian(Big_endian); + + // For the old iiop versions, it is important to set the size + // correctly. + if (ior.Internet.version.until_inclusive(1, 1)) + { + BufferedCdrOutput measure = new BufferedCdrOutput(); + measure.setOffset(12); + if (m_rqh == null) + m_rqh = new gnu.CORBA.GIOP.v1_0.RequestHeader(); + m_rqh.operation = m_operation; + m_rqh.object_key = ior.key; + m_rqh.write(measure); + m_parameter_buffer.setOffset(12 + measure.buffer.size()); + } + + return m_parameter_buffer; + } + + /** + * Creates a shallow copy of this request. + */ + public gnuRequest Clone() + { + try + { + return (gnuRequest) clone(); + } + catch (CloneNotSupportedException ex) + { + throw new Unexpected(ex); + } + } + + /** {@inheritDoc} */ + public Any add_in_arg() + { + gnuNamedValue v = new gnuNamedValue(); + v.setFlags(ARG_IN.value); + m_args.add(v); + return v.value(); + } + + /** {@inheritDoc} */ + public Any add_inout_arg() + { + gnuNamedValue v = new gnuNamedValue(); + v.setFlags(ARG_INOUT.value); + m_args.add(v); + return v.value(); + } + + /** {@inheritDoc} */ + public Any add_named_in_arg(String name) + { + gnuNamedValue v = new gnuNamedValue(); + v.setFlags(ARG_IN.value); + v.setName(name); + m_args.add(v); + return v.value(); + } + + /** {@inheritDoc} */ + public Any add_named_inout_arg(String name) + { + gnuNamedValue v = new gnuNamedValue(); + v.setFlags(ARG_INOUT.value); + v.setName(name); + m_args.add(v); + return v.value(); + } + + /** {@inheritDoc} */ + public Any add_named_out_arg(String name) + { + gnuNamedValue v = new gnuNamedValue(); + v.setFlags(ARG_OUT.value); + v.setName(name); + m_args.add(v); + return v.value(); + } + + /** {@inheritDoc} */ + public Any add_out_arg() + { + gnuNamedValue v = new gnuNamedValue(); + v.setFlags(ARG_OUT.value); + m_args.add(v); + return v.value(); + } + + /** {@inheritDoc} */ + public NVList arguments() + { + return m_args; + } + + /** {@inheritDoc} */ + public ContextList contexts() + { + return m_context_list; + } + + /** {@inheritDoc} */ + public Context ctx() + { + return m_context; + } + + /** {@inheritDoc} */ + public void ctx(Context a_context) + { + m_context = a_context; + } + + /** {@inheritDoc} */ + public Environment env() + { + return m_environment; + } + + /** {@inheritDoc} */ + public ExceptionList exceptions() + { + return m_exceptions; + } + + /** {@inheritDoc} */ + public void get_response() throws org.omg.CORBA.WrongTransaction + { + /** + * The response is ready after it is received. FIXME implement context + * checks and any other functionality, if required. + */ + } + + /** + * Submit the request, suspending the current thread until the answer is + * received. + * + * This implementation requires to set the IOR property ({@link #setIOR(IOR)} + * before calling this method. + * + * @throws BAD_INV_ORDER, minor code 0, if the IOR has not been previously + * set. + * + * @throws SystemException if this exception has been thrown on remote side. + * The exact exception type and the minor code are the same as they have been + * for the exception, thrown on remoted side. + */ + public synchronized void invoke() throws BAD_INV_ORDER + { + waitWhileBusy(); + complete = false; + running = true; + + if (ior == null) + throw new BAD_INV_ORDER("Set IOR property first"); + + try + { + Forwardings: + while (true) + { + try + { + p_invoke(); + break Forwardings; + } + catch (ForwardRequest e) + { + try + { + ObjectImpl impl = (ObjectImpl) e.forward; + SimpleDelegate delegate = + (SimpleDelegate) impl._get_delegate(); + ior = delegate.getIor(); + } + catch (Exception ex) + { + BAD_PARAM bad = + new BAD_PARAM("Unsupported forwarding target"); + bad.initCause(ex); + throw bad; + } + } + } + } + finally + { + running = false; + complete = true; + } + } + + /** {@inheritDoc} */ + public String operation() + { + return m_operation; + } + + /** + * Get the orb, related to the invocation target. + */ + public ORB orb() + { + return orb; + } + + /** {@inheritDoc} */ + public boolean poll_response() + { + return complete && !running; + } + + /** {@inheritDoc} */ + public NamedValue result() + { + return m_result; + } + + /** + * {@inheritDoc} + * + */ + public Any return_value() + { + return m_result.value(); + } + + /** {@inheritDoc} */ + public synchronized void send_deferred() + { + waitWhileBusy(); + new Thread() + { + public void run() + { + invoke(); + } + }.start(); + } + + /** + * Send a request and forget about it, not waiting for a response. This can be + * done also for methods that normally are expected to return some values. + * + * TODO It is generally recommended to reuse the threads. Reuse? + */ + public void send_oneway() + { + final gnuRequest cloned = Clone(); + cloned.oneWay = true; + + new Thread() + { + public void run() + { + cloned.invoke(); + } + }.start(); + } + + /** + * Set the argument list. This field is initialised as empty non null instance + * by default, so the method is only used in cases when the direct replacement + * is desired. + * + * @param a_args the argument list. + */ + public void set_args(NVList a_args) + { + if (a_args instanceof gnuNVList) + m_args = (gnuNVList) a_args; + else + { + try + { + // In case if this is another implementation of the NVList. + m_args.list.clear(); + for (int i = 0; i < a_args.count(); i++) + { + m_args.add(a_args.item(i)); + } + } + catch (Bounds ex) + { + Unexpected.error(ex); + } + } + } + + /** + * Set the context list that is later returned by the method + * {@link #contexts()}. + * + * @param a_context_list a new context list. + */ + public void set_context_list(ContextList a_context_list) + { + m_context_list = a_context_list; + } + + /** + * Set the exception container. This field is initialised as empty non null + * instance by default, so the method is only used in cases when the direct + * replacement is desired. + * + * @param a_environment the new exception container. + */ + public void set_environment(Environment a_environment) + { + m_environment = a_environment; + } + + /** + * Set the list of exceptions. This field is initialised as empty non null + * instance by default, so the method is only used in cases when the direct + * replacement is desired. + * + * @param a_exceptions a list of exceptions. + */ + public void set_exceptions(ExceptionList a_exceptions) + { + m_exceptions = a_exceptions; + } + + /** + * Set the operation name. + * + * @param a_operation the operation name. + */ + public void set_operation(String a_operation) + { + m_operation = a_operation; + } + + /** + * Set the named value, returned as result. This field is initialised as empty + * non null instance by default, so the method is only used in cases when the + * direct replacement is desired. + * + * @param a_result the result keeper. + */ + public void set_result(NamedValue a_result) + { + m_result = a_result; + } + + /** + * Set the type of the named value, returned as a result. Instantiates a new + * instance of the result value. + */ + public void set_return_type(TypeCode returns) + { + if (m_result == null || !returns.equal(m_result.value().type())) + { + m_result = new gnuNamedValue(); + m_result.value().type(returns); + } + } + + /** + * Set the invocation target. + * + * @param a_target the CORBA object for that the method will be invoked. + */ + public void set_target(org.omg.CORBA.Object a_target) + { + m_target = a_target; + } + + /** + * Do the actual invocation. This implementation requires to set the IOR + * property ({@link #setIOR(IOR)} before calling this method. + * + * @throws BAD_INV_ORDER, minor code 0, if the IOR has not been previously set + * or if the direct argument addition is mixed with the direct + * argument writing into the output stream. + * @return the server response in binary form. + */ +public synchronized RawReply submit() + throws ForwardRequest + { + gnu.CORBA.GIOP.MessageHeader header = new gnu.CORBA.GIOP.MessageHeader(); + + header.setBigEndian(Big_endian); + + // The byte order will be Big Endian by default. + header.message_type = gnu.CORBA.GIOP.MessageHeader.REQUEST; + header.version = useVersion(ior.Internet.version); + + RequestHeader rh = header.create_request_header(); + rh.operation = m_operation; + rh.object_key = ior.key; + + // Update interceptor. + m_rqh = rh; + + if (m_interceptor != null) + m_interceptor.send_request(m_info); + + // Prepare the submission. + BufferedCdrOutput request_part = new BufferedCdrOutput(); + + request_part.setOffset(header.getHeaderSize()); + request_part.setVersion(header.version); + request_part.setCodeSet(CodeSetServiceContext.negotiate(ior.Internet.CodeSets)); + request_part.setOrb(orb); + request_part.setBigEndian(header.isBigEndian()); + + // This also sets the stream encoding to the encoding, specified + // in the header. + rh.write(request_part); + + if (m_args != null && m_args.count() > 0) + { + write_parameters(header, request_part); + + if (m_parameter_buffer != null) + throw new BAD_INV_ORDER("Please either add parameters or " + + "write them into stream, but not both " + "at once."); + } + + if (m_parameter_buffer != null) + { + write_parameter_buffer(header, request_part); + } + + // Now the message size is available. + header.message_size = request_part.buffer.size(); + + Socket socket = null; + + java.lang.Object key = ior.Internet.host + ":" + ior.Internet.port; + + synchronized (SocketRepository.class) + { + socket = SocketRepository.get_socket(key); + } + + try + { + long pause = PAUSE_INITIAL; + + if (socket == null) + { + // The IOException may be thrown under very heavy parallel + // load. For some time, just wait, exceptiong the socket to free. + Open: for (int i = 0; i < PAUSE_STEPS; i++) + { + try + { + if (orb instanceof OrbFunctional) + socket = ((OrbFunctional) orb).socketFactory. + createClientSocket( + ior.Internet.host, ior.Internet.port); + else + socket = new Socket(ior.Internet.host, ior.Internet.port); + break Open; + } + catch (IOException ex) + { + try + { + // Expecting to free a socket via finaliser. + System.gc(); + Thread.sleep(pause); + pause = pause * 2; + if (pause > PAUSE_MAX) + pause = PAUSE_MAX; + } + catch (InterruptedException iex) + { + } + } + } + } + + if (socket == null) + throw new NO_RESOURCES(ior.Internet.host + ":" + ior.Internet.port + + " in use"); + socket.setKeepAlive(true); + + OutputStream socketOutput = socket.getOutputStream(); + + // Write the message header. + header.write(socketOutput); + + // Write the request header and parameters (if present). + request_part.buffer.writeTo(socketOutput); + + socketOutput.flush(); + if (!socket.isClosed() && !oneWay) + { + MessageHeader response_header = new MessageHeader(); + InputStream socketInput = socket.getInputStream(); + response_header.read(socketInput); + + byte[] r; + if (orb instanceof OrbFunctional) + { + OrbFunctional fo = (OrbFunctional) orb; + r = response_header.readMessage(socketInput, socket, + fo.TOUT_WHILE_READING, fo.TOUT_AFTER_RECEIVING); + } + else + r = response_header.readMessage(socketInput, null, 0, 0); + + return new RawReply(orb, response_header, r); + } + else + return EMPTY; + } + catch (IOException io_ex) + { + COMM_FAILURE m = new COMM_FAILURE("Unable to open a socket at " + + ior.Internet.host + ":" + ior.Internet.port, 0xC9, + CompletionStatus.COMPLETED_NO); + m.initCause(io_ex); + throw m; + } + finally + { + try + { + if (socket != null && !socket.isClosed()) + { + socket.setSoTimeout(OrbFunctional.TANDEM_REQUESTS); + SocketRepository.put_socket(key, socket); + } + } + catch (IOException scx) + { + InternalError ierr = new InternalError(); + ierr.initCause(scx); + throw ierr; + } + } + } + + /** {@inheritDoc} */ + public org.omg.CORBA.Object target() + { + return m_target; + } + + /** + * Get the used version. Normally, it is better to respond using the same + * version as it is specified in IOR, but not above the maximal supported + * version. + */ + public Version useVersion(Version desired) + { + if (desired.until_inclusive(MAX_SUPPORTED.major, MAX_SUPPORTED.minor)) + return desired; + else + return MAX_SUPPORTED; + } + + /** + * Wait while the response to request, submitted using + * {@link #send_deferred()} or {@link #invoke()} (from other thread) is + * returned. + * + * FIXME It is possible to rewrite this using Object.wait() and + * Object.notify(), but be sure to prepare the test as well. + */ + public synchronized void waitWhileBusy() + { + // Waiting constants. + long wait = 10; + long increment = 2; + long max = 5000; + + while (running) + { + try + { + Thread.sleep(wait); + if (wait < max) + wait = wait * increment; + } + catch (InterruptedException ex) + { + } + } + } + + /** + * Do actual invocation. This method recursively calls itself if the + * redirection is detected. + */ + private void p_invoke() + throws SystemException, ForwardRequest + { + RawReply response = submit(); + + // If this is a one way message, do not care about the response. + if (oneWay && response == EMPTY) + return; + + if (m_rph == null) + m_rph = response.header.create_reply_header(); + + BufferredCdrInput input = response.getStream(); + input.setOrb(orb); + + m_rph.read(input); + + // The stream must be aligned sinve v1.2, but only once. + boolean align = response.header.version.since_inclusive(1, 2); + + switch (m_rph.reply_status) + { + case ReplyHeader.NO_EXCEPTION: + + NamedValue arg; + + // Read return value, if set. + if (m_result != null) + { + if (align) + { + input.align(8); + align = false; + } + m_result.value().read_value(input, m_result.value().type()); + } + + // Read returned parameters, if set. + if (m_args != null) + for (int i = 0; i < m_args.count(); i++) + { + try + { + arg = m_args.item(i); + + // Both ARG_INOUT and ARG_OUT have this binary flag set. + if ((arg.flags() & ARG_OUT.value) != 0) + { + if (align) + { + input.align(8); + align = false; + } + + arg.value().read_value(input, arg.value().type()); + } + } + catch (Bounds ex) + { + Unexpected.error(ex); + } + } + + if (m_interceptor != null) + m_interceptor.receive_reply(m_info); + + break; + + case ReplyHeader.SYSTEM_EXCEPTION: + if (align) + { + input.align(8); + align = false; + } + readExceptionId(input); + + m_sys_ex = ObjectCreator.readSystemException(input, + m_rph.service_context); + m_environment.exception(m_sys_ex); + + if (m_interceptor != null) + m_interceptor.receive_exception(m_info); + + throw m_sys_ex; + + case ReplyHeader.USER_EXCEPTION: + if (align) + { + input.align(8); + align = false; + } + readExceptionId(input); + + // Prepare an Any that will hold the exception. + gnuAny exc = new gnuAny(); + exc.setOrb(orb); + + exc.insert_Streamable(new StreamHolder(input)); + + UnknownUserException unuex = new UnknownUserException(exc); + m_environment.exception(unuex); + + if (m_interceptor != null) + m_interceptor.receive_exception(m_info); + + break; + + case ReplyHeader.LOCATION_FORWARD_PERM: + case ReplyHeader.LOCATION_FORWARD: + if (response.header.version.since_inclusive(1, 2)) + input.align(8); + + IOR forwarded = new IOR(); + try + { + forwarded._read_no_endian(input); + } + catch (IOException ex) + { + new MARSHAL("Cant read forwarding info", 5103, + CompletionStatus.COMPLETED_NO); + } + + setIor(forwarded); + + m_forward_ior = forwarded; + + if (m_interceptor != null) + m_interceptor.receive_other(m_info); + + // Repeat with the forwarded information. + p_invoke(); + return; + + default: + throw new MARSHAL("Unknow reply status", 8100 + m_rph.reply_status, + CompletionStatus.COMPLETED_NO); + } + } + + /** + * Read exception id without changing the stream pointer position. + */ + void readExceptionId(BufferredCdrInput input) + { + input.mark(2048); + m_exception_id = input.read_string(); + input.reset(); + } + + /** + * Write the operation parameters. + * + * @param header the message header + * @param request_part the stream to write parameters into + * + * @throws MARSHAL if the attempt to write the parameters has failde. + */ + protected void write_parameter_buffer(MessageHeader header, + BufferedCdrOutput request_part + ) throws MARSHAL + { + try + { + if (header.version.since_inclusive(1, 2)) + { + request_part.align(8); + } + m_parameter_buffer.buffer.writeTo(request_part); + } + catch (IOException ex) + { + MARSHAL m = new MARSHAL("Unable to write method arguments to CDR output."); + m.minor = Minor.CDR; + throw m; + } + } + + /** + * Write the operation parameters. + * + * @param header the message header + * @param request_part the stream to write parameters into + * + * @throws MARSHAL if the attempt to write the parameters has failde. + */ + protected void write_parameters(MessageHeader header, + BufferedCdrOutput request_part + ) throws MARSHAL + { + // Align after 1.2, but only once. + boolean align = header.version.since_inclusive(1, 2); + NamedValue para; + + try + { + // Write parameters now. + for (int i = 0; i < m_args.count(); i++) + { + para = m_args.item(i); + + // This bit is set both for ARG_IN and ARG_INOUT + if ((para.flags() & ARG_IN.value) != 0) + { + if (align) + { + request_part.align(8); + align = false; + } + para.value().write_value(request_part); + } + } + } + catch (Bounds ex) + { + InternalError ierr = new InternalError(); + ierr.initCause(ex); + throw ierr; + } + } + + /* **************Implementation of the request info operations. ***** */ + + /** + * Add context to request. + */ + public void add_request_service_context(ServiceContext service_context, + boolean replace + ) + { + m_rqh.addContext(service_context, replace); + } + + /** + * Get the Internet profile as an effective profile. + */ + public TaggedProfile effective_profile() + { + BufferedCdrOutput buf = new BufferedCdrOutput(512); + buf.setOrb(orb); + ior.Internet.write(buf); + + TaggedProfile p = new TaggedProfile(); + p.tag = TAG_INTERNET_IOP.value; + p.profile_data = buf.buffer.toByteArray(); + return p; + } + + /** + * Return either target or forwarded targed. + */ + public org.omg.CORBA.Object effective_target() + { + return new IorObject(orb, ior); + } + + /** + * Get effective component with the give id from the Internet profile. + */ + public TaggedComponent get_effective_component(int id) + throws BAD_PARAM + { + if (id == TAG_CODE_SETS.value) + { + // Codesets are encoded separately. + BufferedCdrOutput buf = new BufferedCdrOutput(512); + buf.setOrb(orb); + ior.Internet.CodeSets.write(buf); + + TaggedComponent t = new TaggedComponent(); + t.tag = TAG_CODE_SETS.value; + t.component_data = buf.buffer.toByteArray(); + return t; + } + else + { + for (int i = 0; i < ior.Internet.components.size(); i++) + { + TaggedComponent c = + (TaggedComponent) ior.Internet.components.get(i); + if (c.tag == id) + return c; + } + } + throw new BAD_PARAM("No component " + id + " in the Internet profile", 28, + CompletionStatus.COMPLETED_MAYBE + ); + } + + /** + * Get all components with the given id from the internet profile. + */ + public TaggedComponent[] get_effective_components(int id) + throws BAD_PARAM + { + if (id == TAG_CODE_SETS.value) + return new TaggedComponent[] { get_effective_component(TAG_CODE_SETS.value) }; + else + { + ArrayList components = new ArrayList(ior.Internet.components.size()); + for (int i = 0; i < ior.Internet.components.size(); i++) + { + TaggedComponent c = + (TaggedComponent) ior.Internet.components.get(i); + if (c.tag == id) + components.add(c); + } + if (components.size() == 0) + throw new BAD_PARAM("No component " + id + + " in the Internet profile", 28, CompletionStatus.COMPLETED_MAYBE + ); + else + { + TaggedComponent[] t = new TaggedComponent[ components.size() ]; + for (int i = 0; i < t.length; i++) + t [ i ] = (TaggedComponent) components.get(i); + return t; + } + } + } + + /** + * This should be not implemented up till jdk 1.5 inclusive. + */ + public Policy get_request_policy(int type) throws INV_POLICY + { + throw new NO_IMPLEMENT(); + } + + /** @inheritDoc */ + public String received_exception_id() + { + return m_exception_id; + } + + /** @inheritDoc */ + public Any received_exception() + { + if (m_exception_id == null) + return null; + + if (m_sys_ex != null) + { + Any a = orb.create_any(); + ObjectCreator.insertSysException(a, m_sys_ex); + return a; + } + + Exception mex = m_environment.exception(); + + UnknownUserException ex = (UnknownUserException) mex; + if (ex == null) + return null; + else + return ex.except; + } + + /** + * Return the forwarded reference, null if none. + */ + public org.omg.CORBA.Object forward_reference() + { + if (m_forwarding_target != null) + return m_forwarding_target; + + if (m_forward_ior != null) + return new IorObject(orb, m_forward_ior); + else + return null; + } + + /** + * Get the slot from the slot array inside this request. + */ + public Any get_slot(int id) throws InvalidSlot + { + try + { + return m_slots [ id ]; + } + catch (Exception e) + { + throw new InvalidSlot("slot id " + id + ":" + e); + } + } + + /** + * Get the reply status. + */ + public short reply_status() + { + if (m_rph == null) + throw new BAD_INV_ORDER("Request not yet sent", 14, + CompletionStatus.COMPLETED_NO + ); + return (short) m_rph.reply_status; + } + + /** + * Get the request id. + */ + public int request_id() + { + return m_rqh.request_id; + } + + /** + * Return true if the response is expected. + */ + public boolean response_expected() + { + return !oneWay; + } + + /** + * Determines how far the request shall progress before control is returned to + * the client. However up till JDK 1.5 inclusive this method always returns + * SYNC_WITH_TRANSPORT. + * + * @return {@link org.omg.Messaging.SYNC_WITH_TRANSPORT.value (1), always. + * + * @specnote as defined in the Suns 1.5 JDK API. + */ + public short sync_scope() + { + return org.omg.Messaging.SYNC_WITH_TRANSPORT.value; + } + + /** @inheritDoc */ + public ServiceContext get_request_service_context(int ctx_name) + throws BAD_PARAM + { + return gnu.CORBA.GIOP.ServiceContext.findContext(ctx_name, + m_rqh.service_context + ); + } + + /** @inheritDoc */ + public ServiceContext get_reply_service_context(int ctx_name) + throws BAD_PARAM + { + if (m_rph == null) + throw new BAD_INV_ORDER("Reply context not yet available"); + return gnu.CORBA.GIOP.ServiceContext.findContext(ctx_name, + m_rph.service_context + ); + } + + /** @inheritDoc */ + public String[] operation_context() + { + return ice_contexts(); + } + + /** + * Get contexts as required by interceptor. + */ + public String[] ice_contexts() + { + if (m_context_list == null) + return new String[ 0 ]; + else + { + try + { + String[] cn = new String[ m_context_list.count() ]; + for (int i = 0; i < cn.length; i++) + cn [ i ] = m_context_list.item(i); + return cn; + } + catch (Bounds e) + { + throw new Unexpected(e); + } + } + } + + /** + * Check if the call is done via DII. + */ + public void checkDii() + { + if (m_parameter_buffer != null) + throw new NO_RESOURCES("The invocation method provides " + + "no access to this resource. DII call required.", 1, + CompletionStatus.COMPLETED_MAYBE + ); + } +} diff --git a/libjava/classpath/gnu/CORBA/gnuValueHolder.java b/libjava/classpath/gnu/CORBA/gnuValueHolder.java new file mode 100644 index 000000000..d3f2b6b58 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/gnuValueHolder.java @@ -0,0 +1,135 @@ +/* gnuValueHolder.java -- + 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.CORBA; + +import gnu.CORBA.CDR.Vio; + +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.ValueBaseHolder; +import org.omg.CORBA.portable.BoxedValueHelper; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.OutputStream; + +import java.io.Serializable; + +/** + * Boxed value holder that also remembers the value type and the value helper. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class gnuValueHolder + extends ValueBaseHolder +{ + /** + * The type code of the stored value. + */ + TypeCode type; + + /** + * The helper that could read and write fields of the boxed value. + */ + transient BoxedValueHelper helper; + + /** + * If true, the helper not available. + */ + transient boolean helper_NA; + + /** + * Create a new instance for the given value and given type. + */ + public gnuValueHolder(Serializable value, TypeCode a_type) + { + super(value); + type = a_type; + } + + /** + * Get the true type, as it was passed in the constructor. + */ + public TypeCode _type() + { + return type; + } + + /** + * Write content to the output stream. Tries to locate the + * corresponding helper class. + */ + public void _write(OutputStream output) + { + findHelper(); + if (helper == null) + super._write(output); + else + Vio.write(output, value, helper); + } + + /** + * Read, trying to locate helper, if possible. + */ + public void _read(InputStream input) + { + findHelper(); + if (helper == null) + super._read(input); + else + value = Vio.read(input, helper); + } + + /** + * Set the read and write methods. + */ + void findHelper() + { + if (helper != null || helper_NA) + return; + try + { + Class helperClass = + ObjectCreator.forName(ObjectCreator.toHelperName(type.id())); + + helper = (BoxedValueHelper) helperClass.newInstance(); + } + catch (Exception ex) + { + helper_NA = true; + } + } +} diff --git a/libjava/classpath/gnu/CORBA/interfaces/SocketFactory.java b/libjava/classpath/gnu/CORBA/interfaces/SocketFactory.java new file mode 100644 index 000000000..d1d7d418b --- /dev/null +++ b/libjava/classpath/gnu/CORBA/interfaces/SocketFactory.java @@ -0,0 +1,95 @@ +/* SocketFactory.java -- + 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.CORBA.interfaces; + +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; + +/** + * This class produces sockets for serving and submitting CORBA requests. The + * socket factory can be set using {@link gnuOrb.setSocketFactory()} for + * producting all sockets for that ORB. This is needed for using secure sockets, + * for implementing the desired timeout policies, for HTTP tunnels and in some + * other similar cases. While such functionality is provided by near all + * existing CORBA implementations, no standard mechanism is defined. + * + * The socket factory may need to put additional information to the IORs of the + * objects, released by the ORB. Because of this reason, this interface extends + * IORInterceptorOperations. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public interface SocketFactory +{ + /** + * The name of the ORB property that forces the ORB to use the socket + * factory class, the name of that (String) is the value of this property. + */ + final String PROPERTY = "gnu.CORBA.SocketFactory"; + + /** + * Create a server socket that should serve remote invocations on the given + * port. The ORB may use this socket to serve either one or more objects. + * + * @param port the port, on that the socket should be listening for requests. + * The port policy can be controlled by {@link gnuPortManager}. + * + * @throws IOException if the socket cannot be created on the given port due + * any reasons. The ORB may try to open the socket on another port, calling + * this method with the different parameter. + */ + ServerSocket createServerSocket(int port) + throws IOException; + + /** + * Create a client socket that should send a request to the remote side. When + * returned, the socket should be opened and ready to communicate. + * + * @param port the port, on that the socket should be openend. The port is + * usually part of the internet profile. + * + * @throws IOException if the socket cannot be created on the given port due + * any reasons. The ORB may try to open the socket on another port, calling + * this method with the different parameter. + */ + Socket createClientSocket(String host, int port) + throws IOException; + +} diff --git a/libjava/classpath/gnu/CORBA/interfaces/package.html b/libjava/classpath/gnu/CORBA/interfaces/package.html new file mode 100644 index 000000000..101475b2d --- /dev/null +++ b/libjava/classpath/gnu/CORBA/interfaces/package.html @@ -0,0 +1,49 @@ + + + + +GNU Classpath - gnu.CORBA.interfaces + + +

This package contains Classpath specific interfaces that +the user program may be forced to use in cases when no +other, better solution of the problem is available. The +existing classes and methods in this package should not +be removed without the real need

+ + diff --git a/libjava/classpath/gnu/CORBA/typecodes/AliasTypeCode.java b/libjava/classpath/gnu/CORBA/typecodes/AliasTypeCode.java new file mode 100644 index 000000000..41d0fbe8a --- /dev/null +++ b/libjava/classpath/gnu/CORBA/typecodes/AliasTypeCode.java @@ -0,0 +1,148 @@ +/* AliasTypeCode.java -- + 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.CORBA.typecodes; + + +import org.omg.CORBA.TCKind; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.TypeCodePackage.BadKind; + +/** + * The type code that is an alias of another type code. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class AliasTypeCode + extends PrimitiveTypeCode +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * The typecode repository id. + */ + protected final String id; + + /** + * The typecode name. + */ + protected final String name; + + /** + * The type code for that this typecode is an alias. + */ + protected final TypeCode aliasFor; + + /** + * Create the typecode, specifying for that typecode it is an + * alias and the id and name of the newly created typecode. + * + * @param an_aliasFor the typecode, for that this typecode is an + * alias. + * + * @param an_id the repository id fo the newly created typecode. + * + * @param a_name the name of the newly created typecode. + */ + public AliasTypeCode(TypeCode an_aliasFor, String an_id, String a_name) + { + super(TCKind.tk_alias); + aliasFor = an_aliasFor; + id = an_id; + name = a_name; + } + + /** + * Get the typecode, for that this typecode is an alias. + */ + public TypeCode content_type() + { + return aliasFor; + } + + /** + * The objects are assumed to be equal if they repository + * ids are both equal or both unavailable and the + * kind values are equal. + * + * @param other the other typecode to compare. + */ + public boolean equal(TypeCode other) + { + if (super.equal(other)) + return true; + try + { + return id.equals(other.id()); + } + catch (BadKind ex) + { + return false; + } + } + + /** + * Return true if the given typecode is equal for + * either this typecode of the alias typecode. + * + * @param other the typecode to compare. + */ + public boolean equivalent(TypeCode other) + { + return other.equal(this) || other.equal(aliasFor); + } + + /** + * Get the repository id of this typecode. + */ + public String id() + { + return id; + } + + /** + * Get the name of this typecode. + */ + public String name() + { + return name; + } +} diff --git a/libjava/classpath/gnu/CORBA/typecodes/ArrayTypeCode.java b/libjava/classpath/gnu/CORBA/typecodes/ArrayTypeCode.java new file mode 100644 index 000000000..394efb36a --- /dev/null +++ b/libjava/classpath/gnu/CORBA/typecodes/ArrayTypeCode.java @@ -0,0 +1,272 @@ +/* ArrayTypeCode.java -- + 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.CORBA.typecodes; + + +import org.omg.CORBA.TCKind; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.TypeCodePackage.BadKind; + +/** + * A TypeCode for arrays. + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class ArrayTypeCode + extends PrimitiveTypeCode +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + + /** + * The array components. + */ + TypeCode of; + + /** + * The length of the array, must be updated when setting + * a new value. + */ + private int length; + + /** + * Create a primitive array type code, defining the sequence + * {@link TCKind.tk_sequence)} with + * the given member type. + * + * @param array_of the sequence member type. + */ + public ArrayTypeCode(TCKind array_of) + { + super(TCKind.tk_sequence); + of = new PrimitiveTypeCode(array_of); + } + + /** + * Create a primitive array type code, defining the array, sequence + * or other type with the given member type. + * + * @param this_type the type of this type (normally either + * sequence of array). + * @param array_of the sequence member type. + */ + public ArrayTypeCode(TCKind this_type, TypeCode array_of) + { + super(this_type); + of = array_of; + } + + /** + * Return the array component type. + * @return the array component type + * @throws org.omg.CORBA.TypeCodePackage.BadKind + */ + public TypeCode content_type() + throws org.omg.CORBA.TypeCodePackage.BadKind + { + return of; + } + + /** + * Return true if the other TypeCode defines the array, having elements + * of the same type. The sizes of arrays are not taken into + * consideration. + * + * @param other the other TypeCode + * @return true if other is an array with the same + * component type. + */ + public boolean equal(TypeCode other) + { + try + { + return kind() == other.kind() && + content_type() == other.content_type(); + } + catch (BadKind ex) + { + // Should not be thrown. + return false; + } + } + + /** + * Returns the agreed Id in the form of + * IDL:omg.org/CORBA/ {type name} Seq:1.0. + * + * @return the Id of this TypeCode. + * + * @throws org.omg.CORBA.TypeCodePackage.BadKind if the content type + * is not one of the constants, defined in {@link TCKind}. + * This package class should not be used as TypeCode for the arrays, + * holding the user defined components. + */ + public String id() + throws org.omg.CORBA.TypeCodePackage.BadKind + { + switch (content_type().kind().value()) + { + case TCKind._tk_null : + return "IDL:omg.org/CORBA/NullSeq:1.0"; + + case TCKind._tk_void : + return "IDL:omg.org/CORBA/VoidSeq:1.0"; + + case TCKind._tk_short : + return "IDL:omg.org/CORBA/ShortSeq:1.0"; + + case TCKind._tk_long : + return "IDL:omg.org/CORBA/LongSeq:1.0"; + + case TCKind._tk_ushort : + return "IDL:omg.org/CORBA/UShortSeq:1.0"; + + case TCKind._tk_ulong : + return "IDL:omg.org/CORBA/ULongSeq:1.0"; + + case TCKind._tk_float : + return "IDL:omg.org/CORBA/FloatSeq:1.0"; + + case TCKind._tk_double : + return "IDL:omg.org/CORBA/DoubleSeq:1.0"; + + case TCKind._tk_boolean : + return "IDL:omg.org/CORBA/BooleanSeq:1.0"; + + case TCKind._tk_char : + return "IDL:omg.org/CORBA/CharSeq:1.0"; + + case TCKind._tk_octet : + return "IDL:omg.org/CORBA/OctetSeq:1.0"; + + case TCKind._tk_any : + return "IDL:omg.org/CORBA/AnySeq:1.0"; + + case TCKind._tk_TypeCode : + return "IDL:omg.org/CORBA/TypeCodeSeq:1.0"; + + case TCKind._tk_Principal : + return "IDL:omg.org/CORBA/PrincipalSeq:1.0"; + + case TCKind._tk_objref : + return "IDL:omg.org/CORBA/ObjrefSeq:1.0"; + + case TCKind._tk_struct : + return "IDL:omg.org/CORBA/StructSeq:1.0"; + + case TCKind._tk_union : + return "IDL:omg.org/CORBA/UnionSeq:1.0"; + + case TCKind._tk_enum : + return "IDL:omg.org/CORBA/EnumSeq:1.0"; + + case TCKind._tk_string : + return "IDL:omg.org/CORBA/StringSeq:1.0"; + + case TCKind._tk_sequence : + return "IDL:omg.org/CORBA/SequenceSeq:1.0"; + + case TCKind._tk_array : + return "IDL:omg.org/CORBA/ArraySeq:1.0"; + + case TCKind._tk_alias : + return "IDL:omg.org/CORBA/AliasSeq:1.0"; + + case TCKind._tk_except : + return "IDL:omg.org/CORBA/ExceptSeq:1.0"; + + case TCKind._tk_longlong : + return "IDL:omg.org/CORBA/LongLongSeq:1.0"; + + case TCKind._tk_ulonglong : + return "IDL:omg.org/CORBA/ULongLongSeq:1.0"; + + case TCKind._tk_longdouble : + return "IDL:omg.org/CORBA/LongDoubleSeq:1.0"; + + case TCKind._tk_wchar : + return "IDL:omg.org/CORBA/WCharSeq:1.0"; + + case TCKind._tk_wstring : + return "IDL:omg.org/CORBA/WStringSeq:1.0"; + + case TCKind._tk_fixed : + return "IDL:omg.org/CORBA/FixedSeq:1.0"; + + case TCKind._tk_value : + return "IDL:omg.org/CORBA/ValueSeq:1.0"; + + case TCKind._tk_value_box : + return "IDL:omg.org/CORBA/Value_boxSeq:1.0"; + + case TCKind._tk_native : + return "IDL:omg.org/CORBA/NativeSeq:1.0"; + + case TCKind._tk_abstract_interface : + return "IDL:omg.org/CORBA/Abstract_interfaceSeq:1.0"; + + default : + throw new BadKind(); + } + } + + /** + * Return the array length. + * @return the length of the array. + * @throws org.omg.CORBA.TypeCodePackage.BadKind + */ + public int length() + throws org.omg.CORBA.TypeCodePackage.BadKind + { + return length; + } + + /** + * Sets the array length to the supplied value. + * + * @param l the new length. + */ + public void setLength(int l) + { + this.length = l; + } + +} diff --git a/libjava/classpath/gnu/CORBA/typecodes/FixedTypeCode.java b/libjava/classpath/gnu/CORBA/typecodes/FixedTypeCode.java new file mode 100644 index 000000000..9e9f3eff6 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/typecodes/FixedTypeCode.java @@ -0,0 +1,152 @@ +/* FixedTypeCode.java -- + 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.CORBA.typecodes; + + +import java.math.BigDecimal; + +import org.omg.CORBA.TCKind; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.TypeCodePackage.BadKind; + +/** + * A typecode for CORBA fixed + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class FixedTypeCode + extends PrimitiveTypeCode +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + + /** + * The number of the used digits. + */ + private short digits; + + /** + * The number of the digits after the decimal point. + */ + private short scale; + + /** + * Creates the instance of the fixed type code. + */ + public FixedTypeCode() + { + super(TCKind.tk_fixed); + } + + /** + * Creates the instance of the fixed type code, + * setting the digits and scale by example. + */ + public FixedTypeCode(BigDecimal example) + { + super(TCKind.tk_fixed); + if (example != null) + { + setScale(example.scale()); + setDigits(countDigits(example)); + } + } + + /** + * Set the number of digits. + */ + public void setDigits(int a_digits) + { + this.digits = (short) a_digits; + } + + /** + * Set the number of digits after the decimal point. + */ + public void setScale(int a_scale) + { + this.scale = (short) a_scale; + } + + /** + * Get the number of digits in thid BigDecimal + * + * @param number a BigDecimal to check. + */ + public static int countDigits(BigDecimal number) + { + return number.unscaledValue().abs().toString().length(); + } + + /** + * Compare with other type code for equality. + */ + public boolean equal(TypeCode other) + { + if (other == this) return true; + try + { + TypeCode that = (TypeCode) other; + return kind() == that.kind() && digits == that.fixed_digits() && + scale == that.fixed_scale(); + } + catch (BadKind ex) + { + return false; + } + } + + /** + * Get the number of digits. + */ + public short fixed_digits() + { + return digits; + } + + /** + * Get the number of digits after the decimal point. + */ + public short fixed_scale() + { + return scale; + } +} diff --git a/libjava/classpath/gnu/CORBA/typecodes/GeneralTypeCode.java b/libjava/classpath/gnu/CORBA/typecodes/GeneralTypeCode.java new file mode 100644 index 000000000..a00f69823 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/typecodes/GeneralTypeCode.java @@ -0,0 +1,249 @@ +/* GeneralTypeCode.java -- + 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.CORBA.typecodes; + +import gnu.CORBA.CDR.BufferedCdrOutput; + +import java.util.Arrays; +import java.util.BitSet; + +import org.omg.CORBA.TCKind; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.TypeCodePackage.BadKind; + +/** + * A typecode for types, requiring to provide various additional + * properties but still not requiring to store the + * members of the structure. The property can be retrieved + * by the corresponding method if it has been previously assigned. + * Otherwise, a {@link BadKind} is thrown. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class GeneralTypeCode + extends PrimitiveTypeCode +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + + /** + * Indicates that the field value has not been previously set. + */ + protected static int UNSET = Integer.MIN_VALUE; + + /** + * The kinds for that the length() must return 0 even if it + * has not been previously set. + */ + private static final BitSet lengthAllowed = new BitSet(); + + static + { + lengthAllowed.set(TCKind._tk_array); + lengthAllowed.set(TCKind._tk_sequence); + lengthAllowed.set(TCKind._tk_string); + lengthAllowed.set(TCKind._tk_wstring); + } + + private String id; + private String name; + private TypeCode concrete_base_type; + private TypeCode content_type; + private int len; + private int type_modifier = UNSET; + + /** + * Create a new instance, setting kind to the given kind. + * @param a_kind the kind of the typecode being created. + */ + public GeneralTypeCode(TCKind a_kind) + { + super(a_kind); + if (!lengthAllowed.get(a_kind.value())) + len = UNSET; + } + + /** + * Set this property. + */ + public void setConcreteBase_type(TypeCode a_concrete_base_type) + { + this.concrete_base_type = a_concrete_base_type; + } + + /** + * Set the component content type. + */ + public void setContentType(TypeCode a_content_type) + { + this.content_type = a_content_type; + } + + /** + * Set this property. + */ + public void setId(String an_id) + { + this.id = an_id; + } + + /** + * Set the length property. + * @param l + */ + public void setLength(int l) + { + len = l; + } + + /** + * Set this property. + */ + public void setName(String a_name) + { + this.name = a_name; + } + + /** + * Set the type modifier. + */ + public void setTypeModifier(int a_type_modifier) + { + this.type_modifier = a_type_modifier; + } + + /** {@inheritDoc} */ + public TypeCode concrete_base_type() + throws BadKind + { + if (concrete_base_type != null) + return concrete_base_type; + throw new BadKind("concrete_base_type"); + } + + /** + * Returns the content type that must be explicitly set + * for this class. + * + * @throws BadKind if the content type has not been set. + */ + public TypeCode content_type() + throws BadKind + { + if (content_type != null) + return content_type; + throw new BadKind("content_type"); + } + + /** + * Returns true if both typecodes, if written into CDR + * stream, would result the same stream content. + */ + public boolean equal(TypeCode other) + { + if (this == other) + return true; + if (kind() != other.kind()) + return false; + + BufferedCdrOutput a = new BufferedCdrOutput(16); + BufferedCdrOutput b = new BufferedCdrOutput(16); + + a.write_TypeCode(this); + b.write_TypeCode(other); + + return Arrays.equals(a.buffer.toByteArray(), b.buffer.toByteArray()); + } + + /** + * Delegates functionality to {@link #equal}. + */ + public boolean equivalent(TypeCode other) + { + return equal(other); + } + + /** {@inheritDoc} */ + public String id() + throws BadKind + { + if (id != null) + return id; + throw new BadKind("id"); + } + + /** + * Get the length. For sequences, arrays, strings and wstrings + * this method returns 0 rather than throwing a BadKind even + * if {@link setLength(int)} has not been previously called. + * + * @return the length of string, array or sequence. + * + * @throws BadKind if the method cannot be invoked for the + * given kind of typecode. + */ + public int length() + throws BadKind + { + if (len != UNSET) + return len; + throw new BadKind("length"); + } + + /** {@inheritDoc} */ + public String name() + throws BadKind + { + if (name != null) + return name; + throw new BadKind("name"); + } + + /** {@inheritDoc} */ + public short type_modifier() + throws BadKind + { + if (type_modifier != UNSET) + return (short) type_modifier; + throw new BadKind("type_modifier"); + } +} diff --git a/libjava/classpath/gnu/CORBA/typecodes/PrimitiveTypeCode.java b/libjava/classpath/gnu/CORBA/typecodes/PrimitiveTypeCode.java new file mode 100644 index 000000000..8f8ce3ea3 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/typecodes/PrimitiveTypeCode.java @@ -0,0 +1,201 @@ +/* PrimitiveTypeCode.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + + 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.CORBA.typecodes; + +import java.io.Serializable; + +import org.omg.CORBA.Any; +import org.omg.CORBA.NO_IMPLEMENT; +import org.omg.CORBA.TCKind; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.TypeCodePackage.BadKind; +import org.omg.CORBA.TypeCodePackage.Bounds; +import org.omg.CORBA.portable.IDLEntity; + +/** + * An information about a primitive CORBA data type + * (boolean, char, wchar, octet and also signed or unsigned short, long, + * long long, float and double). + * This class only implements the methods {@link #kind() } + * and {@link equal() } that are valid for + * all TypeCode kinds. Other methods are implemented in derived + * subclasses. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class PrimitiveTypeCode + extends TypeCode + implements IDLEntity, Serializable +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * The kind of this TypeCode. + */ + protected final TCKind kind; + + public PrimitiveTypeCode(TCKind a_kind) + { + kind = a_kind; + } + + public TypeCode concrete_base_type() + throws BadKind + { + throw new BadKind(); + } + + public TypeCode content_type() + throws BadKind + { + throw new BadKind(); + } + + public int default_index() + throws BadKind + { + throw new BadKind(); + } + + public TypeCode discriminator_type() + throws BadKind + { + throw new BadKind(); + } + + /** + * Test two types for equality. The default implementation + * returs true of the types of the same kind. + * @param other the other type to compere with + * @return true if the types are interchangeable. + */ + public boolean equal(TypeCode other) + { + return kind() == other.kind(); + } + + public boolean equivalent(TypeCode parm1) + { + throw new NO_IMPLEMENT(); + } + + public short fixed_digits() + throws BadKind + { + throw new BadKind("fixed_digits"); + } + + public short fixed_scale() + throws BadKind + { + throw new BadKind("fixed_scale"); + } + + public TypeCode get_compact_typecode() + { + throw new NO_IMPLEMENT(); + } + + public String id() + throws BadKind + { + throw new BadKind("id"); + } + + /** + * Return the kind of this type code object. + * @return one of the TCKind.t_.. fields. + */ + public TCKind kind() + { + return kind; + } + + public int length() + throws BadKind + { + throw new BadKind("length"); + } + + public int member_count() + throws BadKind + { + throw new BadKind("member_count"); + } + + public Any member_label(int index) + throws BadKind, Bounds + { + throw new BadKind("member_label"); + } + + public String member_name(int index) + throws BadKind, Bounds + { + throw new BadKind("member_name"); + } + + public TypeCode member_type(int index) + throws BadKind, Bounds + { + throw new BadKind("member_type"); + } + + public short member_visibility(int index) + throws BadKind, Bounds + { + throw new BadKind("member_visibility"); + } + + public String name() + throws BadKind + { + throw new BadKind("name"); + } + + public short type_modifier() + throws BadKind + { + throw new BadKind("type_modifier"); + } +} diff --git a/libjava/classpath/gnu/CORBA/typecodes/RecordTypeCode.java b/libjava/classpath/gnu/CORBA/typecodes/RecordTypeCode.java new file mode 100644 index 000000000..8f13de9a9 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/typecodes/RecordTypeCode.java @@ -0,0 +1,252 @@ +/* RecordTypeCode.java -- + 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.CORBA.typecodes; + +import gnu.CORBA.CorbaList; + +import org.omg.CORBA.Any; +import org.omg.CORBA.StructMember; +import org.omg.CORBA.TCKind; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.TypeCodePackage.BadKind; +import org.omg.CORBA.TypeCodePackage.Bounds; +import org.omg.CORBA.UnionMember; +import org.omg.CORBA.ValueMember; + +/** + * The type code that also has the member property getters + * supported. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class RecordTypeCode + extends GeneralTypeCode +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * The individual field of the record. + */ + public static class Field + { + /** + * The record label. + */ + public Any label; + + /** + * The record name. + */ + public String name; + + /** + * The record type. + */ + public TypeCode type; + + /** + * The record visibility. + */ + public int visibility = UNSET; + } + + /** + * The members of this data structure. + */ + protected CorbaList members = new CorbaList(); + private TypeCode discriminator_type; + private int default_index = UNSET; + + /** + * Creates the type code of the given kind. + */ + public RecordTypeCode(TCKind a_kind) + { + super(a_kind); + } + + /** + * Set the default index. + */ + public void setDefaultIndex(int a_default_index) + { + this.default_index = a_default_index; + } + + /** + * Set the discriminator type. + */ + public void setDiscriminator_type(TypeCode a_discriminator_type) + { + this.discriminator_type = a_discriminator_type; + } + + public Field getField(int p) + { + return (Field) members.get(p); + } + + public void add(Field field) + { + members.add(field); + } + + /** + * Adds a new field, taking values from the passed + * {@link StructMember}. + */ + public void add(StructMember m) + { + Field f = field(); + f.name = m.name; + f.type = m.type; + } + + /** + * Adds a new field, taking values from the passed + * {@link ValueMember}. + */ + public void add(ValueMember m) + { + Field f = field(); + f.name = m.name; + f.type = m.type; + f.visibility = m.access; + + } + + /** + * Adds a new field, taking values from the passed + * {@link UnionMember}. + */ + public void add(UnionMember m) + { + Field f = field(); + f.name = m.name; + f.type = m.type; + f.label = m.label; + } + + public int default_index() + throws BadKind + { + if (default_index != UNSET) + return default_index; + throw new BadKind(); + } + + public TypeCode discriminator_type() + throws BadKind + { + if (discriminator_type != null) + return discriminator_type; + throw new BadKind(); + } + + /** + * Creates, adds and returns new field. + */ + public Field field() + { + Field f = new Field(); + members.add(f); + return f; + } + + /** {@inheritDoc} */ + public int member_count() + { + return members.size(); + } + + /** {@inheritDoc} */ + public Any member_label(int index) + throws BadKind, Bounds + { + Field f = getField(index); + if (f.label != null) + { + return f.label; + } + else + throw new BadKind(); + } + + /** {@inheritDoc} */ + public String member_name(int index) + throws BadKind + { + Field f = getField(index); + if (f.name != null) + { + return f.name; + } + else + throw new BadKind(); + } + + /** {@inheritDoc} */ + public TypeCode member_type(int index) + throws BadKind, Bounds + { + Field f = getField(index); + if (f.type != null) + { + return f.type; + } + else + throw new BadKind(); + } + + /** {@inheritDoc} */ + public short member_visibility(int index) + throws BadKind, Bounds + { + Field f = getField(index); + if (f.visibility != UNSET) + { + return (short) f.visibility; + } + else + throw new BadKind(); + } +} diff --git a/libjava/classpath/gnu/CORBA/typecodes/RecursiveTypeCode.java b/libjava/classpath/gnu/CORBA/typecodes/RecursiveTypeCode.java new file mode 100644 index 000000000..727773674 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/typecodes/RecursiveTypeCode.java @@ -0,0 +1,84 @@ +/* RecursiveTypeCode.java -- + 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.CORBA.typecodes; + + +import org.omg.CORBA.TCKind; + +/** + * The typecode, serving as a placeholder in defining + * typecodes, containing recursion. + */ +public class RecursiveTypeCode + extends PrimitiveTypeCode +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * The id of the type for that this type serves as a + * placeholder. + */ + private final String the_id; + + /** + * Create a typecode that serves as a placeholder for + * the typecode with the given id. + * + * @param an_id the Id of the type for that this type serves as a + * placeholder. + */ + public RecursiveTypeCode(String an_id) + { + super(TCKind.tk_null); + the_id = an_id; + } + + /** + * Get the id of the type for that this type serves as a + * placeholder. + */ + public String id() + throws org.omg.CORBA.TypeCodePackage.BadKind + { + return the_id; + } +} diff --git a/libjava/classpath/gnu/CORBA/typecodes/StringTypeCode.java b/libjava/classpath/gnu/CORBA/typecodes/StringTypeCode.java new file mode 100644 index 000000000..7f463d7b0 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/typecodes/StringTypeCode.java @@ -0,0 +1,89 @@ +/* StringTypeCode.java -- + 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.CORBA.typecodes; + + +import org.omg.CORBA.TCKind; + +/** + * The typecode for string and wide string. + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class StringTypeCode + extends PrimitiveTypeCode +{ + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + private int len = 0; + + /** + * Create a new instance of the string type code. + * + * @param a_kind a kind of this typecode, normally + * either tk_string or tk_wstring. + */ + public StringTypeCode(TCKind a_kind) + { + super(a_kind); + } + + /** + * Set the length property. + * + * @param a_length a length. + */ + public void setLength(int a_length) + { + len = a_length; + } + + /** + * Get the length of the string. This method returns 0 + * (unbounded) if the property has not been set. + * + * @return the length (bound) of the string. + */ + public int length() + { + return len; + } +} diff --git a/libjava/classpath/gnu/CORBA/typecodes/package.html b/libjava/classpath/gnu/CORBA/typecodes/package.html new file mode 100644 index 000000000..891b3b965 --- /dev/null +++ b/libjava/classpath/gnu/CORBA/typecodes/package.html @@ -0,0 +1,48 @@ + + + + +GNU Classpath - gnu.CORBA.typecodes + + + Contains GNU Classpath specific typecode definitions. + + @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + + + diff --git a/libjava/classpath/gnu/classpath/.cvsignore b/libjava/classpath/gnu/classpath/.cvsignore new file mode 100644 index 000000000..11f6639eb --- /dev/null +++ b/libjava/classpath/gnu/classpath/.cvsignore @@ -0,0 +1 @@ +Configuration.java diff --git a/libjava/classpath/gnu/classpath/Configuration.java.in b/libjava/classpath/gnu/classpath/Configuration.java.in new file mode 100644 index 000000000..4a9b65f56 --- /dev/null +++ b/libjava/classpath/gnu/classpath/Configuration.java.in @@ -0,0 +1,114 @@ +/* Configuration.java -- + Copyright (C) 1998, 2001, 2003, 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.classpath; + +/** + * This file defines compile-time constants that can be accessed by + * java code. It is pre-processed by configure. + */ +public interface Configuration +{ + /** + * The value of CLASSPATH_HOME is the location that the classpath + * libraries and support files where installed in. It is set according to + * the argument for --prefix given to configure and used to set the + * System property gnu.classpath.home. + */ + String CLASSPATH_HOME = "@prefix@"; + + /** + * The release version number of GNU Classpath. + * It is set according to the value of 'version' in the configure[.in] file + * and used to set the System property gnu.classpath.version. + */ + String CLASSPATH_VERSION = "@VERSION@"; + + /** + * The value of DEBUG is substituted according to whether the + * "--enable-debug" argument was passed to configure. Code + * which is made conditional based on the value of this flag - typically + * code that generates debugging output - will be removed by the optimizer + * in a non-debug build. + */ + boolean DEBUG = @LIBDEBUG@; + + /** + * The value of LOAD_LIBRARY is substituted according to whether the + * "--enable-load-library" or "--disable-load-library" argument was passed + * to configure. By default, configure should define this is as true. + * If set to false, loadLibrary() calls to load native function + * implementations, typically found in static initializers of classes + * which contain native functions, will be omitted. This is useful for + * runtimes which pre-link their native function implementations and do + * not require additional shared libraries to be loaded. + */ + boolean INIT_LOAD_LIBRARY = @INIT_LOAD_LIBRARY@; + + /** + * Name of default AWT peer library. + */ + String default_awt_peer_toolkit = "@default_toolkit@"; + + /** + * Whether to automatically run the init* methods in java.lang.System + * (the default) at class initialization time or whether to have the VM + * explicitly invoke them. + * + * The default is false, meaning the VM does not explicitly run the + * initializers. + * + */ + boolean JAVA_LANG_SYSTEM_EXPLICIT_INITIALIZATION = + @JAVA_LANG_SYSTEM_EXPLICIT_INITIALIZATION@; + + /** + * The Eclipse Java Compiler jar file for use by the + * com.sun.tools.javac implementation in tools.zip. + */ + String ECJ_JAR = "@ECJ_JAR@"; + + /** + * Set to true if the config script found that (a) an + * implementation of java.math.BigInteger, based on the GNU MP library, is + * desired in preference to a pure Java one, and (b) the GNU MP library was + * found on the platform where the JVM is to run. Otherwise, this field is + * set to false. + */ + boolean WANT_NATIVE_BIG_INTEGER = @WANT_NATIVE_BIG_INTEGER@; + +} diff --git a/libjava/classpath/gnu/classpath/NotImplementedException.java b/libjava/classpath/gnu/classpath/NotImplementedException.java new file mode 100644 index 000000000..5b8c7f6d3 --- /dev/null +++ b/libjava/classpath/gnu/classpath/NotImplementedException.java @@ -0,0 +1,61 @@ +/* NotImplementedException.java -- Marker for stub 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.classpath; + +/** + * This class is used as a marker to indicate that a given method + * is merely a stub, requiring implementation. For historical + * reasons, GNU Classpath includes a number of stub methods. We + * don't wish to remove them, but we do want to make them easily + * discoverable. JAPI will notice methods declared as throwing + * this exception and mark them appropriately. + */ +public class NotImplementedException + extends RuntimeException +{ + private static final long serialVersionUID = 5112972057211125814L; + + /** + * This class is not instantiable. It should only be used + * in a method 'throws' clause -- not actually ever thrown. + */ + private NotImplementedException() + { + } +} diff --git a/libjava/classpath/gnu/classpath/Pair.java b/libjava/classpath/gnu/classpath/Pair.java new file mode 100644 index 000000000..f7a07a29c --- /dev/null +++ b/libjava/classpath/gnu/classpath/Pair.java @@ -0,0 +1,126 @@ +/* Pair.java -- A heterogenous pair of objects. + 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; + +/** + * A container for a pair of heterogenous objects. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ +public class Pair +{ + + /** + * The left-hand side of the pair. + */ + private A left; + + /** + * The right-hand side of the pair. + */ + private B right; + + /** + * Constructs a new pair using the given left and + * right values. + * + * @param left the left-hand side of the pair. + * @param right the right-hand side of the pair. + */ + public Pair(A left, B right) + { + this.left = left; + this.right = right; + } + + /** + * Returns the left-hand side of the pair. + * + * @return the left-hand value. + */ + public A getLeft() + { + return left; + } + + /** + * Returns the right-hand side of the pair. + * + * @return the right-hand value. + */ + public B getRight() + { + return right; + } + + /** + * Returns true if the specified object is also a + * pair with equivalent left and right values. + * + * @param obj the object to compare. + * @return true if the two are equal. + */ + public boolean equals(Object obj) + { + if (obj instanceof Pair) + { + Pair p = (Pair) obj; + A lp = p.getLeft(); + B rp = p.getRight(); + return (lp == null ? left == null : lp.equals(left)) && + (rp == null ? right == null : rp.equals(right)); + } + return false; + } + + /** + * Returns a hashcode for the pair, created by the + * summation of the hashcodes of the left and right + * hand values. + * + * @return a hashcode for the pair. + */ + public int hashCode() + { + return (left == null ? 0 : left.hashCode()) + + (right == null ? 0 : right.hashCode()); + } + +} diff --git a/libjava/classpath/gnu/classpath/Pointer.java b/libjava/classpath/gnu/classpath/Pointer.java new file mode 100644 index 000000000..bc1ce62c2 --- /dev/null +++ b/libjava/classpath/gnu/classpath/Pointer.java @@ -0,0 +1,47 @@ +/* Pointer.java -- Pointer to VM specific data + Copyright (C) 1999, 2000, 2004 Free Software Foundation + +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. */ + +/* This file is originally part of libgcj. */ + +package gnu.classpath; + +/** A type used to indicate special data used by native code that should not + be marked by the garbage collector. */ + +public abstract class Pointer +{ +} diff --git a/libjava/classpath/gnu/classpath/Pointer32.java b/libjava/classpath/gnu/classpath/Pointer32.java new file mode 100644 index 000000000..13d72e12e --- /dev/null +++ b/libjava/classpath/gnu/classpath/Pointer32.java @@ -0,0 +1,52 @@ +/* Pointer32.java -- 32 bit Pointer + Copyright (C) 2004 Free Software Foundation + +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; + +/** + * A type used to indicate special data used by native code that should not + * be marked by the garbage collector. + */ +public final class Pointer32 extends Pointer +{ + final int data; + + public Pointer32(int data) + { + this.data = data; + } +} diff --git a/libjava/classpath/gnu/classpath/Pointer64.java b/libjava/classpath/gnu/classpath/Pointer64.java new file mode 100644 index 000000000..5db60a80e --- /dev/null +++ b/libjava/classpath/gnu/classpath/Pointer64.java @@ -0,0 +1,52 @@ +/* Pointer64.java -- 64 bit Pointer + Copyright (C) 2004 Free Software Foundation + +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; + +/** + * A type used to indicate special data used by native code that should not + * be marked by the garbage collector. + */ +public final class Pointer64 extends Pointer +{ + final long data; + + public Pointer64(long data) + { + this.data = data; + } +} diff --git a/libjava/classpath/gnu/classpath/ServiceFactory.java b/libjava/classpath/gnu/classpath/ServiceFactory.java new file mode 100644 index 000000000..f41d8e191 --- /dev/null +++ b/libjava/classpath/gnu/classpath/ServiceFactory.java @@ -0,0 +1,653 @@ +/* ServiceFactory.java -- Factory for plug-in services. + Copyright (C) 2004 Free Software Foundation + +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; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; +import java.util.ServiceConfigurationError; +import java.util.logging.Level; +import java.util.logging.LogRecord; +import java.util.logging.Logger; + + +/** + * A factory for plug-ins that conform to a service provider + * interface. This is a general mechanism that gets used by a number + * of packages in the Java API. For instance, {@link + * java.nio.charset.spi.CharsetProvider} allows to write custom + * encoders and decoders for character sets, {@link + * javax.imageio.spi.ImageReaderSpi} allows to support custom image + * formats, and {@link javax.print.PrintService} makes it possible to + * write custom printer drivers. + * + *

The plug-ins are concrete implementations of the service + * provider interface, which is defined as an interface or an abstract + * class. The implementation classes must be public and have a public + * constructor that takes no arguments. + * + *

Plug-ins are usually deployed in JAR files. A JAR that provides + * an implementation of a service must declare this in a resource file + * whose name is the fully qualified service name and whose location + * is the directory META-INF/services. This UTF-8 encoded + * text file lists, on separate lines, the fully qualified names of + * the concrete implementations. Thus, one JAR file can provide an + * arbitrary number of implementations for an arbitrary count of + * service provider interfaces. + * + *

Example + * + *

For example, a JAR might provide two implementations of the + * service provider interface org.foo.ThinkService, + * namely com.acme.QuickThinker and + * com.acme.DeepThinker. The code for QuickThinker + * woud look as follows: + * + *

+ * package com.acme;
+ *
+ * /**
+ * * Provices a super-quick, but not very deep implementation of ThinkService.
+ * */
+ * public class QuickThinker
+ *   implements org.foo.ThinkService
+ * {
+ *   /**
+ *   * Constructs a new QuickThinker. The service factory (which is
+ *   * part of the Java environment) calls this no-argument constructor
+ *   * when it looks up the available implementations of ThinkService.
+ *   *
+ *   * <p>Note that an application might query all available
+ *   * ThinkService providers, but use just one of them. Therefore,
+ *   * constructing an instance should be very inexpensive. For example,
+ *   * large data structures should only be allocated when the service
+ *   * actually gets used.
+ *   */
+ *   public QuickThinker()
+ *   {
+ *   }
+ *
+ *   /**
+ *   * Returns the speed of this ThinkService in thoughts per second.
+ *   * Applications can choose among the available service providers
+ *   * based on this value.
+ *   */
+ *   public double getSpeed()
+ *   {
+ *     return 314159.2654;
+ *   }
+ *
+ *   /**
+ *   * Produces a thought. While the returned thoughts are not very
+ *   * deep, they are generated in very short time.
+ *   */
+ *   public Thought think()
+ *   {
+ *     return null;
+ *   }
+ * }
+ * 
+ * + *

The code for com.acme.DeepThinker is left as an + * exercise to the reader. + * + *

Acme’s ThinkService plug-in gets deployed as + * a JAR file. Besides the bytecode and resources for + * QuickThinker and DeepThinker, it also + * contains the text file + * META-INF/services/org.foo.ThinkService: + * + *

+ * # Available implementations of org.foo.ThinkService
+ * com.acme.QuickThinker
+ * com.acme.DeepThinker
+ * 
+ * + *

Thread Safety + * + *

It is safe to use ServiceFactory from multiple + * concurrent threads without external synchronization. + * + *

Note for User Applications + * + *

User applications that want to load plug-ins should not directly + * use gnu.classpath.ServiceFactory, because this class + * is only available in Java environments that are based on GNU + * Classpath. Instead, it is recommended that user applications call + * {@link + * javax.imageio.spi.ServiceRegistry#lookupProviders(Class)}. This API + * is actually independent of image I/O, and it is available on every + * environment. + * + * @author Sascha Brawer + */ +public final class ServiceFactory +{ + /** + * A logger that gets informed when a service gets loaded, or + * when there is a problem with loading a service. + * + *

Because {@link java.util.logging.Logger#getLogger(String)} + * is thread-safe, we do not need to worry about synchronization + * here. + */ + private static final Logger LOGGER = Logger.getLogger("gnu.classpath"); + + /** + * Declared private in order to prevent constructing instances of + * this utility class. + */ + private ServiceFactory() + { + } + + + /** + * Finds service providers that are implementing the specified + * Service Provider Interface. + * + *

On-demand loading: Loading and initializing service + * providers is delayed as much as possible. The rationale is that + * typical clients will iterate through the set of installed service + * providers until one is found that matches some criteria (like + * supported formats, or quality of service). In such scenarios, it + * might make sense to install only the frequently needed service + * providers on the local machine. More exotic providers can be put + * onto a server; the server will only be contacted when no suitable + * service could be found locally. + * + *

Security considerations: Any loaded service providers + * are loaded through the specified ClassLoader, or the system + * ClassLoader if classLoader is + * null. When lookupProviders is called, + * the current {@link AccessControlContext} gets recorded. This + * captured security context will determine the permissions when + * services get loaded via the next() method of the + * returned Iterator. + * + * @param spi the service provider interface which must be + * implemented by any loaded service providers. + * + * @param loader the class loader that will be used to load the + * service providers, or null for the system class + * loader. For using the context class loader, see {@link + * #lookupProviders(Class)}. + * + * @return an iterator over instances of spi. + * + * @throws IllegalArgumentException if spi is + * null. + */ + public static

Iterator

lookupProviders(Class

spi, + ClassLoader loader) + { + return lookupProviders(spi, loader, false); + } + + /** + * Finds service providers that are implementing the specified + * Service Provider Interface. + * + *

On-demand loading: Loading and initializing service + * providers is delayed as much as possible. The rationale is that + * typical clients will iterate through the set of installed service + * providers until one is found that matches some criteria (like + * supported formats, or quality of service). In such scenarios, it + * might make sense to install only the frequently needed service + * providers on the local machine. More exotic providers can be put + * onto a server; the server will only be contacted when no suitable + * service could be found locally. + * + *

Security considerations: Any loaded service providers + * are loaded through the specified ClassLoader, or the system + * ClassLoader if classLoader is + * null. When lookupProviders is called, + * the current {@link AccessControlContext} gets recorded. This + * captured security context will determine the permissions when + * services get loaded via the next() method of the + * returned Iterator. + * + * @param spi the service provider interface which must be + * implemented by any loaded service providers. + * + * @param loader the class loader that will be used to load the + * service providers, or null for the system class + * loader. For using the context class loader, see {@link + * #lookupProviders(Class)}. + * @param error true if a {@link ServiceConfigurationError} + * should be thrown when an error occurs, rather + * than it merely being logged. + * @return an iterator over instances of spi. + * + * @throws IllegalArgumentException if spi is + * null. + */ + public static

Iterator

lookupProviders(Class

spi, + ClassLoader loader, + boolean error) + { + String resourceName; + Enumeration urls; + + if (spi == null) + throw new IllegalArgumentException(); + + if (loader == null) + loader = ClassLoader.getSystemClassLoader(); + + resourceName = "META-INF/services/" + spi.getName(); + try + { + urls = loader.getResources(resourceName); + } + catch (IOException ioex) + { + /* If an I/O error occurs here, we cannot provide any service + * providers. In this case, we simply return an iterator that + * does not return anything (no providers installed). + */ + log(Level.WARNING, "cannot access {0}", resourceName, ioex); + if (error) + throw new ServiceConfigurationError("Failed to access + " + + resourceName, ioex); + else + { + List

empty = Collections.emptyList(); + return empty.iterator(); + } + } + + return new ServiceIterator

(spi, urls, loader, error, + AccessController.getContext()); + } + + + /** + * Finds service providers that are implementing the specified + * Service Provider Interface, using the context class loader + * for loading providers. + * + * @param spi the service provider interface which must be + * implemented by any loaded service providers. + * + * @return an iterator over instances of spi. + * + * @throws IllegalArgumentException if spi is + * null. + * + * @see #lookupProviders(Class, ClassLoader) + */ + public static

Iterator

lookupProviders(Class

spi) + { + ClassLoader ctxLoader; + + ctxLoader = Thread.currentThread().getContextClassLoader(); + return lookupProviders(spi, ctxLoader); + } + + + /** + * 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(Class, ClassLoader)}. + * + * @author Sascha Brawer + */ + private static final class ServiceIterator

+ implements Iterator

+ { + /** + * The service provider interface (usually an interface, sometimes + * an abstract class) which the services must implement. + */ + private final Class

spi; + + + /** + * An Enumeration over the URLs that contain a resource + * META-INF/services/<org.foo.SomeService>, + * as returned by {@link ClassLoader#getResources(String)}. + */ + private final Enumeration urls; + + + /** + * The class loader used for loading service providers. + */ + private final ClassLoader loader; + + + /** + * 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(Class, ClassLoader)} has + * been called. + */ + private final AccessControlContext securityContext; + + + /** + * A reader for the current file listing class names of service + * implementors, or null when the last reader has + * been fetched. + */ + private BufferedReader reader; + + + /** + * The URL currently being processed. This is only used for + * emitting error messages. + */ + private URL currentURL; + + + /** + * The service provider that will be returned by the next call to + * {@link #next()}, or null if the iterator has + * already returned all service providers. + */ + private P nextProvider; + + /** + * True if a {@link ServiceConfigurationError} should be thrown + * when an error occurs, instead of it merely being logged. + */ + private boolean error; + + /** + * Constructs an Iterator that loads and initializes services on + * demand. + * + * @param spi the service provider interface which the services + * must implement. Usually, this is a Java interface type, but it + * might also be an abstract class or even a concrete superclass. + * + * @param urls an Enumeration over the URLs that contain a + * resource + * META-INF/services/<org.foo.SomeService>, as + * determined by {@link ClassLoader#getResources(String)}. + * + * @param loader the ClassLoader that gets used for loading + * service providers. + * + * @param error true if a {@link ServiceConfigurationError} + * should be thrown when an error occurs, rather + * than it merely being logged. + * + * @param securityContext the security context to use when loading + * and initializing service providers. + */ + ServiceIterator(Class

spi, Enumeration urls, ClassLoader loader, + boolean error, AccessControlContext securityContext) + { + this.spi = spi; + this.urls = urls; + this.loader = loader; + this.securityContext = securityContext; + this.error = error; + this.nextProvider = loadNextServiceProvider(); + } + + + /** + * @throws NoSuchElementException if {@link #hasNext} returns + * false. + */ + public P next() + { + P result; + + if (!hasNext()) + throw new NoSuchElementException(); + + result = nextProvider; + nextProvider = loadNextServiceProvider(); + return result; + } + + + public boolean hasNext() + { + return nextProvider != null; + } + + + public void remove() + { + throw new UnsupportedOperationException(); + } + + + private P loadNextServiceProvider() + { + String line; + + if (reader == null) + advanceReader(); + + for (;;) + { + /* If we have reached the last provider list, we cannot + * retrieve any further lines. + */ + if (reader == null) + return null; + + try + { + line = reader.readLine(); + } + catch (IOException readProblem) + { + log(Level.WARNING, "IOException upon reading {0}", currentURL, + readProblem); + line = null; + if (error) + throw new ServiceConfigurationError("Error reading " + + currentURL, readProblem); + } + + /* When we are at the end of one list of services, + * switch over to the next one. + */ + if (line == null) + { + advanceReader(); + continue; + } + + + // Skip whitespace at the beginning and end of each line. + line = line.trim(); + + // Skip empty lines. + if (line.length() == 0) + continue; + + // Skip comment lines. + if (line.charAt(0) == '#') + continue; + + try + { + log(Level.FINE, + "Loading service provider \"{0}\", specified" + + " by \"META-INF/services/{1}\" in {2}.", + new Object[] { line, spi.getName(), currentURL }, + null); + + /* Load the class in the security context that was + * active when calling lookupProviders. + */ + return AccessController.doPrivileged( + new ServiceProviderLoadingAction

(spi, line, loader), + securityContext); + } + catch (Exception ex) + { + String msg = "Cannot load service provider class \"{0}\"," + + " specified by \"META-INF/services/{1}\" in {2}"; + if (ex instanceof PrivilegedActionException + && ex.getCause() instanceof ClassCastException) + msg = "Service provider class \"{0}\" is not an instance" + + " of \"{1}\". Specified" + + " by \"META-INF/services/{1}\" in {2}."; + + log(Level.WARNING, msg, + new Object[] { line, spi.getName(), currentURL }, + ex); + if (error) + throw new ServiceConfigurationError("Cannot load service "+ + "provider class " + + line + " specified by "+ + "\"META-INF/services/"+ + spi.getName() + "\" in "+ + currentURL, ex); + continue; + } + } + } + + + private void advanceReader() + { + do + { + if (reader != null) + { + try + { + reader.close(); + log(Level.FINE, "closed {0}", currentURL, null); + } + catch (Exception ex) + { + log(Level.WARNING, "cannot close {0}", currentURL, ex); + if (error) + throw new ServiceConfigurationError("Cannot close " + + currentURL, ex); + } + reader = null; + currentURL = null; + } + + if (!urls.hasMoreElements()) + return; + + currentURL = urls.nextElement(); + try + { + reader = new BufferedReader(new InputStreamReader( + currentURL.openStream(), "UTF-8")); + log(Level.FINE, "opened {0}", currentURL, null); + } + catch (Exception ex) + { + log(Level.WARNING, "cannot open {0}", currentURL, ex); + if (error) + throw new ServiceConfigurationError("Cannot open " + + currentURL, ex); + } + } + while (reader == null); + } + } + + + // Package-private to avoid a trampoline. + /** + * Passes a log message to the java.util.logging + * framework. This call returns very quickly if no log message will + * be produced, so there is not much overhead in the standard case. + * + * @param level the severity of the message, for instance {@link + * Level#WARNING}. + * + * @param msg the log message, for instance “Could not + * load {0}.” + * + * @param param the parameter(s) for the log message, or + * null if msg does not specify any + * parameters. If param is not an array, an array with + * param as its single element gets passed to the + * logging framework. + * + * @param t a Throwable that is associated with the log record, or + * null if the log message is not associated with a + * Throwable. + */ + static void log(Level level, String msg, Object param, Throwable t) + { + LogRecord rec; + + // Return quickly if no log message will be produced. + if (!LOGGER.isLoggable(level)) + return; + + rec = new LogRecord(level, msg); + if (param != null && param.getClass().isArray()) + rec.setParameters((Object[]) param); + else + rec.setParameters(new Object[] { param }); + + rec.setThrown(t); + + // While java.util.logging can sometimes infer the class and + // method of the caller, this automatic inference is not reliable + // on highly optimizing VMs. Also, log messages make more sense to + // developers when they display a public method in a public class; + // otherwise, they might feel tempted to figure out the internals + // of ServiceFactory in order to understand the problem. + rec.setSourceClassName(ServiceFactory.class.getName()); + rec.setSourceMethodName("lookupProviders"); + + LOGGER.log(rec); + } +} diff --git a/libjava/classpath/gnu/classpath/ServiceProviderLoadingAction.java b/libjava/classpath/gnu/classpath/ServiceProviderLoadingAction.java new file mode 100644 index 000000000..78a11cd50 --- /dev/null +++ b/libjava/classpath/gnu/classpath/ServiceProviderLoadingAction.java @@ -0,0 +1,149 @@ +/* ServiceProviderLoadingAction.java -- Action for loading plug-in services. + Copyright (C) 2004 Free Software Foundation + +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; + +import java.security.PrivilegedExceptionAction; + +/** + * A privileged action for creating a new instance of a service + * provider. + * + *

Class loading and instantiation is encapsulated in a + * PriviledgedAction in order to restrict the loaded + * service providers to the {@link java.security.AccessControlContext} + * that was active when {@link + * 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 Sascha Brawer + */ +final class ServiceProviderLoadingAction

+ implements PrivilegedExceptionAction

+{ + /** + * The interface to which the loaded service provider implementation + * must conform. Usually, this is a Java interface type, but it + * might also be an abstract class or even a concrete class. + */ + private final Class

spi; + + + /** + * The fully qualified name of the class that gets loaded when + * this action is executed. + */ + private final String providerName; + + + /** + * The ClassLoader that gets used for loading the service provider + * class. + */ + private final ClassLoader loader; + + + /** + * Constructs a privileged action for loading a service provider. + * + * @param spi the interface to which the loaded service provider + * implementation must conform. Usually, this is a Java interface + * type, but it might also be an abstract class or even a concrete + * superclass. + * + * @param providerName the fully qualified name of the class that + * gets loaded when this action is executed. + * + * @param loader the ClassLoader that gets used for loading the + * service provider class. + * + * @throws IllegalArgumentException if spi, + * providerName or loader is + * null. + */ + ServiceProviderLoadingAction(Class

spi, String providerName, + ClassLoader loader) + { + if (spi == null || providerName == null || loader == null) + throw new IllegalArgumentException(); + + this.spi = spi; + this.providerName = providerName; + this.loader = loader; + } + + + /** + * Loads an implementation class for a service provider, and creates + * a new instance of the loaded class by invoking its public + * no-argument constructor. + * + * @return a new instance of the class whose name was passed as + * providerName to the constructor. + * + * @throws ClassCastException if the service provider does not + * implement the spi interface that was passed to the + * constructor. + * + * @throws IllegalAccessException if the service provider class or + * its no-argument constructor are not public. + * + * @throws InstantiationException if the service provider class is + * abstract, an interface, a primitive type, an array + * class, or void; or if service provider class does not have a + * no-argument constructor; or if there some other problem with + * creating a new instance of the service provider. + */ + public P run() + throws Exception + { + Class

loadedClass; + P serviceProvider; + + loadedClass = (Class

) loader.loadClass(providerName); + serviceProvider = loadedClass.newInstance(); + + // Ensure that the loaded provider is actually implementing + // the service provider interface. + if (!spi.isInstance(serviceProvider)) + throw new ClassCastException(spi.getName()); + + return serviceProvider; + } +} diff --git a/libjava/classpath/gnu/classpath/SystemProperties.java b/libjava/classpath/gnu/classpath/SystemProperties.java new file mode 100644 index 000000000..4aad2612e --- /dev/null +++ b/libjava/classpath/gnu/classpath/SystemProperties.java @@ -0,0 +1,173 @@ +/* SystemProperties.java -- Manage the System properties. + Copyright (C) 2004, 2005 Free Software Foundation + +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; + +import java.util.Properties; + +/** + * The class manages the System properties. This class is only available to + * privileged code (i.e. code loaded by the bootstrap class loader) and + * therefore doesn't do any security checks. + * This class is separated out from java.lang.System to simplify bootstrap + * dependencies and to allow trusted code a simple and efficient mechanism + * to access the system properties. + */ +public class SystemProperties +{ + /** + * Stores the current system properties. This can be modified by + * {@link #setProperties(Properties)}, but will never be null, because + * setProperties(null) sucks in the default properties. + */ + private static Properties properties; + + /** + * The default properties. Once the default is stabilized, + * it should not be modified; + * instead it is cloned when calling setProperties(null). + */ + private static final Properties defaultProperties = new Properties(); + + static + { + VMSystemProperties.preInit(defaultProperties); + + defaultProperties.put("gnu.classpath.home", Configuration.CLASSPATH_HOME); + defaultProperties.put("gnu.classpath.version", + Configuration.CLASSPATH_VERSION); + + // Set base URL if not already set. + if (defaultProperties.get("gnu.classpath.home.url") == null) + defaultProperties.put("gnu.classpath.home.url", + "file://" + + Configuration.CLASSPATH_HOME + + "/lib"); + + // Set short name if not already set. + if (defaultProperties.get("gnu.classpath.vm.shortname") == null) + { + String value = defaultProperties.getProperty("java.vm.name"); + int index = value.lastIndexOf(' '); + if (index != -1) + value = value.substring(index + 1); + defaultProperties.put("gnu.classpath.vm.shortname", value); + } + + // Network properties + if (defaultProperties.get("http.agent") == null) + { + String userAgent = ("gnu-classpath/" + + defaultProperties.getProperty("gnu.classpath.version") + + " (" + + defaultProperties.getProperty("gnu.classpath.vm.shortname") + + "/" + + defaultProperties.getProperty("java.vm.version") + + ")"); + defaultProperties.put("http.agent", userAgent); + } + + // 8859_1 is a safe default encoding to use when not explicitly set + if (defaultProperties.get("file.encoding") == null) + defaultProperties.put("file.encoding", "8859_1"); + + // XXX FIXME - Temp hack for old systems that set the wrong property + if (defaultProperties.get("java.io.tmpdir") == null) + defaultProperties.put("java.io.tmpdir", + defaultProperties.get("java.tmpdir")); + + // FIXME: we need a better way to handle this. + // For instance, having a single VM class for each OS might help. + if (defaultProperties.get("gnu.classpath.mime.types.file") == null + && "Linux".equals(defaultProperties.get("os.name"))) + defaultProperties.put("gnu.classpath.mime.types.file", + "/etc/mime.types"); + + VMSystemProperties.postInit(defaultProperties); + + // Note that we use clone here and not new. Some programs assume + // that the system properties do not have a parent. + properties = (Properties) defaultProperties.clone(); + } + + public static String getProperty(String name) + { + return properties.getProperty(name); + } + + public static String getProperty(String name, String defaultValue) + { + return properties.getProperty(name, defaultValue); + } + + public static String setProperty(String name, String value) + { + return (String) properties.setProperty(name, value); + } + + public static Properties getProperties() + { + return properties; + } + + public static void setProperties(Properties properties) + { + if (properties == null) + { + // Note that we use clone here and not new. Some programs + // assume that the system properties do not have a parent. + properties = (Properties)defaultProperties.clone(); + } + + SystemProperties.properties = properties; + } + + /** + * Removes the supplied system property and its current value. + * If the specified property does not exist, nothing happens. + * + * @throws NullPointerException if the property name is null. + * @return the value of the removed property, or null if no + * such property exists. + */ + public static String remove(String name) + { + return (String) properties.remove(name); + } + +} diff --git a/libjava/classpath/gnu/classpath/debug/Component.java b/libjava/classpath/gnu/classpath/debug/Component.java new file mode 100644 index 000000000..3cad8a2a7 --- /dev/null +++ b/libjava/classpath/gnu/classpath/debug/Component.java @@ -0,0 +1,175 @@ +/* Component.java -- a component log level. + 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 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.debug; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.logging.Level; + +public final class Component extends Level +{ + + /* + * HOW TO ADD NEW COMPONENTS: + * + * If you want to add a new, simple component, that you will use in + * logging statements, simply create a new class variable that + * instantiates this class, and choose an appropriate string name + * and a integer constant not used by any other component level. + * + * For example, if my component had to do with 'frobbing', I would + * add this entry below: + * + * private static final Component FROBBING = new Component ("FROBBING", 7); + * + * Then, I would update the component 'EVERYTHING' to have and end + * index ONE GREATER THAN the index of the new component. + * + * ADDING NEW COMPONENT CLASSES: + * + * A "component class" is a run of more than one component, which can + * be enabled all at once. EVERYTHING and SSL are examples of component + * classes. To add a new class, create a new component with a start index + * equal to the index of the first member component, and with an end + * index equal to the index of the last member component plus one. + */ + + /** + * Signifies that everything should be logged. This should be used to + * enable or disable levels only; logging code should not use it. + */ + public static final Component EVERYTHING = new Component ("*", 0, 11); + + /** + * Signifies that all SSL related messages should be logged. This should + * be used to enable or disable levels only; logging code should not use + * it. + */ + public static final Component SSL = new Component ("SSL", 0, 5); + + /** + * Traces the progression of an SSL handshake. + */ + public static final Component SSL_HANDSHAKE = new Component ("SSL HANDSHAKE", 0); + + /** + * Traces record layer messages during SSL communications. + */ + public static final Component SSL_RECORD_LAYER = new Component ("SSL RECORD LAYER", 1); + + /** + * Trace details about the SSL key exchange. + */ + public static final Component SSL_KEY_EXCHANGE = new Component ("SSL KEY EXCHANGE", 2); + + /** + * Trace running of delegated tasks. + */ + public static final Component SSL_DELEGATED_TASK = new Component ("SSL DELEGATED TASK", 3); + + /* Index 4 reserved for future use by SSL components. */ + + /** + * Trace the operation of cryptographic primitives. + */ + public static final Component CRYPTO = new Component ("CRYPTO", 5); + + /** + * Trace the parsing of X.509 certificates and related objects. + */ + public static final Component X509 = new Component ("X.509", 6); + + /** + * Trace access control policies, including the parsing of + * java.policy files. + */ + public static final Component POLICY = new Component ("POLICY", 7); + + /** + * Trace ipp implementation. + */ + public static final Component IPP = new Component ("IPP", 10); + + private final int startIndex; + private final int endIndex; + + private Component (final String name, final int bitIndex) + { + this (name, bitIndex, bitIndex + 1); + } + + private Component (final String name, final int startIndex, final int endIndex) + { + super (name, Level.FINE.intValue ()); + this.startIndex = startIndex; + this.endIndex = endIndex; + } + + /** + * Return the component for the given name. + * + * @param name The name of the component to get. + * @return The named component, or null if there is no such component. + */ + public static Component forName (final String name) + { + try + { + Field f = Component.class.getField (name.toUpperCase ()); + if (!Modifier.isStatic (f.getModifiers ()) + || Component.class.isAssignableFrom (f.getClass ())) + return null; + return (Component) f.get (null); + } + catch (Throwable _) + { + return null; + } + } + + public int startIndex () + { + return startIndex; + } + + public int endIndex () + { + return endIndex; + } +} diff --git a/libjava/classpath/gnu/classpath/debug/PreciseFilter.java b/libjava/classpath/gnu/classpath/debug/PreciseFilter.java new file mode 100644 index 000000000..91f5a9e6c --- /dev/null +++ b/libjava/classpath/gnu/classpath/debug/PreciseFilter.java @@ -0,0 +1,105 @@ +/* PreciseFilter.java -- filter log messages by precise level. + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; 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.debug; + +import java.util.BitSet; +import java.util.logging.Filter; +import java.util.logging.LogRecord; + +public final class PreciseFilter implements Filter +{ + + /** + * The singleton filter instance. + */ + public static final PreciseFilter GLOBAL = new PreciseFilter (); + + private final BitSet enabled; + + private PreciseFilter () + { + enabled = new BitSet (); + } + + /** + * Disable logging of a component. + * + * @param component The component to disable logging for. + * @throws NullPointerException If component is null. + */ + public void disable (final Component component) + { + enabled.clear (component.startIndex (), component.endIndex ()); + } + + /** + * Enable logging of a component. + * + * @param component The component to enable logging for. + * @throws NullPointerException If component is null. + */ + public void enable (final Component component) + { + enabled.set (component.startIndex (), component.endIndex ()); + } + + /** + * Tell if a component is enabled for logging. + * + * @param component The component to test. + * @return True iff the specified component is enabled for logging. + * @throws NullPointerException If component is null. + */ + public boolean isEnabled (final Component component) + { + return (enabled.get (component.startIndex ())); + } + + public boolean isLoggable (final LogRecord record) + { + try + { + return isEnabled ((Component) record.getLevel ()); + } + catch (ClassCastException cce) + { + return true; + } + } +} diff --git a/libjava/classpath/gnu/classpath/debug/Simple1LineFormatter.java b/libjava/classpath/gnu/classpath/debug/Simple1LineFormatter.java new file mode 100644 index 000000000..96573193a --- /dev/null +++ b/libjava/classpath/gnu/classpath/debug/Simple1LineFormatter.java @@ -0,0 +1,161 @@ +/* Simple1LineFormatter.java -- A simple 1-line logging formatter + 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.debug; + +import gnu.java.security.action.GetPropertyAction; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.security.AccessController; +import java.text.DateFormat; +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.logging.Formatter; +import java.util.logging.LogRecord; + +/** + * A simple 1-line formatter to use instead of the 2-line SimpleFormatter used + * by default in the JDK logging handlers. + *

+ * The fixed format of this formatter is as follows: + *

+ *

    + *
  1. Date: As a yyyy-MM-dd string.
  2. + *
  3. Time: As a HH:mm:ss.SSSS Z string.
  4. + *
  5. Thread identifier, right-justified, and framed in an 11-digit field.
  6. + *
  7. Class name, without its package name, left-justified, and framed in a + * 32-character field.
  8. + *
  9. Method name, left-justified, and framed in a 32-character field.
  10. + *
  11. Level name, left-justified, and framed in a 6-character field.
  12. + *
  13. User message and arguments.
  14. + *
  15. Platform-dependent line-separator.
  16. + *
  17. Optionally, if the log-record contains a thrown exception, that + * exception's stack trace is appended to the output.
  18. + *
+ *

+ * Here is an example of the output generated by this formatter: + *

+ *

+ * 2006-02-27 21:59:12.0881 +1100 -1343151280 EncodedKeyFactory                engineGeneratePublic()           FINER - ENTRY java.security.spec.X509EncodedKeySpec@b00d7fc0
+ * 2006-02-27 21:59:12.0887 +1100 -1343151280 EncodedKeyFactory                engineGeneratePublic()           FINE  - Exception in DSSPublicKey.valueOf(). Ignore
+ * java.security.InvalidParameterException: Unexpected OID: 1.2.840.113549.1.1.1
+ *    at gnu.java.security.key.dss.DSSKeyPairX509Codec.decodePublicKey (DSSKeyPairX509Codec.java:205)
+ *    at gnu.java.security.key.dss.DSSPublicKey.valueOf (DSSPublicKey.java:136)
+ *    at gnu.java.security.jce.sig.EncodedKeyFactory.engineGeneratePublic (EncodedKeyFactory.java:218)
+ *    at java.security.KeyFactory.generatePublic (KeyFactory.java:219)
+ *    at gnu.java.security.x509.X509Certificate.parse (X509Certificate.java:657)
+ *    at gnu.java.security.x509.X509Certificate. (X509Certificate.java:163)
+ *    ...
+ * 2006-02-27 21:59:12.0895 +1100 -1343151280 RSAKeyPairX509Codec              decodePublicKey()                FINER - ENTRY [B@b00d7fd0
+ * 2006-02-27 21:59:12.0897 +1100 -1343151280 RSAKeyPairX509Codec              decodePublicKey()                FINER - RETURN gnu.java.security.key.rsa.GnuRSAPublicKey@b00fb940
+ * 
+ */ +public class Simple1LineFormatter + extends Formatter +{ + private static final String DAT_PATTERN = "yyyy-MM-dd HH:mm:ss.SSSS Z "; + private static final String THREAD_PATTERN = " #########0;-#########0"; + private static final String SPACES_32 = " "; + private static final String SPACES_6 = " "; + private static final String LS = (String) AccessController.doPrivileged + (new GetPropertyAction("line.separator")); + private DateFormat dateFormat; + private NumberFormat threadFormat; + + // default 0-arguments constructor + + public String format(LogRecord record) + { + if (dateFormat == null) + dateFormat = new SimpleDateFormat(DAT_PATTERN); + + if (threadFormat == null) + threadFormat = new DecimalFormat(THREAD_PATTERN); + + StringBuilder sb = new StringBuilder(180) + .append(dateFormat.format(new Date(record.getMillis()))) + .append(threadFormat.format(record.getThreadID())) + .append(" "); + String s = record.getSourceClassName(); + if (s == null) + sb.append(SPACES_32); + else + { + s = s.trim(); + int i = s.lastIndexOf("."); + if (i != - 1) + s = s.substring(i + 1); + + s = (s + SPACES_32).substring(0, 32); + } + + sb.append(s).append(" "); + s = record.getSourceMethodName(); + if (s == null) + sb.append(SPACES_32); + else + { + s = s.trim(); + if (s.endsWith("()")) + s = (s.trim() + SPACES_32).substring(0, 32); + else + s = (s.trim() + "()" + SPACES_32).substring(0, 32); + } + + sb.append(s).append(" "); + s = String.valueOf(record.getLevel()); + if (s == null) + sb.append(SPACES_6); + else + s = (s.trim() + SPACES_6).substring(0, 6); + + sb.append(s).append(" - ").append(formatMessage(record)).append(LS); + Throwable cause = record.getThrown(); + if (cause != null) + { + StringWriter sw = new StringWriter(); + cause.printStackTrace(new PrintWriter(sw, true)); + sb.append(sw.toString()); + } + + return sb.toString(); + } +} diff --git a/libjava/classpath/gnu/classpath/debug/SystemLogger.java b/libjava/classpath/gnu/classpath/debug/SystemLogger.java new file mode 100644 index 000000000..eaca0fe98 --- /dev/null +++ b/libjava/classpath/gnu/classpath/debug/SystemLogger.java @@ -0,0 +1,102 @@ +/* SystemLogger.java -- Classpath's system debugging logger. + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; 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.debug; + +import gnu.java.security.action.GetPropertyAction; + +import java.security.AccessController; +import java.util.StringTokenizer; +import java.util.logging.Level; +import java.util.logging.Logger; + +public final class SystemLogger extends Logger +{ + public static final SystemLogger SYSTEM = new SystemLogger(); + + static + { + SYSTEM.setFilter (PreciseFilter.GLOBAL); + String defaults = (String) AccessController.doPrivileged + (new GetPropertyAction("gnu.classpath.debug.components")); + + if (defaults != null) + { + StringTokenizer tok = new StringTokenizer (defaults, ","); + while (tok.hasMoreTokens ()) + { + Component c = Component.forName (tok.nextToken ()); + if (c != null) + PreciseFilter.GLOBAL.enable (c); + SYSTEM.log (Level.INFO, "enabled: {0}", c); + } + } + } + + /** + * Fetch the system logger instance. The logger returned is meant for debug + * and diagnostic logging for Classpath internals. + * + * @return The system logger. + */ + public static SystemLogger getSystemLogger() + { + // XXX Check some permission here? + return SYSTEM; + } + + /** + * Keep only one instance of the system logger. + */ + private SystemLogger() + { + super("gnu.classpath", null); + } + + /** + * Variable-arguments log method. + * + * @param level The level to log to. + * @param format The format string. + * @param args The arguments. + */ + public void logv(Level level, String format, Object... args) + { + log(level, format, args); + } +} diff --git a/libjava/classpath/gnu/classpath/debug/TeeInputStream.java b/libjava/classpath/gnu/classpath/debug/TeeInputStream.java new file mode 100644 index 000000000..0b17633f6 --- /dev/null +++ b/libjava/classpath/gnu/classpath/debug/TeeInputStream.java @@ -0,0 +1,98 @@ +/* TeeInputStream.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 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.debug; + +import java.io.*; + +/** + * An input stream that copies all its input to a byte sink. + * + * @author Chris Burdess + */ +public class TeeInputStream + extends InputStream +{ + + private final InputStream in; + private final OutputStream out; + + /** + * Constructs a tee input stream. + * @param in the underlying input stream + * @param out the output sink + */ + public TeeInputStream(InputStream in, OutputStream out) + { + this.in = in; + this.out = out; + } + + public int read() + throws IOException + { + int ret = in.read(); + out.write(ret); + out.flush(); + return ret; + } + + public int read(byte[] b, int off, int len) + throws IOException + { + int ret = in.read(b, off, len); + if (ret != -1) + { + out.write(b, off, ret); + out.flush(); + } + return ret; + } + + public void close() + throws IOException + { + in.close(); + out.close(); + } + + public final boolean markSupported() + { + return false; + } + +} diff --git a/libjava/classpath/gnu/classpath/debug/TeeOutputStream.java b/libjava/classpath/gnu/classpath/debug/TeeOutputStream.java new file mode 100644 index 000000000..cff60894a --- /dev/null +++ b/libjava/classpath/gnu/classpath/debug/TeeOutputStream.java @@ -0,0 +1,93 @@ +/* TeeOutputStream.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 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.debug; + +import java.io.*; + +/** + * An output stream that copies all its output to an additional byte sink. + * + * @author Chris Burdess + */ +public class TeeOutputStream + extends OutputStream +{ + + private final OutputStream out; + private final OutputStream sink; + + /** + * Constructs a tee output stream. + * @param out the underlying output stream + * @param sink the output sink + */ + public TeeOutputStream(OutputStream out, OutputStream sink) + { + this.out = out; + this.sink = sink; + } + + public void write(int c) + throws IOException + { + out.write(c); + sink.write(c); + } + + public void write(byte[] b, int off, int len) + throws IOException + { + out.write(b, off, len); + sink.write(b, off, len); + } + + public void flush() + throws IOException + { + out.flush(); + sink.flush(); + } + + public void close() + throws IOException + { + out.close(); + sink.close(); + } + +} diff --git a/libjava/classpath/gnu/classpath/debug/TeeReader.java b/libjava/classpath/gnu/classpath/debug/TeeReader.java new file mode 100644 index 000000000..d1f755dc9 --- /dev/null +++ b/libjava/classpath/gnu/classpath/debug/TeeReader.java @@ -0,0 +1,98 @@ +/* TeeReader.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 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.debug; + +import java.io.*; + +/** + * A reader that copies all characters read to an output sink. + * + * @author Chris Burdess + */ +public class TeeReader + extends Reader +{ + + private final Reader in; + private final Writer out; + + /** + * Constructs a tee reader. + * @param in the input + * @param out the output sink + */ + public TeeReader(Reader in, Writer out) + { + this.in = in; + this.out = out; + } + + public int read() + throws IOException + { + int ret = in.read(); + out.write(ret); + out.flush(); + return ret; + } + + public int read(char[] b, int off, int len) + throws IOException + { + int ret = in.read(b, off, len); + if (ret != -1) + { + out.write(b, off, ret); + out.flush(); + } + return ret; + } + + public void close() + throws IOException + { + in.close(); + out.close(); + } + + public final boolean markSupported() + { + return false; + } + +} diff --git a/libjava/classpath/gnu/classpath/debug/TeeWriter.java b/libjava/classpath/gnu/classpath/debug/TeeWriter.java new file mode 100644 index 000000000..f226c2165 --- /dev/null +++ b/libjava/classpath/gnu/classpath/debug/TeeWriter.java @@ -0,0 +1,93 @@ +/* TeeWriter.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 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.debug; + +import java.io.*; + +/** + * A writer that copies all its output to an additional character sink. + * + * @author Chris Burdess + */ +public class TeeWriter + extends Writer +{ + + private final Writer out; + private final Writer sink; + + /** + * Constructs a tee writer. + * @param out the underlying writer + * @param sink the output sink + */ + public TeeWriter(Writer out, Writer sink) + { + this.out = out; + this.sink = sink; + } + + public void write(int c) + throws IOException + { + out.write(c); + sink.write(c); + } + + public void write(char[] b, int off, int len) + throws IOException + { + out.write(b, off, len); + sink.write(b, off, len); + } + + public void flush() + throws IOException + { + out.flush(); + sink.flush(); + } + + public void close() + throws IOException + { + out.close(); + sink.close(); + } + +} diff --git a/libjava/classpath/gnu/classpath/jdwp/Jdwp.java b/libjava/classpath/gnu/classpath/jdwp/Jdwp.java new file mode 100644 index 000000000..e90a2c762 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/Jdwp.java @@ -0,0 +1,416 @@ +/* Jdwp.java -- Virtual machine to JDWP back-end programming interface + Copyright (C) 2005, 2006, 2007 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp; + +import gnu.classpath.jdwp.event.Event; +import gnu.classpath.jdwp.event.EventManager; +import gnu.classpath.jdwp.event.EventRequest; +import gnu.classpath.jdwp.exception.JdwpException; +import gnu.classpath.jdwp.processor.PacketProcessor; +import gnu.classpath.jdwp.transport.ITransport; +import gnu.classpath.jdwp.transport.JdwpConnection; +import gnu.classpath.jdwp.transport.TransportException; +import gnu.classpath.jdwp.transport.TransportFactory; + +import java.io.IOException; +import java.security.AccessController; +import java.util.ArrayList; +import java.util.HashMap; + +/** + * Main interface from the virtual machine to the JDWP back-end. + * + * The thread created by this class is only used for initialization. + * Once it exits, the JDWP backend is fully initialized. + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class Jdwp + extends Thread +{ + // The single instance of the back-end + private static Jdwp _instance = null; + + /** + * Are we debugging? Only true if debugging + * *and* initialized. + */ + public static boolean isDebugging = false; + + // Packet processor + private PacketProcessor _packetProcessor; + private Thread _ppThread; + + // JDWP configuration properties + private HashMap _properties; + + // The suspend property of the configure string + // (-Xrunjdwp:..suspend=) + private static final String _PROPERTY_SUSPEND = "suspend"; + + // Connection to debugger + private JdwpConnection _connection; + + // Are we shutting down the current session? + private boolean _shutdown; + + // A thread group for the JDWP threads + private ThreadGroup _group; + + // Initialization synchronization + private Object _initLock = new Object (); + private int _initCount = 0; + + /** + * constructor + */ + public Jdwp () + { + _shutdown = false; + _instance = this; + } + + /** + * Returns the JDWP back-end, creating an instance of it + * if one does not already exist. + */ + public static Jdwp getDefault () + { + return _instance; + } + + /** + * Get the thread group used by JDWP threads + * + * @return the thread group + */ + public ThreadGroup getJdwpThreadGroup() + { + return _group; + } + + /** + * Should the virtual machine suspend on startup? + */ + public static boolean suspendOnStartup () + { + Jdwp jdwp = getDefault (); + if (jdwp != null) + { + String suspend = (String) jdwp._properties.get (_PROPERTY_SUSPEND); + if (suspend != null && suspend.equals ("y")) + return true; + } + + return false; + } + + /** + * Configures the back-end + * + * @param configArgs a string of configury options + */ + public void configure (String configArgs) + { + _processConfigury (configArgs); + } + + // A helper function to initialize the transport layer + private void _doInitialization () + throws TransportException + { + _group = new ThreadGroup ("JDWP threads"); + // initialize transport + ITransport transport = TransportFactory.newInstance (_properties); + _connection = new JdwpConnection (_group, transport); + _connection.initialize (); + _connection.start (); + + // Create processor + _packetProcessor = new PacketProcessor (_connection); + _ppThread = new Thread (_group, new Runnable () + { + public void run () + { + AccessController.doPrivileged (_packetProcessor); + } + }, "packet processor"); + _ppThread.start (); + } + + /** + * Shutdown the JDWP back-end + * + * NOTE: This does not quite work properly. See notes in + * run() on this subject (catch of InterruptedException). + */ + public void shutdown () + { + if (!_shutdown) + { + _packetProcessor.shutdown (); + _ppThread.interrupt (); + _connection.shutdown (); + _shutdown = true; + isDebugging = false; + + /* FIXME: probably need to check state of user's + program -- if it is suspended, we need to either + resume or kill them. */ + + interrupt (); + } + } + + /** + * Notify the debugger of an event. This method should not + * be called if debugging is not active (but it would not + * cause any harm). Places where event notifications occur + * should check isDebugging before doing anything. + * + * The event is filtered through the event manager before being + * sent. + * + * @param event the event to report + */ + public static void notify(Event event) + { + Jdwp jdwp = getDefault(); + if (jdwp != null) + { + EventManager em = EventManager.getDefault(); + EventRequest[] requests = em.getEventRequests(event); + for (int i = 0; i < requests.length; ++i) + { + try + { + sendEvent(requests[i], event); + jdwp._enforceSuspendPolicy(requests[i].getSuspendPolicy()); + } + catch (Exception e) + { + /* Really not much we can do. For now, just print out + a warning to the user. */ + System.out.println ("Jdwp.notify: caught exception: " + e); + } + } + } + } + + /** + * Notify the debugger of "co-located" events. This method should + * not be called if debugging is not active (but it would not + * cause any harm). Places where event notifications occur + * should check isDebugging before doing anything. + * + * The events are filtered through the event manager before being + * sent. + * + * @param events the events to report + */ + public static void notify(Event[] events) + { + Jdwp jdwp = getDefault(); + + if (jdwp != null) + { + byte suspendPolicy = JdwpConstants.SuspendPolicy.NONE; + EventManager em = EventManager.getDefault(); + ArrayList allEvents = new ArrayList (); + ArrayList allRequests = new ArrayList (); + for (int i = 0; i < events.length; ++i) + { + EventRequest[] r = em.getEventRequests(events[i]); + for (int j = 0; j < r.length; ++j) + { + /* This is hacky, but it's not clear whether this + can really happen, and if it does, what should + occur. */ + allEvents.add (events[i]); + allRequests.add (r[j]); + + // Perhaps this is overkill? + if (r[j].getSuspendPolicy() > suspendPolicy) + suspendPolicy = r[j].getSuspendPolicy(); + } + } + + try + { + Event[] e = new Event[allEvents.size()]; + allEvents.toArray(e); + EventRequest[] r = new EventRequest[allRequests.size()]; + allRequests.toArray(r); + sendEvents(r, e, suspendPolicy); + jdwp._enforceSuspendPolicy(suspendPolicy); + } + catch (Exception e) + { + /* Really not much we can do. For now, just print out + a warning to the user. */ + System.out.println ("Jdwp.notify: caught exception: " + e); + } + } + } + + /** + * Sends the event to the debugger. + * + * This method bypasses the event manager's filtering. + * + * @param request the debugger request for the event + * @param event the event to send + * @throws IOException if a communications failure occurs + */ + public static void sendEvent (EventRequest request, Event event) + throws IOException + { + sendEvents (new EventRequest[] { request }, new Event[] { event }, + request.getSuspendPolicy()); + } + + /** + * Sends the events to the debugger. + * + * This method bypasses the event manager's filtering. + * + * @param requests list of debugger requests for the events + * @param events the events to send + * @param suspendPolicy the suspendPolicy enforced by the VM + * @throws IOException if a communications failure occurs + */ + public static void sendEvents (EventRequest[] requests, Event[] events, + byte suspendPolicy) + throws IOException + { + Jdwp jdwp = getDefault(); + if (jdwp != null) + { + synchronized (jdwp._connection) + { + jdwp._connection.sendEvents (requests, events, suspendPolicy); + } + } + } + + // Helper function to enforce suspend policies on event notification + private void _enforceSuspendPolicy (byte suspendPolicy) + throws JdwpException + { + switch (suspendPolicy) + { + case EventRequest.SUSPEND_NONE: + // do nothing + break; + + case EventRequest.SUSPEND_THREAD: + VMVirtualMachine.suspendThread (Thread.currentThread ()); + break; + + case EventRequest.SUSPEND_ALL: + VMVirtualMachine.suspendAllThreads (); + break; + } + } + + /** + * Allows subcomponents to specify that they are + * initialized. + * + * Subcomponents include JdwpConnection and PacketProcessor. + */ + public void subcomponentInitialized () + { + synchronized (_initLock) + { + ++_initCount; + _initLock.notify (); + } + } + + public void run () + { + try + { + _doInitialization (); + + /* We need a little internal synchronization here, so that + when this thread dies, the back-end will be fully initialized, + ready to start servicing the VM and debugger. */ + synchronized (_initLock) + { + while (_initCount != 2) + _initLock.wait (); + } + _initLock = null; + } + catch (Throwable t) + { + System.out.println ("Exception in JDWP back-end: " + t); + System.exit (1); + } + + /* Force creation of the EventManager. If the event manager + has not been created when isDebugging is set, it is possible + that the VM will call Jdwp.notify (which uses EventManager) + while the EventManager is being created (or at least this is + a problem with gcj/gij). */ + EventManager.getDefault(); + + // Now we are finally ready and initialized + isDebugging = true; + } + + // A helper function to process the configure string "-Xrunjdwp:..." + private void _processConfigury (String configString) + { + // Loop through configuration arguments looking for a + // transport name + _properties = new HashMap (); + String[] options = configString.split (","); + for (int i = 0; i < options.length; ++i) + { + String[] property = options[i].split ("="); + if (property.length == 2) + _properties.put (property[0], property[1]); + // ignore malformed options + } + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/JdwpConstants.java b/libjava/classpath/gnu/classpath/jdwp/JdwpConstants.java new file mode 100644 index 000000000..80dd3f73a --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/JdwpConstants.java @@ -0,0 +1,901 @@ +/* JdwpConstants.java -- Constants defined by JDWP 1.4 specification + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp; + +/** + * Constants defined by JDWP specification. + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class JdwpConstants +{ + public static final class Version + { + public static final int MAJOR = 1; + public static final int MINOR = 4; + } + + //////////////////////////////////////// + // Commands/Sets // + //////////////////////////////////////// + + public static final class CommandSet + { + public static final class VirtualMachine + { + public static final byte CS_VALUE = 1; + + // commands + public static final byte VERSION = 1; + public static final byte CLASSES_BY_SIGNATURE = 2; + public static final byte ALL_CLASSES = 3; + public static final byte ALL_THREADS = 4; + public static final byte TOP_LEVEL_THREAD_GROUPS = 5; + public static final byte DISPOSE = 6; + public static final byte IDSIZES = 7; + public static final byte SUSPEND = 8; + public static final byte RESUME = 9; + public static final byte EXIT = 10; + public static final byte CREATE_STRING = 11; + public static final byte CAPABILITIES = 12; + public static final byte CLASS_PATHS = 13; + public static final byte DISPOSE_OBJECTS = 14; + public static final byte HOLD_EVENTS = 15; + public static final byte RELEASE_EVENTS = 16; + public static final byte CAPABILITIES_NEW = 17; + public static final byte REDEFINE_CLASSES = 18; + public static final byte SET_DEFAULT_STRATUM = 19; + public static final byte ALL_CLASSES_WITH_GENERIC = 20; + } + + public static final class ReferenceType + { + public static final byte CS_VALUE = 2; + + // commands + public static final byte SIGNATURE= 1; + public static final byte CLASS_LOADER= 2; + public static final byte MODIFIERS = 3; + public static final byte FIELDS = 4; + public static final byte METHODS = 5; + public static final byte GET_VALUES = 6; + public static final byte SOURCE_FILE = 7; + public static final byte NESTED_TYPES = 8; + public static final byte STATUS = 9; + public static final byte INTERFACES= 10; + public static final byte CLASS_OBJECT = 11; + public static final byte SOURCE_DEBUG_EXTENSION = 12; + public static final byte SIGNATURE_WITH_GENERIC = 13; + public static final byte FIELDS_WITH_GENERIC = 14; + public static final byte METHODS_WITH_GENERIC = 15; + } + + public static final class ClassType + { + public static final byte CS_VALUE = 3; + + // commands + public static final byte SUPERCLASS = 1; + public static final byte SET_VALUES = 2; + public static final byte INVOKE_METHOD = 3; + public static final byte NEW_INSTANCE = 4; + } + + public static final class ArrayType + { + public static final byte CS_VALUE = 4; + + // commands + public static final byte NEW_INSTANCE = 1; + } + + public static final class InterfaceType + { + public static final byte CS_VALUE = 5; + + // commands + } + + public static final class Method + { + public static final byte CS_VALUE = 6; + + // commands + public static final byte LINE_TABLE = 1; + public static final byte VARIABLE_TABLE = 2; + public static final byte BYTE_CODES = 3; + public static final byte IS_OBSOLETE = 4; + public static final byte VARIABLE_TABLE_WITH_GENERIC = 5; + } + + public static final class Field + { + public static final byte CS_VALUE = 8; + + // commands + } + + public static final class ObjectReference + { + public static final byte CS_VALUE = 9; + + // commands + public static final byte REFERENCE_TYPE = 1; + public static final byte GET_VALUES = 2; + public static final byte SET_VALUES = 3; + public static final byte MONITOR_INFO = 5; + public static final byte INVOKE_METHOD = 6; + public static final byte DISABLE_COLLECTION = 7; + public static final byte ENABLE_COLLECTION = 8; + public static final byte IS_COLLECTED = 9; + } + + public static final class StringReference + { + public static final byte CS_VALUE = 10; + + // commands + public static final byte VALUE = 1; + } + + public static final class ThreadReference + { + public static final byte CS_VALUE = 11; + + // commands + public static final byte NAME = 1; + public static final byte SUSPEND = 2; + public static final byte RESUME = 3; + public static final byte STATUS = 4; + public static final byte THREAD_GROUP = 5; + public static final byte FRAMES = 6; + public static final byte FRAME_COUNT = 7; + public static final byte OWNED_MONITORS = 8; + public static final byte CURRENT_CONTENDED_MONITOR = 9; + public static final byte STOP = 10; + public static final byte INTERRUPT = 11; + public static final byte SUSPEND_COUNT = 12; + } + + public static final class ThreadGroupReference + { + public static final byte CS_VALUE = 12; + + // commands + public static final byte NAME = 1; + public static final byte PARENT = 2; + public static final byte CHILDREN = 3; + } + + public static final class ArrayReference + { + public static final byte CS_VALUE = 13; + + // commands + public static final byte LENGTH = 1; + public static final byte GET_VALUES = 2; + public static final byte SET_VALUES = 3; + } + + public static final class ClassLoaderReference + { + public static final byte CS_VALUE = 14; + + // commands + public static final byte VISIBLE_CLASSES = 1; + } + + public static final class EventRequest + { + public static final byte CS_VALUE = 15; + + // commands + public static final byte SET = 1; + public static final byte CLEAR = 2; + public static final byte CLEAR_ALL_BREAKPOINTS = 3; + } + + public static final class StackFrame + { + public static final byte CS_VALUE = 16; + + // commands + public static final byte GET_VALUES = 1; + public static final byte SET_VALUES = 2; + public static final byte THIS_OBJECT = 3; + public static final byte POP_FRAMES = 4; + } + + public static final class ClassObjectReference + { + public static final byte CS_VALUE = 17; + + // commands + public static final byte REFLECTED_TYPE = 1; + } + + public static final int MAXIMUM = ClassObjectReference.CS_VALUE; + + public static final class Event + { + public static final byte CS_VALUE = 64; + + // commands + public static final byte COMPOSITE = 100; + } + } + + //////////////////////////////////////// + // Constants // + //////////////////////////////////////// + + /* + * Error constants + */ + public static final class Error + { + /** + * No error has occurred + */ + public static final short NONE = 0; + + /** + * Passed thread is null, is not a valid thread or has exited + */ + public static final short INVALID_THREAD = 10; + + /** + * Thread group invalid + */ + public static final short INVALID_THREAD_GROUP = 11; + + /** + * Invalid priority + */ + public static final short INVALID_PRIORITY = 12; + + /** + * Specified thread has not been suspended by an event + */ + public static final short THREAD_NOT_SUSPENDED = 13; + + /** + * Thread already suspended + */ + public static final short THREAD_SUSPENDED = 14; + + /** + * Reference type has been unloaded and garbage collected + */ + public static final short INVALID_OBJECT = 20; + + /** + * Invalid class + */ + public static final short INVALID_CLASS = 21; + + /** + * Class has been loaded but not yet prepared + */ + public static final short CLASS_NOT_PREPARED = 22; + + /** + * Invalid method + */ + public static final short INVALID_METHODID = 23; + + /** + * Invalid location + */ + public static final short INVALID_LOCATION = 24; + + /** + * Invalid field + */ + public static final short INVALID_FIELDID = 25; + + /** + * Invaliid frame + */ + public static final short INVALID_FRAMEID = 30; + + /** + * There are no more Java or JNI frames on the call stack + */ + public static final short NO_MORE_FRAMES = 31; + + /** + * Information about the frame is not available + */ + public static final short OPAQUE_FRAME = 32; + + /** + * Operation can only be performed on current frame + */ + public static final short NOT_CURRENT_FRAME = 33; + + /** + * Variable is not an appropriate type for the function used + */ + public static final short TYPE_MISMATCH = 34; + + /** + * Invalid slot + */ + public static final short INVALID_SLOT = 35; + + /** + * Item already set + */ + public static final short DUPLICATE = 40; + + /** + * Desired element not found + */ + public static final short NOT_FOUND = 41; + + /** + * Invalid monitor + */ + public static final short INVALID_MONITOR = 50; + + /** + * Thread doesn't own the monitor + */ + public static final short NOT_MONITOR_OWNER = 51; + + /** + * Call has been interrupted before completion + */ + public static final short INTERRUPT = 52; + + /** + * Virtual machine attempted to read a class file and determined that + * the file is malformed or otherwise cannot be interpreted as a class + * file + */ + public static final short INVALID_CLASS_FORMAT = 60; + + /** + * Circularity has been detected while initializing a class + */ + public static final short CIRCULAR_CLASS_DEFINITION = 61; + + /** + * Verifier detected that a class file, though well formed, contained + * some sort of internal inconsistency or security problem + */ + public static final short FAILS_VERIFICATION = 62; + + /** + * Adding methods has not been implemented + */ + public static final short ADD_METHOD_NOT_IMPLEMENTED = 63; + + /** + * Schema change has not been implemented + */ + public static final short SCHEMA_CHANGE_NOT_IMPLEMENTED = 64; + + /** + * State of the thread has been modified and is now inconsistent + */ + public static final short INVALID_TYPESTATE = 65; + + /** + * A direct superclass is different for the new class version, or the set + * of directly implemented interfaces is different and + * canUnrestrictedlyRedefineClasses is false + */ + public static final short HIERARCHY_CHANGE_NOT_IMPLEMENTED = 66; + + /** + * New class version does not declare a method declared in the old + * class version and canUnrestrictedlyRedefineClasses + * is false + */ + public static final short DELETE_METHOD_NOT_IMPLEMENTED = 67; + + /** + * Class file has a version number not supported by this VM + */ + public static final short UNSUPPORTED_VERSION = 68; + + /** + * Class name defined in the new class file is different from the name + * in the old class object + */ + public static final short NAMES_DONT_MATCH = 69; + + /** + * New class version has different modifiers and + * canUnrestrictedlyRedefineClasses is false + */ + public static final short CLASS_MODIFIERS_CHANGE_NOT_IMPLEMENTED = 70; + + /** + * A method in the new class version has different modifiers than its + * counterpart in the old class version and + * canUnrestrictedlyRedefineClasses is false. + */ + public static final short METHOD_MODIFIERS_CHANGE_NOT_IMPLEMENTED = 71; + + /** + * Functionality is not implemented in this virtual machine + */ + public static final short NOT_IMPLEMENTED = 99; + + /** + * Invalid pointer + */ + public static final short NULL_POINTER = 100; + + /** + * Desired information is not available + */ + public static final short ABSENT_INFORMATION = 101; + + /** + * Specified event type id is not recognized + */ + public static final short INVALID_EVENT_TYPE = 102; + + /** + * Illegal argument + */ + public static final short ILLEGAL_ARGUMENT = 103; + + /** + * The function needed to allocate memory and no more memory was + * available for allocation + */ + public static final short OUT_OF_MEMORY = 110; + + /** + * Debugging has not been enabled in this virtual machine. JVMDI cannot + * be used + */ + public static final short ACCESS_DENIED = 111; + + /** + * The virtual machine is not running + */ + public static final short VM_DEAD = 112; + + /** + * An unexpected internal error has occurred + */ + public static final short INTERNAL = 113; + + /** + * The thread being used to call this function is not attached to the + * virtual machine. Calls must be made from attached threads. + */ + public static final short UNATTACHED_THREAD = 115; + + /** + * Invalid object type id or class tag + */ + public static final short INVALID_TAG = 500; + + /** + * Previous invoke not complete + */ + public static final short ALREADY_INVOKING = 502; + + /** + * Invalid index + */ + public static final short INVALID_INDEX = 503; + + /** + * Invalid length + */ + public static final short INVALID_LENGTH = 504; + + /** + * Invalid string + */ + public static final short INVALID_STRING = 506; + + /** + * Invalid class loader + */ + public static final short INVALID_CLASS_LOADER = 507; + + /** + * Invalid array + */ + public static final short INVALID_ARRAY = 508; + + /** + * Unable to load the transport + */ + public static final short TRANSPORT_LOAD = 509; + + /** + * Unablie to initialize the transport + */ + public static final short TRANSPORT_INIT = 510; + + /** + * Method is native + */ + public static final short NATIVE_METHOD = 511; + + /** + * Invalid count + */ + public static final short INVALID_COUNT = 512; + } + + /* + * EventKind constants + */ + public static final class EventKind + { + public static final byte SINGLE_STEP = 1; + public static final byte BREAKPOINT = 2; + public static final byte FRAME_POP = 3; + public static final byte EXCEPTION = 4; + public static final byte USER_DEFINED = 5; + public static final byte THREAD_START = 6; + public static final byte THREAD_END = 7; + public static final byte CLASS_PREPARE = 8; + public static final byte CLASS_UNLOAD = 9; + public static final byte CLASS_LOAD = 10; + public static final byte FIELD_ACCESS = 20; + public static final byte FIELD_MODIFICATION = 21; + public static final byte EXCEPTION_CATCH = 30; + public static final byte METHOD_ENTRY = 40; + public static final byte METHOD_EXIT = 41; + public static final byte VM_INIT = 90; + public static final byte VM_DEATH = 99; + public static final byte VM_DISCONNECTED = 100; + + public static final byte VM_START = VM_INIT; + public static final byte THREAD_DEATH = THREAD_END; + } + + /* + * ModKind constants (event filters) + */ + public static final class ModKind + { + /** + * Limit the requested event to be reported at most once after a + * given number of occurrences. May be used with any event. + */ + public static final byte COUNT = 1; + + /** + * Conditional on expression + */ + public static final byte CONDITIONAL = 2; + + /** + * Restricts reported events to those in the given thread. + * May be used with any event except for class unload. + */ + public static final byte THREAD_ONLY = 3; + + /** + * For class prepare events, restricts generated events + * to be the preparation of the given reference type and any + * subtypes. + * + * For other events, restricts the generated events to those where + * location is in the given reference type or any of its subtypes. + * + * An event will be generated for any location in a reference type + * that can be safely cast to the given reference type. + * + * May be used with any event except class unload, thread start, + * and thread end. + */ + public static final byte CLASS_ONLY = 4; + + /** + * Restricts reported events to those for classes whose name matches + * the given restricted regular expression. + * + * For class prepare events, the prepared class name is matched. + * For class unload events, the unloaded class name is matched. + * For other events, the class name of the event's location is matched. + * + * May be used with any event except thread start and thread end. + */ + public static final byte CLASS_MATCH = 5; + + /** + * Restricts reported events to those for classes whose name does not + * match the given restricted regular expression. + * + * For class prepare events, the prepared class name is matched. + * For class unload events, the unloaded class name is matched. + * For other events, the class name of the event's location is matched. + * + * May be used with any event except thread start and thread end. + */ + public static final byte CLASS_EXCLUDE = 6; + + /** + * Restricts reported events to those that occur at the given location. + * + * May be used with breakpoint, field access, field modification, step, + * and exception event kinds. + */ + public static final byte LOCATION_ONLY = 7; + + /** + * Restricts reported exceptions by their class and whether they are + * caught or uncaught. + * + * May be used with exception event kinds only. + */ + public static final byte EXCEPTION_ONLY = 8; + + /** + * Restricts reported events to those that occur for a given field. + * + * May be used with field access and field modification event kinds only. + */ + public static final byte FIELD_ONLY = 9; + + /** + * Restricts reported step events to those which satisfy depth and + * size constraints. + * + * May be used with step event kinds only. + */ + public static final byte STEP = 10; + + /** + * Restricts reported events to those whose active 'this' object is + * the given object. Match value is the null object for static methods. + * + * May be used with any event except class prepare, class unload, + * thread start, and thread end. + */ + public static final byte INSTANCE_ONLY = 11; + } + + /* + * ThreadStatus constants + */ + public static final class ThreadStatus + { + public static final int ZOMBIE = 0; + public static final int RUNNING = 1; + public static final int SLEEPING = 2; + public static final int MONITOR = 3; + public static final int WAIT = 4; + } + + /* + * SuspendStatus constants + */ + public static final class SuspendStatus + { + public static final byte SUSPENDED = 1; + } + + /* + * ClassStatus constants + */ + public static final class ClassStatus + { + public static final int VERIFIED = 1; + public static final int PREPARED = 2; + public static final int INITIALIZED = 4; + public static final int ERROR = 8; + } + + /* + * TypeTag constants + */ + public static final class TypeTag + { + public static final byte CLASS = 1; + public static final byte INTERFACE = 2; + public static final byte ARRAY = 3; + } + + /* + * Tag constants + */ + public static final class Tag + { + /** + * Array object (objectID size) + */ + public static final byte ARRAY = '['; + + /** + * Byte value (1 byte) + */ + public static final byte BYTE = 'B'; + + /** + * Character value (2 bytes) + */ + public static final byte CHAR = 'C'; + + /** + * Object (objectID size) + */ + public static final byte OBJECT = 'L'; + + /** + * Float value (4 bytes) + */ + public static final byte FLOAT = 'F'; + + /** + * Double value (8 bytes) + */ + public static final byte DOUBLE = 'D'; + + /** + * Int value (4 bytes) + */ + public static final byte INT = 'I'; + + /** + * Long value (8 bytes) + */ + public static final byte LONG = 'J'; + + /** + * Short value (2 bytes) + */ + public static final byte SHORT = 'S'; + + /** + * Void value (no bytes) + */ + public static final byte VOID = 'V'; + + /** + * Boolean value (1 byte) + */ + public static final byte BOOLEAN = 'Z'; + + /** + * String object (objectID size) + */ + public static final byte STRING = 's'; + + /** + * Thread object (objectID size) + */ + public static final byte THREAD = 't'; + + /** + * ThreadGroup object (objectID size) + */ + public static final byte THREAD_GROUP = 'g'; + + /** + * ClassLoader object (objectID size) + */ + public static final byte CLASS_LOADER = 'l'; + + /** + * Class object object (objectID size) + */ + public static final byte CLASS_OBJECT = 'c'; + } + + /* + * StepDepth constants + */ + public static final class StepDepth + { + /** + * Step into any method calls that occur before the end of the step + */ + public static final int INTO = 0; + + /** + * Step over any method calls that occur before the end of the step + */ + public static final int OVER = 1; + + /** + * Step out of the current method + */ + public static final int OUT = 2; + } + + /* + * StepSize constants + */ + public static final class StepSize + { + /** + * Step by the minimum possible amount (often a bytecode instruction) + */ + public static final int MIN = 0; + + /** + * Step to the next source line unless there is no line number information, + * in which case MIN step is done instead + */ + public static final int LINE = 1; + } + + /* + * SuspendPolicy constants + */ + public static final class SuspendPolicy + { + /** + * Suspend no threads when this event is encountered + */ + public static final byte NONE = 0; + + /** + * Suspend the event thread when this event is encountered + */ + public static final byte EVENT_THREAD = 1; + + /** + * Suspend all threads when this event is encountered + */ + public static final byte ALL = 2; + } + + /* + * InvokeOptions flag constants + */ + public static final class InvokeOptions + { + /** + * otherwise, all threads started + */ + public static final int INVOKE_SINGLE_THREADED = 0x1; + + /** + * otherwise, normal virtual invoke (instance methods only) + */ + public static final int INVOKE_NONVIRTUAL = 0x2; + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/event/BreakpointEvent.java b/libjava/classpath/gnu/classpath/jdwp/event/BreakpointEvent.java new file mode 100644 index 000000000..46e50de16 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/event/BreakpointEvent.java @@ -0,0 +1,117 @@ +/* BreakpointEvent.java -- An event specifying that the interpreter + has hit a breakpoint + Copyright (C) 2006 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.event; + +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.VMIdManager; +import gnu.classpath.jdwp.id.ThreadId; +import gnu.classpath.jdwp.util.Location; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * "Notification of a breakpoint in the target VM. The breakpoint event is + * generated before the code at its location is executed." + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class BreakpointEvent + extends Event +{ + // The thread in which this event occurred + private Thread _thread; + + // Location where breakpoint occurred + private Location _location; + + //object instance + private Object _instance; + + /** + * Constructs a new BreakpointEvent + * + * @param thread thread in which event occurred + * @param loc location where breakpoint occurred + * @param instance object instance + */ + public BreakpointEvent(Thread thread, Location loc, Object instance) + { + super(JdwpConstants.EventKind.BREAKPOINT); + _thread = thread; + _location = loc; + _instance = instance; + } + + /** + * Returns a specific filtering parameter for this event. + * Valid types are thread and location. + * + * @param type the type of parameter desired + * @returns the desired parameter or null + */ + public Object getParameter(int type) + { + if (type == EVENT_THREAD) + return _thread; + else if (type == EVENT_LOCATION) + return _location; + else if (type == EVENT_INSTANCE) + return _instance; + + return null; + } + + /** + * Writes the event to the given stream + * + * @param outStream the output stream to write the event to + */ + protected void _writeData (DataOutputStream outStream) + throws IOException + { + VMIdManager idm = VMIdManager.getDefault(); + ThreadId tid = (ThreadId) idm.getObjectId(_thread); + + tid.write(outStream); + _location.write(outStream); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/event/ClassPrepareEvent.java b/libjava/classpath/gnu/classpath/jdwp/event/ClassPrepareEvent.java new file mode 100644 index 000000000..f21f8e7c0 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/event/ClassPrepareEvent.java @@ -0,0 +1,147 @@ +/* ClassPrepareEvent.java -- An event specifying that a class has been + prepared by the virtual machine + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.event; + +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.VMIdManager; +import gnu.classpath.jdwp.id.ReferenceTypeId; +import gnu.classpath.jdwp.id.ThreadId; +import gnu.classpath.jdwp.util.JdwpString; +import gnu.classpath.jdwp.util.Signature; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * "Notification of a class prepare in the target VM. See the JVM + * specification for a definition of class preparation. Class prepare + * events are not generated for primtiive classes (for example, + * java.lang.Integer.TYPE)." -- JDWP 1.4.2 + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class ClassPrepareEvent + extends Event +{ + // The thread in which this event occurred + private Thread _thread; + + // The class that was prepared + private Class _class; + + // Prepare flags + private int _status; + + /** + * Class has been verified + */ + public static final int STATUS_VERIFIED + = JdwpConstants.ClassStatus.VERIFIED; + + /** + * Class has been prepared + */ + public static final int STATUS_PREPARED + = JdwpConstants.ClassStatus.PREPARED; + + /** + * Class has been initialized + */ + public static final int STATUS_INITIALIZED + = JdwpConstants.ClassStatus.INITIALIZED; + + /** + * Error preparing class + */ + public static final int STATUS_ERROR + = JdwpConstants.ClassStatus.ERROR; + + /** + * Constructs a new ClassPrepareEvent + * + * @param thread thread in which event occurred + * @param clazz class which was prepared + * @param flags prepare status flags + */ + public ClassPrepareEvent (Thread thread, Class clazz, int flags) + { + super (JdwpConstants.EventKind.CLASS_PREPARE); + _thread = thread; + _class = clazz; + _status = flags; + } + + /** + * Returns a specific filtering parameter for this event. + * Valid types are thread and class. + * + * @param type the type of parameter desired + * @returns the desired parameter or null + */ + public Object getParameter (int type) + { + if (type == EVENT_THREAD) + return _thread; + else if (type == EVENT_CLASS) + return _class; + + return null; + } + + /** + * Writes the event to the given stream + * + * @param outStream the output stream to write the event to + */ + protected void _writeData (DataOutputStream outStream) + throws IOException + { + VMIdManager idm = VMIdManager.getDefault(); + ThreadId tid = (ThreadId) idm.getObjectId (_thread); + ReferenceTypeId rid = idm.getReferenceTypeId (_class); + + tid.write (outStream); + rid.writeTagged (outStream); + JdwpString.writeString (outStream, + Signature.computeClassSignature (_class)); + outStream.writeInt (_status); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/event/ClassUnloadEvent.java b/libjava/classpath/gnu/classpath/jdwp/event/ClassUnloadEvent.java new file mode 100644 index 000000000..a35d3b9bd --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/event/ClassUnloadEvent.java @@ -0,0 +1,96 @@ +/* ClassUnloadEvent.java -- event generated when a class is unloaded + 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.jdwp.event; + +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.VMIdManager; +import gnu.classpath.jdwp.util.JdwpString; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * "Notification of a class unload in the target VM" -- JDWP 1.4.2 + * + * @author Kyle Galloway (kgallowa@redhat.com) + */ +public class ClassUnloadEvent + extends Event +{ + //signature directly from VM + private String _signature; + + /** + * Constructs a new ClassUnloadEvent + * + * @param signature the signature reported from the VM + */ + public ClassUnloadEvent(String signature) + { + super(JdwpConstants.EventKind.CLASS_UNLOAD); + _signature = signature; + } + + /** + * Returns a specific filtering parameter for this event. Class is the only + * valid type. + * + * @param type the type of parameter desired + * @returns the desired parameter or null + */ + public Object getParameter(int type) + { + + return null; + } + + /** + * Writes the event to the given stream + * + * @param outStream the output stream to write the event to + */ + protected void _writeData(DataOutputStream outStream) + throws IOException + { + VMIdManager idm = VMIdManager.getDefault(); + + JdwpString.writeString(outStream, _signature); + } + +} diff --git a/libjava/classpath/gnu/classpath/jdwp/event/Event.java b/libjava/classpath/gnu/classpath/jdwp/event/Event.java new file mode 100644 index 000000000..492cadbcc --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/event/Event.java @@ -0,0 +1,180 @@ +/* Event.java -- a base class for all event types + Copyright (C) 2005, 2007 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.event; + +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.transport.JdwpCommandPacket; +import gnu.classpath.jdwp.transport.JdwpPacket; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * This class is a base class for all VM->debugger event + * notifications. + * + * @author Keith Seitz (keiths@redhat.com) + */ +public abstract class Event +{ + /** + * The class of the object in which the event occurred + */ + public static final int EVENT_CLASS = 1; + + /** + * The thread where the event occurred + */ + public static final int EVENT_THREAD = 2; + + /** + * The location where an event occurred + */ + public static final int EVENT_LOCATION = 3; + + /** + * The instance of the class where the event occurred + */ + public static final int EVENT_INSTANCE = 4; + + /** + * The field acted on by an event + */ + public static final int EVENT_FIELD = 5; + + /** + * The class of the exception for ExceptionEvent + */ + public static final int EVENT_EXCEPTION_CLASS = 6; + + /** + * Whether this exception was caught (only valid for ExceptionEvents) + */ + public static final int EVENT_EXCEPTION_CAUGHT = 7; + + // The kind of event represented by this event + private byte _eventKind; + + /** + * Constructs an Event of the given kind + * + * @param kind the type of event + */ + public Event (byte kind) + { + _eventKind = kind; + } + + /** + * Returns the event type of this event + * + * @returns the event kind + */ + public byte getEventKind () + { + return _eventKind; + } + + /** + * Abstract function used by implementing classes to fill in the + * event-specific data. Note that request ID is automatically added + * by this class (since it appears in all event notifications). + * + * @param outStream the stream to which to write data + */ + protected abstract void _writeData (DataOutputStream outStream) + throws IOException; + + /** + * Returns a specific filtering parameter for this event. For example, + * most events may be filtered by thread. Consequently, a call to this + * method with ThreadId.class should return a + * Thread. + * + * @param type the type of parameter to return + * @returns the parameter (not the ID) or null if none is + * is defined for this event + */ + public abstract Object getParameter (int type); + + /** + * Converts the events into to a single JDWP Event.COMPOSITE packet + * + * @param dos the stream to which to write data + * @param events the events to package into the packet + * @param requests the corresponding event requests + * @param suspendPolicy the suspend policy enforced by the VM + * @returns a JdwpPacket of the events + */ + public static JdwpPacket toPacket (DataOutputStream dos, + Event[] events, + EventRequest[] requests, + byte suspendPolicy) + { + JdwpPacket pkt; + try + { + dos.writeByte (suspendPolicy); + dos.writeInt (events.length); + for (int i = 0; i < events.length; ++i) + _toData (dos, events[i], requests[i]); + + pkt + = new JdwpCommandPacket (JdwpConstants.CommandSet.Event.CS_VALUE, + JdwpConstants.CommandSet.Event.COMPOSITE); + } + catch (IOException ioe) + { + pkt = null; + } + + return pkt; + } + + // Helper function for toPacket + private static void _toData (DataOutputStream dos, Event event, + EventRequest request) + throws IOException + { + dos.writeByte (event._eventKind); + dos.writeInt (request.getId ()); + event._writeData (dos); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/event/EventManager.java b/libjava/classpath/gnu/classpath/jdwp/event/EventManager.java new file mode 100644 index 000000000..3f34a5ee9 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/event/EventManager.java @@ -0,0 +1,305 @@ +/* EventManager.java -- event management and notification infrastructure + Copyright (C) 2005, 2006, 2007 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.event; + +import gnu.classpath.jdwp.Jdwp; +import gnu.classpath.jdwp.VMVirtualMachine; +import gnu.classpath.jdwp.exception.InvalidEventTypeException; +import gnu.classpath.jdwp.exception.JdwpException; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Hashtable; +import java.util.Iterator; + +/** + * Manages event requests and filters event notifications. + * + * The purpose of this class is actually two-fold: + * + * 1) Maintain a list of event requests from the debugger + * 2) Filter event notifications from the VM + * + * If an event request arrives from the debugger, the back-end will + * call {@link #requestEvent}, which will first check for a valid event. + * If it is valid, EventManager will record the request + * internally and register the event with the virtual machine, which may + * choose to handle the request itself (as is likely the case with + * breakpoints and other execution-related events), or it may decide to + * allow the EventManager to handle notifications and all + * filtering (which is convenient for other events such as class (un)loading). + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class EventManager +{ + // Single instance + private static EventManager _instance = null; + + // maps event (EVENT_*) to lists of EventRequests + private Hashtable _requests = null; + + /** + * Returns an instance of the event manager + * + * @return the event manager + */ + public static EventManager getDefault() + { + if (_instance == null) + _instance = new EventManager(); + + return _instance; + } + + // Private constructs a new EventManager + private EventManager () + { + _requests = new Hashtable (); + + // Add lists for all the event types + _requests.put (new Byte (EventRequest.EVENT_SINGLE_STEP), + new Hashtable ()); + _requests.put (new Byte (EventRequest.EVENT_BREAKPOINT), + new Hashtable ()); + _requests.put (new Byte (EventRequest.EVENT_FRAME_POP), + new Hashtable ()); + _requests.put (new Byte (EventRequest.EVENT_EXCEPTION), + new Hashtable ()); + _requests.put (new Byte (EventRequest.EVENT_USER_DEFINED), + new Hashtable ()); + _requests.put (new Byte (EventRequest.EVENT_THREAD_START), + new Hashtable ()); + _requests.put (new Byte (EventRequest.EVENT_THREAD_END), + new Hashtable ()); + _requests.put (new Byte (EventRequest.EVENT_CLASS_PREPARE), + new Hashtable ()); + _requests.put (new Byte (EventRequest.EVENT_CLASS_UNLOAD), + new Hashtable ()); + _requests.put (new Byte (EventRequest.EVENT_CLASS_LOAD), + new Hashtable ()); + _requests.put (new Byte (EventRequest.EVENT_FIELD_ACCESS), + new Hashtable ()); + _requests.put (new Byte (EventRequest.EVENT_FIELD_MODIFY), + new Hashtable ()); + _requests.put (new Byte (EventRequest.EVENT_METHOD_ENTRY), + new Hashtable ()); + _requests.put (new Byte (EventRequest.EVENT_METHOD_EXIT), + new Hashtable ()); + _requests.put (new Byte (EventRequest.EVENT_VM_INIT), + new Hashtable ()); + _requests.put (new Byte (EventRequest.EVENT_VM_DEATH), + new Hashtable ()); + + // Add auto-generated event notifications + // only two: VM_INIT, VM_DEATH + try + { + byte sp = (Jdwp.suspendOnStartup() + ? EventRequest.SUSPEND_THREAD : EventRequest.SUSPEND_NONE); + requestEvent (new EventRequest (0, + EventRequest.EVENT_VM_INIT, sp)); + requestEvent (new EventRequest (0, + EventRequest.EVENT_VM_DEATH, + EventRequest.SUSPEND_NONE)); + } + catch (JdwpException e) + { + // This can't happen + } + } + + /** + * Returns all requests for the given event. This method will only + * be used if the EventManager is handling event filtering. + * + * @param event the event + * @return requests that are interested in this event + * or null if none (and event should not be sent) + * @throws IllegalArgumentException for invalid event kind + */ + public EventRequest[] getEventRequests(Event event) + { + ArrayList interestedEvents = new ArrayList(); + Hashtable requests; + Byte kind = new Byte(event.getEventKind()); + requests = (Hashtable) _requests.get(kind); + if (requests == null) + { + // Did not get a valid event type + throw new IllegalArgumentException("invalid event kind: " + kind); + } + + // Loop through the requests. Must look at ALL requests in order + // to evaluate all filters (think count filter). + Iterator rIter = requests.values().iterator(); + while (rIter.hasNext()) + { + EventRequest request = (EventRequest) rIter.next(); + if (request.matches(event)) + interestedEvents.add(request); + } + + EventRequest[] r = new EventRequest[interestedEvents.size()]; + interestedEvents.toArray(r); + return r; + } + + /** + * Requests monitoring of an event. + * + * The debugger registers for event notification through + * an event filter. If no event filter is specified for an event + * in the VM, it is assumed that the debugger is not interested in + * receiving notifications of this event. + * + * The virtual machine will be notified of the request. + * + * @param request the request to monitor + * @throws InvalidEventTypeException for invalid event kind + * @throws JdwpException for other errors involving request + */ + public void requestEvent (EventRequest request) + throws JdwpException + { + // Add request to request list + Hashtable requests; + Byte kind = new Byte (request.getEventKind ()); + requests = (Hashtable) _requests.get (kind); + if (requests == null) + { + // Did not get a valid event type + throw new InvalidEventTypeException (request.getEventKind ()); + } + + // Register the event with the VM + VMVirtualMachine.registerEvent (request); + requests.put (new Integer (request.getId ()), request); + } + + /** + * Deletes the given request from the management table + * + * @param kind the event kind + * @param id the ID of the request to delete + * @throws IllegalArgumentException for invalid event kind + * @throws JdwpException for other errors deleting request + */ + public void deleteRequest (byte kind, int id) + throws JdwpException + { + Hashtable requests; + requests = (Hashtable) _requests.get (new Byte (kind)); + if (requests == null) + { + // Did not get a valid event type + throw new IllegalArgumentException ("invalid event kind: " + kind); + } + + Integer iid = new Integer (id); + EventRequest request = (EventRequest) requests.get (iid); + if (request != null) + { + VMVirtualMachine.unregisterEvent (request); + requests.remove (iid); + } + } + + /** + * Clears all the requests for a given event + * + * @param kind the event kind + * @throws IllegalArgumentException for invalid event kind + * @throws JdwpException for error clearing events + */ + public void clearRequests (byte kind) + throws JdwpException + { + Hashtable requests = (Hashtable) _requests.get (new Byte (kind)); + if (requests == null) + { + // Did not get a valid event type + throw new IllegalArgumentException ("invalid event kind: " + kind); + } + + VMVirtualMachine.clearEvents (kind); + requests.clear (); + } + + /** + * Returns a given event request for an event + * + * @param kind the kind of event for the request + * @param id the integer request id to return + * @return the request for the given event kind with the given id + * (or null if not found) + * @throws IllegalArgumentException for invalid event kind + */ + public EventRequest getRequest (byte kind, int id) + { + Hashtable requests = (Hashtable) _requests.get (new Byte (kind)); + if (requests == null) + { + // Did not get a valid event type + throw new IllegalArgumentException ("invalid event kind: " + kind); + } + + return (EventRequest) requests.get (new Integer (id)); + } + + /** + * Returns all requests of the given event kind + * + * @param kind the event kind + * @returns a Collection of all the registered requests + * @throws IllegalArgumentException for invalid event kind + */ + public Collection getRequests (byte kind) + { + Hashtable requests = (Hashtable) _requests.get (new Byte (kind)); + if (requests == null) + { + // Did not get a valid event type + throw new IllegalArgumentException ("invalid event kind: " + kind); + } + + return requests.values (); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/event/EventRequest.java b/libjava/classpath/gnu/classpath/jdwp/event/EventRequest.java new file mode 100644 index 000000000..891da229b --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/event/EventRequest.java @@ -0,0 +1,383 @@ +/* EventRequest.java -- an event request from the debugger + Copyright (C) 2005, 2006 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.event; + +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.event.filters.*; +import gnu.classpath.jdwp.exception.JdwpIllegalArgumentException; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; + +/** + * A class which represents a request by the debugger for an event + * in the VM. EventRequests usually have event filters + * associated with them, which allow the debugger to specify conditions + * under which the notification should be sent (specific thread, specific + * class, ignore count, etc). + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class EventRequest +{ + /* + * Event types + */ + + /** + * Single step event + */ + public static final byte EVENT_SINGLE_STEP = + JdwpConstants.EventKind.SINGLE_STEP; + + /** + * Breakpoint event + */ + public static final byte EVENT_BREAKPOINT = + JdwpConstants.EventKind.BREAKPOINT; + + /** + * Frame pop event + */ + public static final byte EVENT_FRAME_POP = + JdwpConstants.EventKind.FRAME_POP; + + /** + * Exception event + */ + public static final byte EVENT_EXCEPTION = + JdwpConstants.EventKind.EXCEPTION; + + /** + * User-defined event + */ + public static final byte EVENT_USER_DEFINED = + JdwpConstants.EventKind.USER_DEFINED; + + /** + * Thread start event + */ + public static final byte EVENT_THREAD_START = + JdwpConstants.EventKind.THREAD_START; + + /** + * Thread end/death event + */ + public static final byte EVENT_THREAD_END = + JdwpConstants.EventKind.THREAD_END; + + /** + * Class prepare event + */ + public static final byte EVENT_CLASS_PREPARE = + JdwpConstants.EventKind.CLASS_PREPARE; + + /** + * Class unload event + */ + public static final byte EVENT_CLASS_UNLOAD = + JdwpConstants.EventKind.CLASS_UNLOAD; + + /** + * Class load event + */ + public static final byte EVENT_CLASS_LOAD = + JdwpConstants.EventKind.CLASS_LOAD; + + /** + * Field access event + */ + public static final byte EVENT_FIELD_ACCESS = + JdwpConstants.EventKind.FIELD_ACCESS; + + /** + * Field modify event + */ + public static final byte EVENT_FIELD_MODIFY = + JdwpConstants.EventKind.FIELD_MODIFICATION; + + /** + * Method entry event + */ + public static final byte EVENT_METHOD_ENTRY = + JdwpConstants.EventKind.METHOD_ENTRY; + + /** + * Method exit event + */ + public static final byte EVENT_METHOD_EXIT = + JdwpConstants.EventKind.METHOD_EXIT; + + /** + * Virtual machine initialization/start + */ + public static final byte EVENT_VM_INIT = + JdwpConstants.EventKind.VM_INIT; + + /** + * Virutal machine death + */ + public static final byte EVENT_VM_DEATH = + JdwpConstants.EventKind.VM_DEATH; + + + /* + * Suspend policies + */ + + /** + * Do not suspend any threads + */ + public static final byte SUSPEND_NONE = + JdwpConstants.SuspendPolicy.NONE; + + /** + * Suspend the thread in which the event occurred + */ + public static final byte SUSPEND_THREAD = + JdwpConstants.SuspendPolicy.EVENT_THREAD; + + /** + * Suspend all threads + */ + public static final byte SUSPEND_ALL = + JdwpConstants.SuspendPolicy.ALL; + + // ID of last EventRequest + private static int _last_id = 0; + private static Object _idLock = new Object (); + + // A list of filters + private LinkedList _filters; + + // The ID of this request + private int _id; + + // The suspend policy to enforce when this event occurs + private byte _suspendPolicy; + + // Kind of event requested + private byte _kind; + + /** + * Construct a new EventRequest + * + * @param kind the kind of event requested + * @param suspendPolicy how to suspend threads when event occurs + */ + public EventRequest (byte kind, byte suspendPolicy) + { + _filters = new LinkedList (); + synchronized (_idLock) + { + _id = ++_last_id; + } + _kind = kind; + _suspendPolicy = suspendPolicy; + } + + /** + * Construct a new EventRequest with the given ID + * + * @param id the id of the request to create + * @param kind the kind of event requested + * @param suspendPolicy how to suspend threads when event occurs + */ + public EventRequest (int id, byte kind, byte suspendPolicy) + { + _filters = new LinkedList (); + _kind = kind; + _suspendPolicy = suspendPolicy; + } + + /** + * Creates a new event filter, adding it to this request + * + * @param filter the filter to add + * @throws JdwpIllegalArgumentException if an invalid or illegal filter + * is added to the request + */ + public void addFilter (IEventFilter filter) + throws JdwpIllegalArgumentException + { + // Check validity of filter for this request + boolean valid = true; + + Class clazz = filter.getClass (); + if (clazz == ClassExcludeFilter.class) + { + if (_kind == EVENT_THREAD_START + || _kind == EVENT_THREAD_END) + valid = false; + } + else if (clazz == ClassMatchFilter.class) + { + if (_kind == EVENT_THREAD_START + || _kind == EVENT_THREAD_END) + valid = false; + } + else if (clazz == ClassOnlyFilter.class) + { + if (_kind == EVENT_CLASS_UNLOAD + || _kind == EVENT_THREAD_START + || _kind == EVENT_THREAD_END) + valid = false; + } + else if (clazz == ConditionalFilter.class) + { + // JDWP 1.4 does not say much about this + } + else if (clazz == CountFilter.class) + { + // may be used with any event + } + else if (clazz == ExceptionOnlyFilter.class) + { + if (_kind != EVENT_EXCEPTION) + valid = false; + } + else if (clazz == FieldOnlyFilter.class) + { + if (_kind != EVENT_FIELD_ACCESS + && _kind != EVENT_FIELD_MODIFY) + valid = false; + } + else if (clazz == InstanceOnlyFilter.class) + { + if (_kind == EVENT_CLASS_PREPARE + || _kind == EVENT_CLASS_UNLOAD + || _kind == EVENT_THREAD_START + || _kind == EVENT_THREAD_END) + valid = false; + } + else if (clazz == LocationOnlyFilter.class) + { + if (_kind != EVENT_BREAKPOINT + && _kind != EVENT_FIELD_ACCESS + && _kind != EVENT_FIELD_MODIFY + && _kind != EVENT_SINGLE_STEP + && _kind != EVENT_EXCEPTION) + valid = false; + } + else if (clazz == StepFilter.class) + { + if (_kind != EVENT_SINGLE_STEP) + valid = false; + } + else if (clazz == ThreadOnlyFilter.class) + { + if (_kind == EVENT_CLASS_UNLOAD) + valid = false; + } + + if (!valid) + { + String msg = ("cannot use " + filter.getClass ().getName () + + " with class unload events"); + throw new JdwpIllegalArgumentException (msg); + } + + // Add filter to list + _filters.add (filter); + } + + /** + * Returns the filters attached to this request + */ + public Collection getFilters () + { + return _filters; + } + + /** + * Returns the suspend policy for this request + */ + public byte getSuspendPolicy () + { + return _suspendPolicy; + } + + /** + * Returns the request id of this request + */ + public int getId () + { + return _id; + } + + /** + * Sets the id of the request (used for auto-generated events) + */ + public void setId (int id) + { + _id = id; + } + + /** + * Returns the kind of event for this request + */ + public byte getEventKind () + { + return _kind; + } + + /** + * Determines whether the given event matches this request + * + * @param theEvent the event to compare to + */ + public boolean matches (Event theEvent) + { + boolean matches = true; + + // Loop through filters; all must match + // Note that we must allow EVERY filter to evaluate. This way + // things like CountFilter will work. + Iterator iter = _filters.iterator (); + while (iter.hasNext ()) + { + IEventFilter filter = (IEventFilter) iter.next (); + if (!filter.matches (theEvent)) + matches = false; + } + + return matches; + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/event/ExceptionEvent.java b/libjava/classpath/gnu/classpath/jdwp/event/ExceptionEvent.java new file mode 100644 index 000000000..e63f5df12 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/event/ExceptionEvent.java @@ -0,0 +1,157 @@ +/* ExceptionEvent.java -- an event specifying an exception has been thrown + 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.jdwp.event; + +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.VMIdManager; +import gnu.classpath.jdwp.id.ObjectId; +import gnu.classpath.jdwp.id.ThreadId; +import gnu.classpath.jdwp.util.Location; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Notification from the VM that an exception has occurred along with where it + * occurred, and if and where it was caught. + * + * @author Kyle Galloway (kgallowa@redhat.com) + */ +public class ExceptionEvent + extends Event +{ + //object instance + private Object _instance; + + // the exception thrown + private Throwable _exception; + + // the thread in which the exception occurred + private Thread _thread; + + // the location where the exception was thrown + private Location _location; + + //the location where the exception was caught + private Location _catchLocation; + + //the class where the exeption was thrown + private Class _klass; + + /** + * Constructs a new ExceptionEvent where the exception was + * caught. + * + * @param exception the throwable object that generated the event + * @param thread the thread where the exception occurred + * @param location the location where the exception was thrown + * @param catchLocation the location where the exception was caught + * @param instance the instance that threw the exception + */ + public ExceptionEvent(Throwable exception, Thread thread, Location location, + Location catchLocation, Class clazz, Object instance) + { + super(JdwpConstants.EventKind.EXCEPTION); + _exception = exception; + _thread = thread; + _location = location; + _catchLocation = catchLocation; + _klass = clazz; + _instance = instance; + } + + /** + * Returns a specific filtering parameter for this event. Valid types are + * thread, location, and catchLocation. + * + * @param type the type of parameter desired + * @returns the desired parameter or null + */ + public Object getParameter(int type) + { + if (type == EVENT_THREAD) + return _thread; + else if (type == EVENT_LOCATION) + return _location; + else if (type == EVENT_INSTANCE) + return _instance; + else if (type == EVENT_CLASS) + return _klass; + else if (type == EVENT_EXCEPTION_CLASS) + return _exception.getClass(); + else if (type == EVENT_EXCEPTION_CAUGHT) + if (_catchLocation.getMethod() != null) + return Boolean.TRUE; + else + return Boolean.FALSE; + + return null; + } + + /** + * Sets the catchLocation, used for exceptions that are caught in different + * stack frames from where they are thrown. + * + * @param catchLoc the location of the catch + */ + public void setCatchLoc(Location catchLoc) + { + _catchLocation = catchLoc; + } + + /** + * Writes the event to the given stream + * + * @param outStream the output stream to write the event to + * @throws IOException + */ + protected void _writeData(DataOutputStream outStream) + throws IOException + { + VMIdManager idm = VMIdManager.getDefault(); + ThreadId tid = (ThreadId) idm.getObjectId(_thread); + ObjectId oid = idm.getObjectId(_exception); + + tid.write(outStream); + _location.write(outStream); + oid.writeTagged(outStream); + _catchLocation.write(outStream); + + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/event/MethodEntryEvent.java b/libjava/classpath/gnu/classpath/jdwp/event/MethodEntryEvent.java new file mode 100644 index 000000000..1ec1a5d4b --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/event/MethodEntryEvent.java @@ -0,0 +1,118 @@ +/* MethodEntryEvent.java -- an event specifying that a method has been invoked + 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.jdwp.event; + +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.VMIdManager; +import gnu.classpath.jdwp.id.ThreadId; +import gnu.classpath.jdwp.util.Location; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Notification from the VM that that a method has been invoked + * + * @author Kyle Galloway (kgallowa@redhat.com) + */ +public class MethodEntryEvent + extends Event +{ + // The thread where the event occurred + private Thread _thread; + + // the location where the event occurred + private Location _location; + + //object instance + private Object _instance; + + /** + * Constructs a new MethodEntryEvent + * + * @param thread the thread where the exception occurred + * @param location the location single stepped to + * @param instance instance from which the method was called + */ + public MethodEntryEvent(Thread thread, Location location, Object instance) + { + super(JdwpConstants.EventKind.METHOD_ENTRY); + _thread = thread; + _location = location; + _instance = instance; + } + + /** + * Returns a specific filtering parameter for this event. Valid types are + * thread and location + * + * @param type the type of parameter desired + * @returns the desired parameter or null + */ + public Object getParameter(int type) + { + if (type == EVENT_THREAD) + return _thread; + else if (type == EVENT_LOCATION) + return _location; + else if (type == EVENT_INSTANCE) + return _instance; + else if (type == EVENT_CLASS) + return _instance.getClass(); + + return null; + } + + /** + * Writes the event to the given stream + * + * @param outStream the output stream to write the event to + * @throws IOException + */ + protected void _writeData(DataOutputStream outStream) + throws IOException + { + VMIdManager idm = VMIdManager.getDefault(); + ThreadId tid = (ThreadId) idm.getObjectId(_thread); + + tid.write(outStream); + _location.write(outStream); + } + +} diff --git a/libjava/classpath/gnu/classpath/jdwp/event/MethodExitEvent.java b/libjava/classpath/gnu/classpath/jdwp/event/MethodExitEvent.java new file mode 100644 index 000000000..84c909901 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/event/MethodExitEvent.java @@ -0,0 +1,115 @@ +/* MethodExitEvent.java -- an event specifying that a method has returned + 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.jdwp.event; + +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.VMIdManager; +import gnu.classpath.jdwp.id.ThreadId; +import gnu.classpath.jdwp.util.Location; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Notification from the VM that that a method has returned + * + * @author Kyle Galloway (kgallowa@redhat.com) + */ +public class MethodExitEvent + extends Event +{ + // The thread where the event occurred + private Thread _thread; + + // the location where the event occurred + private Location _location; + + // object instance + private Object _instance; + + /** + * Constructs a new MethodExitEvent + * + * @param thread the thread where the exception occurred + * @param location the location single stepped to + * @param instance the instance from which the method was called + */ + public MethodExitEvent(Thread thread, Location location, Object instance) + { + super(JdwpConstants.EventKind.METHOD_EXIT); + _thread = thread; + _location = location; + _instance = instance; + } + + /** + * Returns a specific filtering parameter for this event. Valid types are + * thread and location + * + * @param type the type of parameter desired + * @returns the desired parameter or null + */ + public Object getParameter(int type) + { + if (type == EVENT_THREAD) + return _thread; + else if (type == EVENT_LOCATION) + return _location; + else if (type == EVENT_CLASS) + return _instance.getClass(); + + return null; + } + + /** + * Writes the event to the given stream + * + * @param outStream the output stream to write the event to + * @throws IOException + */ + protected void _writeData(DataOutputStream outStream) + throws IOException + { + VMIdManager idm = VMIdManager.getDefault(); + ThreadId tid = (ThreadId) idm.getObjectId(_thread); + + tid.write(outStream); + _location.write(outStream); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/event/SingleStepEvent.java b/libjava/classpath/gnu/classpath/jdwp/event/SingleStepEvent.java new file mode 100644 index 000000000..40cf50c65 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/event/SingleStepEvent.java @@ -0,0 +1,121 @@ +/* SingleStepEvent.java -- an event specifying that a single step has + compleated + 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.jdwp.event; + +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.VMIdManager; +import gnu.classpath.jdwp.id.ThreadId; +import gnu.classpath.jdwp.util.Location; + +import java.io.DataOutputStream; +import java.io.IOException; + + +/** + * Notification from the VM that a single step has compleated including the + * thread and location stepped to + * + * @author Kyle Galloway (kgallowa@redhat.com) + */ +public class SingleStepEvent + extends Event +{ + // the thread where the event occurred + private Thread _thread; + + // the location where the event occurred + private Location _location; + + //object instance + private Object _instance; + + /** + * Constructs a new SingleStepEvent + * + * @param thread the thread where the exception occurred + * @param location the location single stepped to + * @param instance the instance in which the single step occurred + */ + public SingleStepEvent(Thread thread, Location location, Object instance) + { + super(JdwpConstants.EventKind.SINGLE_STEP); + _thread = thread; + _location = location; + _instance = instance; + } + + /** + * Returns a specific filtering parameter for this event. Valid types are + * thread and location + * + * @param type the type of parameter desired + * @returns the desired parameter or null + */ + public Object getParameter(int type) + { + if (type == EVENT_THREAD) + return _thread; + else if (type == EVENT_LOCATION) + return _location; + else if (type == EVENT_INSTANCE) + return _instance; + else if (type == EVENT_CLASS) + return _instance.getClass(); + + return null; + } + + /** + * Writes the event to the given stream + * + * @param outStream the output stream to write the event to + * @throws IOException + */ + protected void _writeData(DataOutputStream outStream) + throws IOException + { + VMIdManager idm = VMIdManager.getDefault(); + ThreadId tid = (ThreadId) idm.getObjectId(_thread); + + tid.write(outStream); + _location.write(outStream); + } + +} diff --git a/libjava/classpath/gnu/classpath/jdwp/event/ThreadEndEvent.java b/libjava/classpath/gnu/classpath/jdwp/event/ThreadEndEvent.java new file mode 100644 index 000000000..a36015a82 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/event/ThreadEndEvent.java @@ -0,0 +1,104 @@ +/* ThreadEndEvent.java -- An event specifying that a thread has died + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.event; + +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.VMIdManager; +import gnu.classpath.jdwp.id.ThreadId; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * "Notification of a completed thread in the target VM. The notification + * is generated by the dying thread before it terminates. Because of this + * timing, it is possible for VirtualMachine.allThreads to return this + * thread after this event is received. + * + *

Note that this event gives no information about the lifetime of the + * thread object. It may or may not be collected soon depending on what + * references exist in the target VM." -- JDWP 1.4.2 + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class ThreadEndEvent + extends Event +{ + private Thread _thread; + + /** + * Constructs a new ThreadEndEvent + * + * @param thread the deceased thread + */ + public ThreadEndEvent (Thread thread) + { + super (JdwpConstants.EventKind.THREAD_END); + _thread = thread; + } + + /** + * Returns a specific filtering parameter for this event. + * Valid types are ThreadId. + * + * @param type the type of parameter desired + * @returns the desired parameter or null + */ + public Object getParameter (int type) + { + if (type == EVENT_THREAD) + return _thread; + + return null; + } + + /** + * Writes the event to the given stream + * + * @param outStream the output stream to write the event to + */ + protected void _writeData (DataOutputStream outStream) + throws IOException + { + VMIdManager idm = VMIdManager.getDefault(); + ThreadId tid = (ThreadId) idm.getObjectId (_thread); + tid.write (outStream); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/event/ThreadStartEvent.java b/libjava/classpath/gnu/classpath/jdwp/event/ThreadStartEvent.java new file mode 100644 index 000000000..4eff4409e --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/event/ThreadStartEvent.java @@ -0,0 +1,109 @@ +/* ThreadStartEvent.java -- An event specifying that a new thread + has started in the virtual machine + Copyright (C) 2005, 2007 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.event; + +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.VMIdManager; +import gnu.classpath.jdwp.id.ThreadId; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * "Notification of a new running thread in the target VM. The new + * thread can be the result of a call to {@link java.lang.Thread#start} or + * the result of attaching a new thread to the VM though JNI. The + * notification is generated by the new thread some time before its + * execution starts. Because of this timing, it is possible to receive + * other events for the thread before this event is received. (Notably, + * Method Entry Events and Method Exit Events might occur during thread + * initialization. It is also possible for the VirtualMachine AllThreads + * command to return a thread before its thread start event is received. + * + *

Note that this event gives no information about the creation of the + * thread object which may have happened much earlier, depending on the + * VM being debugged." -- JDWP 1.4.2 + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class ThreadStartEvent + extends Event +{ + private Thread _thread; + + /** + * Constructs a new ThreadStartEvent object + * + * @param thread the thread ID in which event occurred + */ + public ThreadStartEvent (Thread thread) { + super (JdwpConstants.EventKind.THREAD_START); + _thread = thread; + } + + /** + * Returns a specific filtering parameter for this event. + * Valid types are ThreadId. + * + * @param type the type of parameter desired + * @returns the desired parameter or null + */ + public Object getParameter (int type) + { + if (type == EVENT_THREAD) + return _thread; + + return null; + } + + /** + * Writes the event to the given stream + * + * @param outStream the output stream to write the event to + */ + protected void _writeData (DataOutputStream outStream) + throws IOException + { + VMIdManager idm = VMIdManager.getDefault(); + ThreadId tid = (ThreadId) idm.getObjectId (_thread); + tid.write (outStream); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/event/VmDeathEvent.java b/libjava/classpath/gnu/classpath/jdwp/event/VmDeathEvent.java new file mode 100644 index 000000000..c197ecef4 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/event/VmDeathEvent.java @@ -0,0 +1,83 @@ +/* VmDeathEvent.java -- An event specifying that the VM has terminated + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.event; + +import gnu.classpath.jdwp.JdwpConstants; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Event notifying the debugger that the virtual machine has terminated. + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class VmDeathEvent + extends Event +{ + /** + * Constructs a new VmDeathEvent object + */ + public VmDeathEvent () + { + super (JdwpConstants.EventKind.VM_DEATH); + } + + /** + * Returns a specific filtering parameter for this event. + * This event has no valid types. + * + * @param type the type of parameter desired + * @returns the desired parameter or null + */ + public Object getParameter (int type) + { + return null; + } + + /** + * Writes out event-specific data + */ + protected void _writeData (DataOutputStream outStream) + throws IOException + { + // no data (request ID done by VMIdManager) + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/event/VmInitEvent.java b/libjava/classpath/gnu/classpath/jdwp/event/VmInitEvent.java new file mode 100644 index 000000000..8c1db4f33 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/event/VmInitEvent.java @@ -0,0 +1,94 @@ +/* VmInitEvent.java -- An event specifying that the VM has started + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.event; + +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.VMIdManager; +import gnu.classpath.jdwp.id.ThreadId; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * "Notification of initialization of a target VM. This event is + * received before the main thread is started and before any application + * code has been executed." -- JDWP 1.4.2 + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class VmInitEvent + extends Event +{ + private Thread _initialThread; + + /** + * Constructs a VmInitEvent object + * + * @param thread the initial thread + */ + public VmInitEvent (Thread thread) + { + super (JdwpConstants.EventKind.VM_INIT); + _initialThread = thread; + } + + /** + * Returns a specific filtering parameter for this event. + * This event has no valid types. + * + * @param type the type of parameter desired + * @returns the desired parameter or null + */ + public Object getParameter (int type) + { + return null; + } + + /** + * Writes out event-specific data + */ + protected void _writeData (DataOutputStream outStream) + throws IOException + { + VMIdManager idm = VMIdManager.getDefault(); + ThreadId tid = (ThreadId) idm.getObjectId (_initialThread); + tid.write (outStream); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/event/filters/ClassExcludeFilter.java b/libjava/classpath/gnu/classpath/jdwp/event/filters/ClassExcludeFilter.java new file mode 100644 index 000000000..5514f1b72 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/event/filters/ClassExcludeFilter.java @@ -0,0 +1,75 @@ +/* ClassExcludeFilter.java -- filter on class name (exclusive) + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.event.filters; + +import gnu.classpath.jdwp.event.Event; +import gnu.classpath.jdwp.exception.InvalidStringException; + +/** + * An event filter which excludes events matching a + * specified class pattern (exact match or start/end with "*"). + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class ClassExcludeFilter + extends ClassMatchFilter +{ + /** + * Constructs a new ClassExcludeFilter + * + * @param pattern the pattern to use + * @throws InvalidStringException if pattern is invalid + */ + public ClassExcludeFilter (String pattern) + throws InvalidStringException + { + super (pattern); + } + + /** + * Does the given event match the filter? + * + * @param event the Event to scrutinize + */ + public boolean matches (Event event) + { + return !super.matches (event); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/event/filters/ClassMatchFilter.java b/libjava/classpath/gnu/classpath/jdwp/event/filters/ClassMatchFilter.java new file mode 100644 index 000000000..edb84d7ef --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/event/filters/ClassMatchFilter.java @@ -0,0 +1,112 @@ +/* ClassMatchFilter.java -- filter on class name (inclusive) + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.event.filters; + +import gnu.classpath.jdwp.event.Event; +import gnu.classpath.jdwp.exception.InvalidStringException; + +/** + * An event filter which includes events matching a + * specified class pattern (exact match or start/end with "*"). + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class ClassMatchFilter + implements IEventFilter +{ + // Pattern to match + private String _pattern; + + /** + * Constructs a new ClassMatchFilter + * + * @param pattern the pattern to use + * @throws InvalidStringException if pattern is invalid + */ + public ClassMatchFilter (String pattern) + throws InvalidStringException + { + int index = pattern.indexOf ('*'); + if (index != -1 && index != 0 && index != (pattern.length () - 1)) + { + // '*' must be first char or last char + throw new InvalidStringException ("pattern may be an exact match or " + + "start/end with \"*\""); + } + _pattern = pattern; + } + + /** + * Returns the pattern to be matched + * + * @return the pattern + */ + public String getPattern () + { + return _pattern; + } + + /** + * Does the given event match the filter? + * + * @param event the Event to scrutinize + */ + public boolean matches (Event event) + { + Object type = event.getParameter (Event.EVENT_CLASS); + if (type != null) + { + Class eventClass = (Class) type; + String name = eventClass.getName (); + + if (_pattern.startsWith ("*")) + return name.endsWith (_pattern.substring (1)); + else if (_pattern.endsWith ("*")) + { + int end = _pattern.length () - 1; + return name.startsWith (_pattern.substring (0, end)); + } + else + return name.matches (_pattern); + } + + return false; + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/event/filters/ClassOnlyFilter.java b/libjava/classpath/gnu/classpath/jdwp/event/filters/ClassOnlyFilter.java new file mode 100644 index 000000000..d912cb5ef --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/event/filters/ClassOnlyFilter.java @@ -0,0 +1,109 @@ +/* ClassOnlyFilter.java -- filter on specific class + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.event.filters; + +import gnu.classpath.jdwp.event.Event; +import gnu.classpath.jdwp.exception.InvalidClassException; +import gnu.classpath.jdwp.id.ReferenceTypeId; + +/** + * An event filter which filters out events in uninteresting + * classes. + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class ClassOnlyFilter + implements IEventFilter +{ + // Class ID for which to filter + private ReferenceTypeId _id; + + /** + * Constructs a new ClassOnlyFilter + * + * @param refId the reference type id for a class for which events + * will be reported + * @throws InvalidClassException if the ID is no longer valid + */ + public ClassOnlyFilter (ReferenceTypeId refId) + throws InvalidClassException + { + // validity check + refId.getType (); + _id = refId; + } + + /** + * Returns the class to which to restrict events + * + * @return the class's ID + */ + public ReferenceTypeId getType () + { + return _id; + } + + /** + * Does the given event match the filter? + * + * @param event the Event to scrutinize + */ + public boolean matches (Event event) + { + Object type = event.getParameter (Event.EVENT_CLASS); + if (type != null) + { + try + { + Class clazz = _id.getType (); + Class eventClass = (Class) type; + if (clazz.isAssignableFrom (eventClass)) + return true; + } + catch (InvalidClassException ice) + { + // class is no longer valid + return false; + } + } + + return false; + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/event/filters/ConditionalFilter.java b/libjava/classpath/gnu/classpath/jdwp/event/filters/ConditionalFilter.java new file mode 100644 index 000000000..645a70f42 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/event/filters/ConditionalFilter.java @@ -0,0 +1,82 @@ +/* ConditionalFilter.java -- conditional expression filter + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.event.filters; + +import gnu.classpath.jdwp.event.Event; +import gnu.classpath.jdwp.exception.NotImplementedException; + +/** + * An event filter which allows expression conditionals. + * Note that in JDWP 1.4, this class is marked "for the + * future". + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class ConditionalFilter + implements IEventFilter +{ + // private ConditionalId _exprId; + + /** + * Constructs a new ConditionalFilter with the + * given conditional. + * + *

NOTE: This filter is marked "for the future", + * i.e, there is no way to actually use this yet. + * + * @param conditional the conditional expression + * @throws NotImplementedException if used + */ + public ConditionalFilter (Object conditional) + throws NotImplementedException + { + throw new NotImplementedException ("conditional filters"); + } + + /** + * Does the given event match the filter? + * + * @param event the Event to scrutinize + */ + public boolean matches (Event event) + { + return false; + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/event/filters/CountFilter.java b/libjava/classpath/gnu/classpath/jdwp/event/filters/CountFilter.java new file mode 100644 index 000000000..46148a504 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/event/filters/CountFilter.java @@ -0,0 +1,95 @@ +/* CountFilter.java -- a step filter + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.event.filters; + +import gnu.classpath.jdwp.event.Event; +import gnu.classpath.jdwp.exception.InvalidCountException; + +/** + * An ignore count filter. + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class CountFilter + implements IEventFilter +{ + // the count + private int _count; + + /** + * Constructs a new CountFilter with the given count. + * + * @param count the number of times the event will be ignored + * @throws InvalidCountException if count is invalid (< 1) + */ + public CountFilter (int count) + throws InvalidCountException + { + // Check for valid count + if (count < 1) + throw new InvalidCountException (count); + + _count = count; + } + + /** + * Returns the ignore count + * + * @return the number of times the event should be ignored + */ + public int getCount () + { + return _count; + } + + /** + * Does the given event match the filter? + * + * @param event the Event to scrutinize + */ + public boolean matches (Event event) + { + // This filter only relies on its count + if (--_count == 0) + return true; + + return false; + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/event/filters/ExceptionOnlyFilter.java b/libjava/classpath/gnu/classpath/jdwp/event/filters/ExceptionOnlyFilter.java new file mode 100644 index 000000000..d4687fa4e --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/event/filters/ExceptionOnlyFilter.java @@ -0,0 +1,123 @@ +/* ExceptionOnlyFilter.java -- filter for excetions by caught/uncaught and type + Copyright (C) 2005, 2006 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.event.filters; + +import gnu.classpath.jdwp.event.Event; +import gnu.classpath.jdwp.exception.InvalidClassException; +import gnu.classpath.jdwp.id.ReferenceTypeId; + +/** + * Restricts reported exceptions by their class and whether they are caught + * or uncaught. + * + * This modifier can be used with exception event kinds only. + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class ExceptionOnlyFilter + implements IEventFilter +{ + private ReferenceTypeId _refId; + private boolean _caught; + private boolean _uncaught; + + /** + * Constructs a new ExceptionOnlyFilter + * + * @param refId ID of the exception to report(null for all exceptions) + * @param caught Report caught exceptions + * @param uncaught Report uncaught exceptions + * @throws InvalidClassException if refid is invalid + */ + public ExceptionOnlyFilter (ReferenceTypeId refId, boolean caught, + boolean uncaught) + throws InvalidClassException + { + if (refId != null && refId.getReference().get() == null) + throw new InvalidClassException(refId.getId()); + + _refId = refId; + _caught = caught; + _uncaught = uncaught; + } + + /** + * Returns the exception class to report (null for all) + * + * @return the class's ID + */ + public ReferenceTypeId getType () + { + return _refId; + } + + + /** + * Does the given event match the filter? + * + * @param event the Event to scrutinize + */ + public boolean matches(Event event) + { + boolean classMatch = true; + + // if not allowing all exceptions check if the exception matches + if (_refId != null) + { + try + { + Class klass + = (Class) event.getParameter(Event.EVENT_EXCEPTION_CLASS); + classMatch = klass == _refId.getType(); + } + catch (InvalidClassException ex) + { + classMatch = false; + } + } + + // check against the caught and uncaught options + Boolean caught + = (Boolean) event.getParameter(Event.EVENT_EXCEPTION_CAUGHT); + + return classMatch && ((caught.booleanValue()) ? _caught : _uncaught); + } + +} diff --git a/libjava/classpath/gnu/classpath/jdwp/event/filters/FieldOnlyFilter.java b/libjava/classpath/gnu/classpath/jdwp/event/filters/FieldOnlyFilter.java new file mode 100644 index 000000000..47a804101 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/event/filters/FieldOnlyFilter.java @@ -0,0 +1,112 @@ +/* FieldOnlyFilter.java -- filter on field + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.event.filters; + +import gnu.classpath.jdwp.event.Event; +import gnu.classpath.jdwp.exception.InvalidClassException; +import gnu.classpath.jdwp.exception.InvalidFieldException; +import gnu.classpath.jdwp.id.ReferenceTypeId; + +/** + * Restricts reported events to those that occur for a given field. + * + * This modifier can be used with field access and field modification event + * kinds only. + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class FieldOnlyFilter + implements IEventFilter +{ + private ReferenceTypeId _refId; + private ReferenceTypeId _fieldId; + + /** + * Constructs a new FieldOnlyFilter. + * + * @param refId class for field + * @param fid field + * @throws InvalidClassException if class is invalid + * @throws InvalidFieldException if field is invalid + */ + public FieldOnlyFilter (ReferenceTypeId refId, /*Field*/ReferenceTypeId fid) + throws InvalidClassException, InvalidFieldException + { + if (refId == null || refId.getReference().get () == null) + throw new InvalidClassException (refId.getId ()); + + if (fid == null) + throw new InvalidFieldException (fid.getId ()); + + _refId = refId; + _fieldId = fid; + } + + /** + * Returns the class in which the field is declared + * + * @return the class's id + */ + public ReferenceTypeId getType () + { + return _refId; + } + + /** + * Returns the field for which to restrict events + * + * @return the field's id + */ + public ReferenceTypeId getField () + { + return _fieldId; + } + + /** + * Does the given event match the filter? + * + * @param event the Event to scrutinize + */ + public boolean matches (Event event) + { + // FIXME + throw new RuntimeException ("FieldOnlyFilter.matches not implemented"); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/event/filters/IEventFilter.java b/libjava/classpath/gnu/classpath/jdwp/event/filters/IEventFilter.java new file mode 100644 index 000000000..4a2b5431b --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/event/filters/IEventFilter.java @@ -0,0 +1,65 @@ +/* IEventFilter.java -- an interface for event filters + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.event.filters; + +import gnu.classpath.jdwp.event.Event; + +/** + * An interface for event filters. The debugger registers an event + * filter for a given event when it is interested in receiving + * notifications about that event from the VM. + * + *

Filters are attached to {@link gnu.classpath.jdwp.event.EventRequest}s + * in order to allow the debugger to specify that an event should be sent + * only when the filters for the event request all match. + * + *

No filters means "send all notifications". + * + * @author Keith Seitz (keiths@redhat.com) + */ +public interface IEventFilter +{ + /** + * Does the given event match the filter? + * + * @param event the Event to scrutinize + */ + public boolean matches (Event event); +} diff --git a/libjava/classpath/gnu/classpath/jdwp/event/filters/InstanceOnlyFilter.java b/libjava/classpath/gnu/classpath/jdwp/event/filters/InstanceOnlyFilter.java new file mode 100644 index 000000000..45ab3c428 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/event/filters/InstanceOnlyFilter.java @@ -0,0 +1,101 @@ +/* InstanceOnlyFilter.java -- filter on instance + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.event.filters; + +import gnu.classpath.jdwp.event.Event; +import gnu.classpath.jdwp.exception.InvalidObjectException; +import gnu.classpath.jdwp.id.ObjectId; + +/** + * Restricts reported events to those whose active 'this' object is the + * given object. Match value is the null object for static methods. + * + * This modifier can be used with any event kind except class prepare, + * class unload, thread start, and thread end. Introduced in JDWP version 1.4. + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class InstanceOnlyFilter + implements IEventFilter +{ + private ObjectId _instance; + + /** + * Constructs a new InstanceOnlyFilter. + * + * @param oid the object to which to restrict events (may be null) + * @throws InvalidObjectException if Object is invalid + */ + public InstanceOnlyFilter (ObjectId oid) + throws InvalidObjectException + { + if (oid != null && oid.getReference().get () == null) + throw new InvalidObjectException (oid.getId ()); + + _instance = oid; + } + + /** + * Returns the instance to which to restrict events + * + * @return the object's ID + */ + public ObjectId getInstance () + { + return _instance; + } + + /** + * Does the given event match the filter? + * + * @param event the Event to scrutinize + */ + public boolean matches (Event event) + { + Object eventInstance = event.getParameter (Event.EVENT_INSTANCE); + if (eventInstance != null) + { + Object myInstance = _instance.getReference().get (); + return ((myInstance != null) && (myInstance == eventInstance)); + } + + return false; + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/event/filters/LocationOnlyFilter.java b/libjava/classpath/gnu/classpath/jdwp/event/filters/LocationOnlyFilter.java new file mode 100644 index 000000000..a3125371c --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/event/filters/LocationOnlyFilter.java @@ -0,0 +1,94 @@ +/* LocationOnlyFilter.java -- filter on location + Copyright (C) 2005, 2006, 2007 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.event.filters; + +import gnu.classpath.jdwp.event.Event; +import gnu.classpath.jdwp.exception.InvalidLocationException; +import gnu.classpath.jdwp.util.Location; + +/** + * Restricts reported events to those that occur at the given location. + * + * May be used with breakpoint, field access, field modification, step, + * and exception event kinds. + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class LocationOnlyFilter + implements IEventFilter +{ + private Location _location; + + /** + * Constructs a new LocationOnlyFilter. + * + * @param loc the location for which to report events + * @throws InvalidLocationException if location is invalid + */ + public LocationOnlyFilter (Location loc) + throws InvalidLocationException + { + _location = loc; + } + + /** + * Returns the location at which to restrict events + * + * @return the location + */ + public Location getLocation () + { + return _location; + } + + /** + * Does the given event match the filter? + * + * @param event the Event to scrutinize + */ + public boolean matches(Event event) + { + Location loc = (Location) event.getParameter(Event.EVENT_LOCATION); + if (loc != null) + return (getLocation().equals(loc)); + + return false; + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/event/filters/StepFilter.java b/libjava/classpath/gnu/classpath/jdwp/event/filters/StepFilter.java new file mode 100644 index 000000000..b620b7953 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/event/filters/StepFilter.java @@ -0,0 +1,126 @@ +/* StepFilter.java -- a step filter + Copyright (C) 2005, 2007 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.event.filters; + +import gnu.classpath.jdwp.event.Event; +import gnu.classpath.jdwp.exception.InvalidThreadException; +import gnu.classpath.jdwp.id.ThreadId; + +/** + * "An event filter which restricts reported step events to those which + * satisfy depth and size constraints. This modifier can only be used with + * step event kinds." + * + * This "filter" is not really a filter. It is simply a way to communicate + * stepping information in a convenient way between the JDWP backend and + * the virtual machine. + * + * Consequently, this "filter" always matches. + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class StepFilter + implements IEventFilter +{ + private ThreadId _tid; + private int _size; + private int _depth; + + /** + * Constructs a new StepFilter + * + * @param tid ID of the thread in which to step + * @param size size of each step + * @param depth relative call stack limit + * @throws InvalidThreadException if thread is invalid + */ + public StepFilter (ThreadId tid, int size, int depth) + throws InvalidThreadException + { + if (tid.getReference().get () == null) + throw new InvalidThreadException (tid.getId ()); + + _tid = tid; + _size = size; + _depth = depth; + } + + /** + * Returns the thread in which to step + * + * @return the thread's ID + */ + public ThreadId getThread () + { + return _tid; + } + + /** + * Returns the size of each step (insn, line) + * + * @return the step size + * @see gnu.classpath.jdwp.JdwpConstants.StepSize + */ + public int getSize () + { + return _size; + } + + /** + * Returns the relative call stack limit (into, over, out) + * + * @return how to step + * @see gnu.classpath.jdwp.JdwpConstants.StepDepth + */ + public int getDepth () + { + return _depth; + } + + /** + * Does the given event match the filter? + * + * @param event the Event to scrutinize + */ + public boolean matches (Event event) + { + return true; + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/event/filters/ThreadOnlyFilter.java b/libjava/classpath/gnu/classpath/jdwp/event/filters/ThreadOnlyFilter.java new file mode 100644 index 000000000..de9fb3ec6 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/event/filters/ThreadOnlyFilter.java @@ -0,0 +1,101 @@ +/* ThreadOnlyFilter.java -- a thread filter + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.event.filters; + +import gnu.classpath.jdwp.event.Event; +import gnu.classpath.jdwp.exception.InvalidThreadException; +import gnu.classpath.jdwp.id.ThreadId; + +/** + * An event filter which allows only events within a specific + * thread + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class ThreadOnlyFilter + implements IEventFilter +{ + // the thread + private ThreadId _tid; + + /** + * Constructs a new ThreadOnlyFilter for the given + * thread id + * + * @param tid ID of the thread on which to filter + * @throws InvalidThreadException if the thread is not valid + */ + public ThreadOnlyFilter (ThreadId tid) + throws InvalidThreadException + { + if (tid == null || tid.getReference().get () == null) + throw new InvalidThreadException (tid.getId ()); + + _tid = tid; + } + + /** + * Returns the thread in which to restrict events + * + * @return the thread's ID + */ + public ThreadId getThread () + { + return _tid; + } + + /** + * Does the given event match the filter? + * + * @param event the Event to scrutinize + */ + public boolean matches (Event event) + { + Object thread = event.getParameter (Event.EVENT_THREAD); + if (thread != null) + { + Thread eventThread = (Thread) thread; + Thread myThread = (Thread) _tid.getReference().get (); + return (eventThread == myThread); + } + + return false; + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/AbsentInformationException.java b/libjava/classpath/gnu/classpath/jdwp/exception/AbsentInformationException.java new file mode 100644 index 000000000..5bf383f58 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/exception/AbsentInformationException.java @@ -0,0 +1,56 @@ +/* AbsentInformationException.java -- information not present exception + Copyright (C) 2007 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.exception; + +import gnu.classpath.jdwp.JdwpConstants; + +/** + * An exception thrown when the requested information is not available. + * + * @author Kyle Galloway (kgallowa@redhat.com) + */ +public class AbsentInformationException + extends JdwpException +{ + public AbsentInformationException(String str) + { + super(JdwpConstants.Error.ABSENT_INFORMATION, str); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/InvalidClassException.java b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidClassException.java new file mode 100644 index 000000000..de15000a4 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidClassException.java @@ -0,0 +1,63 @@ +/* InvalidClassException.java -- invalid/unknown class reference id exception + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.exception; + +import gnu.classpath.jdwp.JdwpConstants; + +/** + * An exception thrown by the JDWP back-end when an invalid reference + * type id is used by the debugger. + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class InvalidClassException + extends JdwpException +{ + public InvalidClassException (long id) + { + super (JdwpConstants.Error.INVALID_CLASS, + "invalid class id (" + id + ")"); + } + + public InvalidClassException (Throwable t) + { + super (JdwpConstants.Error.INVALID_CLASS, t); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/InvalidClassLoaderException.java b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidClassLoaderException.java new file mode 100644 index 000000000..ca91e6eb6 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidClassLoaderException.java @@ -0,0 +1,62 @@ +/* InvalidClassLoaderException.java -- an invalid class loader exception + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.exception; + +import gnu.classpath.jdwp.JdwpConstants; + +/** + * An exception thrown when the debugger uses an invalid class loader + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class InvalidClassLoaderException + extends JdwpException +{ + public InvalidClassLoaderException (long id) + { + super (JdwpConstants.Error.INVALID_CLASS_LOADER, + "invalid class loader (" + id + ")"); + } + + public InvalidClassLoaderException (Throwable t) + { + super (JdwpConstants.Error.INVALID_CLASS_LOADER, t); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/InvalidCountException.java b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidCountException.java new file mode 100644 index 000000000..d5f40c96b --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidCountException.java @@ -0,0 +1,61 @@ +/* InvalidCountException -- an invalid count exception + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.exception; + +import gnu.classpath.jdwp.JdwpConstants; + +/** + * An exception thrown when a count filter is given an invalid count. + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class InvalidCountException + extends JdwpException +{ + public InvalidCountException (int id) + { + super (JdwpConstants.Error.INVALID_COUNT, "invalid count (" + id + ")"); + } + + public InvalidCountException (Throwable t) + { + super (JdwpConstants.Error.INVALID_COUNT, t); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/InvalidEventTypeException.java b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidEventTypeException.java new file mode 100644 index 000000000..17341ce1d --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidEventTypeException.java @@ -0,0 +1,63 @@ +/* InvalidEventTypeException.java -- an invalid event kind exception + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.exception; + +import gnu.classpath.jdwp.JdwpConstants; + +/** + * An exception thrown when the debugger asks for an event request + * for a non-existant event + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class InvalidEventTypeException + extends JdwpException +{ + public InvalidEventTypeException (byte kind) + { + super (JdwpConstants.Error.INVALID_EVENT_TYPE, + "invalid event type (" + kind + ")"); + } + + public InvalidEventTypeException (Throwable t) + { + super (JdwpConstants.Error.INVALID_EVENT_TYPE, t); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/InvalidFieldException.java b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidFieldException.java new file mode 100644 index 000000000..47470ab8c --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidFieldException.java @@ -0,0 +1,63 @@ +/* InvalidFieldException.java -- an invalid field id exception + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.exception; + +import gnu.classpath.jdwp.JdwpConstants; + +/** + * An exception thrown when an invalid field id is used by the + * debugger + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class InvalidFieldException + extends JdwpException +{ + public InvalidFieldException (long id) + { + super (JdwpConstants.Error.INVALID_FIELDID, + "invalid field id (" + id + ")"); + } + + public InvalidFieldException (Throwable t) + { + super (JdwpConstants.Error.INVALID_FIELDID, t); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/InvalidFrameException.java b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidFrameException.java new file mode 100644 index 000000000..876c0a88c --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidFrameException.java @@ -0,0 +1,63 @@ +/* InvalidFrameException.java -- invalid jframeid + Copyright (C) 2007 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.exception; + +import gnu.classpath.jdwp.JdwpConstants; + +/** + * An exception thrown when the debugger requests an invalid frame in the call + * stack. + * + * @author Kyle Galloway (kgallowa@redhat.com) + */ +public class InvalidFrameException + extends JdwpException +{ + public InvalidFrameException(long id) + { + super(JdwpConstants.Error.INVALID_FRAMEID, + "invalid frame id (" + id + ")"); + } + + public InvalidFrameException(String msg) + { + super(JdwpConstants.Error.INVALID_FRAMEID, msg); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/InvalidLocationException.java b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidLocationException.java new file mode 100644 index 000000000..e8cc78fac --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidLocationException.java @@ -0,0 +1,62 @@ +/* InvalidLocationException.java -- an invalid location exception + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.exception; + +import gnu.classpath.jdwp.JdwpConstants; + +/** + * An exception thrown when the debugger specifies an invalid location + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class InvalidLocationException + extends JdwpException +{ + public InvalidLocationException (/*something*/) + { + super (JdwpConstants.Error.INVALID_LOCATION, + "invalid location (" + "something" + ")"); + } + + public InvalidLocationException (Throwable t) + { + super (JdwpConstants.Error.INVALID_LOCATION, t); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/InvalidMethodException.java b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidMethodException.java new file mode 100644 index 000000000..83569f481 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidMethodException.java @@ -0,0 +1,63 @@ +/* InvalidMethodException.java -- an invalid method id exception + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.exception; + +import gnu.classpath.jdwp.JdwpConstants; + +/** + * An exception thrown when an invalid method id is used + * by the debugger + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class InvalidMethodException + extends JdwpException +{ + public InvalidMethodException (long id) + { + super (JdwpConstants.Error.INVALID_METHODID, + "invalid method id (" + id + ")"); + } + + public InvalidMethodException (Throwable t) + { + super (JdwpConstants.Error.INVALID_METHODID, t); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/InvalidObjectException.java b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidObjectException.java new file mode 100644 index 000000000..8b1a2802d --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidObjectException.java @@ -0,0 +1,63 @@ +/* InvalidObjectException.java -- an invalid object id exception + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.exception; + +import gnu.classpath.jdwp.JdwpConstants; + +/** + * An exception thrown when an invalid object id is used by + * the debugger + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class InvalidObjectException + extends JdwpException +{ + public InvalidObjectException (long id) + { + super (JdwpConstants.Error.INVALID_OBJECT, + "invalid object id (" + id + ")"); + } + + public InvalidObjectException (Throwable t) + { + super (JdwpConstants.Error.INVALID_OBJECT, t); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/InvalidSlotException.java b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidSlotException.java new file mode 100644 index 000000000..bf6bc904d --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidSlotException.java @@ -0,0 +1,62 @@ +/* InvalidSlotException.java -- an invalid variable slot exception + Copyright (C) 2007 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.exception; + +import gnu.classpath.jdwp.JdwpConstants; + +/** + * An exception thrown when an invalid Slot id is used by the debugger + * (i.e. when trying to access a variable slot which doesn't exist). + * + * @author Kyle Galloway (kgallowa@redhat.com) + */ +public class InvalidSlotException + extends JdwpException +{ + public InvalidSlotException(int slot) + { + super(JdwpConstants.Error.INVALID_SLOT, "invalid slot: " + slot); + } + + public InvalidSlotException(String msg) + { + super(JdwpConstants.Error.INVALID_SLOT, msg); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/InvalidStringException.java b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidStringException.java new file mode 100644 index 000000000..b9864a6e6 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidStringException.java @@ -0,0 +1,68 @@ +/* InvalidStringException.java -- an invalid string exception + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.exception; + +import gnu.classpath.jdwp.JdwpConstants; + +/** + * An exception thrown when the debugger uses an invalid String. + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class InvalidStringException + extends JdwpException +{ + public InvalidStringException (String str) + { + super (JdwpConstants.Error.INVALID_STRING, + "invalid string (" + str + ")"); + } + + public InvalidStringException (long id) + { + super (JdwpConstants.Error.INVALID_STRING, + "invalid string id (" + id + ")"); + } + + public InvalidStringException (Throwable t) + { + super (JdwpConstants.Error.INVALID_STRING, t); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/InvalidTagException.java b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidTagException.java new file mode 100644 index 000000000..738b5e734 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidTagException.java @@ -0,0 +1,57 @@ +/* InvalidTagException.java -- an invalid type tag exception + Copyright (C) 2007 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.exception; + +import gnu.classpath.jdwp.JdwpConstants; + +/** + * An exception thrown when an invalid tag is used by + * the debugger + * + * @author Kyle Galloway (kgallowa@redhat.com) + */ +public class InvalidTagException + extends JdwpException +{ + public InvalidTagException (byte tag) + { + super (JdwpConstants.Error.INVALID_TAG, + "invalid tag (" + tag + ")"); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/InvalidThreadException.java b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidThreadException.java new file mode 100644 index 000000000..9cebfba50 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidThreadException.java @@ -0,0 +1,63 @@ +/* InvalidThreadException.java -- an invalid thread exception + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.exception; + +import gnu.classpath.jdwp.JdwpConstants; + +/** + * An exception thrown when an invalid thread is used + * by the debugger + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class InvalidThreadException + extends JdwpException +{ + public InvalidThreadException (long id) + { + super (JdwpConstants.Error.INVALID_THREAD, + "invalid thread id (" + id + ")"); + } + + public InvalidThreadException (Throwable t) + { + super (JdwpConstants.Error.INVALID_THREAD, t); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/InvalidThreadGroupException.java b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidThreadGroupException.java new file mode 100644 index 000000000..7d9e62252 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/exception/InvalidThreadGroupException.java @@ -0,0 +1,63 @@ +/* InvalidThreadGroupException.java -- an invalid thread group exception + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.exception; + +import gnu.classpath.jdwp.JdwpConstants; + +/** + * An exception thrown when an invalid thread group is used + * by the debugger + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class InvalidThreadGroupException + extends JdwpException +{ + public InvalidThreadGroupException (long id) + { + super (JdwpConstants.Error.INVALID_THREAD_GROUP, + "invalid thread group id (" + id + ")"); + } + + public InvalidThreadGroupException (Throwable t) + { + super (JdwpConstants.Error.INVALID_THREAD_GROUP, t); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/JdwpException.java b/libjava/classpath/gnu/classpath/jdwp/exception/JdwpException.java new file mode 100644 index 000000000..5c96cc56b --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/exception/JdwpException.java @@ -0,0 +1,86 @@ +/* JdwpException.java -- an exception base class for all JDWP exceptions + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.exception; + +/** + * A base class exception for all JDWP back-end exceptions + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class JdwpException + extends Exception +{ + // The integer error code defined by JDWP + private short _errorCode; + + /** + * Constructs a new JdwpException with the + * given error code and given cause + * + * @param code the JDWP error code + * @param t the cause of the exception + */ + public JdwpException (short code, Throwable t) + { + super (t); + _errorCode = code; + } + + /** + * Constructs a new JdwpException with the + * given error code and string error message + * + * @param code the JDWP error code + * @param str an error message + */ + public JdwpException (short code, String str) + { + super (str); + _errorCode = code; + } + + /** + * Returns the JDWP error code represented by this exception + */ + public short getErrorCode () + { + return _errorCode; + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/JdwpIllegalArgumentException.java b/libjava/classpath/gnu/classpath/jdwp/exception/JdwpIllegalArgumentException.java new file mode 100644 index 000000000..1ede37f83 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/exception/JdwpIllegalArgumentException.java @@ -0,0 +1,62 @@ +/* JdwpIllegalArgumentException.java -- an illegal argument exception + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.exception; + +import gnu.classpath.jdwp.JdwpConstants; + +/** + * An illegal argument exception for JDWP. + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class JdwpIllegalArgumentException + extends JdwpException +{ + /** + * Constructs a new JdwpIllegalArgumentException with + * the given error code and given cause + * + * @param msg a message explaining the illegal argument + */ + public JdwpIllegalArgumentException (String msg) + { + super (JdwpConstants.Error.ILLEGAL_ARGUMENT, msg); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/JdwpInternalErrorException.java b/libjava/classpath/gnu/classpath/jdwp/exception/JdwpInternalErrorException.java new file mode 100644 index 000000000..3cf8592f4 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/exception/JdwpInternalErrorException.java @@ -0,0 +1,62 @@ +/* JdwpInternalErrorException.java -- an internal error exception + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.exception; + +import gnu.classpath.jdwp.JdwpConstants; + +/** + * An exception thrown by the JDWP back-end when an unusual runtime + * error occurs internally + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class JdwpInternalErrorException + extends JdwpException +{ + public JdwpInternalErrorException(Throwable cause) + { + super(JdwpConstants.Error.INTERNAL, cause); + } + + public JdwpInternalErrorException(String msg) + { + super(JdwpConstants.Error.INTERNAL, msg); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/NativeMethodException.java b/libjava/classpath/gnu/classpath/jdwp/exception/NativeMethodException.java new file mode 100644 index 000000000..36c03c431 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/exception/NativeMethodException.java @@ -0,0 +1,63 @@ +/* NativeMethodException.java -- a native method exception + Copyright (C) 2006 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.exception; + +import gnu.classpath.jdwp.JdwpConstants; + +/** + * An exception thrown when the debugger attempts to invoke + * an unsupported command on a native method (like setting a breakpoint). + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class NativeMethodException + extends JdwpException +{ + public NativeMethodException(long id) + { + super(JdwpConstants.Error.NATIVE_METHOD, + "invalid method id (" + id + ")"); + } + + public NativeMethodException(Throwable t) + { + super(JdwpConstants.Error.NATIVE_METHOD, t); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/NotImplementedException.java b/libjava/classpath/gnu/classpath/jdwp/exception/NotImplementedException.java new file mode 100644 index 000000000..a4ec7b224 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/exception/NotImplementedException.java @@ -0,0 +1,58 @@ +/* NotImplementedException.java -- an exception for unimplemented JDWP + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.exception; + +import gnu.classpath.jdwp.JdwpConstants; + +/** + * An exception thrown by virtual machines when functionality + * or features are not implemented + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class NotImplementedException + extends JdwpException +{ + public NotImplementedException (String feature) + { + super (JdwpConstants.Error.NOT_IMPLEMENTED, + feature + " is not yet implemented"); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/TypeMismatchException.java b/libjava/classpath/gnu/classpath/jdwp/exception/TypeMismatchException.java new file mode 100644 index 000000000..c6af65223 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/exception/TypeMismatchException.java @@ -0,0 +1,62 @@ +/* TypeMismatchException.java -- mismatched type of local variable + Copyright (C) 2007 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.exception; + +import gnu.classpath.jdwp.JdwpConstants; + +/** + * An exception throw when attempting to access a local variable of the wrong + * type. + * + * @author Kyle Galloway (kgallowa@redhat.com) + */ +public class TypeMismatchException + extends JdwpException +{ + public TypeMismatchException(byte tag) + { + super(JdwpConstants.Error.TYPE_MISMATCH, "incorrect tag: " + tag); + } + + public TypeMismatchException(String msg) + { + super(JdwpConstants.Error.TYPE_MISMATCH, msg); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/exception/VmDeadException.java b/libjava/classpath/gnu/classpath/jdwp/exception/VmDeadException.java new file mode 100644 index 000000000..f3c4a152b --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/exception/VmDeadException.java @@ -0,0 +1,55 @@ +/* VmDeadException.java -- dead virtual machine exception + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.exception; + +import gnu.classpath.jdwp.JdwpConstants; + +/** + * An exception thrown when the virtual machine is dead + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class VmDeadException + extends JdwpException +{ + public VmDeadException () + { + super (JdwpConstants.Error.VM_DEAD, "Virtual machine is dead"); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/id/ArrayId.java b/libjava/classpath/gnu/classpath/jdwp/id/ArrayId.java new file mode 100644 index 000000000..cd428a172 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/id/ArrayId.java @@ -0,0 +1,62 @@ +/* ArrayId.java -- array object IDs + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.id; + +import gnu.classpath.jdwp.JdwpConstants; + +/** + * A class which represents a JDWP array id + * + * @author Keith Seitz + */ +public class ArrayId + extends ObjectId +{ + // Arrays are handled a little differently than other IDs + //public static final Class typeClass = UNDEFINED + + /** + * Constructs a new ArrayId + */ + public ArrayId () + { + super (JdwpConstants.Tag.ARRAY); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/id/ArrayReferenceTypeId.java b/libjava/classpath/gnu/classpath/jdwp/id/ArrayReferenceTypeId.java new file mode 100644 index 000000000..14a73dc5b --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/id/ArrayReferenceTypeId.java @@ -0,0 +1,59 @@ +/* ArrayReferenceTypeId.java -- array reference type ids + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.id; + +import gnu.classpath.jdwp.JdwpConstants; + +/** + * A reference type ID representing java arrays + * + * @author Keith Seitz + */ +public class ArrayReferenceTypeId + extends ReferenceTypeId +{ + /** + * Constructs a new ArrayReferenceTypeId + */ + public ArrayReferenceTypeId () + { + super (JdwpConstants.TypeTag.ARRAY); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/id/ClassLoaderId.java b/libjava/classpath/gnu/classpath/jdwp/id/ClassLoaderId.java new file mode 100644 index 000000000..37c4c3655 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/id/ClassLoaderId.java @@ -0,0 +1,82 @@ +/* ClassLoaderId.java -- class loader IDs + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.id; + +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.exception.InvalidClassLoaderException; + +/** + * A class which represents a JDWP thread id + * + * @author Keith Seitz + */ +public class ClassLoaderId + extends ObjectId +{ + /** + * The object class that this id represents + */ + public static final Class typeClass = ClassLoader.class; + + /** + * Constructs a new ClassLoaderId + */ + public ClassLoaderId () + { + super (JdwpConstants.Tag.CLASS_LOADER); + } + + /** + * Gets the ClassLoader represented by this ID + * + * @throws InvalidClassLoaderException if ClassLoader is garbage collected, + * or otherwise invalid + */ + public ClassLoader getClassLoader () + throws InvalidClassLoaderException + { + ClassLoader cl = (ClassLoader) _reference.get (); + + if (cl == null) + throw new InvalidClassLoaderException (getId ()); + + return cl; + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/id/ClassObjectId.java b/libjava/classpath/gnu/classpath/jdwp/id/ClassObjectId.java new file mode 100644 index 000000000..3e1642212 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/id/ClassObjectId.java @@ -0,0 +1,82 @@ +/* ClassObjectId.java -- class object IDs + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.id; + +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.exception.InvalidClassException; + +/** + * A class which represents a JDWP class object id + * + * @author Keith Seitz + */ +public class ClassObjectId + extends ObjectId +{ + /** + * The object class that this id represents + */ + public static final Class typeClass = Class.class; + + /** + * Constructs a new ClassObjectId + */ + public ClassObjectId () + { + super (JdwpConstants.Tag.CLASS_OBJECT); + } + + /** + * Gets the Class object represented by this ID + * + * @throws InvalidClassException if Class is garbage collected, + * or otherwise invalid + */ + public Class getClassObject () + throws InvalidClassException + { + Class cl = (Class) _reference.get (); + + if (cl == null) + throw new InvalidClassException (getId ()); + + return cl; + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/id/ClassReferenceTypeId.java b/libjava/classpath/gnu/classpath/jdwp/id/ClassReferenceTypeId.java new file mode 100644 index 000000000..6b57673f8 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/id/ClassReferenceTypeId.java @@ -0,0 +1,59 @@ +/* ClassReferenceTypeId.java -- class reference type ids + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.id; + +import gnu.classpath.jdwp.JdwpConstants; + +/** + * A reference type ID representing java classes + * + * @author Keith Seitz + */ +public class ClassReferenceTypeId + extends ReferenceTypeId +{ + /** + * Constructs a new ClassReferenceTypeId + */ + public ClassReferenceTypeId () + { + super (JdwpConstants.TypeTag.CLASS); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/id/InterfaceReferenceTypeId.java b/libjava/classpath/gnu/classpath/jdwp/id/InterfaceReferenceTypeId.java new file mode 100644 index 000000000..bdbd6b6eb --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/id/InterfaceReferenceTypeId.java @@ -0,0 +1,59 @@ +/* InterfaceReferenceTypeId.java -- interface reference type ids + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.id; + +import gnu.classpath.jdwp.JdwpConstants; + +/** + * A reference type ID representing java interfaces + * + * @author Keith Seitz + */ +public class InterfaceReferenceTypeId + extends ReferenceTypeId +{ + /** + * Constructs a new InterfaceReferenceTypeId + */ + public InterfaceReferenceTypeId () + { + super (JdwpConstants.TypeTag.INTERFACE); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/id/JdwpId.java b/libjava/classpath/gnu/classpath/jdwp/id/JdwpId.java new file mode 100644 index 000000000..6caaa3a01 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/id/JdwpId.java @@ -0,0 +1,151 @@ +/* JdwpId.java -- base class for all object ID types + Copyright (C) 2005, 2006 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.id; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.lang.ref.SoftReference; + +/** + * A baseclass for all object types reported to the debugger + * + * @author Keith Seitz + */ +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 + */ + protected long _id; + + /** + * Tag of ID's type (see {@link gnu.classpath.jdwp.JdwpConstants.Tag}) + * for object-like IDs or the type tag (see {@link + * gnu.classpath.jdwp.JdwpConstants.TypeTag}) for reference type IDs. + */ + private byte _tag; + + /** + * The object/class represented by this Id + */ + protected SoftReference _reference; + + /** + * Constructs an empty JdwpId + */ + public JdwpId (byte tag) + { + _tag = tag; + } + + /** + * Sets the id for this object reference + */ + public void setId (long id) + { + _id = id; + } + + /** + * Returns the id for this object reference + */ + public long getId () + { + return _id; + } + + /** + * Gets the object/class reference for this ID + * + * @returns a refernce to the object or class + */ + public SoftReference getReference () + { + return _reference; + } + + /** + * Sets the object/class reference for this ID + * + * @param ref a refernce to the object or class + */ + public void setReference (SoftReference ref) + { + _reference = ref; + } + + /** + * Compares two object ids for equality. Two object ids + * are equal if they point to the same type and contain to + * the same id number. + */ + public boolean equals (JdwpId id) + { + return (id.getId () == getId ()); + } + + /** + * Writes the contents of this type to the DataOutputStream + * @param outStream the DataOutputStream to use + * @throws IOException when an error occurs on the OutputStream + */ + public abstract void write (DataOutputStream outStream) + throws IOException; + + /** + * Writes the contents of this type to the output stream, preceded + * by a one-byte tag for tagged object IDs or type tag for + * reference type IDs. + * + * @param outStream the DataOutputStream to use + * @throws IOException when an error occurs on the OutputStream + */ + public void writeTagged (DataOutputStream outStream) + throws IOException + { + outStream.writeByte (_tag); + write (outStream); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/id/NullObjectId.java b/libjava/classpath/gnu/classpath/jdwp/id/NullObjectId.java new file mode 100644 index 000000000..5dc9753b7 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/id/NullObjectId.java @@ -0,0 +1,79 @@ +/* NullObjectId.java -- special objectId for null values + Copyright (C) 2007 Free Software Foundation + +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.jdwp.id; + +import gnu.classpath.jdwp.exception.InvalidObjectException; +import gnu.classpath.jdwp.util.NullObject; + +import java.lang.ref.SoftReference; + +/** + * This is a special case of an ObjectId. When a varaible slot contains + * null as its value, this is a valid value despite the fact that it does + * not reference an object. To represent this, this will always be the id + * of the NullObject (0). + * + * @author Kyle Galloway + */ +public class NullObjectId + extends ObjectId +{ + /** + * The object class that this id represents + */ + public static final Class typeClass = NullObject.class; + + /** + * Constructs a new NullObjectId + */ + public NullObjectId() + { + super(); + setId((long) 0); + _reference = new SoftReference(new NullObject()); + try + { + disableCollection(); + } + catch(InvalidObjectException ex) + { + //This will not happen + } + } + +} diff --git a/libjava/classpath/gnu/classpath/jdwp/id/ObjectId.java b/libjava/classpath/gnu/classpath/jdwp/id/ObjectId.java new file mode 100644 index 000000000..a4a37fd13 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/id/ObjectId.java @@ -0,0 +1,131 @@ +/* ObjectId.java -- object IDs + Copyright (C) 2005, 2006 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.id; + +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.exception.InvalidObjectException; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * This is a base class for all ObjectID-like entities in JDWP, + * inculding Objects, ClassObject, ClassLoader, Thread, ThreadGroup, + * etc. + * + * @author Keith Seitz + */ +public class ObjectId + extends JdwpId +{ + /** + * The object class that this id represents + */ + public static final Class typeClass = Object.class; + + // Handle to disable garbage collection + private Object _handle; + + /** + * Constructs a new ObjectId + */ + public ObjectId () + { + super (JdwpConstants.Tag.OBJECT); + } + + /** + * Constructs a new ObjectId of the + * given type. + * + * @param tag the tag of this type of object ID + */ + public ObjectId (byte tag) + { + super (tag); + } + + /** + * Returns the object referred to by this ID + * + * @returns the object + * @throws InvalidObjectException if the object was garbage collected + * or is invalid + */ + public Object getObject () + throws InvalidObjectException + { + Object obj = _reference.get (); + if (obj == null) + throw new InvalidObjectException (_id); + + return obj; + } + + /** + * Writes the id to the stream + * + * @param outStream the stream to which to write + * @throws IOException when an error occurs on the OutputStream + */ + public void write (DataOutputStream outStream) + throws IOException + { + // All we need to do is write out our id as an 8-byte integer + outStream.writeLong (_id); + } + + /** + * Disable garbage collection on object + */ + public void disableCollection () + throws InvalidObjectException + { + _handle = getObject (); + } + + /** + * Enable garbage collection on object + */ + public void enableCollection () + { + _handle = null; + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/id/ReferenceTypeId.java b/libjava/classpath/gnu/classpath/jdwp/id/ReferenceTypeId.java new file mode 100644 index 000000000..b82acf34a --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/id/ReferenceTypeId.java @@ -0,0 +1,91 @@ +/* ReferenceTypeId.java -- a base class for all reference type IDs + Copyright (C) 2005, 2006 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.id; + +import gnu.classpath.jdwp.exception.InvalidClassException; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Base class for reference type IDs. This class usurps + * JdwpId's tag member for its own use (type tag). + * + * @author Keith Seitz + */ +public class ReferenceTypeId + extends JdwpId +{ + /** + * Constructor used by {Array,Interface,Class}ReferenceTypeId + */ + public ReferenceTypeId (byte tag) + { + super (tag); + } + + /** + * Gets the class associated with this ID + * + * @returns the class + * @throws InvalidClassException if the class is not valid + */ + public Class getType () + throws InvalidClassException + { + Class clazz = (Class) _reference.get (); + if (clazz == null) + throw new InvalidClassException (_id); + + return clazz; + } + + /** + * Outputs the reference type ID to the given output stream + * + * @param outStream the stream to which to write the data + * @throws IOException for errors writing to the stream + */ + public void write (DataOutputStream outStream) + throws IOException + { + outStream.writeLong (_id); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/id/StringId.java b/libjava/classpath/gnu/classpath/jdwp/id/StringId.java new file mode 100644 index 000000000..1ba8f6d4d --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/id/StringId.java @@ -0,0 +1,82 @@ +/* StringId.java -- string IDs + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.id; + +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.exception.InvalidStringException; + +/** + * A class which represents a JDWP string id + * + * @author Keith Seitz + */ +public class StringId + extends ObjectId +{ + /** + * The object class that this id represents + */ + public static final Class typeClass = String.class; + + /** + * Constructs a new StringId + */ + public StringId () + { + super (JdwpConstants.Tag.STRING); + } + + /** + * Gets the String represented by this ID + * + * @throws InvalidStringException if String is garbage collected, + * or otherwise invalid + */ + public String getString () + throws InvalidStringException + { + String string = (String) _reference.get (); + + if (string == null) + throw new InvalidStringException (getId ()); + + return string; + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/id/ThreadGroupId.java b/libjava/classpath/gnu/classpath/jdwp/id/ThreadGroupId.java new file mode 100644 index 000000000..f4d9d803d --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/id/ThreadGroupId.java @@ -0,0 +1,82 @@ +/* ThreadGroupId.java -- thread group IDs + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.id; + +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.exception.InvalidThreadGroupException; + +/** + * A class which represents a JDWP thread group id + * + * @author Keith Seitz + */ +public class ThreadGroupId + extends ObjectId +{ + /** + * The object class that this id represents + */ + public static final Class typeClass = ThreadGroup.class; + + /** + * Constructs a new ThreadGroupId + */ + public ThreadGroupId () + { + super (JdwpConstants.Tag.THREAD_GROUP); + } + + /** + * Gets the thread group represented by this ID + * + * @throws InvalidThreadGroupException if the group is invalid + * or garbage collected + */ + public ThreadGroup getThreadGroup () + throws InvalidThreadGroupException + { + ThreadGroup group = (ThreadGroup) _reference.get (); + + if (group == null) + throw new InvalidThreadGroupException (getId ()); + + return group; + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/id/ThreadId.java b/libjava/classpath/gnu/classpath/jdwp/id/ThreadId.java new file mode 100644 index 000000000..207d6b0a1 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/id/ThreadId.java @@ -0,0 +1,85 @@ +/* ThreadId.java -- thread IDs + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.id; + +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.exception.InvalidThreadException; + +/** + * A class which represents a JDWP thread id + * + * @author Keith Seitz + */ +public class ThreadId + extends ObjectId +{ + /** + * The object class that this id represents + */ + public static final Class typeClass = Thread.class; + + /** + * Constructs a new ThreadId + */ + public ThreadId () + { + super (JdwpConstants.Tag.THREAD); + } + + /** + * Gets the Thread represented by this ID + * + * @throws InvalidThreadException if thread is garbage collected, + * exited, or otherwise invalid + */ + public Thread getThread () + throws InvalidThreadException + { + Thread thread = (Thread) _reference.get (); + + /* Spec says if thread is null, not valid, or exited, + throw invalid thread */ + // FIXME: not valid? exited? Is this check valid? + if (thread == null || !thread.isAlive ()) + throw new InvalidThreadException (getId ()); + + return thread; + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/processor/ArrayReferenceCommandSet.java b/libjava/classpath/gnu/classpath/jdwp/processor/ArrayReferenceCommandSet.java new file mode 100644 index 000000000..93c9d73e3 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/processor/ArrayReferenceCommandSet.java @@ -0,0 +1,176 @@ +/* ArrayReferenceCommandSet.java -- class to implement the Array + Reference Command Set + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.processor; + +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.exception.InvalidObjectException; +import gnu.classpath.jdwp.exception.JdwpException; +import gnu.classpath.jdwp.exception.JdwpInternalErrorException; +import gnu.classpath.jdwp.exception.NotImplementedException; +import gnu.classpath.jdwp.id.ObjectId; +import gnu.classpath.jdwp.value.Value; +import gnu.classpath.jdwp.value.ValueFactory; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.lang.reflect.Array; +import java.nio.ByteBuffer; + +/** + * A class representing the ArrayReference Command Set. + * + * @author Aaron Luchko + */ +public class ArrayReferenceCommandSet + extends CommandSet +{ + public boolean runCommand(ByteBuffer bb, DataOutputStream os, byte command) + throws JdwpException + { + try + { + switch (command) + { + case JdwpConstants.CommandSet.ArrayReference.LENGTH: + executeLength(bb, os); + break; + case JdwpConstants.CommandSet.ArrayReference.GET_VALUES: + executeGetValues(bb, os); + break; + case JdwpConstants.CommandSet.ArrayReference.SET_VALUES: + executeSetValues(bb, os); + break; + default: + throw new NotImplementedException("Command " + command + + " not found in Array Reference Command Set."); + } + } + catch (IOException ex) + { + // The DataOutputStream we're using isn't talking to a socket at all + // So if we throw an IOException we're in serious trouble + throw new JdwpInternalErrorException(ex); + } + + return false; + } + + private void executeLength(ByteBuffer bb, DataOutputStream os) + throws InvalidObjectException, IOException + { + ObjectId oid = idMan.readObjectId(bb); + Object array = oid.getObject(); + os.writeInt(Array.getLength(array)); + } + + private void executeGetValues(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ObjectId oid = idMan.readObjectId(bb); + Object array = oid.getObject(); + int first = bb.getInt(); + int length = bb.getInt(); + + // We need to write out the byte signifying the type of array first + Class clazz = array.getClass().getComponentType(); + + // Uugh, this is a little ugly but it's the only time we deal with + // arrayregions + if (clazz == byte.class) + os.writeByte(JdwpConstants.Tag.BYTE); + else if (clazz == char.class) + os.writeByte(JdwpConstants.Tag.CHAR); + else if (clazz == float.class) + os.writeByte(JdwpConstants.Tag.FLOAT); + else if (clazz == double.class) + os.writeByte(JdwpConstants.Tag.DOUBLE); + else if (clazz == int.class) + os.writeByte(JdwpConstants.Tag.BYTE); + else if (clazz == long.class) + os.writeByte(JdwpConstants.Tag.LONG); + else if (clazz == short.class) + os.writeByte(JdwpConstants.Tag.SHORT); + else if (clazz == void.class) + os.writeByte(JdwpConstants.Tag.VOID); + else if (clazz == boolean.class) + os.writeByte(JdwpConstants.Tag.BOOLEAN); + else if (clazz.isArray()) + os.writeByte(JdwpConstants.Tag.ARRAY); + else if (String.class.isAssignableFrom(clazz)) + os.writeByte(JdwpConstants.Tag.STRING); + else if (Thread.class.isAssignableFrom(clazz)) + os.writeByte(JdwpConstants.Tag.THREAD); + else if (ThreadGroup.class.isAssignableFrom(clazz)) + os.writeByte(JdwpConstants.Tag.THREAD_GROUP); + else if (ClassLoader.class.isAssignableFrom(clazz)) + os.writeByte(JdwpConstants.Tag.CLASS_LOADER); + else if (Class.class.isAssignableFrom(clazz)) + os.writeByte(JdwpConstants.Tag.CLASS_OBJECT); + else + os.writeByte(JdwpConstants.Tag.OBJECT); + + // Write all the values, primitives should be untagged and Objects must be + // tagged + for (int i = first; i < first + length; i++) + { + Value val = ValueFactory.createFromObject(Array.get(array, i), clazz); + if (clazz.isPrimitive()) + val.writeUntagged(os); + else + val.writeTagged(os); + } + } + + private void executeSetValues(ByteBuffer bb, DataOutputStream os) + throws IOException, JdwpException + { + ObjectId oid = idMan.readObjectId(bb); + Object array = oid.getObject(); + int first = bb.getInt(); + int length = bb.getInt(); + Class type = array.getClass().getComponentType(); + for (int i = first; i < first + length; i++) + { + Object value = Value.getUntaggedObject(bb, type); + Array.set(array, i, value); + } + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/processor/ArrayTypeCommandSet.java b/libjava/classpath/gnu/classpath/jdwp/processor/ArrayTypeCommandSet.java new file mode 100644 index 000000000..899bf2997 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/processor/ArrayTypeCommandSet.java @@ -0,0 +1,105 @@ +/* ArrayTypeCommandSet.java -- class to implement the ArrayType Command Set + Copyright (C) 2005 Free Software Foundation + +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.jdwp.processor; + +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.exception.JdwpException; +import gnu.classpath.jdwp.exception.JdwpInternalErrorException; +import gnu.classpath.jdwp.exception.NotImplementedException; +import gnu.classpath.jdwp.id.ObjectId; +import gnu.classpath.jdwp.id.ReferenceTypeId; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.lang.reflect.Array; +import java.nio.ByteBuffer; + +/** + * A class representing the ArrayType Command Set. + * + * @author Aaron Luchko + */ +public class ArrayTypeCommandSet + extends CommandSet +{ + public boolean runCommand(ByteBuffer bb, DataOutputStream os, byte command) + throws JdwpException + { + + // Although there's only a single command to choose from we still use + // a switch to maintain consistency with the rest of the CommandSets + try + { + switch (command) + { + case JdwpConstants.CommandSet.ArrayType.NEW_INSTANCE: + executeNewInstance(bb, os); + break; + default: + throw new NotImplementedException("Command " + command + + " not found in ArrayType Command Set."); + } + } + catch (IOException ex) + { + // The DataOutputStream we're using isn't talking to a socket at all + // So if we throw an IOException we're in serious trouble + throw new JdwpInternalErrorException(ex); + } + + return false; + } + + public void executeNewInstance(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ReferenceTypeId refId = idMan.readReferenceTypeId(bb); + Class arrayType = refId.getType(); + Class componentType = arrayType.getComponentType(); + + int length = bb.getInt(); + Object newArray = Array.newInstance(componentType, length); + ObjectId oid = idMan.getObjectId(newArray); + + // Since this array isn't referenced anywhere we'll disable garbage + // collection on it so it's still around when the debugger gets back to it. + oid.disableCollection(); + oid.writeTagged(os); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/processor/ClassLoaderReferenceCommandSet.java b/libjava/classpath/gnu/classpath/jdwp/processor/ClassLoaderReferenceCommandSet.java new file mode 100644 index 000000000..295410f6c --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/processor/ClassLoaderReferenceCommandSet.java @@ -0,0 +1,108 @@ +/* ClassLoaderReferenceCommandSet.java -- class to implement the + ClassLoaderReference Command Set + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.processor; + +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.VMVirtualMachine; +import gnu.classpath.jdwp.exception.JdwpException; +import gnu.classpath.jdwp.exception.JdwpInternalErrorException; +import gnu.classpath.jdwp.exception.NotImplementedException; +import gnu.classpath.jdwp.id.ObjectId; +import gnu.classpath.jdwp.id.ReferenceTypeId; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Iterator; + +/** + * A class representing the ClassLoaderReference Command Set. + * + * @author Aaron Luchko + */ +public class ClassLoaderReferenceCommandSet + extends CommandSet +{ + public boolean runCommand(ByteBuffer bb, DataOutputStream os, byte command) + throws JdwpException + { + + // Although there's only a single command to choose from we still use + // a switch to maintain consistency with the rest of the CommandSets + try + { + switch (command) + { + case JdwpConstants.CommandSet.ClassLoaderReference.VISIBLE_CLASSES: + executeVisibleClasses(bb, os); + break; + default: + throw new NotImplementedException("Command " + command + + " not found in ClassLoaderReference Command Set."); + } + } + catch (IOException ex) + { + // The DataOutputStream we're using isn't talking to a socket at all + // So if we throw an IOException we're in serious trouble + throw new JdwpInternalErrorException(ex); + } + + return false; + } + + public void executeVisibleClasses(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ObjectId oId = idMan.readObjectId(bb); + ClassLoader cl = (ClassLoader) oId.getObject(); + ArrayList loadRequests = VMVirtualMachine.getLoadRequests(cl); + os.writeInt(loadRequests.size()); + for (Iterator iter = loadRequests.iterator(); iter.hasNext();) + { + Class clazz = (Class)iter.next(); + ReferenceTypeId refId = idMan.getReferenceTypeId(clazz); + refId.writeTagged(os); + } + } + +} diff --git a/libjava/classpath/gnu/classpath/jdwp/processor/ClassObjectReferenceCommandSet.java b/libjava/classpath/gnu/classpath/jdwp/processor/ClassObjectReferenceCommandSet.java new file mode 100644 index 000000000..b32dbc2e5 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/processor/ClassObjectReferenceCommandSet.java @@ -0,0 +1,97 @@ +/* ClassObjectReferenceCommandSet.java -- class to implement the + ClassObjectReference Command Set + Copyright (C) 2005 Free Software Foundation + +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.jdwp.processor; + +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.exception.JdwpException; +import gnu.classpath.jdwp.exception.JdwpInternalErrorException; +import gnu.classpath.jdwp.exception.NotImplementedException; +import gnu.classpath.jdwp.id.ObjectId; +import gnu.classpath.jdwp.id.ReferenceTypeId; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; + +/** + * A class representing the ClassObjectReference Command Set. + * + * @author Aaron Luchko + */ +public class ClassObjectReferenceCommandSet + extends CommandSet +{ + public boolean runCommand(ByteBuffer bb, DataOutputStream os, byte command) + throws JdwpException + { + try + { + switch (command) + { + case JdwpConstants.CommandSet.ClassObjectReference.REFLECTED_TYPE: + executeReflectedType(bb, os); + break; + default: + throw new NotImplementedException("Command " + command + + " not found in ClassObject Reference Command Set."); + } + } + catch (IOException ex) + { + // The DataOutputStream we're using isn't talking to a socket at all + // So if we throw an IOException we're in serious trouble + throw new JdwpInternalErrorException(ex); + } + + return false; + } + + public void executeReflectedType(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ObjectId oid = idMan.readObjectId(bb); + Class clazz = (Class) oid.getObject(); + + // The difference between a ClassObjectId and a ReferenceTypeId is one is + // stored as an ObjectId and the other as a ReferenceTypeId. + ReferenceTypeId refId = idMan.getReferenceTypeId(clazz); + refId.writeTagged(os); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/processor/ClassTypeCommandSet.java b/libjava/classpath/gnu/classpath/jdwp/processor/ClassTypeCommandSet.java new file mode 100644 index 000000000..ec496bfe9 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/processor/ClassTypeCommandSet.java @@ -0,0 +1,205 @@ +/* ClassTypeCommandSet.java -- class to implement the ClassType + Command Set + Copyright (C) 2005, 2007 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.processor; + +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.VMMethod; +import gnu.classpath.jdwp.VMVirtualMachine; +import gnu.classpath.jdwp.exception.InvalidFieldException; +import gnu.classpath.jdwp.exception.JdwpException; +import gnu.classpath.jdwp.exception.JdwpInternalErrorException; +import gnu.classpath.jdwp.exception.NotImplementedException; +import gnu.classpath.jdwp.id.ObjectId; +import gnu.classpath.jdwp.id.ReferenceTypeId; +import gnu.classpath.jdwp.util.MethodResult; +import gnu.classpath.jdwp.value.ObjectValue; +import gnu.classpath.jdwp.value.Value; +import gnu.classpath.jdwp.value.ValueFactory; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.lang.reflect.Field; +import java.nio.ByteBuffer; + +/** + * A class representing the ClassType Command Set. + * + * @author Aaron Luchko + */ +public class ClassTypeCommandSet + extends CommandSet +{ + public boolean runCommand(ByteBuffer bb, DataOutputStream os, byte command) + throws JdwpException + { + try + { + switch (command) + { + case JdwpConstants.CommandSet.ClassType.SUPERCLASS: + executeSuperclass(bb, os); + break; + case JdwpConstants.CommandSet.ClassType.SET_VALUES: + executeSetValues(bb, os); + break; + case JdwpConstants.CommandSet.ClassType.INVOKE_METHOD: + executeInvokeMethod(bb, os); + break; + case JdwpConstants.CommandSet.ClassType.NEW_INSTANCE: + executeNewInstance(bb, os); + break; + default: + throw new NotImplementedException("Command " + command + + " not found in ClassType Command Set."); + } + } + catch (IOException ex) + { + // The DataOutputStream we're using isn't talking to a socket at all + // So if we throw an IOException we're in serious trouble + throw new JdwpInternalErrorException(ex); + } + + return false; + } + + private void executeSuperclass(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ReferenceTypeId refId = idMan.readReferenceTypeId(bb); + Class clazz = refId.getType(); + Class superClazz = clazz.getSuperclass(); + + if (superClazz == null) { + os.writeLong(0L); + } else { + ReferenceTypeId clazzId = idMan.getReferenceTypeId(superClazz); + clazzId.write(os); + } + } + + private void executeSetValues(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ReferenceTypeId refId = idMan.readReferenceTypeId(bb); + + // We don't actually seem to need this... + Class clazz = refId.getType(); + + int numValues = bb.getInt(); + + for (int i = 0; i < numValues; i++) + { + ObjectId fieldId = idMan.readObjectId(bb); + Field field = (Field) (fieldId.getObject()); + Object value = Value.getUntaggedObject(bb, field.getType()); + try + { + field.setAccessible(true); // Might be a private field + field.set(null, value); + } + catch (IllegalArgumentException ex) + { + throw new InvalidFieldException(ex); + } + catch (IllegalAccessException ex) + { // Since we set it as accessible this really shouldn't happen + throw new JdwpInternalErrorException(ex); + } + } + } + + private void executeInvokeMethod(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + MethodResult mr = invokeMethod(bb); + + Throwable exception = mr.getThrownException(); + ObjectId eId = idMan.getObjectId(exception); + mr.getReturnedValue().writeTagged(os); + eId.writeTagged(os); + } + + private void executeNewInstance(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + MethodResult mr = invokeMethod(bb); + Throwable exception = mr.getThrownException(); + + if (exception == null && ! (mr.getReturnedValue() instanceof ObjectValue)) + throw new JdwpInternalErrorException("new instance returned non-object"); + + ObjectValue ov = (ObjectValue) mr.getReturnedValue(); + ObjectId oId = idMan.getObjectId(ov.getValue()); + + ObjectId eId = idMan.getObjectId(exception); + + oId.writeTagged(os); + eId.writeTagged(os); + } + + /** + * Execute the static method and return the resulting MethodResult. + */ + private MethodResult invokeMethod(ByteBuffer bb) + throws JdwpException, IOException + { + ReferenceTypeId refId = idMan.readReferenceTypeId(bb); + Class clazz = refId.getType(); + + ObjectId tId = idMan.readObjectId(bb); + Thread thread = (Thread) tId.getObject(); + + VMMethod method = VMMethod.readId(clazz, bb); + + int args = bb.getInt(); + Value[] values = new Value[args]; + + for (int i = 0; i < args; i++) + values[i] = ValueFactory.createFromTagged(bb); + + int invokeOpts = bb.getInt(); + MethodResult mr = VMVirtualMachine.executeMethod(null, thread, + clazz, method, + values, invokeOpts); + return mr; + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/processor/CommandSet.java b/libjava/classpath/gnu/classpath/jdwp/processor/CommandSet.java new file mode 100644 index 000000000..e1b71c10d --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/processor/CommandSet.java @@ -0,0 +1,74 @@ +/* CommandSet.java -- An interface defining JDWP Command Sets + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.processor; + +import gnu.classpath.jdwp.exception.JdwpException; +import gnu.classpath.jdwp.VMIdManager; + +import java.io.DataOutputStream; +import java.nio.ByteBuffer; + +/** + * A class representing a JDWP Command Set. This class serves as a generic + * interface for all Command Sets types used by JDWP. + * + * @author Aaron Luchko + */ +public abstract class CommandSet +{ + /** + * The VM's ID manager + */ + protected final VMIdManager idMan = VMIdManager.getDefault (); + + /** + * Runs the given command with the data in distr and writes the data for the + * reply packet to ostr. + * + * @param bb holds the data portion of the Command Packet + * @param os data portion of the Reply Packet will be written here + * @param command the command field of the Command Packet + * @return true if the JDWP layer should shut down in response to this packet + * @throws JdwpException command wasn't carried out successfully + */ + public abstract boolean runCommand(ByteBuffer bb, DataOutputStream os, + byte command) + throws JdwpException; +} diff --git a/libjava/classpath/gnu/classpath/jdwp/processor/EventRequestCommandSet.java b/libjava/classpath/gnu/classpath/jdwp/processor/EventRequestCommandSet.java new file mode 100644 index 000000000..477a79d83 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/processor/EventRequestCommandSet.java @@ -0,0 +1,220 @@ +/* EventRequestCommandSet.java -- class to implement the EventRequest Command + Set + Copyright (C) 2005, 2007 Free Software Foundation + +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.jdwp.processor; + +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.VMVirtualMachine; +import gnu.classpath.jdwp.event.EventManager; +import gnu.classpath.jdwp.event.EventRequest; +import gnu.classpath.jdwp.event.filters.ClassExcludeFilter; +import gnu.classpath.jdwp.event.filters.ClassMatchFilter; +import gnu.classpath.jdwp.event.filters.ClassOnlyFilter; +import gnu.classpath.jdwp.event.filters.ConditionalFilter; +import gnu.classpath.jdwp.event.filters.CountFilter; +import gnu.classpath.jdwp.event.filters.ExceptionOnlyFilter; +import gnu.classpath.jdwp.event.filters.FieldOnlyFilter; +import gnu.classpath.jdwp.event.filters.IEventFilter; +import gnu.classpath.jdwp.event.filters.InstanceOnlyFilter; +import gnu.classpath.jdwp.event.filters.LocationOnlyFilter; +import gnu.classpath.jdwp.event.filters.StepFilter; +import gnu.classpath.jdwp.event.filters.ThreadOnlyFilter; +import gnu.classpath.jdwp.exception.JdwpException; +import gnu.classpath.jdwp.exception.JdwpInternalErrorException; +import gnu.classpath.jdwp.exception.NotImplementedException; +import gnu.classpath.jdwp.id.ObjectId; +import gnu.classpath.jdwp.id.ReferenceTypeId; +import gnu.classpath.jdwp.id.ThreadId; +import gnu.classpath.jdwp.util.JdwpString; +import gnu.classpath.jdwp.util.Location; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; + +/** + * A class representing the EventRequest Command Set. + * + * @author Aaron Luchko + */ +public class EventRequestCommandSet + extends CommandSet +{ + public boolean runCommand(ByteBuffer bb, DataOutputStream os, byte command) + throws JdwpException + { + try + { + switch (command) + { + case JdwpConstants.CommandSet.EventRequest.SET: + executeSet(bb, os); + break; + case JdwpConstants.CommandSet.EventRequest.CLEAR: + executeClear(bb, os); + break; + case JdwpConstants.CommandSet.EventRequest.CLEAR_ALL_BREAKPOINTS: + executeClearAllBreakpoints(bb, os); + break; + default: + throw new NotImplementedException("Command " + command + + " not found in EventRequest Reference Command Set."); + } + } + catch (IOException ex) + { + // The DataOutputStream we're using isn't talking to a socket at all + // So if we throw an IOException we're in serious trouble + throw new JdwpInternalErrorException(ex); + } + + return false; + } + + private void executeSet(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + byte eventKind = bb.get(); + byte suspendPolicy = bb.get(); + int modifiers = bb.getInt(); + + switch (eventKind) + { + case JdwpConstants.EventKind.FIELD_ACCESS: + if (!VMVirtualMachine.canWatchFieldAccess) + { + String msg = "watching field accesses is not supported"; + throw new NotImplementedException(msg); + } + break; + + case JdwpConstants.EventKind.FIELD_MODIFICATION: + if (!VMVirtualMachine.canWatchFieldModification) + { + String msg = "watching field modifications is not supported"; + throw new NotImplementedException(msg); + } + break; + + default: + // okay + } + + EventRequest eventReq = new EventRequest(eventKind, suspendPolicy); + IEventFilter filter = null; + ReferenceTypeId refId; + for (int i = 0; i < modifiers; i++) + { + byte modKind = bb.get(); + switch (modKind) + { + case JdwpConstants.ModKind.COUNT: + filter = new CountFilter(bb.getInt()); + break; + case JdwpConstants.ModKind.CONDITIONAL: + filter = new ConditionalFilter(idMan.readObjectId(bb)); + break; + case JdwpConstants.ModKind.THREAD_ONLY: + filter = new ThreadOnlyFilter((ThreadId) idMan.readObjectId(bb)); + break; + case JdwpConstants.ModKind.CLASS_ONLY: + filter = new ClassOnlyFilter(idMan.readReferenceTypeId(bb)); + break; + case JdwpConstants.ModKind.CLASS_MATCH: + filter = new ClassMatchFilter(JdwpString.readString(bb)); + break; + case JdwpConstants.ModKind.CLASS_EXCLUDE: + filter = new ClassExcludeFilter(JdwpString.readString(bb)); + break; + case JdwpConstants.ModKind.LOCATION_ONLY: + filter = new LocationOnlyFilter(new Location(bb)); + break; + case JdwpConstants.ModKind.EXCEPTION_ONLY: + long id = bb.getLong(); + if (id == 0) + refId = null; + else + refId = idMan.getReferenceType(id); + boolean caught = (bb.get() == 0) ? false : true; + boolean unCaught = (bb.get() == 0) ? false : true; + filter = new ExceptionOnlyFilter(refId, caught, unCaught); + break; + case JdwpConstants.ModKind.FIELD_ONLY: + refId = idMan.readReferenceTypeId(bb); + ReferenceTypeId fieldId = idMan.readReferenceTypeId(bb); + filter = new FieldOnlyFilter(refId, fieldId); + break; + case JdwpConstants.ModKind.STEP: + ThreadId tid = (ThreadId) idMan.readObjectId(bb); + int size = bb.getInt(); + int depth = bb.getInt(); + filter = new StepFilter(tid, size, depth); + break; + case JdwpConstants.ModKind.INSTANCE_ONLY: + ObjectId oid = idMan.readObjectId(bb); + filter = new InstanceOnlyFilter(oid); + break; + default: + throw new NotImplementedException("modKind " + modKind + + " is not implemented."); + } + eventReq.addFilter(filter); + } + + EventManager.getDefault().requestEvent(eventReq); + os.writeInt(eventReq.getId()); + + } + + private void executeClear(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + byte eventKind = bb.get(); + int requestId = bb.getInt(); + EventManager.getDefault().deleteRequest(eventKind, requestId); + } + + private void executeClearAllBreakpoints(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + byte eventKind = bb.get (); + EventManager.getDefault().clearRequests (eventKind); + } + +} diff --git a/libjava/classpath/gnu/classpath/jdwp/processor/FieldCommandSet.java b/libjava/classpath/gnu/classpath/jdwp/processor/FieldCommandSet.java new file mode 100644 index 000000000..d7bb64878 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/processor/FieldCommandSet.java @@ -0,0 +1,67 @@ +/* FieldCommandSet.java -- class to implement the Field Command Set + Copyright (C) 2005 Free Software Foundation + +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.jdwp.processor; + +import gnu.classpath.jdwp.exception.JdwpException; +import gnu.classpath.jdwp.exception.NotImplementedException; + +import java.io.DataOutputStream; +import java.nio.ByteBuffer; + +/** + * A class representing the Field Command Set. + * + * @author Aaron Luchko + */ +public class FieldCommandSet + extends CommandSet +{ + /** + * There are no commands for this CommandSet at this time so we just throw a + * NotImplementedException whenever it's called. + * + * @throws JdwpException An exception will always be thrown + */ + public boolean runCommand(ByteBuffer bb, DataOutputStream os, byte command) + throws JdwpException + { + throw new NotImplementedException( + "No commands for command set Field implemented."); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/processor/InterfaceTypeCommandSet.java b/libjava/classpath/gnu/classpath/jdwp/processor/InterfaceTypeCommandSet.java new file mode 100644 index 000000000..74e2f4c4d --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/processor/InterfaceTypeCommandSet.java @@ -0,0 +1,68 @@ +/* InterfaceTypeCommandSet.java -- class to implement the InterfaceType + Command Set + Copyright (C) 2005 Free Software Foundation + +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.jdwp.processor; + +import gnu.classpath.jdwp.exception.JdwpException; +import gnu.classpath.jdwp.exception.NotImplementedException; + +import java.io.DataOutputStream; +import java.nio.ByteBuffer; + +/** + * A class representing the InterfaceType Command Set. + * + * @author Aaron Luchko + */ +public class InterfaceTypeCommandSet + extends CommandSet +{ + /** + * There are no commands for this CommandSet at this time so we just throw a + * NotImplementedException whenever it's called. + * + * @throws JdwpException An exception will always be thrown + */ + public boolean runCommand(ByteBuffer bb, DataOutputStream os, byte command) + throws JdwpException + { + throw new NotImplementedException( + "No commands for command set InterfaceType implemented."); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/processor/MethodCommandSet.java b/libjava/classpath/gnu/classpath/jdwp/processor/MethodCommandSet.java new file mode 100644 index 000000000..043be7cf0 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/processor/MethodCommandSet.java @@ -0,0 +1,157 @@ +/* MethodCommandSet.java -- class to implement the Method Command Set + Copyright (C) 2005, 2006, 2007 Free Software Foundation + +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.jdwp.processor; + +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.VMMethod; +import gnu.classpath.jdwp.VMVirtualMachine; +import gnu.classpath.jdwp.exception.JdwpException; +import gnu.classpath.jdwp.exception.JdwpInternalErrorException; +import gnu.classpath.jdwp.exception.NotImplementedException; +import gnu.classpath.jdwp.id.ReferenceTypeId; +import gnu.classpath.jdwp.util.LineTable; +import gnu.classpath.jdwp.util.VariableTable; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; + +/** + * A class representing the Method Command Set. + * + * @author Aaron Luchko + */ +public class MethodCommandSet + extends CommandSet +{ + public boolean runCommand(ByteBuffer bb, DataOutputStream os, byte command) + throws JdwpException + { + try + { + switch (command) + { + case JdwpConstants.CommandSet.Method.LINE_TABLE: + executeLineTable(bb, os); + break; + case JdwpConstants.CommandSet.Method.VARIABLE_TABLE: + executeVariableTable(bb, os); + break; + case JdwpConstants.CommandSet.Method.BYTE_CODES: + executeByteCodes(bb, os); + break; + case JdwpConstants.CommandSet.Method.IS_OBSOLETE: + executeIsObsolete(bb, os); + break; + case JdwpConstants.CommandSet.Method.VARIABLE_TABLE_WITH_GENERIC: + executeVariableTableWithGeneric(bb, os); + break; + default: + throw new NotImplementedException( + "Command " + command + " not found in Method Command Set."); + } + } + catch (IOException ex) + { + // The DataOutputStream we're using isn't talking to a socket at all + // So if we throw an IOException we're in serious trouble + throw new JdwpInternalErrorException(ex); + } + + return false; + } + + private void executeLineTable(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ReferenceTypeId refId = idMan.readReferenceTypeId(bb); + Class clazz = refId.getType(); + + VMMethod method = VMMethod.readId(clazz, bb); + LineTable lt = method.getLineTable(); + lt.write(os); + } + + private void executeVariableTable(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ReferenceTypeId refId = idMan.readReferenceTypeId(bb); + Class clazz = refId.getType(); + + VMMethod method = VMMethod.readId(clazz, bb); + VariableTable vt = method.getVariableTable(); + vt.write(os); + } + + private void executeByteCodes(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + if (!VMVirtualMachine.canGetBytecodes) + { + String msg = "getting bytecodes is unsupported"; + throw new NotImplementedException(msg); + } + + ReferenceTypeId id = idMan.readReferenceTypeId(bb); + Class klass = id.getType(); + VMMethod method = VMMethod.readId(klass, bb); + byte[] bytecode = VMVirtualMachine.getBytecodes(method); + os.writeInt(bytecode.length); + os.write(bytecode); + } + + private void executeIsObsolete(ByteBuffer bb, DataOutputStream os) + throws IOException + { + // The debugger is really asking if this method has been redefined using + // VirtualMachineCommandSet.RedefineClasses. Since we don't implement that + // command the answer to this will always be false. + os.writeBoolean(false); + } + + private void executeVariableTableWithGeneric(ByteBuffer bb, + DataOutputStream os) + throws JdwpException + { + // We don't have generics yet + throw new NotImplementedException( + "Command VariableTableWithGeneric not implemented."); + } + +} diff --git a/libjava/classpath/gnu/classpath/jdwp/processor/ObjectReferenceCommandSet.java b/libjava/classpath/gnu/classpath/jdwp/processor/ObjectReferenceCommandSet.java new file mode 100644 index 000000000..f6bf8a656 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/processor/ObjectReferenceCommandSet.java @@ -0,0 +1,255 @@ +/* ObjectReferenceCommandSet.java -- class to implement the ObjectReference + Command Set + Copyright (C) 2005, 2007 Free Software Foundation + +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.jdwp.processor; + +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.VMMethod; +import gnu.classpath.jdwp.VMVirtualMachine; +import gnu.classpath.jdwp.exception.InvalidFieldException; +import gnu.classpath.jdwp.exception.JdwpException; +import gnu.classpath.jdwp.exception.JdwpInternalErrorException; +import gnu.classpath.jdwp.exception.NotImplementedException; +import gnu.classpath.jdwp.id.ObjectId; +import gnu.classpath.jdwp.id.ReferenceTypeId; +import gnu.classpath.jdwp.util.MethodResult; +import gnu.classpath.jdwp.util.MonitorInfo; +import gnu.classpath.jdwp.value.Value; +import gnu.classpath.jdwp.value.ValueFactory; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.lang.reflect.Field; +import java.nio.ByteBuffer; + +/** + * A class representing the ObjectReference Command Set. + * + * @author Aaron Luchko + */ +public class ObjectReferenceCommandSet + extends CommandSet +{ + public boolean runCommand(ByteBuffer bb, DataOutputStream os, byte command) + throws JdwpException + { + try + { + switch (command) + { + case JdwpConstants.CommandSet.ObjectReference.REFERENCE_TYPE: + executeReferenceType(bb, os); + break; + case JdwpConstants.CommandSet.ObjectReference.GET_VALUES: + executeGetValues(bb, os); + break; + case JdwpConstants.CommandSet.ObjectReference.SET_VALUES: + executeSetValues(bb, os); + break; + case JdwpConstants.CommandSet.ObjectReference.MONITOR_INFO: + executeMonitorInfo(bb, os); + break; + case JdwpConstants.CommandSet.ObjectReference.INVOKE_METHOD: + executeInvokeMethod(bb, os); + break; + case JdwpConstants.CommandSet.ObjectReference.DISABLE_COLLECTION: + executeDisableCollection(bb, os); + break; + case JdwpConstants.CommandSet.ObjectReference.ENABLE_COLLECTION: + executeEnableCollection(bb, os); + break; + case JdwpConstants.CommandSet.ObjectReference.IS_COLLECTED: + executeIsCollected(bb, os); + break; + default: + throw new NotImplementedException("Command " + command + + " not found in ObjectReference Command Set."); + } + } + catch (IOException ex) + { + // The DataOutputStream we're using isn't talking to a socket at all + // So if we throw an IOException we're in serious trouble + throw new JdwpInternalErrorException(ex); + } + + return false; + } + + private void executeReferenceType(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ObjectId oid = idMan.readObjectId(bb); + Object obj = oid.getObject(); + Class clazz = obj.getClass(); + ReferenceTypeId refId = idMan.getReferenceTypeId(clazz); + refId.writeTagged(os); + } + + private void executeGetValues(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ObjectId oid = idMan.readObjectId(bb); + Object obj = oid.getObject(); + + int numFields = bb.getInt(); + + os.writeInt(numFields); // Looks pointless but this is the protocol + + for (int i = 0; i < numFields; i++) + { + Field field = (Field) idMan.readObjectId(bb).getObject(); + try + { + field.setAccessible(true); // Might be a private field + Object value = field.get(obj); + Value val = ValueFactory.createFromObject(value, + field.getType()); + val.writeTagged(os); + } + catch (IllegalArgumentException ex) + { + // I suppose this would best qualify as an invalid field then + throw new InvalidFieldException(ex); + } + catch (IllegalAccessException ex) + { + // Since we set it as accessible this really shouldn't happen + throw new JdwpInternalErrorException(ex); + } + } + } + + private void executeSetValues(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ObjectId oid = idMan.readObjectId(bb); + Object obj = oid.getObject(); + + int numFields = bb.getInt(); + + for (int i = 0; i < numFields; i++) + { + Field field = (Field) idMan.readObjectId(bb).getObject(); + Object value = Value.getUntaggedObject(bb, field.getType()); + try + { + field.setAccessible(true); // Might be a private field + field.set(obj, value); + } + catch (IllegalArgumentException ex) + { + // I suppose this would best qualify as an invalid field then + throw new InvalidFieldException(ex); + } + catch (IllegalAccessException ex) + { + // Since we set it as accessible this really shouldn't happen + throw new JdwpInternalErrorException(ex); + } + } + } + + private void executeMonitorInfo(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + if (!VMVirtualMachine.canGetMonitorInfo) + { + String msg = "getting monitor info not supported"; + throw new NotImplementedException(msg); + } + + ObjectId oid = idMan.readObjectId(bb); + Object obj = oid.getObject(); + MonitorInfo info = VMVirtualMachine.getMonitorInfo(obj); + info.write(os); + } + + private void executeInvokeMethod(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ObjectId oid = idMan.readObjectId(bb); + Object obj = oid.getObject(); + + ObjectId tid = idMan.readObjectId(bb); + Thread thread = (Thread) tid.getObject(); + + ReferenceTypeId rid = idMan.readReferenceTypeId(bb); + Class clazz = rid.getType(); + + VMMethod method = VMMethod.readId(clazz, bb); + + int args = bb.getInt(); + Value[] values = new Value[args]; + + for (int i = 0; i < args; i++) + values[i] = ValueFactory.createFromTagged(bb); + + int invokeOptions = bb.getInt(); + MethodResult mr = VMVirtualMachine.executeMethod(obj, thread, + clazz, method, + values, invokeOptions); + Throwable exception = mr.getThrownException(); + ObjectId eId = idMan.getObjectId(exception); + mr.getReturnedValue().writeTagged(os); + eId.writeTagged(os); + } + + private void executeDisableCollection(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ObjectId oid = idMan.readObjectId(bb); + oid.disableCollection(); + } + + private void executeEnableCollection(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ObjectId oid = idMan.readObjectId(bb); + oid.enableCollection(); + } + + private void executeIsCollected(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ObjectId oid = idMan.readObjectId(bb); + boolean collected = (oid.getReference().get () == null); + os.writeBoolean(collected); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/processor/PacketProcessor.java b/libjava/classpath/gnu/classpath/jdwp/processor/PacketProcessor.java new file mode 100644 index 000000000..c4818aed8 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/processor/PacketProcessor.java @@ -0,0 +1,221 @@ +/* PacketProcessor.java -- a thread which processes command packets + from the debugger + Copyright (C) 2005, 2006 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.processor; + +import gnu.classpath.jdwp.Jdwp; +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.exception.JdwpException; +import gnu.classpath.jdwp.transport.JdwpCommandPacket; +import gnu.classpath.jdwp.transport.JdwpConnection; +import gnu.classpath.jdwp.transport.JdwpPacket; +import gnu.classpath.jdwp.transport.JdwpReplyPacket; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.security.PrivilegedAction; + +/** + * This class is responsible for processing packets from the + * debugger. It waits for an available packet from the connection + * ({@link gnu.classpath.jdwp.transport.JdwpConnection}) and then + * processes the packet and any reply. + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class PacketProcessor + implements PrivilegedAction +{ + // The connection to the debugger + private JdwpConnection _connection; + + // Shutdown this thread? + private boolean _shutdown; + + // A Mapping of the command set (Byte) to the specific CommandSet + private CommandSet[] _sets; + + // Contents of the ReplyPackets data field + private ByteArrayOutputStream _outputBytes; + + // Output stream around _outputBytes + private DataOutputStream _os; + + /** + * Constructs a new PacketProcessor object + * Connection must be validated before getting here! + * + * @param con the connection + */ + public PacketProcessor (JdwpConnection con) + { + _connection = con; + _shutdown = false; + + // MAXIMUM is the value of the largest command set we may receive + _sets = new CommandSet[JdwpConstants.CommandSet.MAXIMUM + 1]; + _outputBytes = new ByteArrayOutputStream(); + _os = new DataOutputStream (_outputBytes); + + // Create all the Command Sets and add them to our array + _sets[JdwpConstants.CommandSet.VirtualMachine.CS_VALUE] = + new VirtualMachineCommandSet(); + _sets[JdwpConstants.CommandSet.ReferenceType.CS_VALUE] = + new ReferenceTypeCommandSet(); + _sets[JdwpConstants.CommandSet.ClassType.CS_VALUE] = + new ClassTypeCommandSet(); + _sets[JdwpConstants.CommandSet.ArrayType.CS_VALUE] = + new ArrayTypeCommandSet(); + _sets[JdwpConstants.CommandSet.InterfaceType.CS_VALUE] = + new InterfaceTypeCommandSet(); + _sets[JdwpConstants.CommandSet.Method.CS_VALUE] = + new MethodCommandSet(); + _sets[JdwpConstants.CommandSet.Field.CS_VALUE] = + new FieldCommandSet(); + _sets[JdwpConstants.CommandSet.ObjectReference.CS_VALUE] = + new ObjectReferenceCommandSet(); + _sets[JdwpConstants.CommandSet.StringReference.CS_VALUE] = + new StringReferenceCommandSet(); + _sets[JdwpConstants.CommandSet.ThreadReference.CS_VALUE] = + new ThreadReferenceCommandSet(); + _sets[JdwpConstants.CommandSet.ThreadGroupReference.CS_VALUE] = + new ThreadGroupReferenceCommandSet(); + _sets[JdwpConstants.CommandSet.ArrayReference.CS_VALUE] = + new ArrayReferenceCommandSet(); + _sets[JdwpConstants.CommandSet.ClassLoaderReference.CS_VALUE] = + new ClassLoaderReferenceCommandSet(); + _sets[JdwpConstants.CommandSet.EventRequest.CS_VALUE] = + new EventRequestCommandSet(); + _sets[JdwpConstants.CommandSet.StackFrame.CS_VALUE] = + new StackFrameCommandSet(); + _sets[JdwpConstants.CommandSet.ClassObjectReference.CS_VALUE] = + new ClassObjectReferenceCommandSet(); + } + + /** + * Main run routine for this thread. Will loop getting packets + * from the connection and processing them. + */ + public Object run () + { + // Notify initialization thread (gnu.classpath.jdwp.Jdwp) that + // the PacketProcessor thread is ready. + Jdwp.getDefault().subcomponentInitialized (); + + try + { + while (!_shutdown) + { + _processOnePacket (); + } + } + catch (Exception ex) + { + ex.printStackTrace(); + } + // Time to shutdown, tell Jdwp to shutdown + Jdwp.getDefault().shutdown(); + return null; + } + + /** + * Shutdown the packet processor + */ + public void shutdown () + { + _shutdown = true; + } + + // Helper function which actually does all the work of waiting + // for a packet and getting it processed. + private void _processOnePacket () + throws IOException + { + JdwpPacket pkt = _connection.getPacket (); + + if (!(pkt instanceof JdwpCommandPacket)) + { + // We're not supposed to get these from the debugger! + // Drop it on the floor + return; + } + + if (pkt != null) + { + JdwpCommandPacket commandPkt = (JdwpCommandPacket) pkt; + JdwpReplyPacket reply = new JdwpReplyPacket(commandPkt); + + // Reset our output stream + _outputBytes.reset(); + + // Create a ByteBuffer around the command packet + ByteBuffer bb = ByteBuffer.wrap(commandPkt.getData()); + byte command = commandPkt.getCommand(); + byte commandSet = commandPkt.getCommandSet(); + + CommandSet set = null; + try + { + // There is no command set with value 0 + if (commandSet > 0 && commandSet < _sets.length) + { + set = _sets[commandPkt.getCommandSet()]; + } + if (set != null) + { + _shutdown = set.runCommand(bb, _os, command); + reply.setData(_outputBytes.toByteArray()); + } + else + { + // This command set wasn't in our tree + reply.setErrorCode(JdwpConstants.Error.NOT_IMPLEMENTED); + } + } + catch (JdwpException ex) + { + reply.setErrorCode(ex.getErrorCode ()); + } + _connection.sendPacket (reply); + } + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/processor/ReferenceTypeCommandSet.java b/libjava/classpath/gnu/classpath/jdwp/processor/ReferenceTypeCommandSet.java new file mode 100644 index 000000000..3489588df --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/processor/ReferenceTypeCommandSet.java @@ -0,0 +1,341 @@ +/* ReferenceTypeCommandSet.java -- class to implement the ReferenceType + Command Set + Copyright (C) 2005, 2006, 2007 Free Software Foundation + +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.jdwp.processor; + +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.VMMethod; +import gnu.classpath.jdwp.VMVirtualMachine; +import gnu.classpath.jdwp.exception.InvalidFieldException; +import gnu.classpath.jdwp.exception.JdwpException; +import gnu.classpath.jdwp.exception.JdwpInternalErrorException; +import gnu.classpath.jdwp.exception.NotImplementedException; +import gnu.classpath.jdwp.id.ObjectId; +import gnu.classpath.jdwp.id.ReferenceTypeId; +import gnu.classpath.jdwp.util.JdwpString; +import gnu.classpath.jdwp.util.Signature; +import gnu.classpath.jdwp.value.Value; +import gnu.classpath.jdwp.value.ValueFactory; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.lang.reflect.Field; +import java.nio.ByteBuffer; + +/** + * A class representing the ReferenceType Command Set. + * + * @author Aaron Luchko + */ +public class ReferenceTypeCommandSet + extends CommandSet +{ + public boolean runCommand(ByteBuffer bb, DataOutputStream os, byte command) + throws JdwpException + { + try + { + switch (command) + { + case JdwpConstants.CommandSet.ReferenceType.SIGNATURE: + executeSignature(bb, os); + break; + case JdwpConstants.CommandSet.ReferenceType.CLASS_LOADER: + executeClassLoader(bb, os); + break; + case JdwpConstants.CommandSet.ReferenceType.MODIFIERS: + executeModifiers(bb, os); + break; + case JdwpConstants.CommandSet.ReferenceType.FIELDS: + executeFields(bb, os); + break; + case JdwpConstants.CommandSet.ReferenceType.METHODS: + executeMethods(bb, os); + break; + case JdwpConstants.CommandSet.ReferenceType.GET_VALUES: + executeGetValues(bb, os); + break; + case JdwpConstants.CommandSet.ReferenceType.SOURCE_FILE: + executeSourceFile(bb, os); + break; + case JdwpConstants.CommandSet.ReferenceType.NESTED_TYPES: + executeNestedTypes(bb, os); + break; + case JdwpConstants.CommandSet.ReferenceType.STATUS: + executeStatus(bb, os); + break; + case JdwpConstants.CommandSet.ReferenceType.INTERFACES: + executeInterfaces(bb, os); + break; + case JdwpConstants.CommandSet.ReferenceType.CLASS_OBJECT: + executeClassObject(bb, os); + break; + case JdwpConstants.CommandSet.ReferenceType.SOURCE_DEBUG_EXTENSION: + executeSourceDebugExtension(bb, os); + break; + case JdwpConstants.CommandSet.ReferenceType.SIGNATURE_WITH_GENERIC: + executeSignatureWithGeneric(bb, os); + break; + case JdwpConstants.CommandSet.ReferenceType.FIELDS_WITH_GENERIC: + executeFieldWithGeneric(bb, os); + break; + case JdwpConstants.CommandSet.ReferenceType.METHODS_WITH_GENERIC: + executeMethodsWithGeneric(bb, os); + break; + default: + throw new NotImplementedException("Command " + command + + " not found in ReferenceType Command Set."); + } + } + catch (IOException ex) + { + // The DataOutputStream we're using isn't talking to a socket at all + // So if we throw an IOException we're in serious trouble + throw new JdwpInternalErrorException(ex); + } + + return false; + } + + private void executeSignature(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ReferenceTypeId refId = idMan.readReferenceTypeId(bb); + String sig = Signature.computeClassSignature(refId.getType()); + JdwpString.writeString(os, sig); + } + + private void executeClassLoader(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ReferenceTypeId refId = idMan.readReferenceTypeId(bb); + + Class clazz = refId.getType(); + ClassLoader loader = clazz.getClassLoader(); + ObjectId oid = idMan.getObjectId(loader); + oid.write(os); + } + + private void executeModifiers(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ReferenceTypeId refId = idMan.readReferenceTypeId(bb); + + Class clazz = refId.getType(); + os.writeInt(clazz.getModifiers()); + } + + private void executeFields(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ReferenceTypeId refId = idMan.readReferenceTypeId(bb); + Class clazz = refId.getType(); + + Field[] fields = clazz.getFields(); + os.writeInt(fields.length); + for (int i = 0; i < fields.length; i++) + { + Field field = fields[i]; + idMan.getObjectId(field).write(os); + JdwpString.writeString(os, field.getName()); + JdwpString.writeString(os, Signature.computeFieldSignature(field)); + os.writeInt(field.getModifiers()); + } + } + + private void executeMethods(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ReferenceTypeId refId = idMan.readReferenceTypeId(bb); + Class clazz = refId.getType(); + + VMMethod[] methods = VMVirtualMachine.getAllClassMethods(clazz); + os.writeInt (methods.length); + for (int i = 0; i < methods.length; i++) + { + VMMethod method = methods[i]; + method.writeId(os); + JdwpString.writeString(os, method.getName()); + JdwpString.writeString(os, method.getSignature()); + os.writeInt(method.getModifiers()); + } + } + + private void executeGetValues(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ReferenceTypeId refId = idMan.readReferenceTypeId(bb); + Class clazz = refId.getType(); + + int numFields = bb.getInt(); + os.writeInt(numFields); // Looks pointless but this is the protocol + for (int i = 0; i < numFields; i++) + { + ObjectId fieldId = idMan.readObjectId(bb); + Field field = (Field) (fieldId.getObject()); + Class fieldClazz = field.getDeclaringClass(); + + // We don't actually need the clazz to get the field but we might as + // well check that the debugger got it right + if (fieldClazz.isAssignableFrom(clazz)) + { + try + { + field.setAccessible(true); // Might be a private field + Object value = field.get(null); + Value val = ValueFactory.createFromObject(value, + field.getType()); + val.writeTagged(os); + } + catch (IllegalArgumentException ex) + { + // I suppose this would best qualify as an invalid field then + throw new InvalidFieldException(ex); + } + catch (IllegalAccessException ex) + { + // Since we set it as accessible this really shouldn't happen + throw new JdwpInternalErrorException(ex); + } + } + else + throw new InvalidFieldException(fieldId.getId()); + } + } + + private void executeSourceFile(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ReferenceTypeId refId = idMan.readReferenceTypeId(bb); + Class clazz = refId.getType(); + + // We'll need to go into the jvm for this unless there's an easier way + String sourceFileName = VMVirtualMachine.getSourceFile(clazz); + JdwpString.writeString(os, sourceFileName); + // clazz.getProtectionDomain().getCodeSource().getLocation(); + } + + private void executeNestedTypes(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ReferenceTypeId refId = idMan.readReferenceTypeId(bb); + Class clazz = refId.getType(); + Class[] declaredClazzes = clazz.getDeclaredClasses(); + os.writeInt(declaredClazzes.length); + for (int i = 0; i < declaredClazzes.length; i++) + { + Class decClazz = declaredClazzes[i]; + ReferenceTypeId clazzId = idMan.getReferenceTypeId(decClazz); + clazzId.writeTagged(os); + } + } + + private void executeStatus(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ReferenceTypeId refId = idMan.readReferenceTypeId(bb); + Class clazz = refId.getType(); + + // I don't think there's any other way to get this + int status = VMVirtualMachine.getClassStatus(clazz); + os.writeInt(status); + } + + private void executeInterfaces(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ReferenceTypeId refId = idMan.readReferenceTypeId(bb); + Class clazz = refId.getType(); + Class[] interfaces = clazz.getInterfaces(); + os.writeInt(interfaces.length); + for (int i = 0; i < interfaces.length; i++) + { + Class interfaceClass = interfaces[i]; + ReferenceTypeId intId = idMan.getReferenceTypeId(interfaceClass); + intId.write(os); + } + } + + private void executeClassObject(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ReferenceTypeId refId = idMan.readReferenceTypeId(bb); + Class clazz = refId.getType(); + ObjectId clazzObjectId = idMan.getObjectId(clazz); + clazzObjectId.write(os); + } + + private void executeSourceDebugExtension(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + if (!VMVirtualMachine.canGetSourceDebugExtension) + { + String msg = "source debug extension is not supported"; + throw new NotImplementedException(msg); + } + + ReferenceTypeId id = idMan.readReferenceTypeId(bb); + String ext = VMVirtualMachine.getSourceDebugExtension (id.getType()); + JdwpString.writeString(os, ext); + } + + private void executeSignatureWithGeneric(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + // We don't have generics yet + throw new NotImplementedException( + "Command SignatureWithGeneric not implemented."); + } + + private void executeFieldWithGeneric(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + // We don't have generics yet + throw new NotImplementedException( + "Command executeFieldWithGeneric not implemented."); + } + + private void executeMethodsWithGeneric(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + // We don't have generics yet + throw new NotImplementedException( + "Command executeMethodsWithGeneric not implemented."); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/processor/StackFrameCommandSet.java b/libjava/classpath/gnu/classpath/jdwp/processor/StackFrameCommandSet.java new file mode 100644 index 000000000..2b82e05ff --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/processor/StackFrameCommandSet.java @@ -0,0 +1,170 @@ +/* StackFrameCommandSet.java -- class to implement the StackFrame Command Set + Copyright (C) 2005, 2007 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.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; +import gnu.classpath.jdwp.exception.NotImplementedException; +import gnu.classpath.jdwp.id.ThreadId; +import gnu.classpath.jdwp.value.ObjectValue; +import gnu.classpath.jdwp.value.Value; +import gnu.classpath.jdwp.value.ValueFactory; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; + +/** + * A class representing the StackFrame Command Set. + * + * @author Aaron Luchko + */ +public class StackFrameCommandSet + extends CommandSet +{ + public boolean runCommand(ByteBuffer bb, DataOutputStream os, byte command) + throws JdwpException + { + boolean keepRunning = true; + try + { + switch (command) + { + case JdwpConstants.CommandSet.StackFrame.GET_VALUES: + executeGetValues(bb, os); + break; + case JdwpConstants.CommandSet.StackFrame.SET_VALUES: + executeSetValues(bb, os); + break; + case JdwpConstants.CommandSet.StackFrame.THIS_OBJECT: + executeThisObject(bb, os); + break; + case JdwpConstants.CommandSet.StackFrame.POP_FRAMES: + executePopFrames(bb, os); + break; + default: + throw new NotImplementedException("Command " + command + + " not found in Stack Frame Command Set."); + } + } + catch (IOException ex) + { + // The DataOutputStream we're using isn't talking to a socket at all + // So if we throw an IOException we're in serious trouble + throw new JdwpInternalErrorException(ex); + } + + return false; + } + + private void executeGetValues(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ThreadId tId = (ThreadId) idMan.readObjectId(bb); + Thread thread = tId.getThread(); + + // Although Frames look like other ids they are not. First they are not + // ObjectIds since they don't exist in the users code. Storing them as an + // ObjectId would mean they could be garbage collected since no one else + // has a reference to them. Furthermore they are not ReferenceTypeIds since + // these are held permanently and we want these to be held only as long as + // the Thread is suspended. + long frameID = bb.getLong(); + VMFrame frame = VMVirtualMachine.getFrame(thread, frameID); + int slots = bb.getInt(); + os.writeInt(slots); // Looks pointless but this is the protocol + for (int i = 0; i < slots; i++) + { + int slot = bb.getInt(); + byte sig = bb.get(); + Value val = frame.getValue(slot, sig); + val.writeTagged(os); + } + } + + private void executeSetValues(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ThreadId tId = (ThreadId) idMan.readObjectId(bb); + Thread thread = tId.getThread(); + + long frameID = bb.getLong(); + VMFrame frame = VMVirtualMachine.getFrame(thread, frameID); + + int slots = bb.getInt(); + for (int i = 0; i < slots; i++) + { + int slot = bb.getInt(); + Value value = ValueFactory.createFromTagged(bb); + frame.setValue(slot, value); + } + } + + private void executeThisObject(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ThreadId tId = (ThreadId) idMan.readObjectId(bb); + Thread thread = tId.getThread(); + + long frameID = bb.getLong(); + VMFrame frame = VMVirtualMachine.getFrame(thread, frameID); + + ObjectValue objVal = new ObjectValue(frame.getObject()); + objVal.writeTagged(os); + } + + private void executePopFrames(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + if (!VMVirtualMachine.canPopFrames) + { + String msg = "popping frames is unsupported"; + throw new NotImplementedException(msg); + } + + ThreadId tid = (ThreadId) idMan.readObjectId(bb); + Thread thread = tid.getThread(); + long fid = bb.getLong(); + VMVirtualMachine.popFrames(thread, fid); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/processor/StringReferenceCommandSet.java b/libjava/classpath/gnu/classpath/jdwp/processor/StringReferenceCommandSet.java new file mode 100644 index 000000000..6571bc8e2 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/processor/StringReferenceCommandSet.java @@ -0,0 +1,99 @@ +/* StringReferenceCommandSet.java -- class to implement the StringReference + Command Set + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.processor; + +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.exception.JdwpException; +import gnu.classpath.jdwp.exception.JdwpInternalErrorException; +import gnu.classpath.jdwp.exception.NotImplementedException; +import gnu.classpath.jdwp.id.ObjectId; +import gnu.classpath.jdwp.util.JdwpString; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; + +/** + * A class representing the StringReference Command Set. + * + * @author Aaron Luchko + */ +public class StringReferenceCommandSet + extends CommandSet +{ + + public boolean runCommand(ByteBuffer bb, DataOutputStream os, byte command) + throws JdwpException + { + try + { + + // Although there's only a single command to choose from we still use + // a switch to maintain consistency with the rest of the CommandSets + switch (command) + { + case JdwpConstants.CommandSet.StringReference.VALUE: + executeValue(bb, os); + break; + default: + throw new NotImplementedException("Command " + command + + " not found in String Reference Command Set."); + } + } + catch (IOException ex) + { + // The DataOutputStream we're using isn't talking to a socket at all + // So if we throw an IOException we're in serious trouble + throw new JdwpInternalErrorException(ex); + } + + return false; + } + + private void executeValue(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ObjectId oid = idMan.readObjectId(bb); + + String str = (String) oid.getObject(); + JdwpString.writeString(os, str); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/processor/ThreadGroupReferenceCommandSet.java b/libjava/classpath/gnu/classpath/jdwp/processor/ThreadGroupReferenceCommandSet.java new file mode 100644 index 000000000..7682fa9bf --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/processor/ThreadGroupReferenceCommandSet.java @@ -0,0 +1,179 @@ +/* ThreadGroupReferenceCommandSet.java -- class to implement the + ThreadGroupReference Command Set + Copyright (C) 2005 Free Software Foundation + +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.jdwp.processor; + +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.exception.JdwpException; +import gnu.classpath.jdwp.exception.JdwpInternalErrorException; +import gnu.classpath.jdwp.exception.NotImplementedException; +import gnu.classpath.jdwp.id.ObjectId; +import gnu.classpath.jdwp.util.JdwpString; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; + +/** + * A class representing the ThreadGroupReference Command Set. + * + * @author Aaron Luchko + */ +public class ThreadGroupReferenceCommandSet + extends CommandSet +{ + public boolean runCommand(ByteBuffer bb, DataOutputStream os, byte command) + throws JdwpException + { + try + { + switch (command) + { + case JdwpConstants.CommandSet.ThreadGroupReference.NAME: + executeName(bb, os); + break; + case JdwpConstants.CommandSet.ThreadGroupReference.PARENT: + executeParent(bb, os); + break; + case JdwpConstants.CommandSet.ThreadGroupReference.CHILDREN: + executeChildren(bb, os); + break; + default: + throw new NotImplementedException("Command " + command + + " not found in ThreadGroupReference Command Set."); + } + } + catch (IOException ex) + { + // The DataOutputStream we're using isn't talking to a socket at all + // So if we throw an IOException we're in serious trouble + throw new JdwpInternalErrorException(ex); + } + + return false; + } + + private void executeName(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ObjectId oid = idMan.readObjectId(bb); + ThreadGroup group = (ThreadGroup) oid.getObject(); + JdwpString.writeString(os, group.getName()); + } + + private void executeParent(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ObjectId oid = idMan.readObjectId(bb); + ThreadGroup group = (ThreadGroup) oid.getObject(); + ThreadGroup parent = group.getParent(); + if (parent == null) { + os.writeLong(0L); + } else { + ObjectId parentId = idMan.getObjectId(parent); + parentId.write(os); + } + } + + private void executeChildren(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ObjectId oid = idMan.readObjectId(bb); + ThreadGroup group = (ThreadGroup) oid.getObject(); + + ThreadGroup jdwpGroup = Thread.currentThread().getThreadGroup(); + int numThreads = group.activeCount(); + Thread allThreads[] = new Thread[numThreads]; + + group.enumerate(allThreads, false); + + // We need to loop through for the true count since some threads may have + // been destroyed since we got activeCount so those spots in the array will + // be null. As well we must ignore any threads that belong to jdwp + numThreads = 0; + for (int i = 0; i < allThreads.length; i++) + { + Thread thread = allThreads[i]; + if (thread == null) + break; // No threads after this point + if (!thread.getThreadGroup().equals(jdwpGroup)) + numThreads++; + } + + os.writeInt(numThreads); + + for (int i = 0; i < allThreads.length; i++) + { + Thread thread = allThreads[i]; + if (thread == null) + break; // No threads after this point + if (!thread.getThreadGroup().equals(jdwpGroup)) + idMan.getObjectId(thread).write(os); + } + + int numGroups = group.activeCount(); + ThreadGroup allGroups[] = new ThreadGroup[numGroups]; + + group.enumerate(allGroups, false); + + // We need to loop through for the true count since some ThreadGroups may + // have been destroyed since we got activeCount so those spots in the array + // will be null. As well we must ignore any threads that belong to jdwp. + numGroups = 0; + for (int i = 0; i < allGroups.length; i++) + { + ThreadGroup tgroup = allGroups[i]; + if (tgroup == null) + break; // No ThreadGroups after this point + if (!tgroup.equals(jdwpGroup)) + numGroups++; + } + + os.writeInt(numGroups); + + for (int i = 0; i < allGroups.length; i++) + { + ThreadGroup tgroup = allGroups[i]; + if (tgroup == null) + break; // No ThreadGroups after this point + if (!tgroup.equals(jdwpGroup)) + idMan.getObjectId(tgroup).write(os); + } + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/processor/ThreadReferenceCommandSet.java b/libjava/classpath/gnu/classpath/jdwp/processor/ThreadReferenceCommandSet.java new file mode 100644 index 000000000..2bbff44de --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/processor/ThreadReferenceCommandSet.java @@ -0,0 +1,265 @@ +/* ThreadReferenceCommandSet.java -- class to implement the ThreadReference + Command Set Copyright (C) 2005, 2007 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.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; +import gnu.classpath.jdwp.exception.NotImplementedException; +import gnu.classpath.jdwp.id.ObjectId; +import gnu.classpath.jdwp.id.ThreadId; +import gnu.classpath.jdwp.util.JdwpString; +import gnu.classpath.jdwp.util.Location; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; + +/** + * A class representing the ThreadReference Command Set. + * + * @author Aaron Luchko + */ +public class ThreadReferenceCommandSet + extends CommandSet +{ + public boolean runCommand(ByteBuffer bb, DataOutputStream os, byte command) + throws JdwpException + { + try + { + switch (command) + { + case JdwpConstants.CommandSet.ThreadReference.NAME: + executeName(bb, os); + break; + case JdwpConstants.CommandSet.ThreadReference.SUSPEND: + executeSuspend(bb, os); + break; + case JdwpConstants.CommandSet.ThreadReference.RESUME: + executeResume(bb, os); + break; + case JdwpConstants.CommandSet.ThreadReference.STATUS: + executeStatus(bb, os); + break; + case JdwpConstants.CommandSet.ThreadReference.THREAD_GROUP: + executeThreadGroup(bb, os); + break; + case JdwpConstants.CommandSet.ThreadReference.FRAMES: + executeFrames(bb, os); + break; + case JdwpConstants.CommandSet.ThreadReference.FRAME_COUNT: + executeFrameCount(bb, os); + break; + case JdwpConstants.CommandSet.ThreadReference.OWNED_MONITORS: + executeOwnedMonitors(bb, os); + break; + case JdwpConstants.CommandSet.ThreadReference.CURRENT_CONTENDED_MONITOR: + executeCurrentContendedMonitor(bb, os); + break; + case JdwpConstants.CommandSet.ThreadReference.STOP: + executeStop(bb, os); + break; + case JdwpConstants.CommandSet.ThreadReference.INTERRUPT: + executeInterrupt(bb, os); + break; + case JdwpConstants.CommandSet.ThreadReference.SUSPEND_COUNT: + executeSuspendCount(bb, os); + break; + default: + throw new NotImplementedException("Command " + command + + " not found in Thread Reference Command Set."); + } + } + catch (IOException ex) + { + // The DataOutputStream we're using isn't talking to a socket at all + // So if we throw an IOException we're in serious trouble + throw new JdwpInternalErrorException(ex); + } + + return false; + } + + private void executeName(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ThreadId tid = (ThreadId) idMan.readObjectId(bb); + Thread thread = tid.getThread(); + JdwpString.writeString(os, thread.getName()); + } + + private void executeSuspend(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ThreadId tid = (ThreadId) idMan.readObjectId(bb); + Thread thread = tid.getThread(); + VMVirtualMachine.suspendThread(thread); + } + + private void executeResume(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ThreadId tid = (ThreadId) idMan.readObjectId(bb); + Thread thread = tid.getThread(); + VMVirtualMachine.resumeThread(thread); + } + + private void executeStatus(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ThreadId tid = (ThreadId) idMan.readObjectId(bb); + Thread thread = tid.getThread(); + int threadStatus = VMVirtualMachine.getThreadStatus(thread); + // There's only one possible SuspendStatus... + int suspendStatus = JdwpConstants.SuspendStatus.SUSPENDED; + + os.writeInt(threadStatus); + os.writeInt(suspendStatus); + } + + private void executeThreadGroup(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ThreadId tid = (ThreadId) idMan.readObjectId(bb); + Thread thread = tid.getThread(); + ThreadGroup group = thread.getThreadGroup(); + ObjectId groupId = idMan.getObjectId(group); + groupId.write(os); + } + + private void executeFrames(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ThreadId tid = (ThreadId) idMan.readObjectId(bb); + Thread thread = tid.getThread(); + int startFrame = bb.getInt(); + int length = bb.getInt(); + + ArrayList frames = VMVirtualMachine.getFrames(thread, startFrame, length); + os.writeInt(frames.size()); + for (int i = 0; i < frames.size(); i++) + { + VMFrame frame = (VMFrame) frames.get(i); + os.writeLong(frame.getId()); + Location loc = frame.getLocation(); + loc.write(os); + } + } + + private void executeFrameCount(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ThreadId tid = (ThreadId) idMan.readObjectId(bb); + Thread thread = tid.getThread(); + + int frameCount = VMVirtualMachine.getFrameCount(thread); + os.writeInt(frameCount); + } + + private void executeOwnedMonitors(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + if (!VMVirtualMachine.canGetOwnedMonitorInfo) + { + String msg = "getting owned monitors is not supported"; + throw new NotImplementedException(msg); + } + + ThreadId tid = (ThreadId) idMan.readObjectId(bb); + Thread thread = tid.getThread(); + Object[] monitors = VMVirtualMachine.getOwnedMonitors(thread); + + os.write(monitors.length); + for (int i = 0; i < monitors.length; ++i) + { + ObjectId id = idMan.getObjectId(monitors[i]); + id.writeTagged(os); + } + } + + private void executeCurrentContendedMonitor(ByteBuffer bb, + DataOutputStream os) + throws JdwpException, IOException + { + if (!VMVirtualMachine.canGetCurrentContendedMonitor) + { + String msg = "getting current contended monitor is not supported"; + throw new NotImplementedException(msg); + } + + ThreadId tid = (ThreadId) idMan.readObjectId(bb); + Thread thread = tid.getThread(); + + Object monitor = VMVirtualMachine.getCurrentContendedMonitor(thread); + ObjectId id = idMan.getObjectId(monitor); + id.writeTagged(os); + } + + private void executeStop(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ThreadId tid = (ThreadId) idMan.readObjectId(bb); + Thread thread = tid.getThread(); + ObjectId exception = idMan.readObjectId(bb); + Throwable throwable = (Throwable) exception.getObject(); + thread.stop (throwable); + } + + private void executeInterrupt(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ThreadId tid = (ThreadId) idMan.readObjectId(bb); + Thread thread = tid.getThread(); + thread.interrupt(); + } + + private void executeSuspendCount(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ThreadId tid = (ThreadId) idMan.readObjectId(bb); + Thread thread = tid.getThread(); + int suspendCount = VMVirtualMachine.getSuspendCount(thread); + os.writeInt(suspendCount); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/processor/VirtualMachineCommandSet.java b/libjava/classpath/gnu/classpath/jdwp/processor/VirtualMachineCommandSet.java new file mode 100644 index 000000000..c476a04e9 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/processor/VirtualMachineCommandSet.java @@ -0,0 +1,472 @@ +/* VirtualMachineCommandSet.java -- class to implement the VirtualMachine + Command Set + Copyright (C) 2005, 2006, 2007 Free Software Foundation + +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.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; +import gnu.classpath.jdwp.exception.NotImplementedException; +import gnu.classpath.jdwp.id.ObjectId; +import gnu.classpath.jdwp.id.ReferenceTypeId; +import gnu.classpath.jdwp.util.JdwpString; +import gnu.classpath.jdwp.util.Signature; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.Properties; + +/** + * A class representing the VirtualMachine Command Set. + * + * @author Aaron Luchko + */ +public class VirtualMachineCommandSet + extends CommandSet +{ + public boolean runCommand(ByteBuffer bb, DataOutputStream os, byte command) + throws JdwpException + { + boolean shutdown = false; + try + { + switch (command) + { + case JdwpConstants.CommandSet.VirtualMachine.VERSION: + executeVersion(bb, os); + break; + case JdwpConstants.CommandSet.VirtualMachine.CLASSES_BY_SIGNATURE: + executeClassesBySignature(bb, os); + break; + case JdwpConstants.CommandSet.VirtualMachine.ALL_CLASSES: + executeAllClasses(bb, os); + break; + case JdwpConstants.CommandSet.VirtualMachine.ALL_THREADS: + executeAllThreads(bb, os); + break; + case JdwpConstants.CommandSet.VirtualMachine.TOP_LEVEL_THREAD_GROUPS: + executeTopLevelThreadGroups(bb, os); + break; + case JdwpConstants.CommandSet.VirtualMachine.IDSIZES: + executeIDsizes(bb, os); + break; + case JdwpConstants.CommandSet.VirtualMachine.DISPOSE: + shutdown = true; + executeDispose(bb, os); + break; + case JdwpConstants.CommandSet.VirtualMachine.SUSPEND: + executeSuspend(bb, os); + break; + case JdwpConstants.CommandSet.VirtualMachine.RESUME: + executeResume(bb, os); + break; + case JdwpConstants.CommandSet.VirtualMachine.EXIT: + shutdown = true; + executeExit(bb, os); + break; + case JdwpConstants.CommandSet.VirtualMachine.CREATE_STRING: + executeCreateString(bb, os); + break; + case JdwpConstants.CommandSet.VirtualMachine.CAPABILITIES: + executeCapabilities(bb, os); + break; + case JdwpConstants.CommandSet.VirtualMachine.CLASS_PATHS: + executeClassPaths(bb, os); + break; + case JdwpConstants.CommandSet.VirtualMachine.DISPOSE_OBJECTS: + executeDisposeObjects(bb, os); + break; + case JdwpConstants.CommandSet.VirtualMachine.HOLD_EVENTS: + executeHoldEvents(bb, os); + break; + case JdwpConstants.CommandSet.VirtualMachine.RELEASE_EVENTS: + executeReleaseEvents(bb, os); + break; + case JdwpConstants.CommandSet.VirtualMachine.CAPABILITIES_NEW: + executeCapabilitiesNew(bb, os); + break; + case JdwpConstants.CommandSet.VirtualMachine.REDEFINE_CLASSES: + executeRedefineClasses(bb, os); + break; + case JdwpConstants.CommandSet.VirtualMachine.SET_DEFAULT_STRATUM: + executeSetDefaultStratum(bb, os); + break; + case JdwpConstants.CommandSet.VirtualMachine.ALL_CLASSES_WITH_GENERIC: + executeAllClassesWithGeneric(bb, os); + break; + default: + throw new NotImplementedException("Command " + command + + " not found in VirtualMachine Command Set."); + } + } + catch (IOException ex) + { + // The DataOutputStream we're using isn't talking to a socket at all + // So if we throw an IOException we're in serious trouble + throw new JdwpInternalErrorException(ex); + } + + return shutdown; + } + + private void executeVersion(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + + Properties props = System.getProperties(); + + int jdwpMajor = JdwpConstants.Version.MAJOR; + int jdwpMinor = JdwpConstants.Version.MINOR; + // The description field is pretty loosely defined + String description = "JDWP version " + jdwpMajor + "." + jdwpMinor + + ", JVM version " + props.getProperty("java.vm.name") + + " " + props.getProperty("java.vm.version") + " " + + props.getProperty("java.version"); + String vmVersion = props.getProperty("java.version"); + String vmName = props.getProperty("java.vm.name"); + JdwpString.writeString(os, description); + os.writeInt(jdwpMajor); + os.writeInt(jdwpMinor); + JdwpString.writeString(os, vmName); + JdwpString.writeString(os, vmVersion); + } + + private void executeClassesBySignature(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + String sig = JdwpString.readString(bb); + ArrayList allMatchingClasses = new ArrayList(); + + // This will be an Iterator over all loaded Classes + Collection classes = VMVirtualMachine.getAllLoadedClasses(); + Iterator iter = classes.iterator (); + + while (iter.hasNext()) + { + Class clazz = (Class) iter.next(); + String clazzSig = Signature.computeClassSignature(clazz); + if (clazzSig.equals(sig)) + allMatchingClasses.add(clazz); + } + + os.writeInt(allMatchingClasses.size()); + for (int i = 0; i < allMatchingClasses.size(); i++) + { + Class clazz = (Class) allMatchingClasses.get(i); + ReferenceTypeId id = idMan.getReferenceTypeId(clazz); + id.writeTagged(os); + int status = VMVirtualMachine.getClassStatus(clazz); + os.writeInt(status); + } + } + + private void executeAllClasses(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + Collection classes = VMVirtualMachine.getAllLoadedClasses(); + os.writeInt(classes.size ()); + + Iterator iter = classes.iterator (); + while (iter.hasNext()) + { + Class clazz = (Class) iter.next(); + ReferenceTypeId id = idMan.getReferenceTypeId(clazz); + id.writeTagged(os); + String sig = Signature.computeClassSignature(clazz); + JdwpString.writeString(os, sig); + int status = VMVirtualMachine.getClassStatus(clazz); + os.writeInt(status); + } + } + + private void executeAllThreads(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ThreadGroup jdwpGroup = Thread.currentThread().getThreadGroup(); + ThreadGroup root = getRootThreadGroup(jdwpGroup); + + int numThreads = root.activeCount(); + Thread allThreads[] = new Thread[numThreads]; + root.enumerate(allThreads); + + // We need to loop through for the true count since some threads may have + // been destroyed since we got + // activeCount so those spots in the array will be null. As well we must + // ignore any threads that belong to jdwp + numThreads = 0; + for (int i = 0; i < allThreads.length; i++) + { + Thread thread = allThreads[i]; + if (thread == null) + break; // No threads after this point + if (!thread.getThreadGroup().equals(jdwpGroup)) + numThreads++; + } + + os.writeInt(numThreads); + + for (int i = 0; i < allThreads.length; i++) + { + Thread thread = allThreads[i]; + if (thread == null) + break; // No threads after this point + if (!thread.getThreadGroup().equals(jdwpGroup)) + idMan.getObjectId(thread).write(os); + } + } + + private void executeTopLevelThreadGroups(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + ThreadGroup jdwpGroup = Thread.currentThread().getThreadGroup (); + ThreadGroup root = getRootThreadGroup(jdwpGroup); + + os.writeInt(1); // Just one top level group allowed? + idMan.getObjectId(root).write(os); + } + + private void executeDispose(ByteBuffer bb, DataOutputStream os) + throws JdwpException + { + // resumeAllThreads isn't sufficient as a thread may have been + // suspended multiple times, we likely need a way to keep track of how many + // times a thread has been suspended or else a stronger resume method for + // this purpose + // VMVirtualMachine.resumeAllThreads (); + + // Simply shutting down the jdwp layer will take care of the rest of the + // shutdown other than disabling debugging in the VM + // VMVirtualMachine.disableDebugging(); + + // Don't implement this until we're sure how to remove all the debugging + // effects from the VM. + throw new NotImplementedException( + "Command VirtualMachine.Dispose not implemented"); + + } + + private void executeIDsizes(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + 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) + throws JdwpException + { + VMVirtualMachine.suspendAllThreads (); + } + + private void executeResume(ByteBuffer bb, DataOutputStream os) + throws JdwpException + { + VMVirtualMachine.resumeAllThreads (); + } + + private void executeExit(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + int exitCode = bb.getInt(); + System.exit (exitCode); + } + + private void executeCreateString(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + String string = JdwpString.readString(bb); + ObjectId stringId = idMan.getObjectId(string); + + // Since this string isn't referenced anywhere we'll disable garbage + // collection on it so it's still around when the debugger gets back to it. + stringId.disableCollection(); + stringId.write(os); + } + + private void executeCapabilities(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + os.writeBoolean(VMVirtualMachine.canWatchFieldModification); + os.writeBoolean(VMVirtualMachine.canWatchFieldAccess); + os.writeBoolean(VMVirtualMachine.canGetBytecodes); + os.writeBoolean(VMVirtualMachine.canGetSyntheticAttribute); + os.writeBoolean(VMVirtualMachine.canGetOwnedMonitorInfo); + os.writeBoolean(VMVirtualMachine.canGetCurrentContendedMonitor); + os.writeBoolean(VMVirtualMachine.canGetMonitorInfo); + } + + private void executeClassPaths(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + String baseDir = System.getProperty("user.dir"); + JdwpString.writeString(os, baseDir); + + // Find and write the classpath + String classPath = System.getProperty("java.class.path"); + String[] paths = classPath.split(":"); + + os.writeInt(paths.length); + for (int i = 0; i < paths.length; i++) + JdwpString.writeString(os, paths[i]); + + // Now the bootpath + String bootPath = System.getProperty("sun.boot.class.path"); + paths = bootPath.split(":"); + os.writeInt(paths.length); + for (int i = 0; i < paths.length; i++) + JdwpString.writeString(os, paths[i]); + } + + private void executeDisposeObjects(ByteBuffer bb, DataOutputStream os) + throws JdwpException + { + // Instead of going through the list of objects they give us it's probably + // better just to find the garbage collected objects ourselves + //idMan.update(); + } + + private void executeHoldEvents(ByteBuffer bb, DataOutputStream os) + throws JdwpException + { + // Going to have to implement a send queue somewhere and do this without + // triggering events + // Until then just don't implement + throw new NotImplementedException( + "Command VirtualMachine.HoldEvents not implemented"); + } + + // Opposite of executeHoldEvents + private void executeReleaseEvents(ByteBuffer bb, DataOutputStream os) + throws JdwpException + { + throw new NotImplementedException( + "Command VirtualMachine.ReleaseEvents not implemented"); + } + + private void executeCapabilitiesNew(ByteBuffer bb, DataOutputStream os) + throws JdwpException, IOException + { + final int CAPABILITIES_NEW_SIZE = 32; + + executeCapabilities(bb, os); + os.writeBoolean(VMVirtualMachine.canRedefineClasses); + os.writeBoolean(VMVirtualMachine.canAddMethod); + os.writeBoolean(VMVirtualMachine.canUnrestrictedlyRedefineClasses); + os.writeBoolean(VMVirtualMachine.canPopFrames); + os.writeBoolean(VMVirtualMachine.canUseInstanceFilters); + os.writeBoolean(VMVirtualMachine.canGetSourceDebugExtension); + os.writeBoolean(VMVirtualMachine.canRequestVMDeathEvent); + os.writeBoolean(VMVirtualMachine.canSetDefaultStratum); + for (int i = 15; i < CAPABILITIES_NEW_SIZE; i++) + { + // Future capabilities (currently unused) + os.writeBoolean(false); + } + } + + private void executeRedefineClasses(ByteBuffer bb, DataOutputStream os) + throws JdwpException + { + if (!VMVirtualMachine.canRedefineClasses) + { + String msg = "redefinition of classes is not supported"; + throw new NotImplementedException(msg); + } + + int classes = bb.getInt(); + Class[] types = new Class[classes]; + byte[][] bytecodes = new byte[classes][]; + for (int i = 0; i < classes; ++i) + { + ReferenceTypeId id = idMan.readReferenceTypeId(bb); + int classfile = bb.getInt(); + byte[] bytecode = new byte[classfile]; + bb.get(bytecode); + types[i] = id.getType(); + bytecodes[i] = bytecode; + } + + VMVirtualMachine.redefineClasses (types, bytecodes); + } + + private void executeSetDefaultStratum(ByteBuffer bb, DataOutputStream os) + throws JdwpException + { + if (!VMVirtualMachine.canSetDefaultStratum) + { + String msg = "setting the default stratum is not supported"; + throw new NotImplementedException(msg); + } + + String stratum = JdwpString.readString(bb); + VMVirtualMachine.setDefaultStratum(stratum); + } + + private void executeAllClassesWithGeneric(ByteBuffer bb, DataOutputStream os) + throws JdwpException + { + // We don't handle generics + throw new NotImplementedException( + "Command VirtualMachine.AllClassesWithGeneric not implemented"); + } + + /** + * Find the root ThreadGroup of this ThreadGroup + */ + private ThreadGroup getRootThreadGroup(ThreadGroup group) + { + ThreadGroup parent = group.getParent(); + + while (parent != null) + { + group = parent; + parent = group.getParent(); + } + return group; // This group was the root + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/transport/ITransport.java b/libjava/classpath/gnu/classpath/jdwp/transport/ITransport.java new file mode 100644 index 000000000..cf5542560 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/transport/ITransport.java @@ -0,0 +1,88 @@ +/* ITransport.java -- An interface defining JDWP transports + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.transport; + +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.HashMap; + +/** + * A class representing a transport layer. This class serves as a generic + * interface for all transport types used in the JDWP back-end. + * + * @author Keith Seitz (keiths@redhat.com) + */ +public interface ITransport +{ + /** + * Configure the transport with the given properties + * + * @param properties properties of the transport configuration + * @throws TransportException on configury error + */ + public void configure (HashMap properties) + throws TransportException; + + /** + * Initialize the transport + * + * @throws TransportException on initialization error + */ + public void initialize () + throws TransportException; + + /** + * Shutdown the transport + */ + public void shutdown (); + + /** + * Get the input stream for the transport + */ + public InputStream getInputStream () + throws IOException; + + /** + * Get the output stream for the transport + */ + public OutputStream getOutputStream () + throws IOException; +} diff --git a/libjava/classpath/gnu/classpath/jdwp/transport/JdwpCommandPacket.java b/libjava/classpath/gnu/classpath/jdwp/transport/JdwpCommandPacket.java new file mode 100644 index 000000000..c565ee779 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/transport/JdwpCommandPacket.java @@ -0,0 +1,149 @@ +/* JdwpCommandPacket.java -- JDWP command packet + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.transport; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * A class representing a JDWP command packet. + * This class adds command set and command to the packet header + * information in {@link gnu.classpath.jdwp.transport.JdwpPacket} + * and adds additional command packet-specific processing. + * + * @author Keith Seitz + */ +public class JdwpCommandPacket extends JdwpPacket +{ + /** + * Command set + */ + protected byte _commandSet; + + /** + * Command + */ + protected byte _command; + + // Minimum packet size [excluding super class] + // ( commandSet (1) + command (1) ) + private static final int MINIMUM_LENGTH = 2; + + /** + * Constructs a new JdwpCommandPacket + */ + public JdwpCommandPacket () + { + // Don't assign an id. This constructor is called by + // JdwpPacket.fromBytes, and that will assign a packet id. + } + + /** + * Constructs a new JdwpCommandPacket + * with the given command set and command + * + * @param set the command set + * @param command the command + */ + public JdwpCommandPacket (byte set, byte command) + { + _id = ++_last_id; + _commandSet = set; + _command = command; + } + + /** + * Retuns the length of this packet + */ + public int getLength () + { + return MINIMUM_LENGTH + super.getLength (); + } + + /** + * Returns the command set + */ + public byte getCommandSet () + { + return _commandSet; + } + + /** + * Sets the command set + */ + public void setCommandSet (byte cs) + { + _commandSet = cs; + } + + /** + * Returns the command + */ + public byte getCommand () + { + return _command; + } + + /** + * Sets the command + */ + public void setCommand (byte cmd) + { + _command = cmd; + } + + // Reads command packet data from the given buffer, starting + // at the given offset + protected int myFromBytes (byte[] bytes, int index) + { + int i = 0; + setCommandSet (bytes[index + i++]); + setCommand (bytes[index + i++]); + return i; + } + + // Writes the command packet data into the given buffer + protected void myWrite (DataOutputStream dos) + throws IOException + { + dos.writeByte (getCommandSet ()); + dos.writeByte (getCommand ()); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/transport/JdwpConnection.java b/libjava/classpath/gnu/classpath/jdwp/transport/JdwpConnection.java new file mode 100644 index 000000000..3c91f048e --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/transport/JdwpConnection.java @@ -0,0 +1,307 @@ +/* JdwpConnection.java -- A JDWP-speaking connection + Copyright (C) 2005, 2006, 2007 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.transport; + +import gnu.classpath.jdwp.Jdwp; +import gnu.classpath.jdwp.event.Event; +import gnu.classpath.jdwp.event.EventRequest; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; + +/** + * A connection via some transport to some JDWP-speaking entity. + * This is also a thread which handles all communications to/from + * the debugger. While access to the transport layer may be accessed by + * several threads, start-up and initialization should not be allowed + * to occur more than once. + * + *

This class is also a thread that is responsible for pulling + * packets off the wire and sticking them in a queue for packet + * processing threads. + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class JdwpConnection + extends Thread +{ + // The JDWP handshake + private static final byte[] _HANDSHAKE = {'J', 'D', 'W', 'P', '-', 'H', 'a', + 'n', 'd', 's', 'h', 'a', 'k', 'e'}; + + // Transport method + private ITransport _transport; + + // Command queue + private ArrayList _commandQueue; + + // Shutdown flag + private boolean _shutdown; + + // Input stream from transport + private DataInputStream _inStream; + + // Output stream from transprot + private DataOutputStream _outStream; + + // A buffer used to construct the packet data + private ByteArrayOutputStream _bytes; + + // A DataOutputStream for the byte buffer + private DataOutputStream _doStream; + + /** + * Creates a new JdwpConnection instance + * + * @param transport the transport to use for communications + */ + public JdwpConnection (ThreadGroup group, ITransport transport) + { + super (group, "JDWP connection thread"); + _transport = transport; + _commandQueue = new ArrayList (); + _shutdown = false; + _bytes = new ByteArrayOutputStream (); + _doStream = new DataOutputStream (_bytes); + } + + /** + * Initializes the connection, including connecting + * to socket or shared memory endpoint + * + * @throws TransportException if initialization fails + */ + public void initialize () + throws TransportException + { + // Initialize transport (connect socket, e.g.) + _transport.initialize (); + + // Do handshake + try + { + _inStream = new DataInputStream (_transport.getInputStream ()); + _outStream = new DataOutputStream (_transport.getOutputStream ()); + _doHandshake (); + } + catch (IOException ioe) + { + throw new TransportException (ioe); + } + } + + /* Does the JDWP handshake -- this should not need synchronization + because this is called by VM startup code, i.e., no packet + processing threads have started yet. */ + private void _doHandshake () + throws IOException + { + // According to the spec, the handshake is always initiated by + // the debugger, regardless of whether the JVM is in client mode or + // server mode. + + // Wait for handshake from debugger + byte[] hshake = new byte[_HANDSHAKE.length]; + _inStream.readFully (hshake, 0, _HANDSHAKE.length); + + if (Arrays.equals (hshake, _HANDSHAKE)) + { + // Send reply handshake + _outStream.write (_HANDSHAKE, 0, _HANDSHAKE.length); + return; + } + else + { + throw new IOException ("invalid JDWP handshake (\"" + hshake + "\")"); + } + } + + /** + * Main run method for the thread. This thread loops waiting for + * packets to be read via the connection. When a packet is complete + * and ready for processing, it places the packet in a queue that can + * be accessed via getPacket + */ + public void run () + { + // Notify initialization thread (gnu.classpath.jdwp.Jdwp) that + // the JdwpConnection thread is ready. + Jdwp.getDefault().subcomponentInitialized (); + + while (!_shutdown) + { + try + { + _readOnePacket (); + } + catch (IOException ioe) + { + /* IOException can occur for two reasons: + 1. Lost connection with the other side + 2. Transport was shutdown + In either case, we make sure that all of the + back-end gets shutdown. */ + Jdwp.getDefault().shutdown (); + } + catch (Throwable t) + { + System.out.println ("JdwpConnection.run: caught an exception: " + + t); + // Just keep going + } + } + } + + // Reads a single packet from the connection, adding it to the packet + // queue when a complete packet is ready. + private void _readOnePacket () + throws IOException + { + byte[] data = null; + + // Read in the packet + int length = _inStream.readInt (); + if (length < 11) + { + throw new IOException ("JDWP packet length < 11 (" + + length + ")"); + } + + data = new byte[length]; + data[0] = (byte) (length >>> 24); + data[1] = (byte) (length >>> 16); + data[2] = (byte) (length >>> 8); + data[3] = (byte) length; + _inStream.readFully (data, 4, length - 4); + + JdwpPacket packet = JdwpPacket.fromBytes (data); + if (packet != null) + { + synchronized (_commandQueue) + { + _commandQueue.add (packet); + _commandQueue.notifyAll (); + } + } + } + + /** + * Returns a packet from the queue of ready packets + * + * @returns a JdwpPacket ready for processing + * null when shutting down + */ + public JdwpPacket getPacket () + { + synchronized (_commandQueue) + { + while (_commandQueue.isEmpty ()) + { + try + { + _commandQueue.wait (); + } + catch (InterruptedException ie) + { + /* PacketProcessor is interrupted + when shutting down */ + return null; + } + } + + return (JdwpPacket) _commandQueue.remove (0); + } + } + + /** + * Send a packet to the debugger + * + * @param pkt a JdwpPacket to send + * @throws IOException + */ + public void sendPacket (JdwpPacket pkt) + throws IOException + { + pkt.write (_outStream); + } + + /** + * Send an event notification to the debugger. Note that this + * method will only send out one notification: all the events + * are passed in a single Event.COMPOSITE packet. + * + * @param requests debugger requests for events + * @param events the events to send + * @param suspendPolicy the suspend policy enforced by the VM + * @throws IOException + */ + public void sendEvents(EventRequest[] requests, Event[] events, + byte suspendPolicy) + throws IOException + { + JdwpPacket pkt; + + synchronized (_bytes) + { + _bytes.reset (); + pkt = Event.toPacket (_doStream, events, requests, suspendPolicy); + pkt.setData (_bytes.toByteArray ()); + } + + sendPacket (pkt); + } + + /** + * Shutdown the connection + */ + public void shutdown () + { + if (!_shutdown) + { + _transport.shutdown (); + _shutdown = true; + interrupt (); + } + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/transport/JdwpPacket.java b/libjava/classpath/gnu/classpath/jdwp/transport/JdwpPacket.java new file mode 100644 index 000000000..b967d9bc5 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/transport/JdwpPacket.java @@ -0,0 +1,277 @@ +/* JdwpPacket.java -- Base class for JDWP command and reply packets + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.transport; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * All command and reply packets in JDWP share + * common header type information: + * + * length (4 bytes) : size of entire packet, including length + * id (4 bytes) : unique packet id + * flags (1 byte) : flag byte + * [command packet stuff | reply packet stuff] + * data (variable) : unique command-/reply-specific data + * + * This class deal with everything except the command- and reply-specific + * data, which get handled in {@link + * gnu.classpath.jdwp.transport.JdwpCommandPacket} and {@link + * gnu.classpath.jdwp.transport.JdwpReplyPacket}. + * + * @author Keith Seitz + */ +public abstract class JdwpPacket +{ + // Last id of packet constructed + protected static int _last_id = 0; + + // JDWP reply packet flag + protected static final int JDWP_FLAG_REPLY = 0x80; + + /** + * Minimum packet size excluding sub-class data + * ( length (4) + id (4) + flags (1) ) + */ + protected static final int MINIMUM_SIZE = 9; + + /** + * Id of command/reply + */ + protected int _id; + + /** + * Packet flags + */ + protected byte _flags; + + /** + * Packet-specific data + */ + protected byte[] _data; + + /** + * Constructor + */ + public JdwpPacket () + { + // By default, DON'T assign an id. This way when a packet + // is constructed from fromBytes, _last_id won't increment (i.e., + // it won't leave holes in the outgoing packet ids). + } + + /** + * Constructs a JdwpPacket with the id + * from the given packet. + * + * @param pkt a packet whose id will be used in this new packet + */ + public JdwpPacket (JdwpPacket pkt) + { + _id = pkt.getId (); + } + + /** + * Returns the packet id + */ + public int getId () + { + return _id; + } + + /** + * Sets the packet id + */ + public void setId (int id) + { + _id = id; + } + + /** + * Returns the packet flags + */ + public byte getFlags () + { + return _flags; + } + + /** + * Sets the packet flags + */ + public void setFlags (byte flags) + { + _flags = flags; + } + + /** + * Gets the command/reply-specific data in this packet + */ + public byte[] getData () + { + return _data; + } + + /** + * Sets the command/reply-specific data in this packet + */ + public void setData (byte[] data) + { + _data = data; + } + + /** + * Returns the length of this entire packet + */ + public int getLength () + { + return MINIMUM_SIZE + (_data == null ? 0 : _data.length); + } + + /** + * Allow subclasses to initialize from data + * + * @param bytes packet data from the wire + * @param index index into bytes to start processing + * @return number of bytes in bytes processed + */ + protected abstract int myFromBytes (byte[] bytes, int index); + + /** + * Convert the given bytes into a JdwpPacket. Uses the + * abstract method myFromBytes to allow subclasses to + * process data. + * + * If the given data does not represent a valid JDWP packet, it returns + * null. + * + * @param bytes packet data from the wire + * @return number of bytes in bytes processed + */ + public static JdwpPacket fromBytes (byte[] bytes) + { + int i = 0; + int length = ((bytes[i++] & 0xff) << 24 | (bytes[i++] & 0xff) << 16 + | (bytes[i++] & 0xff) << 8 | (bytes[i++] & 0xff)); + int id = 0; + byte flags = 0; + + if (bytes.length == length) + { + id = ((bytes[i++] & 0xff) << 24 | (bytes[i++] & 0xff) << 16 + | (bytes[i++] & 0xff) << 8 | (bytes[i++] & 0xff)); + flags = bytes[i++]; + + Class clazz = null; + if (flags == 0) + clazz = JdwpCommandPacket.class; + else if ((flags & JDWP_FLAG_REPLY) != 0) + clazz = JdwpReplyPacket.class; + else + { + // Malformed packet. Discard it. + return null; + } + + JdwpPacket pkt = null; + try + { + pkt = (JdwpPacket) clazz.newInstance (); + } + catch (InstantiationException ie) + { + // Discard packet + return null; + } + catch (IllegalAccessException iae) + { + // Discard packet + return null; + } + + pkt.setId (id); + pkt.setFlags (flags); + + i += pkt.myFromBytes (bytes, i); + byte[] data = new byte[length - i]; + System.arraycopy (bytes, i, data, 0, data.length); + pkt.setData (data); + + return pkt; + } + + return null; + } + + /** + * Put subclass information onto the stream + * + * @param dos the output stream to which to write + */ + protected abstract void myWrite (DataOutputStream dos) + throws IOException; + + /** + * Writes the packet to the output stream + * + * @param dos the output stream to which to write the packet + */ + public void write (DataOutputStream dos) + throws IOException + { + // length + int length = getLength (); + dos.writeInt (length); + + // ID + dos.writeInt (getId ()); + + // flag + dos.writeByte (getFlags ()); + + // packet-specific stuff + myWrite (dos); + + // data (if any) + byte[] data = getData (); + if (data != null && data.length > 0) + dos.write (data, 0, data.length); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/transport/JdwpReplyPacket.java b/libjava/classpath/gnu/classpath/jdwp/transport/JdwpReplyPacket.java new file mode 100644 index 000000000..a8dc9978e --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/transport/JdwpReplyPacket.java @@ -0,0 +1,137 @@ +/* JdwpReplyPacket.java -- JDWP reply packet + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.transport; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * A class represents a JDWP reply packet. + * This class adds an error code to the packet header information + * in {@link gnu.classpath.jdwp.transport.JdwpPacket} and adds additional + * reply packet-specific processing. + * + * @author Keith Seitz + */ +public class JdwpReplyPacket extends JdwpPacket +{ + /** + * Error code + */ + protected short _errorCode; + + // Minimum packet size [excluding super class] ( errorCode (2) ) + private static final int MINIMUM_LENGTH = 2; + + /** + * Constructs a JdwpReplyPacket. + */ + public JdwpReplyPacket () + { + // Don't assign a packet id. This is called by JdwpPacket.fromBytes + // which assigns a packet id. (Not that a VM would do that...) + } + + /** + * Constructs a JdwpReplyPacket with the + * id from the given packet and error code + * + * @param pkt the packet whose id this packet will use + * @param errorCode the error code + */ + public JdwpReplyPacket (JdwpPacket pkt, short errorCode) + { + this(pkt); + _errorCode = errorCode; + } + + /** + * Constructs a JdwpReplyPacket with the + * id from the given packet and an empty error code + * + * @param pkt the packet whose id this packet will use + */ + public JdwpReplyPacket (JdwpPacket pkt) + { + super (pkt); + _flags = (byte) JDWP_FLAG_REPLY; + } + + /** + * Returns the length of this packet + */ + public int getLength () + { + return MINIMUM_LENGTH + super.getLength (); + } + + /** + * Returns the error code + */ + public short getErrorCode () + { + return _errorCode; + } + + /** + * Sets the error code + */ + public void setErrorCode (short ec) + { + _errorCode = ec; + } + + // Reads command packet data from the given buffer, starting + // at the given offset + protected int myFromBytes (byte[] bytes, int index) + { + int i = 0; + setErrorCode ((short) ((bytes[index + i++] & 0xff) << 8 + | (bytes[index + i++] & 0xff))); + return i; + } + + // Writes the command packet data into the given buffer + protected void myWrite (DataOutputStream dos) + throws IOException + { + dos.writeShort (getErrorCode ()); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/transport/SocketTransport.java b/libjava/classpath/gnu/classpath/jdwp/transport/SocketTransport.java new file mode 100644 index 000000000..4872ba176 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/transport/SocketTransport.java @@ -0,0 +1,196 @@ +/* SocketTransport.java -- a socket transport + Copyright (C) 2005, 2007 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.transport; + +import gnu.classpath.jdwp.transport.ITransport; +import gnu.classpath.jdwp.transport.TransportException; + +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.HashMap; + +import javax.net.ServerSocketFactory; +import javax.net.SocketFactory; + +/** + * A socket-based transport. This transport uses + * configury string that looks like "name=dt_socket, + * address=localhost:1234,server=y". + * + * @author Keith Seitz (keiths@redhat.com) + */ +class SocketTransport + implements ITransport +{ + /** + * Name of this transport + */ + public static final String NAME = "dt_socket"; + + // Configure properties + private static final String _PROPERTY_ADDRESS = "address"; + private static final String _PROPERTY_SERVER = "server"; + + // Port number + private int _port; + + // Host name + private String _host; + + // Are we acting as a server? + private boolean _server = false; + + // Socket + private Socket _socket; + + /** + * Setup the connection configuration from the given properties + * + * @param properties the properties of the JDWP session + * @throws TransportException for any configury errors + */ + public void configure(HashMap properties) + throws TransportException + { + // Get server [form: "y" or "n"] + String p = (String) properties.get(_PROPERTY_SERVER); + if (p != null) + { + if (p.toLowerCase().equals("y")) + _server = true; + } + + // Get address [form: "hostname:port"] + p = (String) properties.get(_PROPERTY_ADDRESS); + if (p != null) + { + String[] s = p.split(":"); + if (s.length == 1) + { + // Port number only. Assume "localhost" + _port = Integer.parseInt(s[0]); + _host = "localhost"; + } + else + { + if (s[0].length() == 0) + _host = "localhost"; + else + _host = s[0]; + _port = Integer.parseInt(s[1]); + } + } + } + + /** + * Initialize this socket connection. This includes + * connecting to the host (or listening for it). + * + * @throws TransportException if a transport-related error occurs + */ + public void initialize () + throws TransportException + { + try + { + if (_server) + { + // Get a server socket + ServerSocketFactory ssf = ServerSocketFactory.getDefault (); + ServerSocket ss = ssf.createServerSocket (_port, 1); + _socket = ss.accept (); + } + else + { + // Get a client socket (the factory will connect it) + SocketFactory sf = SocketFactory.getDefault (); + _socket = sf.createSocket (_host, _port); + } + } + catch (IOException ioe) + { + // This will grab UnknownHostException, too. + throw new TransportException (ioe); + } + } + + /** + * Shutdown the socket. This could cause SocketExceptions + * for anyone blocked on socket i/o + */ + public void shutdown () + { + try + { + _socket.close (); + } + catch (Throwable t) + { + // We don't really care about errors at this point + } + } + + /** + * Returns an InputStream for the transport + * + * @throws IOException if an I/O error occurs creating the stream + * or the socket is not connected + */ + public InputStream getInputStream () + throws IOException + { + return _socket.getInputStream (); + } + + /** + * Returns an OutputStream for the transport + * + * @throws IOException if an I/O error occurs creating the stream + * or the socket is not connected + */ + public OutputStream getOutputStream () + throws IOException + { + return _socket.getOutputStream (); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/transport/TransportException.java b/libjava/classpath/gnu/classpath/jdwp/transport/TransportException.java new file mode 100644 index 000000000..057422a87 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/transport/TransportException.java @@ -0,0 +1,75 @@ +/* TransportException.java -- Exception for transport configury errors + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.transport; + +/** + * A transport configury or initialization exception thrown by + * JDWP transports. This class is a generic exception class + * that the different transport layers use to report transport-specific + * exceptions that may occur (which could be very different from + * one transport to the next.). + * + * @author Keith Seitz + */ +public class TransportException + extends Exception +{ + /** + * Constructs a TransportException with the + * given message + * + * @param message a message describing the exception + */ + public TransportException (String message) + { + super (message); + } + + /** + * Constructs a TransportException with the + * given Throwable root cause + * + * @param t the cause of the exception + */ + public TransportException (Throwable t) + { + super (t); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/transport/TransportFactory.java b/libjava/classpath/gnu/classpath/jdwp/transport/TransportFactory.java new file mode 100644 index 000000000..681967b77 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/transport/TransportFactory.java @@ -0,0 +1,115 @@ +/* TransportFactory.java -- Factory for transports + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.transport; + +import java.util.HashMap; + +/** + * A factory class that constructs transports for use by + * the JDWP back-end. + * + * @author Keith Seitz + */ +public class TransportFactory +{ + // Keyword in configspec that specifies transport method + private static final String _TRANSPORT_PROPERTY = "transport"; + + // A single transport method mapping + private static class TransportMethod + { + String name; + Class clazz; + public TransportMethod (String name, Class clazz) + { + this.name = name; + this.clazz = clazz; + } + } + + // List of all supported transport methods + private static TransportMethod[] _transportMethods = new TransportMethod[] + { + new TransportMethod (SocketTransport.NAME, SocketTransport.class) + //new TransportMethod (ShmemTransport.NAME, ShmemTransport.class) + }; + + /** + * Get a transport configured as specified in the properties + * + * @param properties a HashMap specifying the JDWP + * configuration properties + * @returns the created and configured transport + * @throws TransportException for invalid configurations + */ + public static ITransport newInstance (HashMap properties) + throws TransportException + { + String name = null; + if (properties != null) + name = (String) properties.get (_TRANSPORT_PROPERTY); + if (name == null) + throw new TransportException ("no transport specified"); + + for (int i = 0; i < _transportMethods.length; ++i) + { + if (_transportMethods[i].name.equals (name)) + { + try + { + ITransport t; + t = (ITransport) _transportMethods[i].clazz.newInstance (); + t.configure (properties); + return t; + } + catch (TransportException te) + { + throw te; + } + catch (Exception e) + { + throw new TransportException (e); + } + } + } + + throw new TransportException ("transport \"" + name + "\" not found"); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/util/JdwpString.java b/libjava/classpath/gnu/classpath/jdwp/util/JdwpString.java new file mode 100644 index 000000000..eca7060fd --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/util/JdwpString.java @@ -0,0 +1,95 @@ +/* JdwpString.java -- utility class to read and write jdwp strings + Copyright (C) 2005 Free Software Foundation + +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.jdwp.util; + +import gnu.classpath.jdwp.exception.JdwpInternalErrorException; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; + +/** + * A class to compute the JDWP representation of Strings. + * + * @author Aaron Luchko + */ +public class JdwpString +{ + + /** + * Write this String to the outStream as a string understood by jdwp. + * + * @param os write the String here + * @param string the String to write + * @throws IOException + */ + public static void writeString(DataOutputStream os, String string) + throws IOException + { + // Get the bytes of the string as a string in UTF-8 + byte[] strBytes = string.getBytes("UTF-8"); + os.writeInt(strBytes.length); + os.write(strBytes); + } + + /** + * Read a jdwp style string from the ByteBuffer. + * + * @param bb contains the string + * @return the String that was read + * @throws JdwpInternalErrorException bb didn't contain a value UTF-8 string + */ + public static String readString(ByteBuffer bb) + throws JdwpInternalErrorException + { + int length = bb.getInt(); + byte[] strBytes = new byte[length]; + bb.get(strBytes); + try + { + return new String(strBytes, "UTF-8"); + } + catch (UnsupportedEncodingException ex) + { + // Any string from the VM should be in UTF-8 so an encoding error + // shouldn't be possible + throw new JdwpInternalErrorException(ex); + } + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/util/LineTable.java b/libjava/classpath/gnu/classpath/jdwp/util/LineTable.java new file mode 100644 index 000000000..2307fa27e --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/util/LineTable.java @@ -0,0 +1,95 @@ +/* LineTable.java -- A class representing a Line Table for a method + Copyright (C) 2005, 2006 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.util; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * A class representing a Line Table for a method. + * + * @author Aaron Luchko + */ +public class LineTable +{ + + private final long start; + private final long end; + private final int[] lineNum; + private final long[] lineCI; + + /** + * Construct a line table with the given parameters. + * + * @param start lowest code index for method, -1 if native + * @param end highest code index for method, -1 if native + * @param lineNum line numbers for in line tables + * @param lineCI code indicies for entries in line tables + */ + public LineTable(long start, long end, int[] lineNum, long[] lineCI) + { + if (lineNum.length != lineCI.length) + throw new AssertionError("code index and line numbers tables " + + "not same length"); + this.start = start; + this.end = end; + this.lineNum = lineNum; + this.lineCI = lineCI; + } + + /** + * Writes this line table to the given DataOutputStream. + * + * @param os the stream to write it to + * @throws IOException + */ + public void write(DataOutputStream os) + throws IOException + { + os.writeLong(start); + os.writeLong(end); + os.writeInt(lineNum.length); + for (int i = 0; i < lineNum.length; i++) + { + os.writeLong(lineCI[i]); + os.writeInt(lineNum[i]); + } + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/util/Location.java b/libjava/classpath/gnu/classpath/jdwp/util/Location.java new file mode 100644 index 000000000..6d8c2e7b9 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/util/Location.java @@ -0,0 +1,168 @@ +/* Location.java -- class to read/write JDWP locations + Copyright (C) 2005, 2006, 2007 Free Software Foundation + +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.jdwp.util; + +import gnu.classpath.jdwp.VMIdManager; +import gnu.classpath.jdwp.VMMethod; +import gnu.classpath.jdwp.exception.JdwpException; +import gnu.classpath.jdwp.id.ClassReferenceTypeId; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; + +/** + * A class to read/write JDWP locations. + * + * @author Aaron Luchko + */ +public class Location +{ + private VMMethod method; + private long index; + + /** + * Create a location with the given parameters. + * + * @param method the method + * @param index location in the method + */ + public Location(VMMethod method, long index) + { + this.method = method; + this.index = index; + } + + /** + * Read a location from the given bytebuffer, consists of a TAG (byte), + * followed by a ReferenceTypeId, a MethodId and an index (long). + * + * @param bb this holds the location + * @throws IOException when an error occurs reading from the buffer + * @throws JdwpException for invalid class or method IDs + */ + public Location(ByteBuffer bb) + throws IOException, JdwpException + { + byte tag = bb.get(); + ClassReferenceTypeId classId = + (ClassReferenceTypeId) VMIdManager.getDefault().readReferenceTypeId(bb); + Class klass = classId.getType(); + method = VMMethod.readId(klass, bb); + index = bb.getLong(); + } + + /** + * Write the given location to an output stream. + * + * @param os stream to write to + * @throws IOException when an error occurs writing to the stream + */ + public void write(DataOutputStream os) + throws IOException + { + // check if this is an empty location + if (method != null) + { + VMIdManager idm = VMIdManager.getDefault(); + ClassReferenceTypeId crti = + (ClassReferenceTypeId) + idm.getReferenceTypeId(method.getDeclaringClass()); + + crti.writeTagged(os); + method.writeId(os); + os.writeLong(index); + } + else + { + os.writeByte(1); + os.writeLong((long) 0); + os.writeLong((long) 0); + os.writeLong((long) 0); + } + } + + /** + * Sets up an empty location + * + * @return new Location (setup as empty) + */ + public static Location getEmptyLocation() + { + return new Location(null, 0); + } + + /** + * Gets the method of this location + * + * @return the method + */ + public VMMethod getMethod() + { + return method; + } + + /** + * Gets the code index of this location + * + * @return the code index + */ + public long getIndex () + { + return index; + } + + // convenient for debugging + public String toString () + { + return method.toString () + "." + index; + } + + public boolean equals(Object obj) + { + if (obj instanceof Location) + { + Location l = (Location) obj; + return (getMethod().equals(l.getMethod()) + && getIndex() == l.getIndex()); + } + + return false; + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/util/MethodResult.java b/libjava/classpath/gnu/classpath/jdwp/util/MethodResult.java new file mode 100644 index 000000000..76d8828f6 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/util/MethodResult.java @@ -0,0 +1,86 @@ +/* MethodResult.java -- class to wrap around values returned from a Method call + in the VM + Copyright (C) 2005, 2007 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.util; + +import gnu.classpath.jdwp.value.Value; + +/** + * A class to wrap around values returned from a Method call in the VM. + * + * @author Aaron Luchko + */ +public class MethodResult +{ + // The Object returned by the executing method + private Value returnedValue; + + // Any Exception that was thrown by the executing method + private Throwable thrownException; + + /** + * Constructs a new MethodResult object + * + * @param return_value the return value of the method invocation + * @param exc exception thrown during the invocation (or null if none) + */ + public MethodResult (Value return_value, Throwable exc) + { + returnedValue = return_value; + thrownException = exc; + } + + /** + * Returns the return value of the method invocation + */ + public Value getReturnedValue() + { + return returnedValue; + } + + /** + * Returns the exception thrown during the method invocation + * (or null if none) + */ + public Throwable getThrownException() + { + return thrownException; + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/util/MonitorInfo.java b/libjava/classpath/gnu/classpath/jdwp/util/MonitorInfo.java new file mode 100644 index 000000000..34c098da2 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/util/MonitorInfo.java @@ -0,0 +1,76 @@ +/* MonitorInfo.java -- class used to return monitor information + for JDWP. + + Copyright (C) 2007 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.util; + +import gnu.classpath.jdwp.VMIdManager; +import gnu.classpath.jdwp.id.ObjectId; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * This class is used to pass monitor information between + * the JDWP back-end and the virtual machine. + * + * @author Keith Seitz (keiths@redhat.com) + */ +public class MonitorInfo +{ + public int entryCount; + public Thread owner; + public Thread[] waiters; + + public void write(DataOutputStream os) + throws IOException + { + VMIdManager idm = VMIdManager.getDefault(); + ObjectId id = idm.getObjectId(owner); + id.write(os); + os.write(entryCount); + os.write(waiters.length); + for (int i = 0; i < waiters.length; ++i) + { + id = idm.getObjectId(waiters[i]); + id.write(os); + } + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/util/NullObject.java b/libjava/classpath/gnu/classpath/jdwp/util/NullObject.java new file mode 100644 index 000000000..ec762fc2f --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/util/NullObject.java @@ -0,0 +1,50 @@ +/* NullObject.java -- placeholder for null values + Copyright (C) 2007 Free Software Foundation + +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.jdwp.util; + +/** + * This is a placeholder for null. There are several places in JDWP where null + * is a valid value (i.e. when geting the value of a variable slot that + * contains a null reference at that time). This class distinguishes between + * these "meaningful" null values and invalid null pointers. + * + * @author Kyle Galloway + */ +public class NullObject +{ +} diff --git a/libjava/classpath/gnu/classpath/jdwp/util/Signature.java b/libjava/classpath/gnu/classpath/jdwp/util/Signature.java new file mode 100644 index 000000000..3d192e897 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/util/Signature.java @@ -0,0 +1,151 @@ +/* Signature.java -- utility class to compute class and method signatures + Copyright (C) 2005 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.util; + +import gnu.java.lang.CPStringBuilder; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +/** + * A class to compute class and method signatures. + * + * @author Tom Tromey (tromey@redhat.com) + * @author Keith Seitz (keiths@redhat.com) + */ +public class Signature +{ + /** + * Computes the class signature, i.e., java.lang.String.class + * returns "Ljava/lang/String;". + * + * @param theClass the class for which to compute the signature + * @return the class's type signature + */ + public static String computeClassSignature (Class theClass) + { + CPStringBuilder sb = new CPStringBuilder (); + _addToSignature (sb, theClass); + return sb.toString (); + } + + /** + * Computes the field signature which is just the class signature of the + * field's type, ie a Field of type java.lang.String this will return + * "Ljava/lang/String;". + * + * @param field the field for which to compute the signature + * @return the field's type signature + */ + public static String computeFieldSignature (Field field) + { + return computeClassSignature (field.getType()); + } + + /** + * Computes the method signature, i.e., java.lang.String.split (String, int) + * returns "(Ljava/lang/String;I)[Ljava/lang/String;" + * + * @param method the method for which to compute the signature + * @return the method's type signature + */ + public static String computeMethodSignature (Method method) + { + return _computeSignature (method.getReturnType (), + method.getParameterTypes ()); + } + + private static String _computeSignature (Class returnType, + Class[] paramTypes) + { + CPStringBuilder sb = new CPStringBuilder ("("); + if (paramTypes != null) + { + for (int i = 0; i < paramTypes.length; ++i) + _addToSignature (sb, paramTypes[i]); + } + sb.append (")"); + _addToSignature (sb, returnType); + return sb.toString(); + } + + private static void _addToSignature (CPStringBuilder sb, Class k) + { + // For some reason there's no easy way to get the signature of a + // class. + if (k.isPrimitive ()) + { + if (k == void.class) + sb.append('V'); + else if (k == boolean.class) + sb.append('Z'); + else if (k == byte.class) + sb.append('B'); + else if (k == char.class) + sb.append('C'); + else if (k == short.class) + sb.append('S'); + else if (k == int.class) + sb.append('I'); + else if (k == float.class) + sb.append('F'); + else if (k == double.class) + sb.append('D'); + else if (k == long.class) + sb.append('J'); + return; + } + + String name = k.getName (); + int len = name.length (); + sb.ensureCapacity (len); + if (! k.isArray ()) + sb.append('L'); + for (int i = 0; i < len; ++i) + { + char c = name.charAt (i); + if (c == '.') + c = '/'; + sb.append (c); + } + if (! k.isArray ()) + sb.append(';'); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/util/VariableTable.java b/libjava/classpath/gnu/classpath/jdwp/util/VariableTable.java new file mode 100644 index 000000000..8cbb299c2 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/util/VariableTable.java @@ -0,0 +1,110 @@ +/* VariableTable.java -- A class representing a Variable Table for a method + Copyright (C) 2005, 2007 Free Software Foundation + +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 +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but 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.jdwp.util; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * A class representing a Variable Table for a method. + * + * @author Aaron Luchko + */ +public class VariableTable +{ + + private final int argCnt; + + private final int slots; + + private final long[] lineCI; + + private int[] slot; + + private int[] lengths; + + private String[] sigs; + + private String[] names; + + /** + * Make a new variable table with the given values. + * + * @param argCnt number of words used by arguments in this frame + * @param slots number of variables + * @param lineCI first code index of given variable (size slots) + * @param names name of given variable (size slots) + * @param sigs signature of given variable (size slots) + * @param lengths size of region where variable is active (size slots) + * @param slot index of variable in this frame (size slots) + */ + public VariableTable(int argCnt, int slots, long lineCI[], String names[], + String sigs[], int lengths[], int slot[]) + { + this.argCnt = argCnt; + this.slots = slots; + this.lineCI = lineCI; + this.names = names; + this.sigs = sigs; + this.lengths = lengths; + this.slot = slot; + } + + /** + * Writes this line table to the given DataOutputStream. + * + * @param os the stream to write it to + * @throws IOException + */ + public void write(DataOutputStream os) throws IOException + { + os.writeInt(argCnt); + os.writeInt(slots); + for (int i = 0; i < slots; i++) + { + os.writeLong(lineCI[i]); + JdwpString.writeString(os, names[i]); + JdwpString.writeString(os, sigs[i]); + os.writeInt(lengths[i]); + os.writeInt(slot[i]); + } + } + +} diff --git a/libjava/classpath/gnu/classpath/jdwp/value/ArrayValue.java b/libjava/classpath/gnu/classpath/jdwp/value/ArrayValue.java new file mode 100644 index 000000000..69b1ebd2a --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/value/ArrayValue.java @@ -0,0 +1,92 @@ +/* ObjectValue.java -- JDWP wrapper class for an Object value + Copyright (C) 2007 Free Software Foundation + +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.jdwp.value; + +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.VMIdManager; +import gnu.classpath.jdwp.id.ObjectId; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Wrapper for an Array value. + * + * @author Kyle Galloway + */ +public class ArrayValue + extends Value +{ + // The Array wrapped by this class represented as a Object + Object _value; + + /** + * Create a new ArrayValue from an Object + * + * @param value the Object to wrap + */ + public ArrayValue(Object value) + { + super(JdwpConstants.Tag.ARRAY); + _value = value; + } + + /** + * Return an object representing this type + * + * @return an Object represntation of this value + */ + @Override + protected Object getObject() + { + return _value; + } + + /** + * Write the wrapped object to the given DataOutputStream. + * + * @param os the output stream to write to + */ + @Override + protected void write(DataOutputStream os) + throws IOException + { + ObjectId oid = VMIdManager.getDefault().getObjectId(_value); + oid.write(os); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/value/BooleanValue.java b/libjava/classpath/gnu/classpath/jdwp/value/BooleanValue.java new file mode 100644 index 000000000..1ae5b4dee --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/value/BooleanValue.java @@ -0,0 +1,99 @@ +/* BooleanValue.java -- JDWP wrapper class for a boolean value + Copyright (C) 2007 Free Software Foundation + +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.jdwp.value; + +import gnu.classpath.jdwp.JdwpConstants; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Wrapper for an boolean value. + * + * @author Kyle Galloway + */ +public final class BooleanValue + extends Value +{ + // The boolean wrapped by this class + boolean _value; + + /** + * Create a new BooleanValue from an boolean + * + * @param value the boolean to wrap + */ + public BooleanValue(boolean value) + { + super(JdwpConstants.Tag.BOOLEAN); + _value = value; + } + + /** + * Get the value held in this Value + * + * @return the value represented by this Value object + */ + public boolean getValue() + { + return _value; + } + + /** + * Return an object representing this type + * + * @return an Object represntation of this value + */ + @Override + protected Object getObject() + { + return new Boolean(_value); + } + + /** + * Write the wrapped boolean to the given DataOutputStream. + * + * @param os the output stream to write to + */ + @Override + protected void write(DataOutputStream os) + throws IOException + { + os.writeBoolean(_value); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/value/ByteValue.java b/libjava/classpath/gnu/classpath/jdwp/value/ByteValue.java new file mode 100644 index 000000000..64de0dc88 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/value/ByteValue.java @@ -0,0 +1,99 @@ +/* ByteValue.java -- JDWP wrapper class for a byte value + Copyright (C) 2007 Free Software Foundation + +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.jdwp.value; + +import gnu.classpath.jdwp.JdwpConstants; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Wrapper for an byte value. + * + * @author Kyle Galloway + */ +public final class ByteValue + extends Value +{ + // The byte wrapped by this class + byte _value; + + /** + * Create a new ByteValue from an byte + * + * @param value the byte to wrap + */ + public ByteValue(byte value) + { + super(JdwpConstants.Tag.BYTE); + _value = value; + } + + /** + * Get the value held in this Value + * + * @return the value represented by this Value object + */ + public byte getValue() + { + return _value; + } + + /** + * Return an object representing this type + * + * @return an Object represntation of this value + */ + @Override + protected Object getObject() + { + return new Byte(_value); + } + + /** + * Write the wrapped byte to the given DataOutputStream. + * + * @param os the output stream to write to + */ + @Override + protected void write(DataOutputStream os) + throws IOException + { + os.writeByte(_value); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/value/CharValue.java b/libjava/classpath/gnu/classpath/jdwp/value/CharValue.java new file mode 100644 index 000000000..3781065a6 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/value/CharValue.java @@ -0,0 +1,99 @@ +/* CharValue.java -- JDWP wrapper class for a char value + Copyright (C) 2007 Free Software Foundation + +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.jdwp.value; + +import gnu.classpath.jdwp.JdwpConstants; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Wrapper for an char value. + * + * @author Kyle Galloway + */ +public final class CharValue + extends Value +{ + // The char wrapped by this class + char _value; + + /** + * Create a new CharValue from an char + * + * @param value the char to wrap + */ + public CharValue(char value) + { + super(JdwpConstants.Tag.CHAR); + _value = value; + } + + /** + * Get the value held in this Value + * + * @return the value represented by this Value object + */ + public char getValue() + { + return _value; + } + + /** + * Return an object representing this type + * + * @return an Object represntation of this value + */ + @Override + protected Object getObject() + { + return new Character(_value); + } + + /** + * Write the wrapped char to the given DataOutputStream. + * + * @param os the output stream to write to + */ + @Override + protected void write(DataOutputStream os) + throws IOException + { + os.writeChar(_value); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/value/DoubleValue.java b/libjava/classpath/gnu/classpath/jdwp/value/DoubleValue.java new file mode 100644 index 000000000..1c9a8714d --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/value/DoubleValue.java @@ -0,0 +1,99 @@ +/* DoubleValue.java -- JDWP wrapper class for a double value + Copyright (C) 2007 Free Software Foundation + +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.jdwp.value; + +import gnu.classpath.jdwp.JdwpConstants; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Wrapper for an double value. + * + * @author Kyle Galloway + */ +public final class DoubleValue + extends Value +{ + // The double wrapped by this class + double _value; + + /** + * Create a new DoubleValue from an double + * + * @param value the double to wrap + */ + public DoubleValue(double value) + { + super(JdwpConstants.Tag.DOUBLE); + _value = value; + } + + /** + * Get the value held in this Value + * + * @return the value represented by this Value object + */ + public double getValue() + { + return _value; + } + + /** + * Return an object representing this type + * + * @return an Object represntation of this value + */ + @Override + protected Object getObject() + { + return new Double(_value); + } + + /** + * Write the wrapped double to the given DataOutputStream. + * + * @param os the output stream to write to + */ + @Override + protected void write(DataOutputStream os) + throws IOException + { + os.writeDouble(_value); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/value/FloatValue.java b/libjava/classpath/gnu/classpath/jdwp/value/FloatValue.java new file mode 100644 index 000000000..ffd79f660 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/value/FloatValue.java @@ -0,0 +1,99 @@ +/* FloatValue.java -- JDWP wrapper class for a float value + Copyright (C) 2007 Free Software Foundation + +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 +afloat 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.jdwp.value; + +import gnu.classpath.jdwp.JdwpConstants; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Wrapper for an float value. + * + * @author Kyle Galloway + */ +public final class FloatValue + extends Value +{ + // The float wrapped by this class + float _value; + + /** + * Create a new FloatValue from an float + * + * @param value the float to wrap + */ + public FloatValue(float value) + { + super(JdwpConstants.Tag.FLOAT); + _value = value; + } + + /** + * Get the value held in this Value + * + * @return the value represented by this Value object + */ + public float getValue() + { + return _value; + } + + /** + * Return an object representing this type + * + * @return an Object represntation of this value + */ + @Override + protected Object getObject() + { + return new Float(_value); + } + + /** + * Write the wrapped float to the given DataOutputStream. + * + * @param os the output stream to write to + */ + @Override + protected void write(DataOutputStream os) + throws IOException + { + os.writeFloat(_value); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/value/IntValue.java b/libjava/classpath/gnu/classpath/jdwp/value/IntValue.java new file mode 100644 index 000000000..b1a07fd1e --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/value/IntValue.java @@ -0,0 +1,99 @@ +/* IntValue.java -- JDWP wrapper class for an int value + Copyright (C) 2007 Free Software Foundation + +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.jdwp.value; + +import gnu.classpath.jdwp.JdwpConstants; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Wrapper for an int value. + * + * @author Kyle Galloway + */ +public final class IntValue + extends Value +{ + // The int wrapped by this class + int _value; + + /** + * Create a new IntValue from an int + * + * @param value the int to wrap + */ + public IntValue(int value) + { + super(JdwpConstants.Tag.INT); + _value = value; + } + + /** + * Get the value held in this Value + * + * @return the value represented by this Value object + */ + public int getValue() + { + return _value; + } + + /** + * Return an object representing this type + * + * @return an Object represntation of this value + */ + @Override + protected Object getObject() + { + return new Integer(_value); + } + + /** + * Write the wrapped int to the given DataOutputStream. + * + * @param os the output stream to write to + */ + @Override + protected void write(DataOutputStream os) + throws IOException + { + os.writeInt(_value); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/value/LongValue.java b/libjava/classpath/gnu/classpath/jdwp/value/LongValue.java new file mode 100644 index 000000000..748311708 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/value/LongValue.java @@ -0,0 +1,99 @@ +/* LongValue.java -- JDWP wrapper class for a long value + Copyright (C) 2007 Free Software Foundation + +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.jdwp.value; + +import gnu.classpath.jdwp.JdwpConstants; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Wrapper for an long value. + * + * @author Kyle Galloway + */ +public final class LongValue + extends Value +{ + // The long wrapped by this class + long _value; + + /** + * Create a new LongValue from an long + * + * @param value the long to wrap + */ + public LongValue(long value) + { + super(JdwpConstants.Tag.LONG); + _value = value; + } + + /** + * Get the value held in this Value + * + * @return the value represented by this Value object + */ + public long getValue() + { + return _value; + } + + /** + * Return an object representing this type + * + * @return an Object represntation of this value + */ + @Override + protected Object getObject() + { + return new Long(_value); + } + + /** + * Write the wrapped long to the given DataOutputStream. + * + * @param os the output stream to write to + */ + @Override + protected void write(DataOutputStream os) + throws IOException + { + os.writeLong(_value); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/value/ObjectValue.java b/libjava/classpath/gnu/classpath/jdwp/value/ObjectValue.java new file mode 100644 index 000000000..d7dc7dae9 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/value/ObjectValue.java @@ -0,0 +1,102 @@ +/* ObjectValue.java -- JDWP wrapper class for an Object value + Copyright (C) 2007 Free Software Foundation + +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.jdwp.value; + +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.VMIdManager; +import gnu.classpath.jdwp.id.ObjectId; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Wrapper for an Object value. + * + * @author Kyle Galloway + */ +public final class ObjectValue + extends Value +{ + // The Object wrapped by this class + Object _value; + + /** + * Create a new ObjectValue from an Object + * + * @param value the Object to wrap + */ + public ObjectValue(Object value) + { + super(JdwpConstants.Tag.OBJECT); + _value = value; + } + + /** + * Get the value held in this Value + * + * @return the value represented by this Value object + */ + public Object getValue() + { + return _value; + } + + /** + * Return an object representing this type + * + * @return an Object represntation of this value + */ + @Override + protected Object getObject() + { + return _value; + } + + /** + * Write the wrapped object to the given DataOutputStream. + * + * @param os the output stream to write to + */ + @Override + protected void write(DataOutputStream os) + throws IOException + { + ObjectId oid = VMIdManager.getDefault().getObjectId(_value); + oid.write(os); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/value/ShortValue.java b/libjava/classpath/gnu/classpath/jdwp/value/ShortValue.java new file mode 100644 index 000000000..16fae4759 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/value/ShortValue.java @@ -0,0 +1,99 @@ +/* ShortValue.java -- JDWP wrapper class for a short value + Copyright (C) 2007 Free Software Foundation + +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.jdwp.value; + +import gnu.classpath.jdwp.JdwpConstants; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Wrapper for an short value. + * + * @author Kyle Galloway + */ +public final class ShortValue + extends Value +{ + // The short wrapped by this class + short _value; + + /** + * Create a new ShortValue from a short + * + * @param value the short to wrap + */ + public ShortValue(short value) + { + super(JdwpConstants.Tag.SHORT); + _value = value; + } + + /** + * Get the value held in this Value + * + * @return the value represented by this Value object + */ + public short getValue() + { + return _value; + } + + /** + * Return an object representing this type + * + * @return an Object represntation of this value + */ + @Override + protected Object getObject() + { + return new Short(_value); + } + + /** + * Write the wrapped short to the given DataOutputStream. + * + * @param os the output stream to write to + */ + @Override + protected void write(DataOutputStream os) + throws IOException + { + os.writeShort(_value); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/value/StringValue.java b/libjava/classpath/gnu/classpath/jdwp/value/StringValue.java new file mode 100644 index 000000000..f64661f9f --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/value/StringValue.java @@ -0,0 +1,103 @@ +/* StringValue.java -- JDWP wrapper class for an String value + Copyright (C) 2007 Free Software Foundation + +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.jdwp.value; + +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.VMIdManager; +import gnu.classpath.jdwp.id.ObjectId; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Wrapper for an String value. + * + * @author Kyle Galloway + */ +public final class StringValue + extends Value +{ + // The String wrapped by this class + String _value; + + /** + * Create a new StringValue from an String + * + * @param value the String to wrap + */ + public StringValue(String value) + { + super(JdwpConstants.Tag.STRING); + _value = value; + } + + /** + * Get the value held in this Value + * + * @return the value represented by this Value object + */ + public String getValue() + { + return _value; + } + + /** + * Return an object representing this type + * + * @return an Object represntation of this value + */ + @Override + protected Object getObject() + { + return _value; + } + + /** + * Write the wrapped object to the given DataOutputStream. + * + * @param os the output stream to write to + */ + @Override + protected void write(DataOutputStream os) + throws IOException + { + ObjectId oid = VMIdManager.getDefault().getObjectId (_value); + oid.write (os); + + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/value/Value.java b/libjava/classpath/gnu/classpath/jdwp/value/Value.java new file mode 100644 index 000000000..39f1c9cce --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/value/Value.java @@ -0,0 +1,155 @@ +/* Value.java -- base class of JDWP values + Copyright (C) 2007 Free Software Foundation + +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.jdwp.value; + +import gnu.classpath.jdwp.exception.InvalidClassException; +import gnu.classpath.jdwp.exception.InvalidObjectException; +import gnu.classpath.jdwp.exception.InvalidTagException; +import gnu.classpath.jdwp.exception.JdwpInternalErrorException; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; + +/** + * Superclass for all JDWP Values. + * + * @author Kyle Galloway + */ +public abstract class Value +{ + // A Tag representing the type of this value + private byte _tag; + + /** + * Create a new value of type tag. + * + * @param tag the type of the value + */ + protected Value(byte tag) + { + _tag = tag; + } + + /** + * Get the tag for this Value + * + * @return the byte tag of this Value + */ + public byte getTag() + { + return _tag; + } + + /** + * Calls the dervied classes writeValue method to write its value to the + * DataOutputStream. + * + * @param os write the value here + * @throws IOException + */ + public void writeUntagged(DataOutputStream os) + throws IOException + { + write(os); + } + + /** + * Will write the given object as a tagged value to the DataOutputStream. + * + * @param os write the value here + * @param obj the Object to write + * @throws IOException + */ + public void writeTagged(DataOutputStream os) + throws IOException + { + os.write (_tag); + write(os); + } + + /** + * This method must write the value to the DataOutputStream in a manner + * appropriate for the type of the value. + * + * @param os DataOutputStream to write to + * @throws IOException + */ + protected abstract void write(DataOutputStream os) + throws IOException; + + /** + * Returns an object representing this type + * + * @return an Object represntation of this value + */ + protected abstract Object getObject(); + + /** + * Get an untagged object from the ByteBuffer + * + * @param bb the ByteBuffer to extract the value from + * @param type a Class representing the type + * @return an Object from the ByteBuffer of the type of the Class parameter + * @throws JdwpInternalErrorException + * @throws InvalidObjectException + */ + public static Object getUntaggedObject(ByteBuffer bb, Class type) + throws JdwpInternalErrorException, InvalidObjectException, InvalidClassException + { + Value val = ValueFactory.createFromUntagged(bb, type); + return val.getObject(); + } + + /** + * Get an untagged object from the ByteBuffer + * + * @param bb the ByteBuffer to extract the value from + * @param tag a byte tag representing the type + * @return an Object from the ByteBuffer of the type of the Class parameter + * @throws JdwpInternalErrorException + * @throws InvalidObjectException + */ + public static Object getTaggedObject(ByteBuffer bb) + throws JdwpInternalErrorException, InvalidObjectException, InvalidTagException + { + Value val = ValueFactory.createFromTagged(bb); + return val.getObject(); + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/value/ValueFactory.java b/libjava/classpath/gnu/classpath/jdwp/value/ValueFactory.java new file mode 100644 index 000000000..ee7ddfae1 --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/value/ValueFactory.java @@ -0,0 +1,247 @@ +/* ValueFactory.java -- factory to create JDWP Values + Copyright (C) 2007 Free Software Foundation + +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.jdwp.value; + +import gnu.classpath.jdwp.JdwpConstants; +import gnu.classpath.jdwp.VMIdManager; +import gnu.classpath.jdwp.exception.InvalidClassException; +import gnu.classpath.jdwp.exception.InvalidObjectException; +import gnu.classpath.jdwp.exception.InvalidTagException; +import gnu.classpath.jdwp.exception.JdwpInternalErrorException; +import gnu.classpath.jdwp.id.ObjectId; +import gnu.classpath.jdwp.util.JdwpString; + +import java.nio.ByteBuffer; + +/** + * A factory to create JDWP Values. + * + * @author Kyle Galloway + */ +public class ValueFactory +{ + /** + * Creates a new Value of appropriate type for the value in the ByteBuffer + * by reading the tag byte from the front of the buffer. + * + * @param bb contains the Object + * @return A new Value of appropriate type + * @throws JdwpInternalErrorException + * @throws InvalidObjectException + */ + public static Value createFromTagged(ByteBuffer bb) + throws JdwpInternalErrorException, InvalidObjectException, InvalidTagException + { + return create(bb, bb.get()); + } + + /** + * Creates a new Value of appropriate type for the value in the ByteBuffer + * by checking the type of the Class passed in. + * + * @param bb contains the Object + * @param type a Class representing the type of the value in the ByteBuffer + * @return A new Value of appropriate type + * @throws JdwpInternalErrorException + * @throws InvalidObjectException + */ + public static Value createFromUntagged(ByteBuffer bb, Class type) + throws JdwpInternalErrorException, InvalidObjectException, InvalidClassException + { + byte tag = getTagForClass(type); + + try + { + return create(bb, tag); + } + catch (InvalidTagException ite) + { + throw new InvalidClassException(ite); + } + } + + /** + * Creates a new Value of appropriate type for the value in the ByteBuffer. + * + * @param bb contains the Object + * @param tag a byte representing the type of the object + * @return A new Value of appropriate type + * @throws JdwpInternalErrorException + * @throws InvalidObjectException + */ + private static Value create(ByteBuffer bb, byte tag) + throws JdwpInternalErrorException, InvalidObjectException, InvalidTagException + { + Value val = null; + switch(tag) + { + case JdwpConstants.Tag.BYTE: + val = new ByteValue(bb.get()); + break; + case JdwpConstants.Tag.BOOLEAN: + val = new BooleanValue((bb.get() != 0)); + break; + case JdwpConstants.Tag.CHAR: + val = new CharValue(bb.getChar()); + break; + case JdwpConstants.Tag.SHORT: + val = new ShortValue(bb.getShort()); + break; + case JdwpConstants.Tag.INT: + val = new IntValue(bb.getInt()); + break; + case JdwpConstants.Tag.FLOAT: + val = new FloatValue(bb.getFloat()); + break; + case JdwpConstants.Tag.LONG: + val = new LongValue(bb.getLong()); + break; + case JdwpConstants.Tag.DOUBLE: + val = new DoubleValue(bb.getDouble()); + break; + case JdwpConstants.Tag.VOID: + val = new VoidValue(); + break; + case JdwpConstants.Tag.ARRAY: + case JdwpConstants.Tag.THREAD: + case JdwpConstants.Tag.OBJECT: + case JdwpConstants.Tag.THREAD_GROUP: + case JdwpConstants.Tag.CLASS_LOADER: + case JdwpConstants.Tag.CLASS_OBJECT: + ObjectId oid = VMIdManager.getDefault().readObjectId(bb); + val = new ObjectValue(oid.getObject()); + break; + case JdwpConstants.Tag.STRING: + val = new StringValue(JdwpString.readString(bb)); + break; + default: + throw new InvalidTagException(tag); + } + + return val; + } + + /** + * Creates a tag for the type of the class. + * + * @param klass the type to get a tag for + * @return a byte tag representing the class + * @throws JdwpInternalErrorException + * @throws InvalidObjectException + */ + private static byte getTagForClass(Class klass) + throws JdwpInternalErrorException + { + byte tag; + + if (klass.isPrimitive()) + { + if (klass == byte.class) + tag = JdwpConstants.Tag.BYTE; + else if (klass == boolean.class) + tag = JdwpConstants.Tag.BOOLEAN; + else if (klass == char.class) + tag = JdwpConstants.Tag.CHAR; + else if (klass == short.class) + tag = JdwpConstants.Tag.SHORT; + else if (klass == int.class) + tag = JdwpConstants.Tag.INT; + else if (klass == float.class) + tag = JdwpConstants.Tag.FLOAT; + else if (klass == long.class) + tag = JdwpConstants.Tag.LONG; + else if (klass == double.class) + tag = JdwpConstants.Tag.DOUBLE; + else if (klass == void.class) + tag = JdwpConstants.Tag.VOID; + else + throw new JdwpInternalErrorException("Invalid primitive class"); + } + else + { + tag = JdwpConstants.Tag.OBJECT; + } + + return tag; + } + + /** + * Create a value type for an Object of type determined by a Class. This is + * a special case where a value needs to be created, but the value to create + * it for is already in an object, not in a buffer. + * + * @param value the Object to convert to a Value + * @param type the Class type of the object + * @return a new Value representing this object + */ + public static Value createFromObject(Object value, Class type) + { + Value val = null; + + if (type.isPrimitive()) + { + if (type == byte.class) + val = new ByteValue(((Byte) value).byteValue()); + else if (type == boolean.class) + val = new BooleanValue(((Boolean) value).booleanValue()); + else if (type == char.class) + val = new CharValue(((Character) value).charValue()); + else if (type == short.class) + val = new ShortValue(((Short) value).shortValue()); + else if (type == int.class) + val = new IntValue(((Integer) value).intValue()); + else if (type == float.class) + val = new FloatValue(((Float) value).floatValue()); + else if (type == long.class) + val = new LongValue(((Long) value).longValue()); + else if (type == double.class) + val = new DoubleValue(((Double) value).doubleValue()); + else if (type == void.class) + val = new VoidValue(); + } + else + { + if (type.isAssignableFrom(String.class)) + val = new StringValue ((String) value); + else + val = new ObjectValue(value); + } + + return val; + } +} diff --git a/libjava/classpath/gnu/classpath/jdwp/value/VoidValue.java b/libjava/classpath/gnu/classpath/jdwp/value/VoidValue.java new file mode 100644 index 000000000..ae117347d --- /dev/null +++ b/libjava/classpath/gnu/classpath/jdwp/value/VoidValue.java @@ -0,0 +1,82 @@ +/* VoidValue.java -- JDWP wrapper class for a void value + Copyright (C) 2007 Free Software Foundation + +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.jdwp.value; + +import gnu.classpath.jdwp.JdwpConstants; + +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * Wrapper for an void value. + * + * @author Kyle Galloway + */ +public class VoidValue + extends Value +{ + /** + * Create a new VoidValue. + */ + public VoidValue () + { + super(JdwpConstants.Tag.VOID); + } + + /** + * Return an object representing this type + * + * @return an Object represntation of this value + */ + @Override + protected Object getObject() + { + return null; + } + + /** + * Write the wrapped void to the given DataOutputStream. + * + * @param os the output stream to write to + */ + @Override + protected void write(DataOutputStream os) + throws IOException + { + } +} diff --git a/libjava/classpath/gnu/classpath/toolkit/DefaultDaemonThreadFactory.java b/libjava/classpath/gnu/classpath/toolkit/DefaultDaemonThreadFactory.java new file mode 100644 index 000000000..29fc0ffd7 --- /dev/null +++ b/libjava/classpath/gnu/classpath/toolkit/DefaultDaemonThreadFactory.java @@ -0,0 +1,59 @@ +/* DefaultDaemonThreadFactory.java -- Factory for Deamon Threads. + + Copyright (C) 2007 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.toolkit; + +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory;; + +/** + * Create a new thread using all the default settings as returned by + * Executors.defaultThreadFactory() plus calling + * thread.setDaemon(true) on the newly created thread. + * + * @author Mario Torre + */ +public class DefaultDaemonThreadFactory implements ThreadFactory +{ + public Thread newThread(Runnable r) + { + Thread thread = Executors.defaultThreadFactory().newThread(r); + thread.setDaemon(true); + return thread; + } +} diff --git a/libjava/classpath/gnu/java/awt/AWTUtilities.java b/libjava/classpath/gnu/java/awt/AWTUtilities.java new file mode 100644 index 000000000..1b308cef4 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/AWTUtilities.java @@ -0,0 +1,898 @@ +/* AWTUtilities.java -- Common utility methods for AWT and Swing. + Copyright (C) 2005, 2007 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; + +import java.applet.Applet; +import java.awt.Component; +import java.awt.Container; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.Window; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.util.AbstractSequentialList; +import java.util.List; +import java.util.ListIterator; +import java.util.NoSuchElementException; +import java.util.WeakHashMap; +import java.lang.reflect.InvocationTargetException; + +/** + * This class mirrors the javax.swing.SwingUtilities class. It + * provides commonly needed functionalities for AWT classes without + * the need to reference classes in the javax.swing package. + */ +public class AWTUtilities +{ + + /** + * This List implementation wraps the Component[] returned by + * {@link Container#getComponents()} and iterates over the visible Components + * in that array. This class is used in {@link #getVisibleChildren}. + */ + static class VisibleComponentList extends AbstractSequentialList + { + /** + * The ListIterator for this List. + */ + class VisibleComponentIterator implements ListIterator + { + /** The current index in the Component[]. */ + int index; + + /** The index in the List of visible Components. */ + int listIndex; + + /** + * Creates a new VisibleComponentIterator that starts at the specified + * listIndex. The array of Components is searched from + * the beginning to find the matching array index. + * + * @param listIndex the index from where to begin iterating + */ + VisibleComponentIterator(int listIndex) + { + this.listIndex = listIndex; + int visibleComponentsFound = 0; + for (index = 0; visibleComponentsFound != listIndex; index++) + { + if (components[index].isVisible()) + visibleComponentsFound++; + } + } + + /** + * Returns true if there are more visible components in the + * array, false otherwise. + * + * @return true if there are more visible components in the + * array, false otherwise + */ + public boolean hasNext() + { + boolean hasNext = false; + for (int i = index; i < components.length; i++) + { + if (components[i].isVisible()) + { + hasNext = true; + break; + } + } + return hasNext; + } + + /** + * Returns the next visible Component in the List. + * + * @return the next visible Component in the List + * + * @throws NoSuchElementException if there is no next element + */ + public Object next() + { + Object o = null; + for (; index < components.length; index++) + { + if (components[index].isVisible()) + { + o = components[index]; + break; + } + } + if (o != null) + { + index++; + listIndex++; + return o; + } + else + throw new NoSuchElementException(); + } + + /** + * Returns true if there are more visible components in the + * array in the reverse direction, false otherwise. + * + * @return true if there are more visible components in the + * array in the reverse direction, false otherwise + */ + public boolean hasPrevious() + { + boolean hasPrevious = false; + for (int i = index - 1; i >= 0; i--) + { + if (components[i].isVisible()) + { + hasPrevious = true; + break; + } + } + return hasPrevious; + } + + /** + * Returns the previous visible Component in the List. + * + * @return the previous visible Component in the List + * + * @throws NoSuchElementException if there is no previous element + */ + public Object previous() + { + Object o = null; + for (index--; index >= 0; index--) + { + if (components[index].isVisible()) + { + o = components[index]; + break; + } + } + if (o != null) + { + listIndex--; + return o; + } + else + throw new NoSuchElementException(); + } + + /** + * Returns the index of the next element in the List. + * + * @return the index of the next element in the List + */ + public int nextIndex() + { + return listIndex + 1; + } + + /** + * Returns the index of the previous element in the List. + * + * @return the index of the previous element in the List + */ + public int previousIndex() + { + return listIndex - 1; + } + + /** + * This operation is not supported because the List is immutable. + * + * @throws UnsupportedOperationException because the List is immutable + */ + public void remove() + { + throw new UnsupportedOperationException + ("VisibleComponentList is immutable"); + } + + /** + * This operation is not supported because the List is immutable. + * + * @param o not used here + * + * @throws UnsupportedOperationException because the List is immutable + */ + public void set(Object o) + { + throw new UnsupportedOperationException + ("VisibleComponentList is immutable"); + } + + /** + * This operation is not supported because the List is immutable. + * + * @param o not used here + * + * @throws UnsupportedOperationException because the List is immutable + */ + public void add(Object o) + { + throw new UnsupportedOperationException + ("VisibleComponentList is immutable"); + } + } + + /** + * The components over which we iterate. Only the visible components + * are returned by this List. + */ + Component[] components; + + /** + * Creates a new instance of VisibleComponentList that wraps the specified + * Component[]. + * + * @param c the Component[] to be wrapped. + */ + VisibleComponentList(Component[] c) + { + components = c; + } + + /** + * Returns a {@link ListIterator} for iterating over this List. + * + * @return a {@link ListIterator} for iterating over this List + */ + public ListIterator listIterator(int index) + { + return new VisibleComponentIterator(index); + } + + /** + * Returns the number of visible components in the wrapped Component[]. + * + * @return the number of visible components + */ + public int size() + { + int visibleComponents = 0; + for (int i = 0; i < components.length; i++) + if (components[i].isVisible()) + visibleComponents++; + return visibleComponents; + } + } + + /** + * The cache for our List instances. We try to hold one instance of + * VisibleComponentList for each Component[] that is requested. Note + * that we use a WeakHashMap for caching, so that the cache itself + * does not keep the array or the List from beeing garbage collected + * if no other objects hold references to it. + */ + static WeakHashMap visibleChildrenCache = new WeakHashMap(); + + /** + * Returns the visible children of a {@link Container}. This method is + * commonly needed in LayoutManagers, because they only have to layout + * the visible children of a Container. + * + * @param c the Container from which to extract the visible children + * + * @return the visible children of c + */ + public static List getVisibleChildren(Container c) + { + Component[] children = c.getComponents(); + Object o = visibleChildrenCache.get(children); + VisibleComponentList visibleChildren = null; + if (o == null) + { + visibleChildren = new VisibleComponentList(children); + visibleChildrenCache.put(children, visibleChildren); + } + else + visibleChildren = (VisibleComponentList) o; + + return visibleChildren; + } + + /** + * 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 bounds of a component in the component's own coordinate + * space. The result has the same height and width as the component's + * bounds, but its location is set to (0,0). + * + * @param aComponent The component to measure + * + * @return The component's bounds in its local coordinate space + */ + public static Rectangle getLocalBounds(Component aComponent) + { + Rectangle bounds = aComponent.getBounds(); + return new Rectangle(0, 0, bounds.width, bounds.height); + } + + /** + * Returns the font metrics object for a given font. The metrics can be + * used to calculate crude bounding boxes and positioning information, + * for laying out components with textual elements. + * + * @param font The font to get metrics for + * + * @return The font's metrics + * + * @see java.awt.font.GlyphMetrics + */ + public static FontMetrics getFontMetrics(Font font) + { + return Toolkit.getDefaultToolkit().getFontMetrics(font); + } + + /** + * Returns the least ancestor of comp which has the + * specified name. + * + * @param name The name to search for + * @param comp The component to search the ancestors of + * + * @return The nearest ancestor of comp with the given + * name, or null if no such ancestor exists + * + * @see java.awt.Component#getName + * @see #getAncestorOfClass + */ + public static Container getAncestorNamed(String name, Component comp) + { + while (comp != null && (comp.getName() != name)) + comp = comp.getParent(); + return (Container) comp; + } + + /** + * Returns the least ancestor of comp which is an instance + * of the specified class. + * + * @param c The class to search for + * @param comp The component to search the ancestors of + * + * @return The nearest ancestor of comp which is an instance + * of the given class, or null if no such ancestor exists + * + * @see #getAncestorOfClass + * @see #windowForComponent + * @see + * + */ + public static Container getAncestorOfClass(Class c, Component comp) + { + while (comp != null && (! c.isInstance(comp))) + comp = comp.getParent(); + return (Container) comp; + } + + /** + * Equivalent to calling getAncestorOfClass(Window, comp). + * + * @param comp The component to search for an ancestor window + * + * @return An ancestral window, or null if none exists + */ + public static Window windowForComponent(Component comp) + { + return (Window) getAncestorOfClass(Window.class, comp); + } + + /** + * Returns the "root" of the component tree containint comp + * The root is defined as either the least ancestor of + * comp which is a {@link Window}, or the greatest + * ancestor of comp which is a {@link Applet} if no {@link + * Window} ancestors are found. + * + * @param comp The component to search for a root + * + * @return The root of the component's tree, or null + */ + public static Component getRoot(Component comp) + { + Applet app = null; + Window win = null; + + while (comp != null) + { + if (win == null && comp instanceof Window) + win = (Window) comp; + else if (comp instanceof Applet) + app = (Applet) comp; + comp = comp.getParent(); + } + + if (win != null) + return win; + else + return app; + } + + /** + * Return true if a descends from b, in other words if b is an + * ancestor of a. + * + * @param a The child to search the ancestry of + * @param b The potential ancestor to search for + * + * @return true if a is a descendent of b, false otherwise + */ + public static boolean isDescendingFrom(Component a, Component b) + { + while (true) + { + if (a == null || b == null) + return false; + if (a == b) + return true; + a = a.getParent(); + } + } + + /** + * Returns the deepest descendent of parent which is both visible and + * contains the point (x,y). Returns parent when either + * parent is not a container, or has no children which contain + * (x,y). Returns null when either + * (x,y) is outside the bounds of parent, or parent is + * null. + * + * @param parent The component to search the descendents of + * @param x Horizontal coordinate to search for + * @param y Vertical coordinate to search for + * + * @return A component containing (x,y), or + * null + * + * @see java.awt.Container#findComponentAt + */ + public static Component getDeepestComponentAt(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.findComponentAt(x, y); + } + + /** + * Converts a point from a component's local coordinate space to "screen" + * coordinates (such as the coordinate space mouse events are delivered + * in). This operation is equivalent to translating the point by the + * location of the component (which is the origin of its coordinate + * space). + * + * @param p The point to convert + * @param c The component which the point is expressed in terms of + * + * @see convertPointFromScreen + */ + public static void convertPointToScreen(Point p, Component c) + { + Point c0 = c.getLocationOnScreen(); + p.translate(c0.x, c0.y); + } + + /** + * Converts a point from "screen" coordinates (such as the coordinate + * space mouse events are delivered in) to a component's local coordinate + * space. This operation is equivalent to translating the point by the + * negation of the component's location (which is the origin of its + * coordinate space). + * + * @param p The point to convert + * @param c The component which the point should be expressed in terms of + */ + public static void convertPointFromScreen(Point p, Component c) + { + Point c0 = c.getLocationOnScreen(); + p.translate(-c0.x, -c0.y); + } + + /** + * Converts a point (x,y) from the coordinate space of one + * component to another. This is equivalent to converting the point from + * source space to screen space, then back from screen space + * to destination space. If exactly one of the two + * Components is null, it is taken to refer to the root + * ancestor of the other component. If both are null, no + * transformation is done. + * + * @param source The component which the point is expressed in terms of + * @param x Horizontal coordinate of point to transform + * @param y Vertical coordinate of point to transform + * @param destination The component which the return value will be + * expressed in terms of + * + * @return The point (x,y) converted from the coordinate + * space of the + * source component to the coordinate space of the destination component + * + * @see #convertPointToScreen + * @see #convertPointFromScreen + * @see #convertRectangle + * @see #getRoot + */ + public static Point convertPoint(Component source, int x, int y, + Component destination) + { + Point pt = new Point(x, y); + + if (source == null && destination == null) + return pt; + + if (source == null) + source = getRoot(destination); + + if (destination == null) + destination = getRoot(source); + + if (source.isShowing() && destination.isShowing()) + { + convertPointToScreen(pt, source); + convertPointFromScreen(pt, destination); + } + + return pt; + } + + + /** + * Converts a rectangle from the coordinate space of one component to + * another. This is equivalent to converting the rectangle from + * source space to screen space, then back from screen space + * to destination space. If exactly one of the two + * Components is null, it is taken to refer to the root + * ancestor of the other component. If both are null, no + * transformation is done. + * + * @param source The component which the rectangle is expressed in terms of + * @param rect The rectangle to convert + * @param destination The component which the return value will be + * expressed in terms of + * + * @return A new rectangle, equal in size to the input rectangle, but + * with its position converted from the coordinate space of the source + * component to the coordinate space of the destination component + * + * @see #convertPointToScreen + * @see #convertPointFromScreen + * @see #convertPoint + * @see #getRoot + */ + public static Rectangle convertRectangle(Component source, Rectangle rect, + Component destination) + { + Point pt = convertPoint(source, rect.x, rect.y, destination); + return new Rectangle(pt.x, pt.y, rect.width, rect.height); + } + + /** + * Convert a mouse event which refrers to one component to another. This + * includes changing the mouse event's coordinate space, as well as the + * source property of the event. If source is + * null, it is taken to refer to destination's + * root component. If destination is null, the + * new event will remain expressed in source's coordinate + * system. + * + * @param source The component the mouse event currently refers to + * @param sourceEvent The mouse event to convert + * @param destination The component the new mouse event should refer to + * + * @return A new mouse event expressed in terms of the destination + * component's coordinate space, and with the destination component as + * its source + * + * @see #convertPoint + */ + public static MouseEvent convertMouseEvent(Component source, + MouseEvent sourceEvent, + Component destination) + { + Point newpt = convertPoint(source, sourceEvent.getX(), sourceEvent.getY(), + destination); + + return new MouseEvent(destination, sourceEvent.getID(), + sourceEvent.getWhen(), sourceEvent.getModifiers(), + newpt.x, newpt.y, sourceEvent.getClickCount(), + sourceEvent.isPopupTrigger(), + sourceEvent.getButton()); + } + + + /** + * Calls {@link java.awt.EventQueue.invokeLater} with the + * specified {@link Runnable}. + */ + public static void invokeLater(Runnable doRun) + { + java.awt.EventQueue.invokeLater(doRun); + } + + /** + * Calls {@link java.awt.EventQueue.invokeAndWait} with the + * specified {@link Runnable}. + */ + public static void invokeAndWait(Runnable doRun) + throws InterruptedException, + InvocationTargetException + { + java.awt.EventQueue.invokeAndWait(doRun); + } + + /** + * Calls {@link java.awt.EventQueue.isEventDispatchThread}. + */ + public static boolean isEventDispatchThread() + { + return java.awt.EventQueue.isDispatchThread(); + } + + /** + * Returns whether the specified key code is valid. + */ + public static boolean isValidKey(int keyCode) + { + switch (keyCode) + { + case KeyEvent.VK_ENTER: + case KeyEvent.VK_BACK_SPACE: + case KeyEvent.VK_TAB: + case KeyEvent.VK_CANCEL: + case KeyEvent.VK_CLEAR: + case KeyEvent.VK_SHIFT: + case KeyEvent.VK_CONTROL: + case KeyEvent.VK_ALT: + case KeyEvent.VK_PAUSE: + case KeyEvent.VK_CAPS_LOCK: + case KeyEvent.VK_ESCAPE: + case KeyEvent.VK_SPACE: + case KeyEvent.VK_PAGE_UP: + case KeyEvent.VK_PAGE_DOWN: + case KeyEvent.VK_END: + case KeyEvent.VK_HOME: + case KeyEvent.VK_LEFT: + case KeyEvent.VK_UP: + case KeyEvent.VK_RIGHT: + case KeyEvent.VK_DOWN: + case KeyEvent.VK_COMMA: + case KeyEvent.VK_MINUS: + case KeyEvent.VK_PERIOD: + case KeyEvent.VK_SLASH: + case KeyEvent.VK_0: + case KeyEvent.VK_1: + case KeyEvent.VK_2: + case KeyEvent.VK_3: + case KeyEvent.VK_4: + case KeyEvent.VK_5: + case KeyEvent.VK_6: + case KeyEvent.VK_7: + case KeyEvent.VK_8: + case KeyEvent.VK_9: + case KeyEvent.VK_SEMICOLON: + case KeyEvent.VK_EQUALS: + case KeyEvent.VK_A: + case KeyEvent.VK_B: + case KeyEvent.VK_C: + case KeyEvent.VK_D: + case KeyEvent.VK_E: + case KeyEvent.VK_F: + case KeyEvent.VK_G: + case KeyEvent.VK_H: + case KeyEvent.VK_I: + case KeyEvent.VK_J: + case KeyEvent.VK_K: + case KeyEvent.VK_L: + case KeyEvent.VK_M: + case KeyEvent.VK_N: + case KeyEvent.VK_O: + case KeyEvent.VK_P: + case KeyEvent.VK_Q: + case KeyEvent.VK_R: + case KeyEvent.VK_S: + case KeyEvent.VK_T: + case KeyEvent.VK_U: + case KeyEvent.VK_V: + case KeyEvent.VK_W: + case KeyEvent.VK_X: + case KeyEvent.VK_Y: + case KeyEvent.VK_Z: + case KeyEvent.VK_OPEN_BRACKET: + case KeyEvent.VK_BACK_SLASH: + case KeyEvent.VK_CLOSE_BRACKET: + case KeyEvent.VK_NUMPAD0: + case KeyEvent.VK_NUMPAD1: + case KeyEvent.VK_NUMPAD2: + case KeyEvent.VK_NUMPAD3: + case KeyEvent.VK_NUMPAD4: + case KeyEvent.VK_NUMPAD5: + case KeyEvent.VK_NUMPAD6: + case KeyEvent.VK_NUMPAD7: + case KeyEvent.VK_NUMPAD8: + case KeyEvent.VK_NUMPAD9: + case KeyEvent.VK_MULTIPLY: + case KeyEvent.VK_ADD: + case KeyEvent.VK_SEPARATOR: + case KeyEvent.VK_SUBTRACT: + case KeyEvent.VK_DECIMAL: + case KeyEvent.VK_DIVIDE: + case KeyEvent.VK_DELETE: + case KeyEvent.VK_NUM_LOCK: + case KeyEvent.VK_SCROLL_LOCK: + case KeyEvent.VK_F1: + case KeyEvent.VK_F2: + case KeyEvent.VK_F3: + case KeyEvent.VK_F4: + case KeyEvent.VK_F5: + case KeyEvent.VK_F6: + case KeyEvent.VK_F7: + case KeyEvent.VK_F8: + case KeyEvent.VK_F9: + case KeyEvent.VK_F10: + case KeyEvent.VK_F11: + case KeyEvent.VK_F12: + case KeyEvent.VK_F13: + case KeyEvent.VK_F14: + case KeyEvent.VK_F15: + case KeyEvent.VK_F16: + case KeyEvent.VK_F17: + case KeyEvent.VK_F18: + case KeyEvent.VK_F19: + case KeyEvent.VK_F20: + case KeyEvent.VK_F21: + case KeyEvent.VK_F22: + case KeyEvent.VK_F23: + case KeyEvent.VK_F24: + case KeyEvent.VK_PRINTSCREEN: + case KeyEvent.VK_INSERT: + case KeyEvent.VK_HELP: + case KeyEvent.VK_META: + case KeyEvent.VK_BACK_QUOTE: + case KeyEvent.VK_QUOTE: + case KeyEvent.VK_KP_UP: + case KeyEvent.VK_KP_DOWN: + case KeyEvent.VK_KP_LEFT: + case KeyEvent.VK_KP_RIGHT: + case KeyEvent.VK_DEAD_GRAVE: + case KeyEvent.VK_DEAD_ACUTE: + case KeyEvent.VK_DEAD_CIRCUMFLEX: + case KeyEvent.VK_DEAD_TILDE: + case KeyEvent.VK_DEAD_MACRON: + case KeyEvent.VK_DEAD_BREVE: + case KeyEvent.VK_DEAD_ABOVEDOT: + case KeyEvent.VK_DEAD_DIAERESIS: + case KeyEvent.VK_DEAD_ABOVERING: + case KeyEvent.VK_DEAD_DOUBLEACUTE: + case KeyEvent.VK_DEAD_CARON: + case KeyEvent.VK_DEAD_CEDILLA: + case KeyEvent.VK_DEAD_OGONEK: + case KeyEvent.VK_DEAD_IOTA: + case KeyEvent.VK_DEAD_VOICED_SOUND: + case KeyEvent.VK_DEAD_SEMIVOICED_SOUND: + case KeyEvent.VK_AMPERSAND: + case KeyEvent.VK_ASTERISK: + case KeyEvent.VK_QUOTEDBL: + case KeyEvent.VK_LESS: + case KeyEvent.VK_GREATER: + case KeyEvent.VK_BRACELEFT: + case KeyEvent.VK_BRACERIGHT: + case KeyEvent.VK_AT: + case KeyEvent.VK_COLON: + case KeyEvent.VK_CIRCUMFLEX: + case KeyEvent.VK_DOLLAR: + case KeyEvent.VK_EURO_SIGN: + case KeyEvent.VK_EXCLAMATION_MARK: + case KeyEvent.VK_INVERTED_EXCLAMATION_MARK: + case KeyEvent.VK_LEFT_PARENTHESIS: + case KeyEvent.VK_NUMBER_SIGN: + case KeyEvent.VK_PLUS: + case KeyEvent.VK_RIGHT_PARENTHESIS: + case KeyEvent.VK_UNDERSCORE: + case KeyEvent.VK_FINAL: + case KeyEvent.VK_CONVERT: + case KeyEvent.VK_NONCONVERT: + case KeyEvent.VK_ACCEPT: + case KeyEvent.VK_MODECHANGE: + case KeyEvent.VK_KANA: + case KeyEvent.VK_KANJI: + case KeyEvent.VK_ALPHANUMERIC: + case KeyEvent.VK_KATAKANA: + case KeyEvent.VK_HIRAGANA: + case KeyEvent.VK_FULL_WIDTH: + case KeyEvent.VK_HALF_WIDTH: + case KeyEvent.VK_ROMAN_CHARACTERS: + case KeyEvent.VK_ALL_CANDIDATES: + case KeyEvent.VK_PREVIOUS_CANDIDATE: + case KeyEvent.VK_CODE_INPUT: + case KeyEvent.VK_JAPANESE_KATAKANA: + case KeyEvent.VK_JAPANESE_HIRAGANA: + case KeyEvent.VK_JAPANESE_ROMAN: + case KeyEvent.VK_KANA_LOCK: + case KeyEvent.VK_INPUT_METHOD_ON_OFF: + case KeyEvent.VK_CUT: + case KeyEvent.VK_COPY: + case KeyEvent.VK_PASTE: + case KeyEvent.VK_UNDO: + case KeyEvent.VK_AGAIN: + case KeyEvent.VK_FIND: + case KeyEvent.VK_PROPS: + case KeyEvent.VK_STOP: + case KeyEvent.VK_COMPOSE: + case KeyEvent.VK_ALT_GRAPH: + case KeyEvent.VK_BEGIN: + case KeyEvent.VK_CONTEXT_MENU: + case KeyEvent.VK_WINDOWS: + return true; + default: + return false; + } + } +} diff --git a/libjava/classpath/gnu/java/awt/BitMaskExtent.java b/libjava/classpath/gnu/java/awt/BitMaskExtent.java new file mode 100644 index 000000000..be66fccc6 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/BitMaskExtent.java @@ -0,0 +1,79 @@ +/* Copyright (C) 2000, 2002 Free Software Foundation + +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; + +/** + * Simple transparent utility class that can be used to perform bit + * mask extent calculations. + */ +public final class BitMaskExtent +{ + /** The number of the least significant bit of the bit mask extent. */ + public byte leastSignificantBit; + + /** The number of bits in the bit mask extent. */ + public byte bitWidth; + + /** + * Set the bit mask. This will calculate and set the leastSignificantBit + * and bitWidth fields. + * + * @see #leastSignificantBit + * @see #bitWidth + */ + public void setMask(long mask) + { + leastSignificantBit = 0; + bitWidth = 0; + if (mask == 0) return; + long shiftMask = mask; + for (; (shiftMask&1) == 0; shiftMask >>>=1) leastSignificantBit++; + for (; (shiftMask&1) != 0; shiftMask >>>=1) bitWidth++; + + if (shiftMask != 0) + throw new IllegalArgumentException("mask must be continuous"); + } + + /** + * Calculate the bit mask based on the values of the + * leastSignificantBit and bitWidth fields. + */ + public long toMask() + { + return ((1<not implement the Porter-Duff + * XOR operator, but an exclusive or of overlapping subpixel regions. + * + *

A screen shot of BitwiseXORComposite in action + * + *

The above screen shot shows the result of applying six different + * BitwiseXORComposites. They were constructed with the colors + * white, blue, black, orange, green, and brown, respectively. Each + * composite was used to paint a fully white rectangle on top of the + * blue bar in the background. + * + *

The purpose of this composite is to support the {@link + * Graphics#setXORMode(Color)} method in composite-aware graphics + * implementations. Applications typically would use + * setXORMode for drawing “highlights” such + * as text selections or cursors by inverting colors temporarily and + * then inverting them back. + * + *

A concrete Graphics implementation may contain + * the following code: + * + *

 public void setXORMode(Color xorColor)
+ * {
+ *   setComposite(new gnu.java.awt.BitwiseXORComposite(xorColor));
+ * }
+ *
+ * public void setPaintMode()
+ * {
+ *   setComposite(java.awt.AlphaComposite.SrcOver);
+ * }
+ * + * @author Graydon Hoare (graydon@redhat.com) + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class BitwiseXORComposite + implements Composite +{ + /** + * The color whose RGB value is xor-ed with the values of each + * pixel. + */ + protected Color xorColor; + + + /** + * Constructs a new composite for xor-ing the pixel value. + * + * @param xorColor the color whose pixel value will be bitwise + * xor-ed with the source and destination pixels. + */ + public BitwiseXORComposite(Color xorColor) + { + this.xorColor = xorColor; + } + + + /** + * Creates a context object for performing the compositing + * operation. Several contexts may co-exist for one composite; each + * context may simultaneously be called from concurrent threads. + * + * @param srcColorModel the color model of the source. + * @param dstColorModel the color model of the destination. + * @param hints hints for choosing between rendering alternatives. + */ + public CompositeContext createContext(ColorModel srcColorModel, + ColorModel dstColorModel, + RenderingHints hints) + { + if (IntContext.isSupported(srcColorModel, dstColorModel, hints)) + return new IntContext(srcColorModel, xorColor); + + return new GeneralContext(srcColorModel, dstColorModel, xorColor); + } + + + /** + * A fallback CompositeContext that performs bitwise XOR of pixel + * values with the pixel value of the specified xorColor. + * + *

Applying this CompositeContext on a 1024x1024 BufferedImage of + * TYPE_INT_RGB took 611 ms on a lightly loaded 2.4 GHz + * Intel Pentium 4 CPU running Sun J2SE 1.4.1_01 on GNU/Linux + * 2.4.20. The timing is the average of ten runs on the same + * BufferedImage. Since the measurements were taken with {@link + * System#currentTimeMillis()}, they are rather inaccurate. + * + * @author Graydon Hoare (graydon@redhat.com) + */ + private static class GeneralContext + implements CompositeContext + { + ColorModel srcColorModel; + ColorModel dstColorModel; + Color xorColor; + + public GeneralContext(ColorModel srcColorModel, + ColorModel dstColorModel, + Color xorColor) + { + this.srcColorModel = srcColorModel; + this.dstColorModel = dstColorModel; + this.xorColor = xorColor; + } + + + public void compose(Raster src, Raster dstIn, WritableRaster dstOut) + { + Rectangle srcRect = src.getBounds(); + Rectangle dstInRect = dstIn.getBounds(); + Rectangle dstOutRect = dstOut.getBounds(); + + int xp = xorColor.getRGB(); + int w = Math.min(Math.min(srcRect.width, dstOutRect.width), + dstInRect.width); + int h = Math.min(Math.min(srcRect.height, dstOutRect.height), + dstInRect.height); + + Object srcPix = null, dstPix = null, rpPix = null; + + // Re-using the rpPix object saved 1-2% of execution time in + // the 1024x1024 pixel benchmark. + + for (int y = 0; y < h; y++) + { + for (int x = 0; x < w; x++) + { + srcPix = src.getDataElements(x + srcRect.x, y + srcRect.y, srcPix); + dstPix = dstIn.getDataElements(x + dstInRect.x, y + dstInRect.y, + dstPix); + int sp = srcColorModel.getRGB(srcPix); + int dp = dstColorModel.getRGB(dstPix); + int rp = sp ^ xp ^ dp; + dstOut.setDataElements(x + dstOutRect.x, y + dstOutRect.y, + dstColorModel.getDataElements(rp, rpPix)); + } + } + } + + + /** + * Disposes any cached resources. The default implementation does + * nothing because no resources are cached. + */ + public void dispose() + { + } + } + + + /** + * An optimized CompositeContext that performs bitwise XOR of + * int pixel values with the pixel value of a specified + * xorColor. This CompositeContext working only for + * rasters whose transfer format is {@link DataBuffer#TYPE_INT}. + * + *

Applying this CompositeContext on a 1024x1024 BufferedImage of + * TYPE_INT_RGB took 69 ms on a lightly loaded 2.4 GHz + * Intel Pentium 4 CPU running Sun J2SE 1.4.1_01 on GNU/Linux + * 2.4.20. The timing is the average of ten runs on the same + * BufferedImage. Since the measurements were taken with {@link + * System#currentTimeMillis()}, they are rather inaccurate. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ + private static class IntContext + extends GeneralContext + { + public IntContext(ColorModel colorModel, Color xorColor) + { + super(colorModel, colorModel, xorColor); + } + + + public void compose(Raster src, Raster dstIn, + WritableRaster dstOut) + { + int aX, bX, dstX, aY, bY, dstY, width, height; + int xorPixel; + int[] srcLine, dstLine; + + aX = src.getMinX(); + aY = src.getMinY(); + bX = dstIn.getMinX(); + bY = dstIn.getMinY(); + dstX = dstOut.getMinX(); + dstY = dstOut.getMinY(); + width = Math.min(Math.min(src.getWidth(), dstIn.getWidth()), + dstOut.getWidth()); + height = Math.min(Math.min(src.getHeight(), dstIn.getHeight()), + dstOut.getHeight()); + if ((width < 1) || (height < 1)) + return; + + srcLine = new int[width]; + dstLine = new int[width]; + + /* We need an int[] array with at least one element here; + * srcLine is as good as any other. + */ + srcColorModel.getDataElements(this.xorColor.getRGB(), srcLine); + xorPixel = srcLine[0]; + + for (int y = 0; y < height; y++) + { + src.getDataElements(aX, y + aY, width, 1, srcLine); + dstIn.getDataElements(bX, y + bY, width, 1, dstLine); + + for (int x = 0; x < width; x++) + dstLine[x] ^= srcLine[x] ^ xorPixel; + + dstOut.setDataElements(dstX, y + dstY, width, 1, dstLine); + } + } + + + /** + * Determines whether an instance of this CompositeContext would + * be able to process the specified color models. + */ + public static boolean isSupported(ColorModel srcColorModel, + ColorModel dstColorModel, + RenderingHints hints) + { + // FIXME: It would be good if someone could review these checks. + // They probably need to be more restrictive. + + int transferType; + + transferType = srcColorModel.getTransferType(); + if (transferType != dstColorModel.getTransferType()) + return false; + + if (transferType != DataBuffer.TYPE_INT) + return false; + + return true; + } + } +} diff --git a/libjava/classpath/gnu/java/awt/Buffers.java b/libjava/classpath/gnu/java/awt/Buffers.java new file mode 100644 index 000000000..0c8d438c7 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/Buffers.java @@ -0,0 +1,225 @@ +/* Buffers.java -- + Copyright (C) 2000, 2002, 2004 Free Software Foundation + +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; + +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.DataBufferDouble; +import java.awt.image.DataBufferFloat; +import java.awt.image.DataBufferInt; +import java.awt.image.DataBufferShort; +import java.awt.image.DataBufferUShort; + +/** + * Utility class for creating and accessing data buffers of arbitrary + * data types. + */ +public final class Buffers +{ + /** + * Create a data buffer of a particular type. + * + * @param dataType the desired data type of the buffer. + * @param data an array containing data, or null + * @param size the size of the data buffer bank + */ + public static DataBuffer createBuffer(int dataType, Object data, + int size) + { + if (data == null) return createBuffer(dataType, size, 1); + + return createBufferFromData(dataType, data, size); + } + + + /** + * Create a data buffer of a particular type. + * + * @param dataType the desired data type of the buffer. + * @param size the size of the data buffer bank + */ + public static DataBuffer createBuffer(int dataType, int size) { + return createBuffer(dataType, size, 1); + } + + /** + * Create a data buffer of a particular type. + * + * @param dataType the desired data type of the buffer. + * @param size the size of the data buffer bank + * @param numBanks the number of banks the buffer should have + */ + public static DataBuffer createBuffer(int dataType, int size, int numBanks) + { + switch (dataType) + { + case DataBuffer.TYPE_BYTE: + return new DataBufferByte(size, numBanks); + case DataBuffer.TYPE_SHORT: + return new DataBufferShort(size, numBanks); + case DataBuffer.TYPE_USHORT: + return new DataBufferUShort(size, numBanks); + case DataBuffer.TYPE_INT: + return new DataBufferInt(size, numBanks); + case DataBuffer.TYPE_FLOAT: + return new DataBufferFloat(size, numBanks); + case DataBuffer.TYPE_DOUBLE: + return new DataBufferDouble(size, numBanks); + default: + throw new UnsupportedOperationException(); + } + } + + /** + * Create a data buffer of a particular type. + * + * @param dataType the desired data type of the buffer + * @param data an array containing the data + * @param size the size of the data buffer bank + */ + public static DataBuffer createBufferFromData(int dataType, Object data, + int size) + { + switch (dataType) + { + case DataBuffer.TYPE_BYTE: + return new DataBufferByte((byte[]) data, size); + case DataBuffer.TYPE_SHORT: + return new DataBufferShort((short[]) data, size); + case DataBuffer.TYPE_USHORT: + return new DataBufferUShort((short[]) data, size); + case DataBuffer.TYPE_INT: + return new DataBufferInt((int[]) data, size); + case DataBuffer.TYPE_FLOAT: + return new DataBufferFloat((float[]) data, size); + case DataBuffer.TYPE_DOUBLE: + return new DataBufferDouble((double[]) data, size); + default: + throw new UnsupportedOperationException(); + } + } + + /** + * Return the data array of a data buffer, regardless of the data + * type. + * + * @return an array of primitive values. The actual array type + * depends on the data type of the buffer. + */ + public static Object getData(DataBuffer buffer) + { + return getData(buffer, 0, null, 0, buffer.getSize()); + } + + + /** + * Copy data from array contained in data buffer, much like + * System.arraycopy. Create a suitable destination array if the + * given destination array is null. + */ + public static Object getData(DataBuffer src, int srcOffset, + Object dest, int dstOffset, + int length) + { + Object from; + switch(src.getDataType()) + { + case DataBuffer.TYPE_BYTE: + if (dest == null) dest = new byte[length+dstOffset]; + for(int i = 0; i < length; i++) + ((byte[])dest)[i + dstOffset] = (byte)src.getElem(i + srcOffset); + break; + + case DataBuffer.TYPE_DOUBLE: + if (dest == null) dest = new double[length+dstOffset]; + for(int i = 0; i < length; i++) + ((double[])dest)[i + dstOffset] = src.getElemDouble(i + srcOffset); + break; + + case DataBuffer.TYPE_FLOAT: + if (dest == null) dest = new float[length+dstOffset]; + for(int i = 0; i < length; i++) + ((float[])dest)[i + dstOffset] = src.getElemFloat(i + srcOffset); + break; + + case DataBuffer.TYPE_INT: + if (dest == null) dest = new int[length+dstOffset]; + for(int i = 0; i < length; i++) + ((int[])dest)[i + dstOffset] = src.getElem(i + srcOffset); + break; + + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + if (dest == null) dest = new short[length+dstOffset]; + for(int i = 0; i < length; i++) + ((short[])dest)[i + dstOffset] = (short)src.getElem(i + srcOffset); + break; + + case DataBuffer.TYPE_UNDEFINED: + throw new ClassCastException("Unknown data buffer type"); + } + return dest; + } + + /** + * @param bits the width of a data element measured in bits + * + * @return the smallest data type that can store data elements of + * the given number of bits, without any truncation. + */ + public static int smallestAppropriateTransferType(int bits) + { + if (bits <= 8) + { + return DataBuffer.TYPE_BYTE; + } + else if (bits <= 16) + { + return DataBuffer.TYPE_USHORT; + } + else if (bits <= 32) + { + return DataBuffer.TYPE_INT; + } + else + { + return DataBuffer.TYPE_UNDEFINED; + } + } +} diff --git a/libjava/classpath/gnu/java/awt/ClasspathGraphicsEnvironment.java b/libjava/classpath/gnu/java/awt/ClasspathGraphicsEnvironment.java new file mode 100644 index 000000000..fecefa03e --- /dev/null +++ b/libjava/classpath/gnu/java/awt/ClasspathGraphicsEnvironment.java @@ -0,0 +1,67 @@ +/* ClasspathGraphicsEnvironment.java + Copyright (C) 2007 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; + +import java.awt.GraphicsEnvironment; +import java.awt.image.ColorModel; +import java.awt.image.SampleModel; +import java.awt.image.WritableRaster; + +/** + * This class extends the GraphicsEnvironment API with some Classpath-specific + * methods, in order to provide optimized graphics handling. + * + * @author Francis Kung + */ +public abstract class ClasspathGraphicsEnvironment + extends GraphicsEnvironment +{ + /** + * Returns an appropriate Raster that can efficiently back a + * BufferedImage with the given ColorModel and SampleModel. + * + * @param cm The color model. + * @param sm The samepl model. + * @return An appropriate WritableRaster, or null if acceleration/optimization + * is not available for the given colour model / sample model. + */ + public WritableRaster createRaster(ColorModel cm, SampleModel sm) + { + return null; + } +} diff --git a/libjava/classpath/gnu/java/awt/ClasspathToolkit.java b/libjava/classpath/gnu/java/awt/ClasspathToolkit.java new file mode 100644 index 000000000..99c186aaa --- /dev/null +++ b/libjava/classpath/gnu/java/awt/ClasspathToolkit.java @@ -0,0 +1,231 @@ +/* ClasspathToolkit.java -- Abstract superclass for Classpath toolkits. + Copyright (C) 2003, 2004, 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.java.awt; + +import gnu.java.awt.peer.ClasspathDesktopPeer; +import gnu.java.awt.peer.ClasspathFontPeer; +import gnu.java.awt.peer.EmbeddedWindowPeer; +import gnu.java.security.action.SetAccessibleAction; + +import java.awt.AWTException; +import java.awt.Desktop; +import java.awt.Font; +import java.awt.FontFormatException; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.HeadlessException; +import java.awt.Toolkit; +import java.awt.peer.DesktopPeer; +import java.awt.peer.RobotPeer; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.security.AccessController; +import java.util.Map; + +import javax.imageio.spi.IIORegistry; + +/** + * An abstract superclass for Classpath toolkits. + * + *

There exist some parts of AWT and Java2D that are specific to + * the underlying platform, but for which the {@link Toolkit} class + * does not provide suitable abstractions. Examples include some + * methods of {@link Font} or {@link GraphicsEnvironment}. Those + * methods use ClasspathToolkit as a central place for obtaining + * platform-specific functionality. + * + *

In addition, ClasspathToolkit implements some abstract methods + * of {@link java.awt.Toolkit} that are not really platform-specific, + * such as the maintenance of a cache of loaded images. + * + *

Thread Safety: The methods of this class may safely be + * called without external synchronization. This also hold for any + * inherited {@link Toolkit} methods. Subclasses are responsible for + * the necessary synchronization. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class ClasspathToolkit + extends Toolkit +{ + /** + * Returns a shared instance of the local, platform-specific + * graphics environment. + * + *

This method is specific to GNU Classpath. It gets called by + * the Classpath implementation of {@link + * GraphicsEnvironment.getLocalGraphcisEnvironment()}. + */ + public abstract GraphicsEnvironment getLocalGraphicsEnvironment(); + + /** + * Acquires an appropriate {@link ClasspathFontPeer}, for use in + * classpath's implementation of {@link java.awt.Font}. + * + * @param name The logical name of the font. This may be either a face + * name or a logical font name, or may even be null. A default + * implementation of name decoding is provided in + * {@link ClasspathFontPeer}, but may be overridden in other toolkits. + * + * @param attrs Any extra {@link java.awt.font.TextAttribute} attributes + * this font peer should have, such as size, weight, family name, or + * transformation. + */ + public abstract ClasspathFontPeer getClasspathFontPeer (String name, + Map attrs); + + /** + * Creates a {@link Font}, in a platform-specific manner. + * + * The default implementation simply constructs a {@link Font}, but some + * toolkits may wish to override this, to return {@link Font} subclasses + * which implement {@link java.awt.font.OpenType} or + * {@link java.awt.font.MultipleMaster}. + */ + public Font getFont (String name, Map attrs) + { + Font f = null; + + // Circumvent the package-privateness of the + // java.awt.Font.Font(String,Map) constructor. + try + { + Constructor fontConstructor = Font.class.getDeclaredConstructor + (new Class[] { String.class, Map.class }); + AccessController.doPrivileged(new SetAccessibleAction(fontConstructor)); + f = (Font) fontConstructor.newInstance(new Object[] { name, attrs }); + } + catch (IllegalAccessException e) + { + throw new AssertionError(e); + } + catch (NoSuchMethodException e) + { + throw new AssertionError(e); + } + catch (InstantiationException e) + { + throw new AssertionError(e); + } + catch (InvocationTargetException e) + { + throw new AssertionError(e); + } + return f; + } + + /** + * Creates a font, reading the glyph definitions from a stream. + * + *

This method provides the platform-specific implementation for + * the static factory method {@link Font#createFont(int, + * java.io.InputStream)}. + * + * @param format the format of the font data, such as {@link + * Font#TRUETYPE_FONT}. An implementation may ignore this argument + * if it is able to automatically recognize the font format from the + * provided data. + * + * @param stream an input stream from where the font data is read + * in. The stream will be advanced to the position after the font + * data, but not closed. + * + * @throws IllegalArgumentException if format is + * not supported. + * + * @throws FontFormatException if stream does not + * contain data in the expected format, or if required tables are + * missing from a font. + * + * @throws IOException if a problem occurs while reading in the + * contents of stream. + */ + public abstract Font createFont(int format, InputStream stream); + + /** + * Creates a RobotPeer on a given GraphicsDevice. + */ + public abstract RobotPeer createRobot (GraphicsDevice screen) + throws AWTException; + + /** + * Creates an embedded window peer, and associates it with an + * EmbeddedWindow object. + * + * @param w The embedded window with which to associate a peer. + */ + public abstract EmbeddedWindowPeer createEmbeddedWindow (EmbeddedWindow w); + + /** + * Used to register ImageIO SPIs provided by the toolkit. + * + * Our default implementation does nothing. + */ + public void registerImageIOSpis(IIORegistry reg) + { + } + + /** + * Returns the number of mouse buttons. + * (used by java.awt.MouseInfo). + * + * This dummy implementation returns -1 (no mouse). + * toolkit implementors should overload this method if possible. + * @since 1.5 + */ + public int getMouseNumberOfButtons() + { + return -1; + } + + /* (non-Javadoc) + * @see java.awt.Toolkit#createDesktopPeer(java.awt.Desktop) + */ + protected DesktopPeer createDesktopPeer(Desktop target) + throws HeadlessException + { + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException(); + + return ClasspathDesktopPeer.getDesktop(); + } + +} diff --git a/libjava/classpath/gnu/java/awt/ComponentDataBlitOp.java b/libjava/classpath/gnu/java/awt/ComponentDataBlitOp.java new file mode 100644 index 000000000..becf54167 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/ComponentDataBlitOp.java @@ -0,0 +1,156 @@ +/* Copyright (C) 2000, 2002, 2004 Free Software Foundation + +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; + +import java.awt.RenderingHints; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.image.ComponentSampleModel; +import java.awt.image.DataBuffer; +import java.awt.image.Raster; +import java.awt.image.RasterOp; +import java.awt.image.WritableRaster; + +/** + * This raster copy operation assumes that both source and destination + * sample models are tightly pixel packed and contain the same number + * of bands. + * + * @throws java.lang.ClassCastException if the sample models of the + * rasters are not of type ComponentSampleModel. + * + * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) + */ +public class ComponentDataBlitOp implements RasterOp +{ + public static final ComponentDataBlitOp INSTANCE = new ComponentDataBlitOp(); + + public WritableRaster filter(Raster src, WritableRaster dest) + { + if (dest == null) + dest = createCompatibleDestRaster(src); + + DataBuffer srcDB = src.getDataBuffer(); + DataBuffer destDB = dest.getDataBuffer(); + + ComponentSampleModel srcSM = (ComponentSampleModel) src.getSampleModel(); + ComponentSampleModel destSM = (ComponentSampleModel) dest.getSampleModel(); + + + // Calculate offset to data in the underlying arrays: + + int srcScanlineStride = srcSM.getScanlineStride(); + int destScanlineStride = destSM.getScanlineStride(); + int srcX = src.getMinX() - src.getSampleModelTranslateX(); + int srcY = src.getMinY() - src.getSampleModelTranslateY(); + int destX = dest.getMinX() - dest.getSampleModelTranslateX(); + int destY = dest.getMinY() - dest.getSampleModelTranslateY(); + + int numBands = srcSM.getNumBands(); + + /* We can't use getOffset(x, y) from the sample model since we + don't want the band offset added in. */ + + int srcOffset = + numBands*srcX + srcScanlineStride*srcY + // from sample model + srcDB.getOffset(); // from data buffer + + int destOffset = + numBands*destX + destScanlineStride*destY + // from sample model + destDB.getOffset(); // from data buffer + + // Determine how much, and how many times to blit. + + int rowSize = src.getWidth()*numBands; + int h = src.getHeight(); + + if ((rowSize == srcScanlineStride) && + (rowSize == destScanlineStride)) + { + // collapse scan line blits to one large blit. + rowSize *= h; + h = 1; + } + + + // Do blitting + + Object srcArray = Buffers.getData(srcDB); + Object destArray = Buffers.getData(destDB); + + for (int yd = 0; ydCIE XYZ conversions in SrgbConverter are used. + * + * @author Sven de Marothy + */ +public class CieXyzConverter implements ColorSpaceConverter +{ + public float[] toCIEXYZ(float[] in) + { + float[] out = new float[3]; + System.arraycopy(in, 0, out, 0, 3); + return out; + } + + public float[] fromCIEXYZ(float[] in) + { + float[] out = new float[3]; + System.arraycopy(in, 0, out, 0, 3); + return out; + } + + public float[] toRGB(float[] in) + { + return SrgbConverter.XYZtoRGB(in); + } + + public float[] fromRGB(float[] in) + { + return SrgbConverter.RGBtoXYZ(in); + } +} diff --git a/libjava/classpath/gnu/java/awt/color/ClutProfileConverter.java b/libjava/classpath/gnu/java/awt/color/ClutProfileConverter.java new file mode 100644 index 000000000..5229ce804 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/color/ClutProfileConverter.java @@ -0,0 +1,152 @@ +/* ClutProfileConverter.java -- Conversion routines for CLUT-Based profiles + Copyright (C) 2004 Free Software Foundation + +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.color; + +import java.awt.color.ICC_Profile; + + +/** + * ClutProfileConverter - conversions through a CLUT-based profile + * + * @author Sven de Marothy + */ +public class ClutProfileConverter implements ColorSpaceConverter +{ + private ColorLookUpTable toPCS; + private ColorLookUpTable fromPCS; + private int nChannels; + + public ClutProfileConverter(ICC_Profile profile) + { + nChannels = profile.getNumComponents(); + + // Sun does not specifiy which rendering intent should be used, + // neither does the ICC v2 spec really. + // Try intent 0 + try + { + toPCS = new ColorLookUpTable(profile, ICC_Profile.icSigAToB0Tag); + } + catch (Exception e) + { + toPCS = null; + } + + try + { + fromPCS = new ColorLookUpTable(profile, ICC_Profile.icSigBToA0Tag); + } + catch (Exception e) + { + fromPCS = null; + } + + if (toPCS != null || fromPCS != null) + return; + + // If no intent 0 clut is available, look for a intent 1 clut. + try + { + toPCS = new ColorLookUpTable(profile, ICC_Profile.icSigAToB1Tag); + } + catch (Exception e) + { + toPCS = null; + } + + try + { + fromPCS = new ColorLookUpTable(profile, ICC_Profile.icSigBToA1Tag); + } + catch (Exception e) + { + fromPCS = null; + } + + if (toPCS != null || fromPCS != null) + return; + + // Last shot.. intent 2 CLUT. + try + { + toPCS = new ColorLookUpTable(profile, ICC_Profile.icSigAToB2Tag); + } + catch (Exception e) + { + toPCS = null; + } + + try + { + fromPCS = new ColorLookUpTable(profile, ICC_Profile.icSigBToA2Tag); + } + catch (Exception e) + { + fromPCS = null; + } + + if (toPCS == null && fromPCS == null) + throw new IllegalArgumentException("No CLUTs in profile!"); + } + + public float[] toCIEXYZ(float[] in) + { + if (toPCS != null) + return toPCS.lookup(in); + else + return new float[3]; + } + + public float[] toRGB(float[] in) + { + return SrgbConverter.XYZtoRGB(toCIEXYZ(in)); + } + + public float[] fromCIEXYZ(float[] in) + { + if (fromPCS != null) + return fromPCS.lookup(in); + else + return new float[nChannels]; + } + + public float[] fromRGB(float[] in) + { + return fromCIEXYZ(SrgbConverter.RGBtoXYZ(in)); + } +} diff --git a/libjava/classpath/gnu/java/awt/color/ColorLookUpTable.java b/libjava/classpath/gnu/java/awt/color/ColorLookUpTable.java new file mode 100644 index 000000000..581320c3e --- /dev/null +++ b/libjava/classpath/gnu/java/awt/color/ColorLookUpTable.java @@ -0,0 +1,429 @@ +/* ColorLookUpTable.java -- ICC v2 CLUT + Copyright (C) 2004 Free Software Foundation + +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.color; + +import java.awt.color.ColorSpace; +import java.awt.color.ICC_Profile; +import java.nio.ByteBuffer; + + +/** + * ColorLookUpTable handles color lookups through a color lookup table, + * as defined in the ICC specification. + * Both 'mft2' and 'mft1' (8 and 16-bit) type CLUTs are handled. + * + * This will have to be updated later for ICC 4.0.0 + * + * @author Sven de Marothy + */ +public class ColorLookUpTable +{ + /** + * CIE 1931 D50 white point (in Lab coordinates) + */ + private static float[] D50 = { 0.96422f, 1.00f, 0.82521f }; + + /** + * Number of input/output channels + */ + int nIn; + + /** + * Number of input/output channels + */ + int nOut; + int nInTableEntries; // Number of input table entries + int nOutTableEntries; // Number of output table entries + int gridpoints; // Number of gridpoints + int nClut; // This is nOut*(gridpoints**nIn) + double[][] inTable; // 1D input table ([channel][table]) + short[][] outTable; // 1D input table ([channel][table]) + double[] clut; // The color lookup table + float[][] inMatrix; // input matrix (XYZ only) + boolean useMatrix; // Whether to use the matrix or not. + int[] multiplier; + int[] offsets; // Hypercube offsets + boolean inputLab; // Set if the CLUT input CS is Lab + boolean outputLab; // Set if the CLUT output CS is Lab + + /** + * Constructor + * Requires a profile file to get the CLUT from and the tag of the + * CLUT to create. (icSigXToYZTag where X,Y = [A | B], Z = [0,1,2]) + */ + public ColorLookUpTable(ICC_Profile profile, int tag) + { + useMatrix = false; + + switch (tag) + { + case ICC_Profile.icSigAToB0Tag: + case ICC_Profile.icSigAToB1Tag: + case ICC_Profile.icSigAToB2Tag: + if (profile.getColorSpaceType() == ColorSpace.TYPE_XYZ) + useMatrix = true; + inputLab = false; + outputLab = (profile.getPCSType() == ColorSpace.TYPE_Lab); + break; + case ICC_Profile.icSigBToA0Tag: + case ICC_Profile.icSigBToA1Tag: + case ICC_Profile.icSigBToA2Tag: + if (profile.getPCSType() == ColorSpace.TYPE_XYZ) + useMatrix = true; + inputLab = (profile.getPCSType() == ColorSpace.TYPE_Lab); + outputLab = false; + break; + default: + throw new IllegalArgumentException("Not a clut-type tag."); + } + + byte[] data = profile.getData(tag); + if (data == null) + throw new IllegalArgumentException("Unsuitable profile, does not contain a CLUT."); + + // check 'mft' + if (data[0] != 0x6d || data[1] != 0x66 || data[2] != 0x74) + throw new IllegalArgumentException("Unsuitable profile, invalid CLUT data."); + + if (data[3] == 0x32) + readClut16(data); + else if (data[3] == 0x31) + readClut8(data); + else + throw new IllegalArgumentException("Unknown/invalid CLUT type."); + } + + /** + * Loads a 16-bit CLUT into our data structures + */ + private void readClut16(byte[] data) + { + ByteBuffer buf = ByteBuffer.wrap(data); + + nIn = data[8] & (0xFF); + nOut = data[9] & (0xFF); + nInTableEntries = buf.getShort(48); + nOutTableEntries = buf.getShort(50); + gridpoints = data[10] & (0xFF); + + inMatrix = new float[3][3]; + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + inMatrix[i][j] = ((float) (buf.getInt(12 + (i * 3 + j) * 4))) / 65536.0f; + + inTable = new double[nIn][nInTableEntries]; + for (int channel = 0; channel < nIn; channel++) + for (int i = 0; i < nInTableEntries; i++) + inTable[channel][i] = (double) ((int) buf.getShort(52 + + (channel * nInTableEntries + + i) * 2) + & (0xFFFF)) / 65536.0; + + nClut = nOut; + multiplier = new int[nIn]; + multiplier[nIn - 1] = nOut; + for (int i = 0; i < nIn; i++) + { + nClut *= gridpoints; + if (i > 0) + multiplier[nIn - i - 1] = multiplier[nIn - i] * gridpoints; + } + + int clutOffset = 52 + nIn * nInTableEntries * 2; + clut = new double[nClut]; + for (int i = 0; i < nClut; i++) + clut[i] = (double) ((int) buf.getShort(clutOffset + i * 2) & (0xFFFF)) / 65536.0; + + outTable = new short[nOut][nOutTableEntries]; + for (int channel = 0; channel < nOut; channel++) + for (int i = 0; i < nOutTableEntries; i++) + outTable[channel][i] = buf.getShort(clutOffset + + (nClut + + channel * nOutTableEntries + i) * 2); + + // calculate the hypercube corner offsets + offsets = new int[(1 << nIn)]; + offsets[0] = 0; + for (int j = 0; j < nIn; j++) + { + int factor = 1 << j; + for (int i = 0; i < factor; i++) + offsets[factor + i] = offsets[i] + multiplier[j]; + } + } + + /** + * Loads a 8-bit CLUT into our data structures. + */ + private void readClut8(byte[] data) + { + ByteBuffer buf = ByteBuffer.wrap(data); + + nIn = (data[8] & (0xFF)); + nOut = (data[9] & (0xFF)); + nInTableEntries = 256; // always 256 + nOutTableEntries = 256; // always 256 + gridpoints = (data[10] & (0xFF)); + + inMatrix = new float[3][3]; + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + inMatrix[i][j] = ((float) (buf.getInt(12 + (i * 3 + j) * 4))) / 65536.0f; + + inTable = new double[nIn][nInTableEntries]; + for (int channel = 0; channel < nIn; channel++) + for (int i = 0; i < nInTableEntries; i++) + inTable[channel][i] = (double) ((int) buf.get(48 + + (channel * nInTableEntries + + i)) & (0xFF)) / 255.0; + + nClut = nOut; + multiplier = new int[nIn]; + multiplier[nIn - 1] = nOut; + for (int i = 0; i < nIn; i++) + { + nClut *= gridpoints; + if (i > 0) + multiplier[nIn - i - 1] = multiplier[nIn - i] * gridpoints; + } + + int clutOffset = 48 + nIn * nInTableEntries; + clut = new double[nClut]; + for (int i = 0; i < nClut; i++) + clut[i] = (double) ((int) buf.get(clutOffset + i) & (0xFF)) / 255.0; + + outTable = new short[nOut][nOutTableEntries]; + for (int channel = 0; channel < nOut; channel++) + for (int i = 0; i < nOutTableEntries; i++) + outTable[channel][i] = (short) (buf.get(clutOffset + nClut + + channel * nOutTableEntries + + i) * 257); + + // calculate the hypercube corner offsets + offsets = new int[(1 << nIn)]; + offsets[0] = 0; + for (int j = 0; j < nIn; j++) + { + int factor = 1 << j; + for (int i = 0; i < factor; i++) + offsets[factor + i] = offsets[i] + multiplier[j]; + } + } + + /** + * Performs a lookup through the Color LookUp Table. + * If the CLUT tag type is AtoB the conversion will be from the device + * color space to the PCS, BtoA type goes in the opposite direction. + * + * For convenience, the PCS values for input or output will always be + * CIE XYZ (D50), if the actual PCS is Lab, the values will be converted. + * + * N-dimensional linear interpolation is used. + */ + float[] lookup(float[] in) + { + float[] in2 = new float[in.length]; + if (useMatrix) + { + for (int i = 0; i < 3; i++) + in2[i] = in[0] * inMatrix[i][0] + in[1] * inMatrix[i][1] + + in[2] * inMatrix[i][2]; + } + else if (inputLab) + in2 = XYZtoLab(in); + else + System.arraycopy(in, 0, in2, 0, in.length); + + // input table + for (int i = 0; i < nIn; i++) + { + int index = (int) Math.floor(in2[i] * (double) (nInTableEntries - 1)); // floor in + + // clip values. + if (index >= nInTableEntries - 1) + in2[i] = (float) inTable[i][nInTableEntries - 1]; + else if (index < 0) + in2[i] = (float) inTable[i][0]; + else + { + // linear interpolation + double alpha = in2[i] * ((double) nInTableEntries - 1.0) - index; + in2[i] = (float) (inTable[i][index] * (1 - alpha) + + inTable[i][index + 1] * alpha); + } + } + + // CLUT lookup + double[] output2 = new double[nOut]; + double[] weights = new double[(1 << nIn)]; + double[] clutalpha = new double[nIn]; // interpolation values + int offset = 0; // = gp + for (int i = 0; i < nIn; i++) + { + int index = (int) Math.floor(in2[i] * ((double) gridpoints - 1.0)); + double alpha = in2[i] * ((double) gridpoints - 1.0) - (double) index; + + // clip values. + if (index >= gridpoints - 1) + { + index = gridpoints - 1; + alpha = 1.0; + } + else if (index < 0) + index = 0; + clutalpha[i] = alpha; + offset += index * multiplier[i]; + } + + // Calculate interpolation weights + weights[0] = 1.0; + for (int j = 0; j < nIn; j++) + { + int factor = 1 << j; + for (int i = 0; i < factor; i++) + { + weights[factor + i] = weights[i] * clutalpha[j]; + weights[i] *= (1.0 - clutalpha[j]); + } + } + + for (int i = 0; i < nOut; i++) + output2[i] = weights[0] * clut[offset + i]; + + for (int i = 1; i < (1 << nIn); i++) + { + int offset2 = offset + offsets[i]; + for (int f = 0; f < nOut; f++) + output2[f] += weights[i] * clut[offset2 + f]; + } + + // output table + float[] output = new float[nOut]; + for (int i = 0; i < nOut; i++) + { + int index = (int) Math.floor(output2[i] * ((double) nOutTableEntries + - 1.0)); + + // clip values. + if (index >= nOutTableEntries - 1) + output[i] = outTable[i][nOutTableEntries - 1]; + else if (index < 0) + output[i] = outTable[i][0]; + else + { + // linear interpolation + double a = output2[i] * ((double) nOutTableEntries - 1.0) + - (double) index; + output[i] = (float) ((double) ((int) outTable[i][index] & (0xFFFF)) * (1 + - a) + + (double) ((int) outTable[i][index + 1] & (0xFFFF)) * a) / 65536f; + } + } + + if (outputLab) + return LabtoXYZ(output); + return output; + } + + /** + * Converts CIE Lab coordinates to (D50) XYZ ones. + */ + private float[] LabtoXYZ(float[] in) + { + // Convert from byte-packed format to a + // more convenient one (actual Lab values) + // (See ICC spec for details) + // factor is 100 * 65536 / 65280 + in[0] = (float) (100.392156862745 * in[0]); + in[1] = (in[1] * 256.0f) - 128.0f; + in[2] = (in[2] * 256.0f) - 128.0f; + + float[] out = new float[3]; + + out[1] = (in[0] + 16.0f) / 116.0f; + out[0] = in[1] / 500.0f + out[1]; + out[2] = out[1] - in[2] / 200.0f; + + for (int i = 0; i < 3; i++) + { + double exp = out[i] * out[i] * out[i]; + if (exp <= 0.008856) + out[i] = (out[i] - 16.0f / 116.0f) / 7.787f; + else + out[i] = (float) exp; + out[i] = D50[i] * out[i]; + } + return out; + } + + /** + * Converts CIE XYZ coordinates to Lab ones. + */ + private float[] XYZtoLab(float[] in) + { + float[] temp = new float[3]; + + for (int i = 0; i < 3; i++) + { + temp[i] = in[i] / D50[i]; + + if (temp[i] <= 0.008856f) + temp[i] = (7.7870689f * temp[i]) + (16f / 116.0f); + else + temp[i] = (float) Math.exp((1.0 / 3.0) * Math.log(temp[i])); + } + + float[] out = new float[3]; + out[0] = (116.0f * temp[1]) - 16f; + out[1] = 500.0f * (temp[0] - temp[1]); + out[2] = 200.0f * (temp[1] - temp[2]); + + // Normalize to packed format + out[0] = (float) (out[0] / 100.392156862745); + out[1] = (out[1] + 128f) / 256f; + out[2] = (out[2] + 128f) / 256f; + for (int i = 0; i < 3; i++) + { + if (out[i] < 0f) + out[i] = 0f; + if (out[i] > 1f) + out[i] = 1f; + } + return out; + } +} diff --git a/libjava/classpath/gnu/java/awt/color/ColorSpaceConverter.java b/libjava/classpath/gnu/java/awt/color/ColorSpaceConverter.java new file mode 100644 index 000000000..63ba08a4f --- /dev/null +++ b/libjava/classpath/gnu/java/awt/color/ColorSpaceConverter.java @@ -0,0 +1,69 @@ +/* ColorSpaceConverter.java -- an interface for colorspace conversion + Copyright (C) 2004 Free Software Foundation + +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.color; + + +/** + * ColorSpaceConverter - used by java.awt.color.ICC_ColorSpace + * + * Color space conversion can occur in several ways: + * + * -Directly (for the built in spaces sRGB, linear RGB, gray, CIE XYZ and PYCC + * -ICC_ProfileRGB works through TRC curves and a matrix + * -ICC_ProfileGray works through a single TRC + * -Everything else is done through Color lookup tables. + * + * The different conversion methods are implemented through + * an interface. The built-in colorspaces are implemented directly + * with the relevant conversion equations. + * + * In this way, we hopefully will always use the fastest and most + * accurate method available. + * + * @author Sven de Marothy + */ +public interface ColorSpaceConverter +{ + float[] toCIEXYZ(float[] in); + + float[] fromCIEXYZ(float[] in); + + float[] toRGB(float[] in); + + float[] fromRGB(float[] in); +} diff --git a/libjava/classpath/gnu/java/awt/color/GrayProfileConverter.java b/libjava/classpath/gnu/java/awt/color/GrayProfileConverter.java new file mode 100644 index 000000000..3f95b07d7 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/color/GrayProfileConverter.java @@ -0,0 +1,137 @@ +/* GrayProfileConverter.java -- Gray profile conversion class + Copyright (C) 2004 Free Software Foundation + +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.color; + +import java.awt.color.ICC_Profile; +import java.awt.color.ICC_ProfileGray; +import java.awt.color.ProfileDataException; + +/** + * GrayProfileConverter - converts Grayscale profiles (ICC_ProfileGray) + * + * This type of profile contains a single tone reproduction curve (TRC). + * Conversion consists of simple TRC lookup. + * + * This implementation is very lazy and does everything applying the TRC and + * utilizing the built-in linear grayscale color space. + * + * @author Sven de Marothy + */ +public class GrayProfileConverter implements ColorSpaceConverter +{ + private GrayScaleConverter gc; + private ToneReproductionCurve trc; + private ColorLookUpTable toPCS; + private ColorLookUpTable fromPCS; + + /** + * Constructs the converter described by an ICC_ProfileGray object + */ + public GrayProfileConverter(ICC_ProfileGray profile) + { + try + { + trc = new ToneReproductionCurve(profile.getGamma()); + } + catch (ProfileDataException e) + { + trc = new ToneReproductionCurve(profile.getTRC()); + } + + // linear grayscale converter + gc = new GrayScaleConverter(); + + // If a CLUT is available, it should be used, and the TRCs ignored. + // Note: A valid profile may only have CLUTs in one direction, and + // TRC:s without useful info, making reverse-transforms impossible. + // In this case the TRC will be used for the reverse-transform with + // unpredictable results. This is in line with the Java specification, + try + { + toPCS = new ColorLookUpTable(profile, ICC_Profile.icSigAToB0Tag); + } + catch (Exception e) + { + toPCS = null; + } + + try + { + fromPCS = new ColorLookUpTable(profile, ICC_Profile.icSigBToA0Tag); + } + catch (Exception e) + { + fromPCS = null; + } + } + + public float[] toCIEXYZ(float[] in) + { + if (toPCS != null) + return toPCS.lookup(in); + float[] gray = new float[1]; + gray[0] = trc.lookup(in[0]); + return gc.toCIEXYZ(gray); + } + + public float[] toRGB(float[] in) + { + float[] gray = new float[1]; + gray[0] = trc.lookup(in[0]); + return gc.toRGB(gray); + } + + public float[] fromRGB(float[] in) + { + // get linear grayscale value + float[] gray = gc.fromRGB(in); + gray[0] = trc.reverseLookup(gray[0]); + return gray; + } + + public float[] fromCIEXYZ(float[] in) + { + if (fromPCS != null) + return fromPCS.lookup(in); + + float[] gray = gc.fromCIEXYZ(in); + gray[0] = trc.reverseLookup(gray[0]); + return gray; + } +} diff --git a/libjava/classpath/gnu/java/awt/color/GrayScaleConverter.java b/libjava/classpath/gnu/java/awt/color/GrayScaleConverter.java new file mode 100644 index 000000000..beea9d287 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/color/GrayScaleConverter.java @@ -0,0 +1,110 @@ +/* GrayScaleConverter.java -- Linear grayscale conversion class + Copyright (C) 2004 Free Software Foundation + +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.color; + + +/** + * Linear Grayscale converter + * + * @author Sven de Marothy + */ +public class GrayScaleConverter implements ColorSpaceConverter +{ + // intensity factors (ITU Rec. BT.709) + double[] coeff = { 0.2125f, 0.7154f, 0.0721f }; + + /** + * CIE 1931 D50 white point (in Lab coordinates) + */ + private static float[] D50 = { 0.96422f, 1.00f, 0.82521f }; + + public float[] toCIEXYZ(float[] in) + { + float g = in[0]; + if (g < 0) + g = 1 + g; + float[] out = { g * D50[0], g * D50[1], g * D50[2] }; // White spot + return out; + } + + public float[] toRGB(float[] in) + { + float[] out = new float[3]; + if (in[0] <= 0.00304f) + out[0] = in[0] * 12.92f; + else + out[0] = 1.055f * ((float) Math.exp((1 / 2.4) * Math.log(in[0]))) + - 0.055f; + out[1] = out[2] = out[0]; + return out; + } + + public float[] fromCIEXYZ(float[] in) + { + float[] temp = new float[3]; + temp[0] = 3.1338f * in[0] - 1.6171f * in[1] - 0.4907f * in[2]; + temp[1] = -0.9785f * in[0] + 1.9160f * in[1] + 0.0334f * in[2]; + temp[2] = 0.0720f * in[0] - 0.2290f * in[1] + 1.4056f * in[2]; + float[] out = new float[1]; + for (int i = 0; i < 3; i++) + out[0] = (float) (temp[i] * coeff[i]); + return out; + } + + public float[] fromRGB(float[] in) + { + float[] out = new float[1]; + + // Convert non-linear RGB coordinates to linear ones, + // numbers from the w3 spec. + out[0] = 0; + for (int i = 0; i < 3; i++) + { + float n = in[i]; + if (n < 0) + n = 0f; + if (n > 1) + n = 1f; + if (n <= 0.03928f) + out[0] += (float) (coeff[i] * n / 12.92); + else + out[0] += (float) (coeff[i] * Math.exp(2.4 * Math.log((n + 0.055) / 1.055))); + } + return out; + } +} diff --git a/libjava/classpath/gnu/java/awt/color/LinearRGBConverter.java b/libjava/classpath/gnu/java/awt/color/LinearRGBConverter.java new file mode 100644 index 000000000..1eaf6479e --- /dev/null +++ b/libjava/classpath/gnu/java/awt/color/LinearRGBConverter.java @@ -0,0 +1,152 @@ +/* LinearRGBConverter.java -- conversion to a linear RGB color space + Copyright (C) 2004 Free Software Foundation + +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.color; + + +/** + * LinearRGBConverter - conversion routines for a linear sRGB colorspace + * sRGB is a standard for RGB colorspaces, adopted by the w3c. + * + * The specification is available at: + * http://www.w3.org/Graphics/Color/sRGB.html + * + * @author Sven de Marothy + */ +public class LinearRGBConverter implements ColorSpaceConverter +{ + /** + * linear RGB --> sRGB + * Use the inverse gamma curve + */ + public float[] toRGB(float[] in) + { + float[] out = new float[3]; + for (int i = 0; i < 3; i++) + { + float n = in[i]; + if (n < 0) + n = 0f; + if (n > 1) + n = 1f; + if (n <= 0.00304f) + out[i] = in[0] * 12.92f; + else + out[i] = 1.055f * ((float) Math.exp((1 / 2.4) * Math.log(n))) + - 0.055f; + } + return out; + } + + /** + * sRGB --> linear RGB + * Use the gamma curve (gamma=2.4 in sRGB) + */ + public float[] fromRGB(float[] in) + { + float[] out = new float[3]; + + // Convert non-linear RGB coordinates to linear ones, + // numbers from the w3 spec. + for (int i = 0; i < 3; i++) + { + float n = in[i]; + if (n < 0) + n = 0f; + if (n > 1) + n = 1f; + if (n <= 0.03928f) + out[i] = (float) (n / 12.92); + else + out[i] = (float) (Math.exp(2.4 * Math.log((n + 0.055) / 1.055))); + } + return out; + } + + /** + * Linear RGB --> CIE XYZ (D50 relative) + * This is a simple matrix transform, the matrix (relative D65) + * is given in the sRGB spec. This has been combined with a + * linear Bradford transform for the D65-->D50 mapping, resulting + * in a single matrix which does the whole thing. + * + */ + public float[] fromCIEXYZ(float[] in) + { + /* + * Note: The numbers which were used to calculate this only had four + * digits of accuracy. So don't be fooled by the number of digits here. + * If someone has more accurate source, feel free to update this. + */ + float[] out = new float[3]; + out[0] = (float) (3.13383065124221 * in[0] - 1.61711949411313 * in[1] + - 0.49071914111101 * in[2]); + out[1] = (float) (-0.97847026691142 * in[0] + 1.91597856031996 * in[1] + + 0.03340430640699 * in[2]); + out[2] = (float) (0.07203679486279 * in[0] - 0.22903073553113 * in[1] + + 1.40557835776234 * in[2]); + if (out[0] < 0) + out[0] = 0f; + if (out[1] < 0) + out[1] = 0f; + if (out[2] < 0) + out[2] = 0f; + if (out[0] > 1.0f) + out[0] = 1.0f; + if (out[1] > 1.0f) + out[1] = 1.0f; + if (out[2] > 1.0f) + out[2] = 1.0f; + return out; + } + + /** + * Linear RGB --> CIE XYZ (D50 relative) + * Uses the inverse of the above matrix. + */ + public float[] toCIEXYZ(float[] in) + { + float[] out = new float[3]; + out[0] = (float) (0.43606375022190 * in[0] + 0.38514960146481 * in[1] + + 0.14308641888799 * in[2]); + out[1] = (float) (0.22245089403542 * in[0] + 0.71692584775182 * in[1] + + 0.06062451125578 * in[2]); + out[2] = (float) (0.01389851860679 * in[0] + 0.09707969011198 * in[1] + + 0.71399604572506 * in[2]); + return out; + } +} diff --git a/libjava/classpath/gnu/java/awt/color/ProfileHeader.java b/libjava/classpath/gnu/java/awt/color/ProfileHeader.java new file mode 100644 index 000000000..2a6402dbc --- /dev/null +++ b/libjava/classpath/gnu/java/awt/color/ProfileHeader.java @@ -0,0 +1,398 @@ +/* ProfileHeader.java -- Encapsules ICC Profile header data + Copyright (C) 2004 Free Software Foundation + +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.color; + +import java.awt.color.ColorSpace; +import java.awt.color.ICC_Profile; +import java.nio.ByteBuffer; + + +/** + * Header, abstracts and validates the header data. + * + * @author Sven de Marothy + */ +public class ProfileHeader +{ + /** + * Magic identifier (ASCII 'acsp') + */ + private static final int icMagicNumber = 0x61637370; + + /** + * Mapping from ICC Profile signatures to ColorSpace types + */ + private static final int[] csTypeMap = + { + ICC_Profile.icSigXYZData, + ColorSpace.TYPE_XYZ, + ICC_Profile.icSigLabData, + ColorSpace.TYPE_Lab, + ICC_Profile.icSigLuvData, + ColorSpace.TYPE_Luv, + ICC_Profile.icSigYCbCrData, + ColorSpace.TYPE_YCbCr, + ICC_Profile.icSigYxyData, + ColorSpace.TYPE_Yxy, + ICC_Profile.icSigRgbData, + ColorSpace.TYPE_RGB, + ICC_Profile.icSigGrayData, + ColorSpace.TYPE_GRAY, + ICC_Profile.icSigHsvData, + ColorSpace.TYPE_HSV, + ICC_Profile.icSigHlsData, + ColorSpace.TYPE_HLS, + ICC_Profile.icSigCmykData, + ColorSpace.TYPE_CMYK, + ICC_Profile.icSigCmyData, + ColorSpace.TYPE_CMY, + ICC_Profile.icSigSpace2CLR, + ColorSpace.TYPE_2CLR, + ICC_Profile.icSigSpace3CLR, + ColorSpace.TYPE_3CLR, + ICC_Profile.icSigSpace4CLR, + ColorSpace.TYPE_4CLR, + ICC_Profile.icSigSpace5CLR, + ColorSpace.TYPE_5CLR, + ICC_Profile.icSigSpace6CLR, + ColorSpace.TYPE_6CLR, + ICC_Profile.icSigSpace7CLR, + ColorSpace.TYPE_7CLR, + ICC_Profile.icSigSpace8CLR, + ColorSpace.TYPE_8CLR, + ICC_Profile.icSigSpace9CLR, + ColorSpace.TYPE_9CLR, + ICC_Profile.icSigSpaceACLR, + ColorSpace.TYPE_ACLR, + ICC_Profile.icSigSpaceBCLR, + ColorSpace.TYPE_BCLR, + ICC_Profile.icSigSpaceCCLR, + ColorSpace.TYPE_CCLR, + ICC_Profile.icSigSpaceDCLR, + ColorSpace.TYPE_DCLR, + ICC_Profile.icSigSpaceECLR, + ColorSpace.TYPE_ECLR, + ICC_Profile.icSigSpaceFCLR, + ColorSpace.TYPE_FCLR + }; + + /** + * Size of an ICC header (128 bytes) + */ + public static final int HEADERSIZE = 128; + + /** + * Mapping of ICC class signatures to profile class constants + */ + private static final int[] classMap = + { + ICC_Profile.icSigInputClass, + ICC_Profile.CLASS_INPUT, + ICC_Profile.icSigDisplayClass, + ICC_Profile.CLASS_DISPLAY, + ICC_Profile.icSigOutputClass, + ICC_Profile.CLASS_OUTPUT, + ICC_Profile.icSigLinkClass, + ICC_Profile.CLASS_DEVICELINK, + ICC_Profile.icSigColorSpaceClass, + ICC_Profile.CLASS_COLORSPACECONVERSION, + ICC_Profile.icSigAbstractClass, + ICC_Profile.CLASS_ABSTRACT, + ICC_Profile.icSigNamedColorClass, + ICC_Profile.CLASS_NAMEDCOLOR + }; + private int size; + private int cmmId; + + // Major/Minor version, The ICC-1998 spec is major v2 + private int majorVersion; + + // Major/Minor version, The ICC-1998 spec is major v2 + private int minorVersion; + private int profileClass; // profile device class + private int colorSpace; // data color space type + private int profileColorSpace; // profile connection space (PCS) type + private byte[] timestamp; // original creation timestamp + private int platform; // platform signature + private int flags; // flags + private int magic; // magic number. + private int manufacturerSig; // manufacturer sig + private int modelSig; // model sig + private byte[] attributes; // Attributes + private int intent; // rendering intent + private byte[] illuminant; // illuminant info (Coordinates of D50 in the PCS) + private int creatorSig; // Creator sig (same type as manufacturer) + + /** + * Creates a 'default' header for use with our predefined profiles. + * Note the device and profile color spaces are not set. + */ + public ProfileHeader() + { + creatorSig = 0; + intent = 0; + modelSig = manufacturerSig = (int) 0x6E6f6E65; // 'none' + magic = icMagicNumber; + cmmId = 0; + platform = 0; // no preferred platform + timestamp = new byte[8]; + majorVersion = 2; + minorVersion = 0x10; + flags = 0; + + // D50 in XYZ format (encoded) + illuminant = new byte[] + { + (byte) 0x00, (byte) 0x00, (byte) 0xf6, (byte) 0xd6, + (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0xd3, (byte) 0x2d + }; + attributes = new byte[8]; + profileClass = ICC_Profile.CLASS_DISPLAY; + } + + /** + * Creates a header from profile data. Only the header portion (128 bytes) + * is read, so the array passed need not be the full profile. + */ + public ProfileHeader(byte[] data) + { + ByteBuffer buf = ByteBuffer.wrap(data); + + // Get size (the sign bit shouldn't matter. + // A valid profile can never be +2Gb) + size = buf.getInt(ICC_Profile.icHdrSize); + + // CMM ID + cmmId = buf.getInt(ICC_Profile.icHdrCmmId); + + // Version number + majorVersion = (int) (data[ICC_Profile.icHdrVersion]); + minorVersion = (int) (data[ICC_Profile.icHdrVersion + 1]); + + // Profile/Device class + int classSig = buf.getInt(ICC_Profile.icHdrDeviceClass); + profileClass = -1; + for (int i = 0; i < classMap.length; i += 2) + if (classMap[i] == classSig) + { + profileClass = classMap[i + 1]; + break; + } + + // get the data color space + int csSig = buf.getInt(ICC_Profile.icHdrColorSpace); + colorSpace = -1; + for (int i = 0; i < csTypeMap.length; i += 2) + if (csTypeMap[i] == csSig) + { + colorSpace = csTypeMap[i + 1]; + break; + } + + // get the profile color space (PCS), must be xyz or lab except + // for device-link-class profiles + int pcsSig = buf.getInt(ICC_Profile.icHdrPcs); + profileColorSpace = -1; + if (profileClass != ICC_Profile.CLASS_DEVICELINK) + { + if (pcsSig == ICC_Profile.icSigXYZData) + profileColorSpace = ColorSpace.TYPE_XYZ; + if (pcsSig == ICC_Profile.icSigLabData) + profileColorSpace = ColorSpace.TYPE_Lab; + } + else + { + for (int i = 0; i < csTypeMap.length; i += 2) + if (csTypeMap[i] == pcsSig) + { + profileColorSpace = csTypeMap[i + 1]; + break; + } + } + + // creation timestamp + timestamp = new byte[8]; + System.arraycopy(data, ICC_Profile.icHdrDate, timestamp, 0, 8); + + // magic number + magic = buf.getInt(ICC_Profile.icHdrMagic); + + // platform info + platform = buf.getInt(ICC_Profile.icHdrPlatform); + // get flags + flags = buf.getInt(ICC_Profile.icHdrFlags); + // get manufacturer sign + manufacturerSig = buf.getInt(ICC_Profile.icHdrManufacturer); + // get header model + modelSig = buf.getInt(ICC_Profile.icHdrModel); + // attributes + attributes = new byte[8]; + System.arraycopy(data, ICC_Profile.icHdrAttributes, attributes, 0, 8); + // rendering intent + intent = buf.getInt(ICC_Profile.icHdrRenderingIntent); + // illuminant info + illuminant = new byte[12]; + System.arraycopy(data, ICC_Profile.icHdrIlluminant, illuminant, 0, 12); + // Creator signature + creatorSig = buf.getInt(ICC_Profile.icHdrCreator); + // The rest of the header (Total size: 128 bytes) is unused.. + } + + /** + * Verify that the header is valid + * @param size equals the file size if it is to be verified, -1 otherwise + * @throws IllegalArgumentException if the header is found to be invalid. + */ + public void verifyHeader(int size) throws IllegalArgumentException + { + // verify size + if (size != -1 && this.size != size) + throw new IllegalArgumentException("Invalid profile length:" + size); + + // Check version number + if (majorVersion != 2) + throw new IllegalArgumentException("Wrong major version number:" + + majorVersion); + + // Profile/Device class + if (profileClass == -1) + throw new IllegalArgumentException("Invalid profile/device class"); + + // get the data color space + if (colorSpace == -1) + throw new IllegalArgumentException("Invalid colorspace"); + + // profile color space + if (profileColorSpace == -1) + throw new IllegalArgumentException("Invalid PCS."); + + // check magic number + if (magic != icMagicNumber) + throw new IllegalArgumentException("Invalid magic number!"); + } + + /** + * Creates a header, setting the header file size at the same time. + * @param size the profile file size. + */ + public byte[] getData(int size) + { + byte[] data = new byte[HEADERSIZE]; + ByteBuffer buf = ByteBuffer.wrap(data); + buf.putInt(ICC_Profile.icHdrSize, size); + buf.putInt(ICC_Profile.icHdrCmmId, cmmId); + buf.putShort(ICC_Profile.icHdrVersion, + (short) (majorVersion << 8 | minorVersion)); + for (int i = 1; i < classMap.length; i += 2) + if (profileClass == classMap[i]) + buf.putInt(ICC_Profile.icHdrDeviceClass, classMap[i - 1]); + for (int i = 1; i < csTypeMap.length; i += 2) + if (csTypeMap[i] == colorSpace) + buf.putInt(ICC_Profile.icHdrColorSpace, csTypeMap[i - 1]); + for (int i = 1; i < csTypeMap.length; i += 2) + if (csTypeMap[i] == profileColorSpace) + buf.putInt(ICC_Profile.icHdrPcs, csTypeMap[i - 1]); + + System.arraycopy(timestamp, 0, data, ICC_Profile.icHdrDate, + timestamp.length); + buf.putInt(ICC_Profile.icHdrMagic, icMagicNumber); + buf.putInt(ICC_Profile.icHdrPlatform, platform); + buf.putInt(ICC_Profile.icHdrFlags, flags); + buf.putInt(ICC_Profile.icHdrManufacturer, manufacturerSig); + buf.putInt(ICC_Profile.icHdrModel, modelSig); + System.arraycopy(attributes, 0, data, ICC_Profile.icHdrAttributes, + attributes.length); + buf.putInt(ICC_Profile.icHdrRenderingIntent, intent); + System.arraycopy(illuminant, 0, data, ICC_Profile.icHdrIlluminant, + illuminant.length); + buf.putInt(ICC_Profile.icHdrCreator, creatorSig); + return buf.array(); + } + + public int getSize() + { + return size; + } + + public void setSize(int s) + { + size = s; + } + + public int getMajorVersion() + { + return majorVersion; + } + + public int getMinorVersion() + { + return minorVersion; + } + + public int getProfileClass() + { + return profileClass; + } + + public void setProfileClass(int pc) + { + profileClass = pc; + } + + public int getColorSpace() + { + return colorSpace; + } + + public int getProfileColorSpace() + { + return profileColorSpace; + } + + public void setColorSpace(int cs) + { + colorSpace = cs; + } + + public void setProfileColorSpace(int pcs) + { + profileColorSpace = pcs; + } + +} diff --git a/libjava/classpath/gnu/java/awt/color/PyccConverter.java b/libjava/classpath/gnu/java/awt/color/PyccConverter.java new file mode 100644 index 000000000..77ea28a3e --- /dev/null +++ b/libjava/classpath/gnu/java/awt/color/PyccConverter.java @@ -0,0 +1,71 @@ +/* PyccConverter.java -- PhotoYCC conversion class + Copyright (C) 2004 Free Software Foundation + +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.color; + +/** + * PyccConverter - conversion routines for the PhotoYCC colorspace + * + * Also known as PhotoCD YCC, it is an expansion of the conventional + * YCC color space to also include colors with over 100% white. + * + * XXX FIXME: Not yet implemented, implementation pending. + * + * @author Sven de Marothy + */ +public class PyccConverter implements ColorSpaceConverter +{ + public float[] toRGB(float[] in) + { + throw new UnsupportedOperationException(); + } + + public float[] fromRGB(float[] in) + { + throw new UnsupportedOperationException(); + } + + public float[] toCIEXYZ(float[] in) + { + throw new UnsupportedOperationException(); + } + + public float[] fromCIEXYZ(float[] in) + { + throw new UnsupportedOperationException(); + } +} diff --git a/libjava/classpath/gnu/java/awt/color/RgbProfileConverter.java b/libjava/classpath/gnu/java/awt/color/RgbProfileConverter.java new file mode 100644 index 000000000..7623890a4 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/color/RgbProfileConverter.java @@ -0,0 +1,244 @@ +/* RgbProfileConverter.java -- RGB Profile conversion class + Copyright (C) 2004 Free Software Foundation + +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.color; + +import java.awt.color.ICC_Profile; +import java.awt.color.ICC_ProfileRGB; +import java.awt.color.ProfileDataException; + +/** + * RgbProfileConverter - converts RGB profiles (ICC_ProfileRGB) + * + * This type of profile contains a matrix and three + * tone reproduction curves (TRCs). + * + * Device RGB --> CIE XYZ is done through first multiplying with + * a matrix, then each component is looked-up against it's TRC. + * + * The opposite transform is done using the inverse of the matrix, + * and TRC:s. + * + * @author Sven de Marothy + */ +public class RgbProfileConverter implements ColorSpaceConverter +{ + private float[][] matrix; + private float[][] inv_matrix; + private ToneReproductionCurve rTRC; + private ToneReproductionCurve gTRC; + private ToneReproductionCurve bTRC; + private ColorLookUpTable toPCS; + private ColorLookUpTable fromPCS; + + /** + * CIE 1931 D50 white point (in Lab coordinates) + */ + private static float[] D50 = { 0.96422f, 1.00f, 0.82521f }; + + /** + * Constructs an RgbProfileConverter from a given ICC_ProfileRGB + */ + public RgbProfileConverter(ICC_ProfileRGB profile) + { + toPCS = fromPCS = null; + matrix = profile.getMatrix(); + + // get TRCs + try + { + rTRC = new ToneReproductionCurve(profile.getGamma(ICC_ProfileRGB.REDCOMPONENT)); + } + catch (ProfileDataException e) + { + rTRC = new ToneReproductionCurve(profile.getTRC(ICC_ProfileRGB.REDCOMPONENT)); + } + try + { + gTRC = new ToneReproductionCurve(profile.getGamma(ICC_ProfileRGB.GREENCOMPONENT)); + } + catch (ProfileDataException e) + { + gTRC = new ToneReproductionCurve(profile.getTRC(ICC_ProfileRGB.GREENCOMPONENT)); + } + try + { + bTRC = new ToneReproductionCurve(profile.getGamma(ICC_ProfileRGB.BLUECOMPONENT)); + } + catch (ProfileDataException e) + { + bTRC = new ToneReproductionCurve(profile.getTRC(ICC_ProfileRGB.BLUECOMPONENT)); + } + + // If a CLUT is available, it should be used, and the TRCs ignored. + // Note: A valid profile may only have CLUTs in one direction, and + // TRC:s without useful info, making reverse-transforms impossible. + // In this case the TRC will be used for the reverse-transform with + // unpredictable results. This is in line with the Java specification, + try + { + toPCS = new ColorLookUpTable(profile, ICC_Profile.icSigAToB0Tag); + } + catch (Exception e) + { + toPCS = null; + } + + try + { + fromPCS = new ColorLookUpTable(profile, ICC_Profile.icSigBToA0Tag); + } + catch (Exception e) + { + fromPCS = null; + } + + // Calculate the inverse matrix if no reverse CLUT is available + if(fromPCS == null) + inv_matrix = invertMatrix(matrix); + else + { + // otherwise just set it to an identity matrix + inv_matrix = new float[3][3]; + inv_matrix[0][0] = inv_matrix[1][1] = inv_matrix[2][2] = 1.0f; + } + } + + public float[] toCIEXYZ(float[] in) + { + // CLUT takes precedence + if (toPCS != null) + return toPCS.lookup(in); + + float[] temp = new float[3]; + float[] out = new float[3]; + + // device space --> linear gamma + temp[0] = rTRC.lookup(in[0]); + temp[1] = gTRC.lookup(in[1]); + temp[2] = bTRC.lookup(in[2]); + + // matrix multiplication + out[0] = matrix[0][0] * temp[0] + matrix[0][1] * temp[1] + + matrix[0][2] * temp[2]; + out[1] = matrix[1][0] * temp[0] + matrix[1][1] * temp[1] + + matrix[1][2] * temp[2]; + out[2] = matrix[2][0] * temp[0] + matrix[2][1] * temp[1] + + matrix[2][2] * temp[2]; + + return out; + } + + public float[] toRGB(float[] in) + { + return SrgbConverter.XYZtoRGB(toCIEXYZ(in)); + } + + public float[] fromCIEXYZ(float[] in) + { + if (fromPCS != null) + return fromPCS.lookup(in); + + float[] temp = new float[3]; + float[] out = new float[3]; + + // matrix multiplication + temp[0] = inv_matrix[0][0] * in[0] + inv_matrix[0][1] * in[1] + + inv_matrix[0][2] * in[2]; + temp[1] = inv_matrix[1][0] * in[0] + inv_matrix[1][1] * in[1] + + inv_matrix[1][2] * in[2]; + temp[2] = inv_matrix[2][0] * in[0] + inv_matrix[2][1] * in[1] + + inv_matrix[2][2] * in[2]; + + // device space --> linear gamma + out[0] = rTRC.reverseLookup(temp[0]); + out[1] = gTRC.reverseLookup(temp[1]); + out[2] = bTRC.reverseLookup(temp[2]); + + // FIXME: Sun appears to clip the return values to [0,1] + // I don't believe that is a Good Thing, + // (some colorspaces may allow values outside that range.) + // So we return the actual values here. + return out; + } + + public float[] fromRGB(float[] in) + { + return fromCIEXYZ(SrgbConverter.RGBtoXYZ(in)); + } + + /** + * Inverts a 3x3 matrix, returns the inverse, + * throws an IllegalArgumentException if the matrix is not + * invertible (this shouldn't happen for a valid profile) + */ + private float[][] invertMatrix(float[][] matrix) + { + float[][] out = new float[3][3]; + double determinant = matrix[0][0] * (matrix[1][1] * matrix[2][2] + - matrix[2][1] * matrix[1][2]) + - matrix[0][1] * (matrix[1][0] * matrix[2][2] + - matrix[2][0] * matrix[1][2]) + + matrix[0][2] * (matrix[1][0] * matrix[2][1] + - matrix[2][0] * matrix[1][1]); + + if (determinant == 0.0) + throw new IllegalArgumentException("Can't invert conversion matrix."); + float invdet = (float) (1.0 / determinant); + + out[0][0] = invdet * (matrix[1][1] * matrix[2][2] + - matrix[1][2] * matrix[2][1]); + out[0][1] = invdet * (matrix[0][2] * matrix[2][1] + - matrix[0][1] * matrix[2][2]); + out[0][2] = invdet * (matrix[0][1] * matrix[1][2] + - matrix[0][2] * matrix[1][1]); + out[1][0] = invdet * (matrix[1][2] * matrix[2][0] + - matrix[1][0] * matrix[2][2]); + out[1][1] = invdet * (matrix[0][0] * matrix[2][2] + - matrix[0][2] * matrix[2][0]); + out[1][2] = invdet * (matrix[0][2] * matrix[1][0] + - matrix[0][0] * matrix[1][2]); + out[2][0] = invdet * (matrix[1][0] * matrix[2][1] + - matrix[1][1] * matrix[2][0]); + out[2][1] = invdet * (matrix[0][1] * matrix[2][0] + - matrix[0][0] * matrix[2][1]); + out[2][2] = invdet * (matrix[0][0] * matrix[1][1] + - matrix[0][1] * matrix[1][0]); + return out; + } +} diff --git a/libjava/classpath/gnu/java/awt/color/SrgbConverter.java b/libjava/classpath/gnu/java/awt/color/SrgbConverter.java new file mode 100644 index 000000000..76831c0ea --- /dev/null +++ b/libjava/classpath/gnu/java/awt/color/SrgbConverter.java @@ -0,0 +1,152 @@ +/* SrgbConverter.java -- sRGB conversion class + Copyright (C) 2004 Free Software Foundation + +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.color; + + +/** + * SrgbConverter - conversion routines for the sRGB colorspace + * sRGB is a standard for RGB colorspaces, adopted by the w3c. + * + * The specification is available at: + * http://www.w3.org/Graphics/Color/sRGB.html + * + * @author Sven de Marothy + */ +/** + * + * Note the matrix numbers used here are NOT identical to those in the + * w3 spec, as those numbers are CIE XYZ relative a D65 white point. + * The CIE XYZ we use is relative a D50 white point, so therefore a + * linear Bradford transform matrix for D65->D50 mapping has been applied. + * (The ICC documents describe this transform) + * + * Linearized Bradford transform: + * 0.8951 0.2664 -0.1614 + * -0.7502 1.7135 0.0367 + * 0.0389 -0.0685 1.0296 + * + * Inverse: + * 0.9870 -0.1471 0.1600 + * 0.4323 0.5184 0.0493 + * -0.00853 0.0400 0.9685 + */ +public class SrgbConverter implements ColorSpaceConverter +{ + public float[] fromCIEXYZ(float[] in) + { + return XYZtoRGB(in); + } + + public float[] toCIEXYZ(float[] in) + { + return RGBtoXYZ(in); + } + + public float[] toRGB(float[] in) + { + float[] out = new float[3]; + System.arraycopy(in, 0, out, 0, 3); + return out; + } + + public float[] fromRGB(float[] in) + { + float[] out = new float[3]; + System.arraycopy(in, 0, out, 0, 3); + return out; + } + + /** + * CIE XYZ (D50 relative) --> sRGB + * + * Static as it's used by other ColorSpaceConverters to + * convert to sRGB if the color space is defined in XYZ. + */ + public static float[] XYZtoRGB(float[] in) + { + float[] temp = new float[3]; + temp[0] = 3.1338f * in[0] - 1.6171f * in[1] - 0.4907f * in[2]; + temp[1] = -0.9785f * in[0] + 1.9160f * in[1] + 0.0334f * in[2]; + temp[2] = 0.0720f * in[0] - 0.2290f * in[1] + 1.4056f * in[2]; + + float[] out = new float[3]; + for (int i = 0; i < 3; i++) + { + if (temp[i] < 0) + temp[i] = 0.0f; + if (temp[i] > 1) + temp[i] = 1.0f; + if (temp[i] <= 0.00304f) + out[i] = temp[i] * 12.92f; + else + out[i] = 1.055f * ((float) Math.exp((1 / 2.4) * Math.log(temp[i]))) + - 0.055f; + } + return out; + } + + /** + * sRGB --> CIE XYZ (D50 relative) + * + * Static as it's used by other ColorSpaceConverters to + * convert to XYZ if the color space is defined in RGB. + */ + public static float[] RGBtoXYZ(float[] in) + { + float[] temp = new float[3]; + float[] out = new float[3]; + for (int i = 0; i < 3; i++) + if (in[i] <= 0.03928f) + temp[i] = in[i] / 12.92f; + else + temp[i] = (float) Math.exp(2.4 * Math.log((in[i] + 0.055) / 1.055)); + + /* + * Note: The numbers which were used to calculate this only had four + * digits of accuracy. So don't be fooled by the number of digits here. + * If someone has more accurate source, feel free to update this. + */ + out[0] = (float) (0.436063750222 * temp[0] + 0.385149601465 * temp[1] + + 0.143086418888 * temp[2]); + out[1] = (float) (0.222450894035 * temp[0] + 0.71692584775 * temp[1] + + 0.060624511256 * temp[2]); + out[2] = (float) (0.0138985186 * temp[0] + 0.097079690112 * temp[1] + + 0.713996045725 * temp[2]); + return out; + } +} diff --git a/libjava/classpath/gnu/java/awt/color/TagEntry.java b/libjava/classpath/gnu/java/awt/color/TagEntry.java new file mode 100644 index 000000000..a97864683 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/color/TagEntry.java @@ -0,0 +1,121 @@ +/* TagEntry.java -- A utility class used for storing the tags in ICC_Profile + Copyright (C) 2004 Free Software Foundation + +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.color; + + +/** + * TagEntry - stores a profile tag. + * These are conveniently stored in a hashtable with the tag signature + * as a key. A legal profile can only have one tag with a given sig, + * so we can conveniently ignore collisions. + * + * @author Sven de Marothy + */ +public class TagEntry +{ + // tag table entry size + public static final int entrySize = 12; + private int signature; + private int size; + private int offset; + private byte[] data; + + public TagEntry(int sig, int offset, int size, byte[] data) + { + this.signature = sig; + this.offset = offset; + this.size = size; + this.data = new byte[size]; + System.arraycopy(data, offset, this.data, 0, size); + } + + public TagEntry(int sig, byte[] data) + { + this.signature = sig; + this.size = data.length; + this.data = new byte[size]; + System.arraycopy(data, offset, this.data, 0, size); + } + + public byte[] getData() + { + byte[] d = new byte[size]; + System.arraycopy(this.data, 0, d, 0, size); + return d; + } + + public String hashKey() + { + return tagHashKey(signature); + } + + public String toString() + { + String s = ""; + s = s + (char) ((byte) ((signature >> 24) & 0xFF)); + s = s + (char) ((byte) ((signature >> 16) & 0xFF)); + s = s + (char) ((byte) ((signature >> 8) & 0xFF)); + s = s + (char) ((byte) (signature & 0xFF)); + return s; + } + + public int getSignature() + { + return signature; + } + + public int getSize() + { + return size; + } + + public int getOffset() + { + return offset; + } + + public void setOffset(int offset) + { + this.offset = offset; + } + + public static String tagHashKey(int sig) + { + return "" + sig; + } +} diff --git a/libjava/classpath/gnu/java/awt/color/ToneReproductionCurve.java b/libjava/classpath/gnu/java/awt/color/ToneReproductionCurve.java new file mode 100644 index 000000000..208e16883 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/color/ToneReproductionCurve.java @@ -0,0 +1,177 @@ +/* ToneReproductionCurve.java -- Representation of an ICC 'curv' type TRC + Copyright (C) 2004 Free Software Foundation + +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.color; + + +/** + * ToneReproductionCurve - TRCs are used to describe RGB + * and Grayscale profiles. The TRC is essentially the gamma + * function of the color space. + * + * For example, Apple RGB has a gamma of 1.8, most monitors are ~2.2, + * sRGB is 2.4 with a small linear part near 0. + * Linear spaces are of course 1.0. + * (The exact function is implemented in SrgbConverter) + * + * The ICC specification allows the TRC to be described as a single + * Gamma value, where the function is thus out = in**gamma. + * Alternatively, the gamma function may be represented by a lookup table + * of values, in which case linear interpolation is used. + * + * @author Sven de Marothy + */ +public class ToneReproductionCurve +{ + private float[] trc; + private float gamma; + private float[] reverseTrc; + + /** + * Constructs a TRC from a gamma values + */ + public ToneReproductionCurve(float gamma) + { + trc = null; + reverseTrc = null; + this.gamma = gamma; + } + + /** + * Constructs a TRC from a set of float values + */ + public ToneReproductionCurve(float[] trcValues) + { + trc = new float[trcValues.length]; + System.arraycopy(trcValues, 0, trc, 0, trcValues.length); + setupReverseTrc(); + } + + /** + * Constructs a TRC from a set of short values normalized to + * the 0-65535 range (as in the ICC profile file). + * (Note the values are treated as unsigned) + */ + public ToneReproductionCurve(short[] trcValues) + { + trc = new float[trcValues.length]; + for (int i = 0; i < trcValues.length; i++) + trc[i] = (float) ((int) trcValues[i] & (0xFFFF)) / 65535.0f; + setupReverseTrc(); + } + + /** + * Performs a TRC lookup + */ + public float lookup(float in) + { + float out; + + if (trc == null) + { + if (in == 0f) + return 0.0f; + return (float) Math.exp(gamma * Math.log(in)); + } + else + { + double alpha = in * (trc.length - 1); + int index = (int) Math.floor(alpha); + alpha = alpha - (double) index; + if (index >= trc.length - 1) + return trc[trc.length - 1]; + if (index <= 0) + return trc[0]; + out = (float) (trc[index] * (1.0 - alpha) + trc[index + 1] * alpha); + } + return out; + } + + /** + * Performs an reverse lookup + */ + public float reverseLookup(float in) + { + float out; + + if (trc == null) + { + if (in == 0f) + return 0.0f; + return (float) Math.exp((1.0 / gamma) * Math.log(in)); + } + else + { + double alpha = in * (reverseTrc.length - 1); + int index = (int) Math.floor(alpha); + alpha = alpha - (double) index; + if (index >= reverseTrc.length - 1) + return reverseTrc[reverseTrc.length - 1]; + if (index <= 0) + return reverseTrc[0]; + out = (float) (reverseTrc[index] * (1.0 - alpha) + + reverseTrc[index + 1] * alpha); + } + return out; + } + + /** + * Calculates a reverse-lookup table. + * We use a whopping 10,000 entries.. This is should be more than any + * real-life TRC table (typically around 256-1024) so we won't be losing + * any precision. + * + * This will of course generate completely invalid results if the curve + * is not monotonic and invertable. But what's the alternative? + */ + public void setupReverseTrc() + { + reverseTrc = new float[10000]; + int j = 0; + for (int i = 0; i < 10000; i++) + { + float n = ((float) i) / 10000f; + while (trc[j + 1] < n && j < trc.length - 2) + j++; + + if (j == trc.length - 2) + reverseTrc[i] = trc[trc.length - 1]; + else + reverseTrc[i] = (j + (n - trc[j]) / (trc[j + 1] - trc[j])) / ((float) trc.length); + } + } +} diff --git a/libjava/classpath/gnu/java/awt/color/package.html b/libjava/classpath/gnu/java/awt/color/package.html new file mode 100644 index 000000000..c4705cce5 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/color/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.awt.color + + +

+ + + diff --git a/libjava/classpath/gnu/java/awt/dnd/GtkMouseDragGestureRecognizer.java b/libjava/classpath/gnu/java/awt/dnd/GtkMouseDragGestureRecognizer.java new file mode 100644 index 000000000..4ef8c2918 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/dnd/GtkMouseDragGestureRecognizer.java @@ -0,0 +1,172 @@ +/* GtkMouseDragGestureRecognizer.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.java.awt.dnd; + +import java.awt.Component; +import java.awt.Point; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.MouseDragGestureRecognizer; +import java.awt.event.MouseEvent; + +public class GtkMouseDragGestureRecognizer + extends MouseDragGestureRecognizer +{ + + public GtkMouseDragGestureRecognizer (DragSource ds) + { + this(ds, null, 0, null); + } + + public GtkMouseDragGestureRecognizer (DragSource ds, Component c) + { + this (ds, c, 0, null); + } + + public GtkMouseDragGestureRecognizer (DragSource ds, Component c, int act) + { + this(ds, c, act, null); + } + + public GtkMouseDragGestureRecognizer (DragSource ds, Component c, int act, + DragGestureListener dgl) + { + super(ds, c, act, dgl); + } + + public void registerListeners () + { + super.registerListeners(); + } + + public void unregisterListeners () + { + super.unregisterListeners(); + } + + public void mouseClicked (MouseEvent e) + { + // Nothing to do here. + } + + public void mousePressed (MouseEvent e) + { + events.clear(); + if (getDropActionFromEvent(e) != DnDConstants.ACTION_NONE) + appendEvent(e); + } + + public void mouseReleased (MouseEvent e) + { + events.clear(); + } + + public void mouseEntered (MouseEvent e) + { + events.clear(); + } + + public void mouseExited(MouseEvent e) + { + if (!events.isEmpty()) + if (getDropActionFromEvent(e) == DnDConstants.ACTION_NONE) + events.clear(); + } + + public void mouseDragged(MouseEvent e) + { + if (!events.isEmpty()) + { + int act = getDropActionFromEvent(e); + + if (act == DnDConstants.ACTION_NONE) + return; + + Point origin = ((MouseEvent) events.get(0)).getPoint(); + Point current = e.getPoint(); + int dx = Math.abs(origin.x - current.x); + int dy = Math.abs(origin.y - current.y); + int threshold = DragSource.getDragThreshold(); + + if (dx > threshold || dy > threshold) + fireDragGestureRecognized(act, origin); + else + appendEvent(e); + } + } + + public void mouseMoved (MouseEvent e) + { + // Nothing to do here. + } + + private int getDropActionFromEvent(MouseEvent e) + { + int modEx = e.getModifiersEx(); + int buttons = modEx & (MouseEvent.BUTTON1_DOWN_MASK + | MouseEvent.BUTTON2_DOWN_MASK | MouseEvent.BUTTON3_DOWN_MASK); + if (!(buttons == MouseEvent.BUTTON1_DOWN_MASK || + buttons == MouseEvent.BUTTON2_DOWN_MASK)) + return DnDConstants.ACTION_NONE; + + // Convert modifier to a drop action + int sourceActions = getSourceActions(); + int mod = modEx + & (MouseEvent.SHIFT_DOWN_MASK | MouseEvent.CTRL_DOWN_MASK); + switch (mod) + { + case MouseEvent.SHIFT_DOWN_MASK | MouseEvent.CTRL_DOWN_MASK: + return DnDConstants.ACTION_LINK & sourceActions; + case MouseEvent.CTRL_DOWN_MASK: + return DnDConstants.ACTION_COPY & sourceActions; + case MouseEvent.SHIFT_DOWN_MASK: + return DnDConstants.ACTION_MOVE & sourceActions; + default: + if ((sourceActions & DnDConstants.ACTION_MOVE) != 0) + return DnDConstants.ACTION_MOVE & sourceActions; + else if ((sourceActions & DnDConstants.ACTION_COPY) != 0) + return DnDConstants.ACTION_COPY & sourceActions; + else if ((sourceActions & DnDConstants.ACTION_LINK) != 0) + return DnDConstants.ACTION_LINK & sourceActions; + } + + return DnDConstants.ACTION_NONE & sourceActions; + } +} diff --git a/libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDragSourceContextPeer.java b/libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDragSourceContextPeer.java new file mode 100644 index 000000000..4d1097626 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDragSourceContextPeer.java @@ -0,0 +1,184 @@ +/* GtkDragSourceContextPeer.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.java.awt.dnd.peer.gtk; + +import gnu.java.awt.peer.gtk.GtkGenericPeer; + +import java.awt.Component; +import java.awt.Cursor; +import java.awt.Image; +import java.awt.Point; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragSourceContext; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceEvent; +import java.awt.dnd.InvalidDnDOperationException; +import java.awt.dnd.peer.DragSourceContextPeer; +import java.awt.peer.ComponentPeer; +import java.awt.peer.LightweightPeer; + +public class GtkDragSourceContextPeer + extends GtkGenericPeer + implements DragSourceContextPeer +{ + private ComponentPeer peer; + private Cursor cursor; + private DragSourceContext context; + public static Component target; + + native void nativeStartDrag(Image i, int x, int y, int action, String target); + native void connectSignals(ComponentPeer comp); + native void create(ComponentPeer comp); + native void nativeSetCursor(int cursor); + native void setTarget(GtkDropTargetContextPeer target); + + public GtkDragSourceContextPeer(DragGestureEvent e) + { + super(e.getComponent()); + Component comp = e.getComponent(); + peer = getComponentPeer(comp); + + create(peer); + connectSignals(peer); + cursor = comp.getCursor(); + + // FIXME: Where do we set the target? + + if ((target != null)) + setTarget(new GtkDropTargetContextPeer(target)); + } + + ComponentPeer getComponentPeer(Component c) + { + if (c == null) + return null; + + Component curr = c; + while (curr.getPeer() instanceof LightweightPeer) + curr = curr.getParent(); + + if (curr != null) + return curr.getPeer(); + return null; + } + + public void startDrag(DragSourceContext context, Cursor c, Image i, Point p) + throws InvalidDnDOperationException + { + this.context = context; + + if (p == null) + p = new Point(); + + // FIXME: use proper DataFlavor, not "text/plain". + // Also, add check to determine if dragging. + + setCursor(c); + nativeStartDrag(i, p.x, p.y, context.getTrigger().getDragAction(), + "text/plain"); + } + + public Cursor getCursor() + { + return cursor; + } + + public void setCursor(Cursor c) throws InvalidDnDOperationException + { + if (c != null) + { + nativeSetCursor(c.getType()); + cursor = c; + } + } + + public void transferablesFlavorsChanged() + { + // Nothing to do here. + } + + /** + * Called from native code. + */ + + public void dragEnter(int action, int modifiers) + { + context.dragEnter(new DragSourceDragEvent(context, action, + action + & context.getSourceActions(), + modifiers)); + } + + public void dragExit(int action, int x, int y) + { + context.dragExit(new DragSourceEvent(context, x, y)); + } + + public void dragDropEnd(int action, boolean success, int x, int y) + { + context.dragDropEnd(new DragSourceDropEvent(context, action, success, x, y)); + } + + public void dragMouseMoved(int action, int modifiers) + { + context.dragMouseMoved(new DragSourceDragEvent(context, + action, + action + & context.getSourceActions(), + modifiers)); + } + + public void dragOver(int action, int modifiers) + { + context.dragOver(new DragSourceDragEvent(context, action, + action + & context.getSourceActions(), + modifiers)); + } + + public void dragActionChanged(int newAction, int modifiers) + { + context.dropActionChanged(new DragSourceDragEvent(context, + newAction, + newAction + & context.getSourceActions(), + modifiers)); + } +} diff --git a/libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDropTargetContextPeer.java b/libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDropTargetContextPeer.java new file mode 100644 index 000000000..315a2bdf1 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDropTargetContextPeer.java @@ -0,0 +1,125 @@ +/* GtkDropTargetContextPeer.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.java.awt.dnd.peer.gtk; + +import gnu.java.awt.peer.gtk.GtkGenericPeer; + +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.dnd.DropTarget; +import java.awt.dnd.InvalidDnDOperationException; +import java.awt.dnd.peer.DropTargetContextPeer; + +public class GtkDropTargetContextPeer + extends GtkGenericPeer + implements DropTargetContextPeer +{ + + public GtkDropTargetContextPeer(Object obj) + { + super(obj); + } + + public void setTargetActions(int actions) + { + // FIXME: Not Implemented + + } + + public int getTargetActions() + { + // FIXME: Not Implemented + return 0; + } + + public DropTarget getDropTarget() + { + // FIXME: Not Implemented + return null; + } + + public DataFlavor[] getTransferDataFlavors() + { + // FIXME: Not Implemented + return null; + } + + public Transferable getTransferable() throws InvalidDnDOperationException + { + // FIXME: Not Implemented + return null; + } + + public boolean isTransferableJVMLocal() + { + // FIXME: Not Implemented + return false; + } + + public void acceptDrag(int dragAction) + { + // FIXME: Not Implemented + + } + + public void rejectDrag() + { + // FIXME: Not Implemented + + } + + public void acceptDrop(int dropAction) + { + // FIXME: Not Implemented + + } + + public void rejectDrop() + { + // FIXME: Not Implemented + + } + + public void dropComplete(boolean success) + { + // FIXME: Not Implemented + + } + +} diff --git a/libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDropTargetPeer.java b/libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDropTargetPeer.java new file mode 100644 index 000000000..0799df5ba --- /dev/null +++ b/libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDropTargetPeer.java @@ -0,0 +1,68 @@ +/* GtkDropTargetPeer.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.java.awt.dnd.peer.gtk; + +import gnu.java.awt.peer.gtk.GtkGenericPeer; + +import java.awt.dnd.DropTarget; +import java.awt.dnd.peer.DropTargetPeer; + +public class GtkDropTargetPeer + extends GtkGenericPeer + implements DropTargetPeer +{ + + public GtkDropTargetPeer() + { + super(null); + } + + public void addDropTarget(DropTarget target) + { + // FIXME: Not Implemented + + } + + public void removeDropTarget(DropTarget target) + { + // FIXME: Not Implemented + + } + +} diff --git a/libjava/classpath/gnu/java/awt/doc-files/BitwiseXORComposite-1.png b/libjava/classpath/gnu/java/awt/doc-files/BitwiseXORComposite-1.png new file mode 100644 index 000000000..588c910dd Binary files /dev/null and b/libjava/classpath/gnu/java/awt/doc-files/BitwiseXORComposite-1.png differ diff --git a/libjava/classpath/gnu/java/awt/font/FontDelegate.java b/libjava/classpath/gnu/java/awt/font/FontDelegate.java new file mode 100644 index 000000000..e5c03a10f --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/FontDelegate.java @@ -0,0 +1,329 @@ +/* FontDelegate.java -- Interface implemented by all font delegates. + 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.font; + +import java.awt.Font; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.geom.Point2D; +import java.text.CharacterIterator; +import java.util.Locale; + + +/** + * The interface that all font delegate objects implement, + * irrespective of where they get their information from. + * + *

Thread Safety: All classes that implement the + * FontDelegate interface must allow calling these + * methods from multiple concurrent threads. The delegates are + * responsible for performing the necessary synchronization. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public interface FontDelegate +{ + public static final int FLAG_FITTED = 1 << 0; + public static final int FLAG_NO_HINT_HORIZONTAL = 1 << 1; + public static final int FLAG_NO_HINT_VERTICAL = 1 << 2; + public static final int FLAG_NO_HINT_EDGE_POINTS = 1 << 3; + public static final int FLAG_NO_HINT_STRONG_POINTS = 1 << 4; + public static final int FLAG_NO_HINT_WEAK_POINTS = 1 << 5; + + /** + * Returns the full name of this font face in the specified + * locale, for example “Univers Light”. + * + * @param locale the locale for which to localize the name. + * + * @return the face name. + */ + public String getFullName(Locale locale); + + + /** + * Returns the name of the family to which this font face belongs, + * for example “Univers”. + * + * @param locale the locale for which to localize the name. + * + * @return the family name. + */ + public String getFamilyName(Locale locale); + + + /** + * Returns the name of this font face inside the family, for example + * “Light”. + * + * @param locale the locale for which to localize the name. + * + * @return the name of the face inside its family. + */ + public String getSubFamilyName(Locale locale); + + + /** + * Returns the PostScript name of this font face, for example + * “Helvetica-Bold”. + * + * @return the PostScript name, or null if the font + * does not provide a PostScript name. + */ + public String getPostScriptName(); + + + /** + * Returns the number of glyphs in this font face. + */ + public int getNumGlyphs(); + + /** + * Returns the glyph code for the specified character. + * + * @param c the character to map + * + * @return the glyph code + */ + public int getGlyphIndex(int c); + + /** + * Returns the index of the glyph which gets displayed if the font + * cannot map a Unicode code point to a glyph. Many fonts show this + * glyph as an empty box. + */ + public int getMissingGlyphCode(); + + + /** + * Creates a GlyphVector by mapping each character in a + * CharacterIterator to the corresponding glyph. + * + *

The mapping takes only the font’s cmap + * tables into consideration. No other operations (such as glyph + * re-ordering, composition, or ligature substitution) are + * performed. This means that the resulting GlyphVector will not be + * correct for text in languages that have complex + * character-to-glyph mappings, such as Arabic, Hebrew, Hindi, or + * Thai. + * + * @param font the font object that the created GlyphVector + * will return when it gets asked for its font. This argument is + * needed because the public API works with java.awt.Font, + * not with some private delegate like OpenTypeFont. + * + * @param frc the font rendering parameters that are used for + * measuring glyphs. The exact placement of text slightly depends on + * device-specific characteristics, for instance the device + * resolution or anti-aliasing. For this reason, any measurements + * will only be accurate if the passed + * FontRenderContext correctly reflects the relevant + * parameters. Hence, frc should be obtained from the + * same Graphics2D that will be used for drawing, and + * any rendering hints should be set to the desired values before + * obtaining frc. + * + * @param ci a CharacterIterator for iterating over the + * characters to be displayed. + */ + public GlyphVector createGlyphVector(Font font, + FontRenderContext frc, + CharacterIterator ci); + + + /** + * Determines the advance width and height for a glyph. + * + * @param glyphIndex the glyph whose advance width is to be + * determined. + * + * @param pointSize the point size of the font. + * + * @param transform a transform that is applied in addition to + * scaling to the specified point size. This is often used for + * scaling according to the device resolution. Those who lack any + * aesthetic sense may also use the transform to slant or stretch + * glyphs. + * + * @param antialias true for anti-aliased rendering, + * false for normal rendering. For hinted fonts, + * this parameter may indeed affect the result. + * + * @param fractionalMetrics true for fractional metrics, + * false for rounding the result to a pixel boundary. + * + * @param horizontal true for horizontal line layout, + * false for vertical line layout. + * + * @param advance a point whose x and y + * fields will hold the advance in each direction. It is well + * possible that both values are non-zero, for example for rotated + * text or for Urdu fonts. + */ + public void getAdvance(int glyphIndex, + float pointSize, + AffineTransform transform, + boolean antialias, + boolean fractionalMetrics, + boolean horizontal, + Point2D advance); + + + /** + * Returns the shape of a glyph. + * + * @param glyphIndex the glyph whose advance width is to be + * determined. + * + * @param pointSize the point size of the font. + * + * @param transform a transform that is applied in addition to + * scaling to the specified point size. This is often used for + * scaling according to the device resolution. Those who lack any + * aesthetic sense may also use the transform to slant or stretch + * glyphs. + * + * @param antialias true for anti-aliased rendering, + * false for normal rendering. For hinted fonts, this + * parameter may indeed affect the result. + * + * @param fractionalMetrics true for fractional + * metrics, false for rounding the result to a pixel + * boundary. + * + * @return the scaled and grid-fitted outline of the specified + * glyph, or null for bitmap fonts. + */ + public GeneralPath getGlyphOutline(int glyphIndex, + float pointSize, + AffineTransform transform, + boolean antialias, + boolean fractionalMetrics, + int type); + + + /** + * Returns a name for the specified glyph. This is useful for + * generating PostScript or PDF files that embed some glyphs of a + * font. + * + *

Names are not unique: Under some rare circumstances, + * the same name can be returned for different glyphs. It is + * therefore recommended that printer drivers check whether the same + * name has already been returned for antoher glyph, and make the + * name unique by adding the string ".alt" followed by the glyph + * index.

+ * + *

This situation would occur for an OpenType or TrueType font + * that has a post table of format 3 and provides a + * mapping from glyph IDs to Unicode sequences through a + * Zapf table. If the same sequence of Unicode + * codepoints leads to different glyphs (depending on contextual + * position, for example, or on typographic sophistication level), + * the same name would get synthesized for those glyphs. + * + * @param glyphIndex the glyph whose name the caller wants to + * retrieve. + */ + public String getGlyphName(int glyphIndex); + + + /** + * Determines the distance between the base line and the highest + * ascender. + * + * @param pointSize the point size of the font. + * + * @param transform a transform that is applied in addition to + * scaling to the specified point size. This is often used for + * scaling according to the device resolution. Those who lack any + * aesthetic sense may also use the transform to slant or stretch + * glyphs. + * + * @param antialiased true for anti-aliased rendering, + * false for normal rendering. For hinted fonts, + * this parameter may indeed affect the result. + * + * @param fractionalMetrics true for fractional metrics, + * false for rounding the result to a pixel boundary. + * + * @param horizontal true for horizontal line layout, + * false for vertical line layout. + * + * @return the ascent, which usually is a positive number. + */ + public float getAscent(float pointSize, + AffineTransform transform, + boolean antialiased, + boolean fractionalMetrics, + boolean horizontal); + + + /** + * Determines the distance between the base line and the lowest + * descender. + * + * @param pointSize the point size of the font. + * + * @param transform a transform that is applied in addition to + * scaling to the specified point size. This is often used for + * scaling according to the device resolution. Those who lack any + * aesthetic sense may also use the transform to slant or stretch + * glyphs. + * + * @param antialiased true for anti-aliased rendering, + * false for normal rendering. For hinted fonts, + * this parameter may indeed affect the result. + * + * @param fractionalMetrics true for fractional metrics, + * false for rounding the result to a pixel boundary. + * + * @param horizontal true for horizontal line layout, + * false for vertical line layout. + * + * @return the descent, which usually is a nagative number. + */ + public float getDescent(float pointSize, + AffineTransform transform, + boolean antialiased, + boolean fractionalMetrics, + boolean horizontal); +} diff --git a/libjava/classpath/gnu/java/awt/font/FontFactory.java b/libjava/classpath/gnu/java/awt/font/FontFactory.java new file mode 100644 index 000000000..53eb5df5f --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/FontFactory.java @@ -0,0 +1,90 @@ +/* FontFactory.java -- Factory for font delegates. + 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.font; + +import java.nio.ByteBuffer; + +import java.awt.FontFormatException; +import gnu.java.awt.font.opentype.OpenTypeFontFactory; + + +/** + * A factory for creating font delegate objects. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public final class FontFactory +{ + /** + * The constructor is private so nobody can construct an instance + */ + private FontFactory() + { + } + + + /** + * Creates FontDelegate objects for the fonts in the specified buffer. + * The following font formats are currently recognized: + * recognized font formats are: + * + *

    + *
  • OpenType (*.otf);
  • + *
  • TrueType (*.ttf);
  • + *
  • TrueType Collections (*.ttc);
  • + *
  • Apple MacOS X data-fork font (*.dfont).
+ * + *

Some formats may contain more than a single font, for example + * *.ttc and *.dfont files. This is the reason why this function + * returns an array. + * + *

The implementation reads data from the buffer only when + * needed. Therefore, it greatly increases efficiency if + * buf has been obtained through mapping a file into + * the virtual address space. + * + * @throws FontFormatException if the font data is not in one of the + * known formats. + */ + public static FontDelegate[] createFonts(ByteBuffer buf) + throws FontFormatException + { + return OpenTypeFontFactory.createFonts(buf); + } +} diff --git a/libjava/classpath/gnu/java/awt/font/GNUGlyphVector.java b/libjava/classpath/gnu/java/awt/font/GNUGlyphVector.java new file mode 100644 index 000000000..9fd80e79e --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/GNUGlyphVector.java @@ -0,0 +1,663 @@ +/* GNUGlyphVector.java -- The GNU implementation of GlyphVector. + 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.font; + +import gnu.java.awt.java2d.ShapeWrapper; + +import java.awt.Font; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphMetrics; +import java.awt.font.GlyphJustificationInfo; +import java.awt.font.GlyphVector; + +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + + +/** + * The GNU implementation of the abstract GlyphVector class, which + * uses the services provided by a FontDelegate for its functionality. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class GNUGlyphVector + extends GlyphVector +{ + private FontDelegate fontDelegate; + private Font font; + private FontRenderContext renderContext; + private int[] glyphs; + private float fontSize; + private AffineTransform transform; + private boolean valid; + + + /** + * The position of each glyph. The horizontal position of the + * i-th glyph is at pos[i * 2], its + * vertical position at pos[i * 2 + 1]. The total + * advance width of the entire vector is stored at + * pos[numGlyphs], the total advance height at + * pos[numGlyphs + 1]. + */ + private float[] pos; + + + private AffineTransform[] transforms; + private int layoutFlags; + + /** + * The cached non-transformed outline of this glyph vector. + */ + private Shape cleanOutline; + + /** + * Constructs a new GNUGlyphVector. + * + * @param fontDelegate the FontDelegate that creates this vector. + * + * @param font the Font that this GlyphVector will return for {@link + * #getFont()}. That object is also used to determine the point + * size, which affects the affine transformation used by the font + * scaler. + * + * @param renderContext an object with parameters for font + * rendering, such as whether anti-aliasing is enabled. + * + * @param glyphs the glyphs in this vector. + */ + public GNUGlyphVector(FontDelegate fontDelegate, + Font font, + FontRenderContext renderContext, + int[] glyphs) + { + this.fontDelegate = fontDelegate; + this.font = font; + this.renderContext = renderContext; + this.glyphs = glyphs; + + fontSize = font.getSize2D(); + transform = font.getTransform(); // returns a modifiable copy + //transform.concatenate(renderContext.getTransform()); + } + + + + /** + * Returns the font of the glyphs in this GlyphVector. + */ + public Font getFont() + { + return font; + } + + + /** + * Returns the FontRenderContext that is used to calculate the + * extent and position of the glyphs. + */ + public FontRenderContext getFontRenderContext() + { + return renderContext; + } + + + /** + * Moves each glyph in the vector to its default position. + */ + public void performDefaultLayout() + { + float x, y, advanceWidth, advanceHeight; + int i, p; + AffineTransform tx; + Point2D.Float advance = new Point2D.Float(); + + pos = new float[(glyphs.length + 1) * 2]; + x = y = 0.0f; + p = 0; + for (i = p = 0; i < glyphs.length; i++) + { + p += 2; + + if ((transforms == null) || (tx = transforms[i]) == null) + tx = this.transform; + else + { + tx = new AffineTransform(tx); + tx.concatenate(this.transform); + } + + fontDelegate.getAdvance(glyphs[i], fontSize, tx, + renderContext.isAntiAliased(), + renderContext.usesFractionalMetrics(), + /* horizontal */ true, + advance); + // FIXME: We shouldn't round here, but instead hint the metrics + // correctly. + pos[p] = x += Math.round(advance.x); + pos[p + 1] = y += advance.y; + } + valid = true; + } + + + /** + * Determines the number of glyphs in this GlyphVector. + */ + public int getNumGlyphs() + { + return glyphs.length; + } + + + /** + * Determines the glyph number by index in this vector. + * Glyph numbers are specific to each font, so two fonts + * will likely assign different numbers to the same glyph. + * + * @param glyphIndex the index of the glyph whose glyph number is to + * be retrieved. + * + * @throws IndexOutOfBoundsException if glyphIndex + * is not in the range . + */ + public int getGlyphCode(int glyphIndex) + { + /* The exception is thrown automatically if the index is out + * of the valid bounds. + */ + return glyphs[glyphIndex]; + } + + + /** + * Returns a slice of this GlyphVector. + * + * @param firstGlyphIndex the index of the first glyph in the + * returned slice. + * + * @param numEntries the size of the returned slice. + * + * @param outCodes a pre-allocated array for storing the slice, + * or null to cause allocation of a new array. + * + * @return a slice of this GlyphVector. If outCodes + * is null, the slice will be stored into a freshly + * allocated array; otherwise, the result will be stored into + * outCodes. + */ + public int[] getGlyphCodes(int firstGlyphIndex, + int numEntries, + int[] outCodes) + { + if (numEntries < 0) + throw new IllegalArgumentException(); + if (outCodes == null) + outCodes = new int[numEntries]; + System.arraycopy(glyphs, firstGlyphIndex, outCodes, 0, numEntries); + return outCodes; + } + + + public Rectangle2D getLogicalBounds() + { + float ascent, descent; + + validate(); + + return new Rectangle2D.Float(0, 0, + pos[pos.length - 2], + getAscent() - getDescent()); + } + + + public Rectangle2D getVisualBounds() + { + validate(); + + // FIXME: Not yet implemented. + return getLogicalBounds(); + } + + + /** + * Returns the shape of this GlyphVector. + */ + public Shape getOutline() + { + return getOutline(0.0f, 0.0f); + } + + + /** + * Returns the shape of this GlyphVector, translated to the + * specified position. + * + * @param x the horizontal position for rendering this vector. + * @param y the vertical position for rendering this vector. + */ + public Shape getOutline(float x, float y) + { + validate(); + + Shape outline; + if (cleanOutline == null) + { + GeneralPath path = new GeneralPath(); + int len = glyphs.length; + for (int i = 0; i < len; i++) + { + GeneralPath p = new GeneralPath(getGlyphOutline(i)); + path.append(p, false); + } + // Protect the cached instance from beeing modified by application + // code. + cleanOutline = new ShapeWrapper(path); + outline = cleanOutline; + } + else + { + outline = cleanOutline; + } + if (x != 0 || y != 0) + { + GeneralPath path = new GeneralPath(outline); + AffineTransform t = new AffineTransform(); + t.translate(x, y); + path.transform(t); + outline = path; + } + return outline; + } + + public Shape getOutline(float x, float y, int type) + { + validate(); + + GeneralPath outline = new GeneralPath(); + int len = glyphs.length; + for (int i = 0; i < len; i++) + { + GeneralPath p = new GeneralPath(getGlyphOutline(i, type)); + outline.append(p, false); + } + AffineTransform t = new AffineTransform(); + t.translate(x, y); + outline.transform(t); + return outline; + } + + /** + * Determines the shape of the specified glyph. + * + * @throws IndexOutOfBoundsException if glyphIndex is + * not in the range . + */ + public Shape getGlyphOutline(int glyphIndex) + { + AffineTransform tx, glyphTx; + GeneralPath path; + + validate(); + + if ((transforms != null) + && ((glyphTx = transforms[glyphIndex]) != null)) + { + tx = new AffineTransform(transform); + tx.concatenate(glyphTx); + } + else + tx = transform; + + path = fontDelegate.getGlyphOutline(glyphs[glyphIndex], fontSize, tx, + renderContext.isAntiAliased(), + renderContext.usesFractionalMetrics(), + FontDelegate.FLAG_FITTED); + + tx = new AffineTransform(); + tx.translate(pos[glyphIndex * 2], pos[glyphIndex * 2 + 1]); + path.transform(tx); + return path; + } + + public Shape getGlyphOutline(int glyphIndex, int type) + { + AffineTransform tx, glyphTx; + GeneralPath path; + + validate(); + + if ((transforms != null) + && ((glyphTx = transforms[glyphIndex]) != null)) + { + tx = new AffineTransform(transform); + tx.concatenate(glyphTx); + } + else + tx = transform; + + path = fontDelegate.getGlyphOutline(glyphs[glyphIndex], fontSize, tx, + renderContext.isAntiAliased(), + renderContext.usesFractionalMetrics(), + type); + + tx = new AffineTransform(); + tx.translate(pos[glyphIndex * 2], pos[glyphIndex * 2 + 1]); + path.transform(tx); + return path; + } + + /** + * Determines the position of the specified glyph, or the + * total advance width and height of the vector. + * + * @param glyphIndex the index of the glyph in question. + * If this value equals getNumGlyphs(), the + * position after the last glyph will be returned, + * which is the total advance width and height of the vector. + * + * @throws IndexOutOfBoundsException if glyphIndex is + * not in the range . + */ + public Point2D getGlyphPosition(int glyphIndex) + { + validate(); + return new Point2D.Float(pos[glyphIndex * 2], + pos[glyphIndex * 2 + 1]); + } + + + /** + * Moves the specified glyph to a new position, or changes the + * advance width and height of the entire glyph vector. + * + *

Note that the position of an individual glyph may also + * affected by its affine transformation. + * + * @param glyphIndex the index of the moved glyph. If + * glyphIndex equals the total number of glyphs in this + * vector, the advance width and height of the vector is changed. + * + * @param position the new position of the glyph. + * + * @throws IndexOutOfBoundsException if glyphIndex is + * not in the range . + */ + public void setGlyphPosition(int glyphIndex, Point2D position) + { + validate(); + pos[glyphIndex * 2] = (float) position.getX(); + pos[glyphIndex * 2 + 1] = (float) position.getY(); + } + + + /** + * Returns the affine transformation that is applied to the + * glyph at the specified index. + * + * @param glyphIndex the index of the glyph whose transformation + * is to be retrieved. + * + * @return an affine transformation, or null + * for the identity transformation. + * + * @throws IndexOutOfBoundsException if glyphIndex is + * not in the range . + */ + public AffineTransform getGlyphTransform(int glyphIndex) + { + if (transforms == null) + return null; + else + return transforms[glyphIndex]; + } + + + /** + * Applies an affine transformation to the glyph at the specified + * index. + * + * @param glyphIndex the index of the glyph to which the + * transformation is applied. + * + * @param transform the affine transformation for the glyph, or + * null for an identity transformation. + */ + public void setGlyphTransform(int glyphIndex, + AffineTransform transform) + { + if (transforms == null) + transforms = new AffineTransform[glyphs.length]; + transforms[glyphIndex] = transform; + + /* If the GlyphVector has only a transform for a single glyph, and + * the caller clears its transform, the FLAG_HAS_TRANSFORMS bit + * should be cleared in layoutFlags. However, this would require + * that we keep track of the number of transformed glyphs, or that + * we count them when a transform is cleared. This would + * complicate the code quite a bit. Note that the only drawback of + * wrongly setting FLAG_HAS_TRANSFORMS is that a slower code path + * might be taken for rendering the vector. Right now, we never + * really look at the flag, so it does not make any difference. + */ + if (transform != null) + layoutFlags |= FLAG_HAS_TRANSFORMS; + valid = false; + } + + + /** + * Returns flags that can be used for optimizing the rendering + * of this GlyphVector. + * + * @return a bit mask with the applicable flags set. + * + * @since 1.4 + * + * @see GlyphVector#FLAG_HAS_POSITION_ADJUSTMENTS + * @see GlyphVector#FLAG_HAS_TRANSFORMS + * @see GlyphVector#FLAG_RUN_RTL + * @see GlyphVector#FLAG_COMPLEX_GLYPHS + * @see GlyphVector#FLAG_MASK + */ + public int getLayoutFlags() + { + return layoutFlags; + } + + + /** + * Returns the positions of a range of glyphs in this vector. + * + * @param firstGlyphIndex the index of the first glyph whose + * position is retrieved. + * + * @param numGlyphs the number of glyphs whose positions + * are retrieved. + * + * @param outPositions an array for storing the results + * (the length must be at least twice numGlyphs), + * or null for freshly allocating an array. + * + * @return an array with the glyph positions. The horizontal + * position of the i-th glyph is at index 2 * + * i, the vertical position at index 2 * i + 1. + * + * @throws IllegalArgumentException if numGlyphs + * is less than zero. + * + * @throws IndexOutOfBoundsException if either + * firstGlyphIndex or (firstGlyphIndex + + * numGlyphs) is not in the range [0 .. getNumGlyphs() - + * 1]. + */ + public float[] getGlyphPositions(int firstGlyphIndex, + int numGlyphs, + float[] outPositions) + { + if (numGlyphs < 0) + throw new IllegalArgumentException(); + + validate(); + if (outPositions == null) + outPositions = new float[numGlyphs * 2]; + + System.arraycopy(/*src */ pos, /* srcStart */ firstGlyphIndex * 2, + /* dest */ outPositions, /* destStart */ 0, + /* length */ numGlyphs * 2); + return outPositions; + } + + + private float getAscent() + { + return fontDelegate.getAscent(fontSize, transform, + renderContext.isAntiAliased(), + renderContext.usesFractionalMetrics(), + /* horizontal */ true); + } + + + private float getDescent() + { + return fontDelegate.getDescent(fontSize, transform, + renderContext.isAntiAliased(), + renderContext.usesFractionalMetrics(), + /* horizontal */ true); + } + + + public Shape getGlyphLogicalBounds(int glyphIndex) + { + float x, y, ascent; + + validate(); + ascent = getAscent(); + x = pos[glyphIndex * 2]; + y = pos[glyphIndex * 2 + 1]; + + return new Rectangle2D.Float(x, y - ascent, + pos[(glyphIndex + 1) * 2] - x, + ascent - getDescent()); + } + + + public Shape getGlyphVisualBounds(int glyphIndex) + { + return getGlyphOutline(glyphIndex).getBounds2D(); + } + + + /** + * Determines the metrics of the glyph at the specified index. + * + * @param glyphIndex the index of the glyph whose metrics is to be + * retrieved. + * + * @throws IndexOutOfBoundsException if glyphIndex is + * not in the range . + */ + public GlyphMetrics getGlyphMetrics(int glyphIndex) + { + // FIXME: Not yet implemented. + throw new UnsupportedOperationException(); + } + + + /** + * Determines the justification information for the glyph at the + * specified index. + * + * @param glyphIndex the index of the glyph whose justification + * information is to be retrieved. + * + * @throws IndexOutOfBoundsException if glyphIndex is + * not in the range . + */ + public GlyphJustificationInfo getGlyphJustificationInfo(int glyphIndex) + { + // FIXME: Not yet implemented. + throw new UnsupportedOperationException(); + } + + + /** + * Determines whether another GlyphVector is for the same font and + * rendering context, uses the same glyphs and positions them to the + * same location. + * + * @param other the GlyphVector to compare with. + * + * @return true if the two vectors are equal, + * false otherwise. + */ + public boolean equals(GlyphVector other) + { + GNUGlyphVector o; + if (!(other instanceof GNUGlyphVector)) + return false; + + o = (GNUGlyphVector) other; + if ((this.font != o.font) + || (this.fontDelegate != o.fontDelegate) + || (this.renderContext != o.renderContext) + || (this.glyphs.length != o.glyphs.length)) + return false; + + for (int i = 0; i < glyphs.length; i++) + if (this.glyphs[i] != o.glyphs[i]) + return false; + + validate(); + o.validate(); + for (int i = 0; i < pos.length; i++) + if (this.pos[i] != o.pos[i]) + return false; + + return true; + } + + private void validate() + { + if (!valid) + performDefaultLayout(); + } +} diff --git a/libjava/classpath/gnu/java/awt/font/OpenTypeFontPeer.java b/libjava/classpath/gnu/java/awt/font/OpenTypeFontPeer.java new file mode 100644 index 000000000..d8bff1199 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/OpenTypeFontPeer.java @@ -0,0 +1,565 @@ +/* XFontPeer2.java -- A Java based TTF font peer for X + 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.font; + + +import gnu.java.awt.peer.ClasspathFontPeer; +import gnu.java.lang.CPStringBuilder; + +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.font.LineMetrics; +import java.awt.font.TextAttribute; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.text.CharacterIterator; +import java.text.StringCharacterIterator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Locale; +import java.util.Map; +import java.util.Properties; +import java.util.Set; + +public class OpenTypeFontPeer + extends ClasspathFontPeer +{ + + /** + * The font mapping as specified in the file fonts.properties. + */ + private static Properties fontProperties; + + /** + * The available font family names. + */ + private static Set availableFontNames; + + /** + * Font spec to file mapping. + */ + private static Map> fontToFileMap; + + static + { + fontProperties = new Properties(); + InputStream in = OpenTypeFontPeer.class.getResourceAsStream("fonts.properties"); + try + { + fontProperties.load(in); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + + private class XLineMetrics + extends LineMetrics + { + + private Font font; + private GlyphVector glyphVector; +// private CharacterIterator characterIterator; +// private int begin; +// private int limit; + private FontRenderContext fontRenderContext; + XLineMetrics(Font f, CharacterIterator ci, int b, int l, + FontRenderContext rc) + { + font = f; +// characterIterator = ci; +// begin = b; +// limit = l; + fontRenderContext = rc; + glyphVector = fontDelegate.createGlyphVector(font, fontRenderContext, + ci); + } + + public float getAscent() + { + return fontDelegate.getAscent(font.getSize(), fontRenderContext.getTransform(), + fontRenderContext.isAntiAliased(), + fontRenderContext.usesFractionalMetrics(), true); + } + + public int getBaselineIndex() + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public float[] getBaselineOffsets() + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public float getDescent() + { + return (int) fontDelegate.getDescent(font.getSize(), IDENDITY, false, + false, false); + } + + public float getHeight() + { + return (float) glyphVector.getLogicalBounds().getHeight(); + } + + public float getLeading() + { + return getHeight() - getAscent() - getDescent(); + } + + public int getNumChars() + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public float getStrikethroughOffset() + { + return 0.F; + } + + public float getStrikethroughThickness() + { + return 0.F; + } + + public float getUnderlineOffset() + { + return 0.F; + } + + public float getUnderlineThickness() + { + return 0.F; + } + + } + + private class XFontMetrics + extends FontMetrics + { + /** + * A cached point instance, to be used in #charWidth(). + */ + private Point2D cachedPoint = new Point2D.Double(); + + XFontMetrics(Font f) + { + super(f); + } + + public int getAscent() + { + return (int) fontDelegate.getAscent(getFont().getSize(), IDENDITY, + false, false, false); + } + + public int getDescent() + { + return (int) fontDelegate.getDescent(getFont().getSize(), IDENDITY, + false, false, false); + } + + public int getHeight() + { + GlyphVector gv = fontDelegate.createGlyphVector(getFont(), + new FontRenderContext(IDENDITY, false, false), + new StringCharacterIterator("m")); + Rectangle2D b = gv.getVisualBounds(); + return (int) b.getHeight(); + } + + public int charWidth(char c) + { + int code = fontDelegate.getGlyphIndex(c); + Point2D advance = cachedPoint; + fontDelegate.getAdvance(code, font.getSize2D(), IDENDITY, + false, false, true, advance); + return (int) advance.getX(); + } + + public int charsWidth(char[] chars, int offs, int len) + { + return stringWidth(new String(chars, offs, len)); + } + + public int stringWidth(String s) + { + GlyphVector gv = fontDelegate.createGlyphVector(getFont(), + new FontRenderContext(IDENDITY, false, false), + new StringCharacterIterator(s)); + Rectangle2D b = gv.getVisualBounds(); + return (int) b.getWidth(); + } + } + + /** + * The indendity transform, to be used in several methods. + */ + private static final AffineTransform IDENDITY = new AffineTransform(); + + private FontDelegate fontDelegate; + + public OpenTypeFontPeer(String name, int style, int size) + { + super(name, style, size); + try + { + String fontSpec = encodeFont(name, style); + String filename = mapFontToFilename(fontSpec); + File fontfile = new File(filename); + FileInputStream in = new FileInputStream(fontfile); + FileChannel ch = in.getChannel(); + ByteBuffer buffer = ch.map(FileChannel.MapMode.READ_ONLY, 0, + fontfile.length()); + fontDelegate = FontFactory.createFonts(buffer)[0]; + } + catch (Exception ex) + { + ex.printStackTrace(); + } + } + + public OpenTypeFontPeer(String name, Map atts) + { + super(name, atts); + try + { + String fontSpec = encodeFont(name, atts); + String filename = mapFontToFilename(fontSpec); + File fontfile = new File(filename); + FileInputStream in = new FileInputStream(fontfile); + FileChannel ch = in.getChannel(); + ByteBuffer buffer = ch.map(FileChannel.MapMode.READ_ONLY, 0, + fontfile.length()); + fontDelegate = FontFactory.createFonts(buffer)[0]; + } + catch (Exception ex) + { + ex.printStackTrace(); + } + } + + public boolean canDisplay(Font font, int c) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public int canDisplayUpTo(Font font, CharacterIterator i, int start, int limit) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public String getSubFamilyName(Font font, Locale locale) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public String getPostScriptName(Font font) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public int getNumGlyphs(Font font) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public int getMissingGlyphCode(Font font) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public byte getBaselineFor(Font font, char c) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public String getGlyphName(Font font, int glyphIndex) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public GlyphVector createGlyphVector(Font font, FontRenderContext frc, CharacterIterator ci) + { + return fontDelegate.createGlyphVector(font, frc, ci); + } + + public GlyphVector createGlyphVector(Font font, FontRenderContext ctx, int[] glyphCodes) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public GlyphVector layoutGlyphVector(Font font, FontRenderContext frc, char[] chars, int start, int limit, int flags) + { + StringCharacterIterator i = new StringCharacterIterator(new String(chars), start, limit, 0); + return fontDelegate.createGlyphVector(font, frc, i); + } + + public FontMetrics getFontMetrics(Font font) + { + return new XFontMetrics(font); + } + + public boolean hasUniformLineMetrics(Font font) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public LineMetrics getLineMetrics(Font font, CharacterIterator ci, int begin, int limit, FontRenderContext rc) + { + return new XLineMetrics(font, ci, begin, limit, rc); + } + + public Rectangle2D getMaxCharBounds(Font font, FontRenderContext rc) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + /** + * Encodes a font name + style + size specification into a X logical font + * description (XLFD) as described here: + * + * http://www.meretrx.com/e93/docs/xlfd.html + * + * This is implemented to look up the font description in the + * fonts.properties of this package. + * + * @param name the font name + * @param atts the text attributes + * + * @return the encoded font description + */ + public static String encodeFont(String name, Map atts) + { + String family = name; + if (family == null || family.equals("")) + family = (String) atts.get(TextAttribute.FAMILY); + if (family == null) + family = "SansSerif"; + + int style = 0; + // Detect italic attribute. + Float posture = (Float) atts.get(TextAttribute.POSTURE); + if (posture != null && !posture.equals(TextAttribute.POSTURE_REGULAR)) + style |= Font.ITALIC; + + // Detect bold attribute. + Float weight = (Float) atts.get(TextAttribute.WEIGHT); + if (weight != null && weight.compareTo(TextAttribute.WEIGHT_REGULAR) > 0) + style |= Font.BOLD; + + return encodeFont(name, style); + } + + /** + * Encodes a font name + style into a combined string. + * + * This is implemented to look up the font description in the + * fonts.properties of this package. + * + * @param name the font name + * @param style the font style + * + * @return the encoded font description + */ + static String encodeFont(String name, int style) + { + CPStringBuilder key = new CPStringBuilder(); + key.append(validName(name)); + key.append('/'); + switch (style) + { + case Font.BOLD: + key.append("b"); + break; + case Font.ITALIC: + key.append("i"); + break; + case (Font.BOLD | Font.ITALIC): + key.append("bi"); + break; + case Font.PLAIN: + default: + key.append("p"); + + } + + return key.toString(); + } + + /** + * Checks the specified font name for a valid font name. If the font name + * is not known, then this returns 'sansserif' as fallback. + * + * @param name the font name to check + * + * @return a valid font name + */ + static String validName(String name) + { + String retVal; + Set fontNames = getFontNames(); + if (fontNames.contains(name)) + { + retVal = name; + } + else + { + retVal = "SansSerif"; + } + return retVal; + } + + public static String[] getAvailableFontFamilyNames(Locale l) + { + Set fontNames = getFontNames(); + int numNames = fontNames.size(); + String[] ret = fontNames.toArray(new String[numNames]); + return ret; + } + + private static synchronized Set getFontNames() + { + if (availableFontNames == null) + { + HashSet familyNames = new HashSet(); + for (Object o : fontProperties.keySet()) + { + if (o instanceof String) + { + String key = (String) o; + int slashIndex = key.indexOf('/'); + String name = key.substring(0, slashIndex); + familyNames.add(name); + } + } + availableFontNames = familyNames; + } + return availableFontNames; + } + + /** + * Takes a font spec as returned by {@link #encodeFont(String, int)}, + * and returns the corresponding font file, or null if no such + * font mapping exists. + * + * @param fontSpec font name and style as returned by + * {@link #encodeFont(String, int)} + * + * @return filename of the corresponding font file + */ + private synchronized String mapFontToFilename(String fontSpec) + { + if (fontToFileMap == null) + { + fontToFileMap = new HashMap>(); + + // Initialize font spec to file mapping according to the + // font.properties. + for (Object o : fontProperties.keySet()) + { + if (o instanceof String) + { + String key = (String) o; + int slashIndex = key.indexOf('/'); + String name = key.substring(0, slashIndex); + String spec = key.substring(slashIndex + 1); + // Handle aliases in the 2nd pass below. + if (! spec.equals("a")) + { + Map specToFileMap = fontToFileMap.get(name); + if (specToFileMap == null) + { + specToFileMap = new HashMap(); + fontToFileMap.put(name, specToFileMap); + } + specToFileMap.put(spec, fontProperties.getProperty(key)); + } + } + } + // 2nd pass for handling aliases. + for (Object o : fontProperties.keySet()) + { + if (o instanceof String) + { + String key = (String) o; + int slashIndex = key.indexOf('/'); + String name = key.substring(0, slashIndex); + String spec = key.substring(slashIndex + 1); + // Handle aliases in the 2nd pass below. + if (spec.equals("a")) + { + String alias = fontProperties.getProperty(key); + Map specToFileMap = fontToFileMap.get(alias); + fontToFileMap.put(name, specToFileMap); + } + } + } + } + // Look up font file. + int slashIndex = fontSpec.indexOf('/'); + String name = fontSpec.substring(0, slashIndex); + String spec = fontSpec.substring(slashIndex + 1); + return fontToFileMap.get(name).get(spec); + } +} diff --git a/libjava/classpath/gnu/java/awt/font/autofit/AutoHinter.java b/libjava/classpath/gnu/java/awt/font/autofit/AutoHinter.java new file mode 100644 index 000000000..b0420ab7a --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/autofit/AutoHinter.java @@ -0,0 +1,83 @@ +/* AutoHinter.java -- The entry point into the hinter implementation. + 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.font.autofit; + +import gnu.java.awt.font.opentype.Hinter; +import gnu.java.awt.font.opentype.OpenTypeFont; +import gnu.java.awt.font.opentype.truetype.Fixed; +import gnu.java.awt.font.opentype.truetype.Zone; + +/** + * The public interface to the automatic gridfitter. + */ +public class AutoHinter + implements Hinter +{ + Latin latinScript; + LatinMetrics metrics; + GlyphHints hints; + + HintScaler scaler = new HintScaler(); + public void init(OpenTypeFont font) + { + // TODO: Should support other scripts too. + latinScript = new Latin(); + metrics = new LatinMetrics(font); + latinScript.initMetrics(metrics, font); + scaler.face = font; + } + + public void applyHints(Zone outline) + { + if (hints == null) + hints = new GlyphHints(); + scaler.xScale = Fixed.valueOf16(outline.scaleX * 64); + scaler.yScale = Fixed.valueOf16(outline.scaleY * 64); + latinScript.scaleMetrics(metrics, scaler); + latinScript.applyHints(hints, outline, metrics); + } + + public void setFlags(int flags) + { + if (hints == null) + hints = new GlyphHints(); + hints.flags = flags; + } + +} diff --git a/libjava/classpath/gnu/java/awt/font/autofit/AxisHints.java b/libjava/classpath/gnu/java/awt/font/autofit/AxisHints.java new file mode 100644 index 000000000..87f2abcc3 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/autofit/AxisHints.java @@ -0,0 +1,112 @@ +/* AxisHints.java -- Hints specific to an axis + 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.font.autofit; + +class AxisHints +{ + + Segment[] segments; + int majorDir; + int numSegments; + int numEdges; + Edge[] edges; + + AxisHints() + { + segments = new Segment[4]; + edges = new Edge[4]; + } + + Segment newSegment() + { + if (numSegments >= segments.length) + { + // Grow array. + int newMax = segments.length; + newMax += (newMax >> 2) + 4; // From FreeType. + Segment[] newSegs = new Segment[newMax]; + System.arraycopy(segments, 0, newSegs, 0, numSegments); + segments = newSegs; + } + Segment seg = new Segment(); + segments[numSegments] = seg; + numSegments++; + return seg; + } + + public Edge newEdge(int pos) + { + if (numEdges >= edges.length) + { + // Grow array. + int newMax = edges.length; + newMax += (newMax >> 2) + 4; // From FreeType. + Edge[] newEdges = new Edge[newMax]; + System.arraycopy(edges, 0, newEdges, 0, numEdges); + edges = newEdges; + } + int edgeIndex = numEdges; + Edge edge = edges[edgeIndex] = new Edge(); + while (edgeIndex > 0 && edges[edgeIndex - 1].fpos > pos) + { + edges[edgeIndex] = edges[edgeIndex - 1]; + edgeIndex--; + } + edges[edgeIndex] = edge; + numEdges++; + edge.fpos = pos; + + return edge; + + } + + int getEdgeIndex(Edge edge2) + { + int idx = -1; + for (int i = 0; i < numEdges; i++) + { + if (edges[i] == edge2) + { + idx = i; + break; + } + } + return idx; + } +} diff --git a/libjava/classpath/gnu/java/awt/font/autofit/Constants.java b/libjava/classpath/gnu/java/awt/font/autofit/Constants.java new file mode 100644 index 000000000..c5b90fa54 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/autofit/Constants.java @@ -0,0 +1,86 @@ +/* Constants.java -- Some constants used in the autofitter + 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.font.autofit; + +/** + * Some constants used in the autofitter. + */ +interface Constants +{ + + /** + * The horizontal dimension. + */ + static final int DIMENSION_HORZ = 0; + + /** + * The vertical dimension. + */ + static final int DIMENSION_VERT = 1; + + /** + * The number of dimensions. + */ + static final int DIMENSION_MAX = 2; + + /** + * Indicates a vector with no specific direction. + */ + static final int DIR_NONE = 0; + + /** + * Right direction. + */ + static final int DIR_RIGHT = 1; + + /** + * Left direction. + */ + static final int DIR_LEFT = -1; + + /** + * Up direction. + */ + static final int DIR_UP = 2; + + /** + * Down direction. + */ + static final int DIR_DOWN = -2; +} diff --git a/libjava/classpath/gnu/java/awt/font/autofit/Edge.java b/libjava/classpath/gnu/java/awt/font/autofit/Edge.java new file mode 100644 index 000000000..6420fa1cb --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/autofit/Edge.java @@ -0,0 +1,82 @@ +/* Edge.java -- An edge of segments + 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.font.autofit; + +import gnu.java.lang.CPStringBuilder; + +class Edge +{ + int fpos; + Segment first; + Segment last; + int opos; + Edge link; + Edge serif; + int flags; + int dir; + Width blueEdge; + int pos; + int scale; + + public String toString() + { + CPStringBuilder s = new CPStringBuilder(); + s.append("[Edge] id"); + s.append(hashCode()); + s.append(", fpos: "); + s.append(fpos); + s.append(", opos: "); + s.append(opos); + s.append(", pos: "); + s.append(pos); + s.append(", dir: "); + s.append(dir); + s.append(", serif: "); + s.append(serif != null ? serif.hashCode() : "null"); + s.append(", link: "); + s.append(link != null ? link.hashCode() : "null"); + s.append(", flags: " + flags); + s.append(", blue: " + blueEdge); + s.append(", first: "); + s.append(first == null ? "null" : first.hashCode()); + s.append(", last: "); + s.append(last == null ? "null" : last.hashCode()); + return s.toString(); + } +} diff --git a/libjava/classpath/gnu/java/awt/font/autofit/GlyphHints.java b/libjava/classpath/gnu/java/awt/font/autofit/GlyphHints.java new file mode 100644 index 000000000..033d63fa4 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/autofit/GlyphHints.java @@ -0,0 +1,640 @@ +/* GlyphHints.java -- Data and methods for actual hinting + 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.font.autofit; + +import gnu.java.awt.font.FontDelegate; +import gnu.java.awt.font.opentype.truetype.Fixed; +import gnu.java.awt.font.opentype.truetype.Point; +import gnu.java.awt.font.opentype.truetype.Zone; + +/** + * The data and methods used for the actual hinting process. + */ +class GlyphHints + implements Constants +{ + + int xScale; + int xDelta; + int yScale; + int yDelta; + + AxisHints[] axis; + + Point[] points; + int numPoints; + int maxPoints; + + Point[] contours; + int numContours; + int maxContours; + + ScriptMetrics metrics; + + int flags; + + GlyphHints() + { + axis = new AxisHints[Constants.DIMENSION_MAX]; + axis[Constants.DIMENSION_VERT] = new AxisHints(); + axis[Constants.DIMENSION_HORZ] = new AxisHints(); + + xScale = Fixed.ONE; + yScale = Fixed.ONE; + } + + void rescale(ScriptMetrics m) + { + metrics = m; + // TODO: Copy scalerFlags. + } + + void reload(Zone outline) + { + numPoints = 0; + numContours = 0; + axis[0].numSegments = 0; + axis[0].numEdges = 0; + axis[1].numSegments = 0; + axis[1].numEdges = 0; + + // Create/reallocate the contours array. + int newMax = outline.getNumContours(); + if (newMax > maxContours || contours == null) + { + newMax = (newMax + 3) & ~3; // Taken from afhints.c . + Point[] newContours = new Point[newMax]; + if (contours != null) + { + System.arraycopy(contours, 0, newContours, 0, maxContours); + } + contours = newContours; + maxContours = newMax; + } + + // Create/reallocate the points array. + newMax = outline.getSize() + 2; + if (newMax > maxPoints || points == null) + { + newMax = (newMax + 2 + 7) & ~7; // Taken from afhints.c . + Point[] newPoints = new Point[newMax]; + if (points != null) + { + System.arraycopy(points, 0, newPoints, 0, maxPoints); + } + points = newPoints; + maxPoints = newMax; + } + + numPoints = outline.getSize() - 4; // 4 phantom points. + numContours = outline.getNumContours(); + + // Set major direction. We don't handle Type 1 fonts yet. + axis[DIMENSION_HORZ].majorDir = DIR_UP; + axis[DIMENSION_VERT].majorDir = DIR_LEFT; + + // TODO: Freetype seems to scale and translate the glyph at that point. + // I suppose that this is not really needed. + // The scales are scaling from font units to 1/64 device pixels. + xScale = Fixed.valueOf16(outline.scaleX * 64); + yScale = Fixed.valueOf16(outline.scaleY * 64); + + // FIXME: What is that xDelta and yDelta used for? + System.arraycopy(outline.getPoints(), 0, points, 0, numPoints); + + // Setup prev and next and contours array. + // TODO: Probably cache this. + contours = new Point[numContours]; + Point currentContour = points[0]; + for (int i = 0, cIndex = 0; i < numPoints; i++) + { + // Start new contour when the last point has been a contour end. + if (outline.isContourEnd(i)) + { + // Connect the contour end point to the start point. + points[i].setNext(currentContour); + currentContour.setPrev(points[i]); + contours[cIndex] = currentContour; + cIndex++; + currentContour = i < numPoints - 1 ? points[i + 1] : null; + } + else + { + // Connect the current and the previous point. + points[i].setNext(points[i + 1]); + points[i + 1].setPrev(points[i]); + } + } + // Compute directions of in and out vectors of all points as well + // as the weak point flag. + for (int i = 0; i < numPoints; i++) + { + // Compute in and out dir. + Point p = points[i]; + Point prev = p.getPrev(); + int inX = p.getOrigX() - prev.getOrigX(); + int inY = p.getOrigY() - prev.getOrigY(); + p.setInDir(Utils.computeDirection(inX, inY)); + Point next = p.getNext(); + int outX = next.getOrigX() - p.getOrigX(); + int outY = next.getOrigY() - p.getOrigY(); + p.setOutDir(Utils.computeDirection(outX, outY)); + + if (p.isControlPoint()) + { + setWeakPoint(p); + } + else if (p.getOutDir() == p.getInDir()) + { + if (p.getOutDir() != DIR_NONE) + setWeakPoint(p); + else + { + int angleIn = Utils.atan(inY, inX); + int angleOut = Utils.atan(outY, outX); + int delta = Utils.angleDiff(angleIn, angleOut); + if (delta < 2 && delta > -2) + setWeakPoint(p); + } + } + else if (p.getInDir() == - p.getOutDir()) + { + setWeakPoint(p); + } + } + computeInflectionPoints(); + } + + private void setWeakPoint(Point p) + { + p.setFlags((byte) (p.getFlags() | Point.FLAG_WEAK_INTERPOLATION)); + } + + /** + * Computes the inflection points for a glyph. + */ + private void computeInflectionPoints() + { + // Do each contour separately. + contours : for (int c = 0; c < contours.length; c++) + { + Point point = contours[c]; + Point first = point; + Point start = point; + Point end = point; + do + { + end = end.getNext(); + if (end == first) + continue contours; + } while (end.getOrigX() == first.getOrigX() + && end.getOrigY() == first.getOrigY()); + + // Extend segment start whenever possible. + Point before = start; + int angleIn; + int angleSeg = Utils.atan(end.getOrigX() - start.getOrigX(), + end.getOrigY() - start.getOrigY()); + do + { + do + { + start = before; + before = before.getPrev(); + if (before == first) + continue contours; + } while (before.getOrigX() == start.getOrigX() + && before.getOrigY() == start.getOrigY()); + angleIn = Utils.atan(start.getOrigX() - before.getOrigX(), + start.getOrigY() - before.getOrigY()); + } while (angleIn == angleSeg); + + first = start; + int diffIn = Utils.angleDiff(angleIn, angleSeg); + // Now, process all segments in the contour. + Point after; + boolean finished = false; + int angleOut, diffOut; + do + { + // First, extend the current segment's end whenever possible. + after = end; + do + { + do + { + end = after; + after = after.getNext(); + if (after == first) + finished = true; + } while (end.getOrigX() == after.getOrigX() + && end.getOrigY() == after.getOrigY()); + angleOut = Utils.atan(after.getOrigX() - end.getOrigX(), + after.getOrigY() - end.getOrigY()); + } while (angleOut == angleSeg); + diffOut = Utils.angleDiff(angleSeg, angleOut); + if ((diffIn ^ diffOut) < 0) + { + // diffIn and diffOut have different signs, we have + // inflection points here. + do + { + start.addFlags(Point.FLAG_INFLECTION); + start = start.getNext(); + } while (start != end); + start.addFlags(Point.FLAG_INFLECTION); + } + start = end; + end = after; + angleSeg = angleOut; + diffIn = diffOut; + } while (! finished); + } + } + + boolean doHorizontal() + { + return (flags & FontDelegate.FLAG_NO_HINT_HORIZONTAL) == 0; + } + + boolean doVertical() + { + return (flags & FontDelegate.FLAG_NO_HINT_VERTICAL) == 0; + } + + void alignWeakPoints(int dim) + { + short touchFlag; + Point point; + // PASS 1 : Move segments to edge positions. + if (dim == DIMENSION_HORZ) + { + touchFlag = Point.FLAG_DONE_X; + for (int p = 0; p < numPoints; p++) + { + point = points[p]; + point.setU(point.getX()); + point.setV(point.getScaledX()); + } + } + else + { + touchFlag = Point.FLAG_DONE_Y; + for (int p = 0; p < numPoints; p++) + { + point = points[p]; + point.setU(point.getY()); + point.setV(point.getScaledY()); + } + } + point = points[0]; + for (int c = 0; c < numContours; c++) + { + point = contours[c]; + int idx = getPointIndex(point); + Point endPoint = point.getPrev(); + int endIdx = getPointIndex(endPoint); + int firstIdx = idx; + while (idx <= endIdx + && (point.getFlags() & touchFlag) == 0) + { + idx++; + point = points[idx]; + } + if (idx <= endIdx) + { + int firstTouched = idx; + int curTouched = idx; + idx++; + point = points[idx]; + while (idx <= endIdx) + { + if ((point.getFlags() & touchFlag) != 0) + { + // We found two successive touch points. We interpolate + // all contour points between them. + iupInterp(curTouched + 1, idx - 1, curTouched, idx); + curTouched = idx; + } + idx++; + point = points[idx]; + } + if (curTouched == firstTouched) + { + // This is a special case: Only one point was touched in the + // contour. We thus simply shift the whole contour. + iupShift(firstIdx, endIdx, curTouched); + } + else + { + // Now interpolate after the last touched point to the end + // of the contour. + iupInterp(curTouched + 1, endIdx, curTouched, firstTouched); + // If the first contour point isn't touched, interpolate + // from the contour start to the first touched point. + if (firstTouched > 0) + { + iupInterp(firstIdx, firstTouched - 1, curTouched, + firstTouched); + } + } + } + } + // Now store the values back. + if (dim == DIMENSION_HORZ) + { + for (int p = 0; p < numPoints; p++) + { + point = points[p]; + point.setX(point.getU()); + } + } + else + { + for (int p = 0; p < numPoints; p++) + { + point = points[p]; + point.setY(point.getU()); + } + } + } + + private void iupShift(int p1, int p2, int ref) + { + int delta = points[ref].getU() - points[ref].getV(); + for (int p = p1; p < ref; p++) + { + points[p].setU(points[p].getV() + delta); + } + for (int p = ref + 1; p <= p2; p++) + { + points[p].setU(points[p].getV() + delta); + } + } + + private void iupInterp(int p1, int p2, int ref1, int ref2) + { + int v1 = points[ref1].getV(); + int v2 = points[ref2].getV(); + int d1 = points[ref1].getU() - v1; + int d2 = points[ref2].getU() - v2; + if (p1 > p2) + return; + if (v1 == v2) + { + for (int p = p1; p <= p2; p++) + { + int u = points[p].getV(); + if (u <= v1) + u += d1; + else + u += d2; + points[p].setU(u); + } + } + else if (v1 < v2) + { + for (int p = p1; p <= p2; p++) + { + int u = points[p].getV(); + if (u <= v1) + u += d1; + else if (u >= v2) + u += d2; + else + { + u = points[ref1].getU() + Utils.mulDiv(u - v1, + points[ref2].getU() + - points[ref1].getU(), + v2 - v1); + } + points[p].setU(u); + } + } + else + { + for (int p = p1; p <= p2; p++) + { + int u = points[p].getV(); + if (u <= v2) + u += d2; + else if (u >= v1) + u += d1; + else + { + u = points[ref1].getU() + Utils.mulDiv(u - v1, + points[ref2].getU() + - points[ref1].getU(), + v2 - v1); + } + points[p].setU(u); + } + } + } + + void alignStrongPoints(int dim) + { + AxisHints ax = axis[dim]; + Edge[] edges = ax.edges; + int numEdges = ax.numEdges; + short touchFlag; + if (dim == DIMENSION_HORZ) + touchFlag = Point.FLAG_DONE_X; + else + touchFlag = Point.FLAG_DONE_Y; + + if (numEdges > 0) + { + for (int p = 0; p < numPoints; p++) + { + Point point = points[p]; + if ((point.getFlags() & touchFlag) != 0) + continue; + // If this point is a candidate for weak interpolation, we + // interpolate it after all strong points have been processed. + if ((point.getFlags() & Point.FLAG_WEAK_INTERPOLATION) != 0 + && (point.getFlags() & Point.FLAG_INFLECTION) == 0) + continue; + + int u, ou, fu, delta; + if (dim == DIMENSION_VERT) + { + u = point.getOrigY(); + ou = point.getScaledY(); + } + else + { + u = point.getOrigX(); + ou = point.getScaledX(); + } + fu = u; + // Is the point before the first edge? + Edge edge = edges[0]; + // Inversed vertical dimension. + delta = edge.fpos - u; + if (delta >= 0) + { + u = edge.pos - (edge.opos - ou); + storePoint(point, u, dim, touchFlag); + } + else + { + // Is the point after the last edge? + edge = edges[numEdges - 1]; + delta = u - edge.fpos; + if (delta >= 0) + { + u = edge.pos + (ou - edge.opos); + storePoint(point, u, dim, touchFlag); + } + else + { + // Find enclosing edges. + int min = 0; + int max = numEdges; + int mid, fpos; + boolean found = false; + while (min < max) + { + mid = (max + min) / 2; + edge = edges[mid]; + fpos = edge.fpos; + if (u < fpos) + max = mid; + else if (u > fpos) + min = mid + 1; + else + { + // Directly on the edge. + u = edge.pos; + storePoint(point, u, dim, touchFlag); + found = true; + break; + } + } + if (! found) + { + Edge before = edges[min - 1]; + Edge after = edges[min]; + if (before.scale == 0) + { + before.scale = Fixed.div16(after.pos - before.pos, + after.fpos - before.fpos); + } + u = before.pos + Fixed.mul16(fu - before.fpos, + before.scale); + } + storePoint(point, u, dim, touchFlag); + } + } + } + } + } + + private void storePoint(Point p, int u, int dim, short touchFlag) + { + if (dim == DIMENSION_HORZ) + p.setX(u); + else + p.setY(u); + p.addFlags(touchFlag); + } + + void alignEdgePoints(int dim) + { + AxisHints ax = axis[dim]; + Edge[] edges = ax.edges; + int numEdges = ax.numEdges; + for (int e = 0; e < numEdges; e++) + { + Edge edge = edges[e]; + Segment seg = edge.first; + do + { + Point point = seg.first; + while (true) + { + if (dim == DIMENSION_HORZ) + { + point.setX(edge.pos); + point.addFlags(Point.FLAG_DONE_X); + } + else + { + point.setY(edge.pos); + point.addFlags(Point.FLAG_DONE_Y); + } + if (point == seg.last) + break; + point = point.getNext(); + } + seg = seg.edgeNext; + } while (seg != edge.first); + } + } + + private int getPointIndex(Point p) + { + int idx = -1; + for (int i = 0; i < numPoints; i++) + { + if (p == points[i]) + { + idx = i; + break; + } + } + return idx; + } + + public boolean doAlignEdgePoints() + { + return (flags & FontDelegate.FLAG_NO_HINT_EDGE_POINTS) == 0; + } + + public boolean doAlignStrongPoints() + { + return (flags & FontDelegate.FLAG_NO_HINT_STRONG_POINTS) == 0; + } + + public boolean doAlignWeakPoints() + { + return (flags & FontDelegate.FLAG_NO_HINT_WEAK_POINTS) == 0; + } +} diff --git a/libjava/classpath/gnu/java/awt/font/autofit/HintScaler.java b/libjava/classpath/gnu/java/awt/font/autofit/HintScaler.java new file mode 100644 index 000000000..01276b4db --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/autofit/HintScaler.java @@ -0,0 +1,53 @@ +/* Scaler.java -- FIXME: briefly describe file purpose + 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.font.autofit; + +import gnu.java.awt.font.opentype.OpenTypeFont; + +class HintScaler +{ + + int xScale; + int xDelta; + int yScale; + int yDelta; + OpenTypeFont face; + int renderMode; + +} diff --git a/libjava/classpath/gnu/java/awt/font/autofit/Latin.java b/libjava/classpath/gnu/java/awt/font/autofit/Latin.java new file mode 100644 index 000000000..c132c2cdc --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/autofit/Latin.java @@ -0,0 +1,1363 @@ +/* Latin.java -- Latin specific glyph handling + 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.font.autofit; + +import java.awt.geom.AffineTransform; +import java.util.HashSet; + +import gnu.java.awt.font.opentype.OpenTypeFont; +import gnu.java.awt.font.opentype.truetype.Fixed; +import gnu.java.awt.font.opentype.truetype.Point; +import gnu.java.awt.font.opentype.truetype.Zone; + +/** + * Implements Latin specific glyph handling. + */ +class Latin + implements Script, Constants +{ + + static final int MAX_WIDTHS = 16; + + private final static int MAX_TEST_CHARS = 12; + + /** + * The types of the 6 blue zones. + */ + private static final int CAPITAL_TOP = 0; + private static final int CAPITAL_BOTTOM = 1; + private static final int SMALL_F_TOP = 2; + private static final int SMALL_TOP = 3; + private static final int SMALL_BOTTOM = 4; + private static final int SMALL_MINOR = 5; + static final int BLUE_MAX = 6; + + /** + * The test chars for the blue zones. + * + * @see #initBlues(LatinMetrics, OpenTypeFont) + */ + private static final String[] TEST_CHARS = + new String[]{"THEZOCQS", "HEZLOCUS", "fijkdbh", + "xzroesc", "xzroesc", "pqgjy"}; + + public void applyHints(GlyphHints hints, Zone outline, ScriptMetrics metrics) + { + hints.reload(outline); + hints.rescale(metrics); + if (hints.doHorizontal()) + { + detectFeatures(hints, DIMENSION_HORZ); + } + if (hints.doVertical()) + { + detectFeatures(hints, DIMENSION_VERT); + computeBlueEdges(hints, (LatinMetrics) metrics); + } + // Grid-fit the outline. + for (int dim = 0; dim < DIMENSION_MAX; dim++) + { + if (dim == DIMENSION_HORZ && hints.doHorizontal() + || dim == DIMENSION_VERT && hints.doVertical()) + { + hintEdges(hints, dim); + if (hints.doAlignEdgePoints()) + hints.alignEdgePoints(dim); + if (hints.doAlignStrongPoints()) + hints.alignStrongPoints(dim); + if (hints.doAlignWeakPoints()) + hints.alignWeakPoints(dim); + + } + } + // FreeType does a save call here. I guess that's not needed as we operate + // on the live glyph data anyway. + } + + private void hintEdges(GlyphHints hints, int dim) + { + AxisHints axis = hints.axis[dim]; + Edge[] edges = axis.edges; + int numEdges = axis.numEdges; + Edge anchor = null; + int hasSerifs = 0; + + // We begin by aligning all stems relative to the blue zone if + // needed -- that's only for horizontal edges. + if (dim == DIMENSION_VERT) + { + for (int e = 0; e < numEdges; e++) + { + Edge edge = edges[e]; + if ((edge.flags & Segment.FLAG_EDGE_DONE) != 0) + continue; + + Width blue = edge.blueEdge; + Edge edge1 = null; + Edge edge2 = edge.link; + if (blue != null) + { + edge1 = edge; + } + else if (edge2 != null && edge2.blueEdge != null) + { + blue = edge2.blueEdge; + edge1 = edge2; + edge2 = edge; + } + if (edge1 == null) + continue; + + edge1.pos = blue.fit; + edge1.flags |= Segment.FLAG_EDGE_DONE; + + if (edge2 != null && edge2.blueEdge == null) + { + alignLinkedEdge(hints, dim, edge1, edge2); + edge2.flags |= Segment.FLAG_EDGE_DONE; + } + if (anchor == null) + anchor = edge; + } + } + + // Now we will align all stem edges, trying to maintain the + // relative order of stems in the glyph. + for (int e = 0; e < numEdges; e++) + { + Edge edge = edges[e]; + if ((edge.flags & Segment.FLAG_EDGE_DONE) != 0) + continue; + Edge edge2 = edge.link; + if (edge2 == null) + { + hasSerifs++; + continue; + } + // Now align the stem. + // This should not happen, but it's better to be safe. + if (edge2.blueEdge != null || axis.getEdgeIndex(edge2) < e) + { + alignLinkedEdge(hints, dim, edge2, edge); + edge.flags |= Segment.FLAG_EDGE_DONE; + continue; + } + + if (anchor == null) + { + int orgLen = edge2.opos - edge.opos; + int curLen = computeStemWidth(hints, dim, orgLen, edge.flags, + edge2.flags); + int uOff, dOff, orgCenter, curPos1, error1, error2; + if (curLen <= 64) // < 1 Pixel. + { + uOff = 32; + dOff = 32; + } + else + { + uOff = 38; + dOff = 26; + } + if (curLen < 96) + { + orgCenter = edge.opos + (orgLen >> 1); + curPos1 = Utils.pixRound(orgCenter); + error1 = orgCenter - (curPos1 - uOff); + if (error1 < 0) + error1 = -error1; + error2 = orgCenter - (curPos1 + dOff); + if (error2 < 0) + error2 = -error2; + if (error1 < error2) + { + curPos1 -= uOff; + } + else + { + curPos1 += dOff; + } + edge.pos = curPos1 - curLen / 2; + edge2.pos = curPos1 + curLen / 2; + } + else + { + edge.pos = Utils.pixRound(edge.opos); + } + anchor = edge; + edge.flags |= Segment.FLAG_EDGE_DONE; + alignLinkedEdge(hints, dim, edge, edge2); + } + else + { + int aDiff = edge.opos - anchor.opos; + int orgPos = anchor.pos + aDiff; + int orgLen = edge2.opos - edge.opos; + int orgCenter = orgPos + (orgLen >> 1); + int curLen = computeStemWidth(hints, dim, orgLen, edge.flags, + edge2.flags); + //System.err.println("stem width: " + curLen); + if (curLen < 96) + { + int uOff, dOff; + int curPos1 = Utils.pixRound(orgCenter); + if (curLen <= 64) + { + uOff = 32; + dOff = 32; + } + else + { + uOff = 38; + dOff = 26; + } + int delta1 = orgCenter - (curPos1 - uOff); + if (delta1 < 0) + delta1 = -delta1; + int delta2 = orgCenter - (curPos1 + dOff); + if (delta2 < 0) + delta2 = -delta2; + if (delta1 < delta2) + { + curPos1 -= uOff; + } + else + { + curPos1 += dOff; + } + edge.pos = curPos1 - curLen / 2; + edge2.pos = curPos1 + curLen / 2; + } + else + { + orgPos = anchor.pos + (edge.opos - anchor.opos); + orgLen = edge2.opos - edge.opos; + orgCenter = orgPos + (orgLen >> 1); + curLen = computeStemWidth(hints, dim, orgLen, edge.flags, + edge2.flags); + int curPos1 = Utils.pixRound(orgPos); + int delta1 = curPos1 + (curLen >> 1) - orgCenter; + if (delta1 < 0) + delta1 = -delta1; + int curPos2 = Utils.pixRound(orgPos + orgLen) - curLen; + int delta2 = curPos2 + (curLen >> 1) - orgCenter; + if (delta2 < 0) + delta2 = -delta2; + edge.pos = (delta1 < delta2) ? curPos1 : curPos2; + edge2.pos = edge.pos + curLen; + } + edge.flags |= Segment.FLAG_EDGE_DONE; + edge2.flags |= Segment.FLAG_EDGE_DONE; + + if (e > 0 && edge.pos < edges[e - 1].pos) + { + edge.pos = edges[e - 1].pos; + } + } + } + // TODO: Implement the lowercase m symmetry thing. + + // Now we hint the remaining edges (serifs and singles) in order + // to complete our processing. + if (hasSerifs > 0 || anchor == null) + { + for (int e = 0; e < numEdges; e++) + { + Edge edge = edges[e]; + if ((edge.flags & Segment.FLAG_EDGE_DONE) != 0) + continue; + if (edge.serif != null) + { + alignSerifEdge(hints, edge.serif, edge); + } + else if (anchor == null) + { + edge.pos = Utils.pixRound(edge.opos); + anchor = edge; + } + else + { + edge.pos = anchor.pos + + Utils.pixRound(edge.opos - anchor.opos); + } + edge.flags |= Segment.FLAG_EDGE_DONE; + + if (e > 0 && edge.pos < edges[e - 1].pos) + { + edge.pos = edges[e - 1].pos; + } + if (e + 1 < numEdges + && (edges[e + 1].flags & Segment.FLAG_EDGE_DONE) != 0 + && edge.pos > edges[e + 1].pos) + { + edge.pos = edges[e + 1].pos; + } + } + } + + // Debug: print all hinted edges. + // System.err.println("hinted edges: " ); + // for (int i = 0; i < numEdges; i++) + // { + // System.err.println("edge#" + i + ": " + edges[i]); + // } + } + + private void alignSerifEdge(GlyphHints hints, Edge base, Edge serif) + { + serif.pos = base.pos + (serif.opos - base.opos); + } + + private int computeStemWidth(GlyphHints hints, int dim, int width, + int baseFlags, int stemFlags) + { + LatinMetrics metrics = (LatinMetrics) hints.metrics; + LatinAxis axis = metrics.axis[dim]; + int dist = width; + int sign = 0; + boolean vertical = dim == DIMENSION_VERT; + if (! doStemAdjust(hints)) + return width; + if (dist < 0) + { + dist = -width; + sign = 1; + } + if ((vertical && ! doVertSnap(hints)) || ! vertical && ! doHorzSnap(hints)) + { + // Smooth hinting process. Very lightly quantize the stem width. + // Leave the widths of serifs alone. + if ((stemFlags & Segment.FLAG_EDGE_SERIF) != 0 && vertical + && dist < 3 * 64) + { + return doneWidth(dist, sign); + } + else if ((baseFlags & Segment.FLAG_EDGE_ROUND) != 0) + { + if (dist < 80) + dist = 64; + } + else if (dist < 56) + { + dist = 56; + } + if (axis.widthCount > 0) + { + int delta; + if (axis.widthCount > 0) + { + delta = dist - axis.widths[0].cur; + if (delta < 0) + { + delta = -delta; + } + if (delta < 40) + { + dist = axis.widths[0].cur; + if (dist < 48) + dist = 48; + return doneWidth(dist, sign); + } + } + if (dist < 3 * 64) // < 3 pixels. + { + delta = dist & 63; + dist &= -64; + if (delta < 10) + dist += delta; + else if (delta < 32) + dist += 10; + else if (delta < 54) + dist += 54; + else + dist += delta; + + } + else + { + dist = (dist + 32) & ~63; + } + } + } + else + { + // Strong hinting process: Snap the stem width to integer pixels. + dist = snapWidth(axis.widths, axis.widthCount, dist); + if (vertical) + { + // In the case of vertical hinting, always round + // the stem heights to integer pixels. + if (dist >= 64) + dist = (dist + 16) & ~63; + else + dist = 64; + } + else + { + if (doMono(hints)) + { + // Monochrome horizontal hinting: Snap widths to integer pixels + // with a different threshold. + if (dist < 64) + dist = 64; + else + dist = (dist + 32) & ~63; + } + else + { + // For anti-aliased hinting, we adopt a more subtle + // approach: We strengthen small stems, round those stems + // whose size is between 1 and 2 pixels to an integer, + // otherwise nothing. + if (dist < 48) + dist = (dist + 64) >> 1; + else if (dist < 128) + dist = (dist + 22) & ~63; + else + // Round otherwise to prevent color fringes in LCD mode. + dist = (dist + 32) & ~63; + } + } + } + return doneWidth(dist, sign); + } + + private boolean doMono(GlyphHints hints) + { + return true; + } + + private int snapWidth(Width[] widths, int count, int width) + { + int best = 64 + 32 + 2; + int reference = width; + for (int n = 0; n < count; n++) + { + int w = widths[n].cur; + int dist = width - w; + if (dist < 0) + dist = -dist; + if (dist < best) + { + best = dist; + reference = w; + } + } + int scaled = Utils.pixRound(reference); + if (width >= reference) + { + if (width < scaled + 48) + width = reference; + } + else + { + if (width > scaled + 48) + width = reference; + } + return width; + } + + private int doneWidth(int w, int s) + { + if (s == 1) + w = -w; + return w; + } + + private boolean doVertSnap(GlyphHints hints) + { + // TODO Auto-generated method stub + return true; + } + + private boolean doHorzSnap(GlyphHints hints) + { + // TODO Auto-generated method stub + return true; + } + + private boolean doStemAdjust(GlyphHints hints) + { + // TODO Auto-generated method stub + return true; + } + + private void alignLinkedEdge(GlyphHints hints, int dim, Edge base, Edge stem) + { + int dist = stem.opos - base.opos; + int fitted = computeStemWidth(hints, dim, dist, base.flags, stem.flags); + stem.pos = base.pos + fitted; + } + + public void doneMetrics(ScriptMetrics metrics) + { + // TODO Auto-generated method stub + + } + + /** + * Initializes the hints object. + * + * @param hints the hints to initialize + * @param metrics the metrics to use + */ + public void initHints(GlyphHints hints, ScriptMetrics metrics) + { + hints.rescale(metrics); + LatinMetrics lm = (LatinMetrics) metrics; + hints.xScale = lm.axis[DIMENSION_HORZ].scale; + hints.xDelta = lm.axis[DIMENSION_HORZ].delta; + hints.yScale = lm.axis[DIMENSION_VERT].scale; + hints.yDelta = lm.axis[DIMENSION_VERT].delta; + // TODO: Set the scaler and other flags. + } + + /** + * Initializes the script metrics. + * + * @param metrics the script metrics to initialize + * @param face the font + */ + public void initMetrics(ScriptMetrics metrics, OpenTypeFont face) + { + assert metrics instanceof LatinMetrics; + LatinMetrics lm = (LatinMetrics) metrics; + lm.unitsPerEm = face.unitsPerEm; + + // TODO: Check for latin charmap. + + initWidths(lm, face, 'o'); + initBlues(lm, face); + } + + public void scaleMetrics(ScriptMetrics metrics, HintScaler scaler) + { + LatinMetrics lm = (LatinMetrics) metrics; + lm.scaler.renderMode = scaler.renderMode; + lm.scaler.face = scaler.face; + scaleMetricsDim(lm, scaler, DIMENSION_HORZ); + scaleMetricsDim(lm, scaler, DIMENSION_VERT); + } + + private void scaleMetricsDim(LatinMetrics lm, HintScaler scaler, int dim) + { + int scale; + int delta; + if (dim == DIMENSION_HORZ) + { + scale = scaler.xScale; + delta = scaler.xDelta; + } + else + { + scale = scaler.yScale; + delta = scaler.yDelta; + } + LatinAxis axis = lm.axis[dim]; + if (axis.orgScale == scale && axis.orgDelta == delta) + // No change, no need to adjust. + return; + axis.orgScale = scale; + axis.orgDelta = delta; + + // Correct X and Y scale to optimize the alignment of the top small + // letters to the pixel grid. + LatinAxis axis2 = lm.axis[DIMENSION_VERT]; + LatinBlue blue = null; +// for (int nn = 0; nn < axis2.blueCount; nn++) +// { +// if ((axis2.blues[nn].flags & LatinBlue.FLAG_ADJUSTMENT) != 0) +// { +// blue = axis2.blues[nn]; +// break; +// } +// } +// if (blue != null) +// { +// int scaled = Fixed.mul16(blue.shoot.org, scaler.yScale); +// int fitted = Utils.pixRound(scaled); +// if (scaled != fitted) +// { +// if (dim == DIMENSION_HORZ) +// { +// if (fitted < scaled) +// { +// scale -= scale / 50; +// } +// } +// else +// { +// scale = Utils.mulDiv(scale, fitted, scaled); +// } +// } +// } + axis.scale = scale; + axis.delta = delta; + if (dim == DIMENSION_HORZ) + { + lm.scaler.xScale = scale; + lm.scaler.xDelta = delta; + } + else + { + lm.scaler.yScale = scale; + lm.scaler.yDelta = delta; + } + // Scale the standard widths. + for (int nn = 0; nn < axis.widthCount; nn++) + { + Width w = axis.widths[nn]; + w.cur = Fixed.mul16(w.org, scale); + w.fit = w.cur; + } + // Scale blue zones. + if (dim == DIMENSION_VERT) + { + for (int nn = 0; nn < axis.blueCount; nn++) + { + blue = axis.blues[nn]; + blue.ref.cur = Fixed.mul16(blue.ref.org, scale) + delta; + blue.ref.fit = blue.ref.cur; + blue.shoot.cur = Fixed.mul16(blue.ref.org, scale) + delta; + blue.flags &= ~LatinBlue.FLAG_BLUE_ACTIVE; + // A blue zone is only active if it is less than 3/4 pixels tall. + int dist = Fixed.mul16(blue.ref.org - blue.shoot.org, scale); + if (dist <= 48 && dist >= -48) + { + int delta1 = blue.shoot.org - blue.ref.org; + int delta2 = delta1; + if (delta1 < 0) + delta2 = -delta2; + delta2 = Fixed.mul16(delta2, scale); + if (delta2 < 32) + delta2 = 0; + else if (delta2 < 64) + delta2 = 32 + (((delta2 - 32) + 16) & ~31); + else + delta2 = Utils.pixRound(delta2); + if (delta1 < 0) + delta2 = -delta2; + blue.ref.fit = Utils.pixRound(blue.ref.cur); + blue.shoot.fit = blue.ref.fit + delta2; + blue.flags |= LatinBlue.FLAG_BLUE_ACTIVE; + } + } + } + } + + /** + * Determines the standard stem widths. + * + * @param metrics the metrics to use + * @param face the font face + * @param ch the character that is used for getting the widths + */ + private void initWidths(LatinMetrics metrics, OpenTypeFont face, char ch) + { + GlyphHints hints = new GlyphHints(); + metrics.axis[DIMENSION_HORZ].widthCount = 0; + metrics.axis[DIMENSION_VERT].widthCount = 0; + int glyphIndex = face.getGlyph(ch); + Zone outline = face.getRawGlyphOutline(glyphIndex, IDENTITY); + LatinMetrics dummy = new LatinMetrics(); + HintScaler scaler = dummy.scaler; + dummy.unitsPerEm = metrics.unitsPerEm; + scaler.xScale = scaler.yScale = 10000; + scaler.xDelta = scaler.yDelta = 0; + scaler.face = face; + hints.rescale(dummy); + hints.reload(outline); + for (int dim = 0; dim < DIMENSION_MAX; dim++) + { + LatinAxis axis = metrics.axis[dim]; + AxisHints axHints = hints.axis[dim]; + int numWidths = 0; + computeSegments(hints, dim); + linkSegments(hints, dim); + Segment[] segs = axHints.segments; + HashSet touched = new HashSet(); + for (int i = 0; i < segs.length; i++) + { + Segment seg = segs[i]; + Segment link = seg.link; + if (link != null && link.link == seg && ! touched.contains(link)) + { + int dist = Math.abs(seg.pos - link.pos); + if (numWidths < MAX_WIDTHS) + axis.widths[numWidths++] = new Width(dist); + } + touched.add(seg); + } + Utils.sort(numWidths, axis.widths); + axis.widthCount = numWidths; + } + for (int dim = 0; dim < DIMENSION_MAX; dim++) + { + LatinAxis axis = metrics.axis[dim]; + int stdw = axis.widthCount > 0 ? axis.widths[0].org + : constant(metrics, 50); + axis.edgeDistanceTreshold= stdw / 5; + } + } + + void linkSegments(GlyphHints hints, int dim) + { + AxisHints axis = hints.axis[dim]; + Segment[] segments = axis.segments; + int numSegs = axis.numSegments; + int majorDir = axis.majorDir; + int lenThreshold = constant((LatinMetrics) hints.metrics, 8); + lenThreshold = Math.min(1, lenThreshold); + int lenScore = constant((LatinMetrics) hints.metrics, 3000); + for (int i1 = 0; i1 < numSegs; i1++) + { + Segment seg1 = segments[i1]; + // The fake segments are introduced to hint the metrics. + // Never link them to anything. + if (seg1.first == seg1.last || seg1.dir != majorDir) + continue; + for (int i2 = 0; i2 < numSegs; i2++) + { + Segment seg2 = segments[i2]; + if (seg2 != seg1 && seg1.dir + seg2.dir == 0) + { + int pos1 = seg1.pos; + int pos2 = seg2.pos; + // The vertical coords are swapped compared to how FT handles + // this. + int dist = dim == DIMENSION_VERT ? pos1 - pos2 : pos2 - pos1; + if (dist >= 0) + { + int min = seg1.minPos; + int max = seg1.maxPos; + int len, score; + if (min < seg2.minPos) + min = seg2.minPos; + if (max > seg2.maxPos) + max = seg2.maxPos; + len = max - min; + if (len > lenThreshold) + { + score = dist + lenScore / len; + if (score < seg1.score) + { + seg1.score = score; + seg1.link = seg2; + } + if (score < seg2.score) + { + seg2.score = score; + seg2.link = seg1; + } + } + } + } + } + } + for (int i1 = 0; i1 < numSegs; i1++) + { + Segment seg1 = segments[i1]; + Segment seg2 = seg1.link; + if (seg2 != null) + { + seg2.numLinked++; + if (seg2.link != seg1) + { + seg1.link = null; + seg1.serif = seg2.link; + } + } + // Uncomment to show all segments. + // System.err.println("segment#" + i1 + ": " + seg1); + } + } + + /** + * Initializes the blue zones of the font. + * + * @param metrics the metrics to use + * @param face the font face to analyze + */ + private void initBlues(LatinMetrics metrics, OpenTypeFont face) + { + int[] flats = new int[MAX_TEST_CHARS]; + int[] rounds = new int[MAX_TEST_CHARS]; + int numFlats; + int numRounds; + LatinBlue blue; + LatinAxis axis = metrics.axis[DIMENSION_VERT]; + // We compute the blues simply by loading each character in the test + // strings, then compute its topmost or bottommost points. + for (int bb = 0; bb < BLUE_MAX; bb++) + { + String p = TEST_CHARS[bb]; + int blueRef; + int blueShoot; + numFlats = 0; + numRounds = 0; + for (int i = 0; i < p.length(); i++) + { + // Load the character. + int glyphIndex = face.getGlyph(p.charAt(i)); + Zone glyph = + face.getRawGlyphOutline(glyphIndex, IDENTITY); + + // Now compute the min and max points. + int numPoints = glyph.getSize() - 4; // 4 phantom points. + Point[] points = glyph.getPoints(); + Point point = points[0]; + int extremum = 0; + int index = 1; + if (isTopBlue(bb)) + { + for (; index < numPoints; index++) + { + point = points[index]; + // We have the vertical direction swapped. The higher + // points have smaller (negative) Y. + if (point.getOrigY() < points[extremum].getOrigY()) + extremum = index; + } + } + else + { + for (; index < numPoints; index++) + { + point = points[index]; + // We have the vertical direction swapped. The higher + // points have smaller (negative) Y. + if (point.getOrigY() > points[extremum].getOrigY()) + extremum = index; + } + } + // Debug, prints out the maxima. + // System.err.println("extremum for " + bb + " / "+ p.charAt(i) + // + ": " + points[extremum]); + + // Now determine if the point is part of a straight or round + // segment. + boolean round; + int idx = extremum; + int first, last, prev, next, end; + int dist; + last = -1; + first = 0; + for (int n = 0; n < glyph.getNumContours(); n++) + { + end = glyph.getContourEnd(n); + // System.err.println("contour end for " + n + ": " + end); + if (end >= idx) + { + last = end; + break; + } + first = end + 1; + } + // Should never happen. + assert last >= 0; + + // Now look for the previous and next points that are not on the + // same Y coordinate. Threshold the 'closeness'. + prev = idx; + next = prev; + do + { + if (prev > first) + prev--; + else + prev = last; + dist = points[prev].getOrigY() - points[extremum].getOrigY(); + if (dist < -5 || dist > 5) + break; + } while (prev != idx); + do + { + if (next < last) + next++; + else + next = first; + dist = points[next].getOrigY() - points[extremum].getOrigY(); + if (dist < -5 || dist > 5) + break; + } while (next != idx); + round = points[prev].isControlPoint() + || points[next].isControlPoint(); + + if (round) + { + rounds[numRounds++] = points[extremum].getOrigY(); + // System.err.println("new round extremum: " + bb + ": " + // + points[extremum].getOrigY()); + } + else + { + flats[numFlats++] = points[extremum].getOrigY(); + // System.err.println("new flat extremum: " + bb + ": " + // + points[extremum].getOrigY()); + } + } + // We have computed the contents of the rounds and flats tables. + // Now determine the reference and overshoot position of the blues -- + // we simply take the median after a simple sort. + Utils.sort(numRounds, rounds); + Utils.sort(numFlats, flats); + blue = axis.blues[axis.blueCount] = new LatinBlue(); + axis.blueCount++; + if (numFlats == 0) + { + blue.ref = blue.shoot = new Width(rounds[numRounds / 2]); + } + else if (numRounds == 0) + { + blue.ref = blue.shoot = new Width(flats[numFlats / 2]); + } + else + { + blue.ref = new Width(flats[numFlats / 2]); + blue.shoot = new Width(rounds[numRounds / 2]); + } + // There are sometimes problems: if the overshoot position of top + // zones is under its reference position, or the opposite for bottom + // zones. We must check everything there and correct problems. + if (blue.shoot != blue.ref) + { + int ref = blue.ref.org; + int shoot = blue.shoot.org; + // Inversed vertical coordinates! + boolean overRef = shoot < ref; + if (isTopBlue(bb) ^ overRef) + { + blue.shoot = blue.ref = new Width((shoot + ref) / 2); + } + } + blue.flags = 0; + if (isTopBlue(bb)) + blue.flags |= LatinBlue.FLAG_TOP; + // The following flag is used later to adjust y and x scales in + // order to optimize the pixel grid alignment of the top small + // letters. + if (bb == SMALL_TOP) + { + blue.flags |= LatinBlue.FLAG_ADJUSTMENT; + } + // Debug: print out the blue zones. + // System.err.println("blue zone #" + bb + ": " + blue); + } + } + + private static final AffineTransform IDENTITY = new AffineTransform(); + + private int constant(LatinMetrics metrics, int c) + { + return c * (metrics.unitsPerEm / 2048); + } + + private void computeSegments(GlyphHints hints, int dim) + { + Point[] points = hints.points; + if (dim == DIMENSION_HORZ) + { + for (int i = 0; i < hints.numPoints; i++) + { + points[i].setU(points[i].getOrigX()); + points[i].setV(points[i].getOrigY()); + } + } + else + { + for (int i = 0; i < hints.numPoints; i++) + { + points[i].setU(points[i].getOrigY()); + points[i].setV(points[i].getOrigX()); + } + } + // Now look at each contour. + AxisHints axis = hints.axis[dim]; + int majorDir = Math.abs(axis.majorDir); + int segmentDir = majorDir; + Point[] contours = hints.contours; + int numContours = hints.numContours; + Segment segment = null; + for (int i = 0; i < numContours; i++) + { + int minPos = 32000; + int maxPos = -32000; + + Point point = contours[i]; + Point last = point.getPrev(); + if (point == last) // Skip singletons. + continue; + if (Math.abs(last.getOutDir()) == majorDir + && Math.abs(point.getOutDir()) == majorDir) + { + // We are already on an edge. Locate its start. + last = point; + while (true) + { + point = point.getPrev(); + if (Math.abs(point.getOutDir()) != majorDir) + { + point = point.getNext(); + break; + } + if (point == last) + break; + } + } + last = point; + boolean passed = false; + boolean onEdge = false; + while (true) + { + int u, v; + if (onEdge) + { + u = point.getU(); + if (u < minPos) + minPos = u; + if (u > maxPos) + maxPos = u; + if (point.getOutDir() != segmentDir || point == last) + { + // Leaving an edge. Record new segment. + segment.last = point; + // (minPos + maxPos) / 2. + segment.pos = (minPos + maxPos) >> 1; + if (segment.first.isControlPoint() + || point.isControlPoint()) + segment.flags |= Segment.FLAG_EDGE_ROUND; + minPos = maxPos = point.getV(); + v = segment.first.getV(); + if (v < minPos) + minPos = v; + if (v > maxPos) + maxPos = v; + segment.minPos = minPos; + segment.maxPos = maxPos; + onEdge = false; + segment = null; + } + } + if (point == last) + { + if (passed) + break; + passed = true; + } + if (! onEdge && Math.abs(point.getOutDir()) == majorDir) + { + // This is the start of a new segment. + segmentDir = point.getOutDir(); + segment = axis.newSegment(); + segment.dir = segmentDir; + segment.flags = Segment.FLAG_EDGE_NORMAL; + minPos = maxPos = point.getU(); + segment.first = point; + segment.last = point; + segment.contour = contours[i]; + segment.score = 32000; + segment.len = 0; + segment.link = null; + onEdge = true; + } + point = point.getNext(); + } + } + + } + + private boolean isTopBlue(int b) + { + return b == CAPITAL_TOP || b == SMALL_F_TOP || b == SMALL_TOP; + } + + private void detectFeatures(GlyphHints hints, int dim) + { + computeSegments(hints, dim); + linkSegments(hints, dim); + computeEdges(hints, dim); + } + + private void computeEdges(GlyphHints hints, int dim) + { + AxisHints axis = hints.axis[dim]; + LatinAxis laxis = ((LatinMetrics) hints.metrics).axis[dim]; + Segment[] segments = axis.segments; + int numSegments = axis.numSegments; + Segment seg; + int upDir; + int scale; + int edgeDistanceThreshold; + axis.numEdges = 0; + scale = dim == DIMENSION_HORZ ? hints.xScale : hints.yScale; + upDir = dim == DIMENSION_HORZ ? DIR_UP : DIR_RIGHT; + + // We will begin by generating a sorted table of edges for the + // current direction. To do so, we simply scan each segment and try + // to find an edge in our table that corresponds to its position. + // + // If no edge is found, we create one and insert a new edge in the + // sorted table. Otherwise, we simply add the segment to the egde's + // list which will be processed in the second step to compute the + // edge's properties. + // + // Note that the edge table is sorted along the segment/edge + // position. + + edgeDistanceThreshold = Fixed.mul16(laxis.edgeDistanceTreshold, scale); + if (edgeDistanceThreshold > 64 / 4) + edgeDistanceThreshold = 64 / 4; + edgeDistanceThreshold = Fixed.div16(edgeDistanceThreshold, scale); + for (int i = 0; i < numSegments; i++) + { + seg = segments[i]; + Edge found = null; + for (int ee = 0; ee < axis.numEdges; ee++) + { + Edge edge = axis.edges[ee]; + int dist = seg.pos - edge.fpos; + if (dist < 0) + dist = -dist; + if (dist < edgeDistanceThreshold) + { + found = edge; + break; + } + } + if (found == null) + { + // Insert new edge in the list and sort according to + // the position. + Edge edge = axis.newEdge(seg.pos); + edge.first = seg; + edge.last = seg; + edge.fpos = seg.pos; + edge.opos = edge.pos = Fixed.mul16(seg.pos, scale); + seg.edgeNext = seg; + seg.edge = edge; + } + else + { + seg.edgeNext = found.first; + found.last.edgeNext = seg; + found.last = seg; + seg.edge = found; + } + } + // Good. We will now compute each edge's properties according to + // segments found on its position. Basically these are: + // - Edge's main direction. + // - Stem edge, serif edge, or both (which defaults to stem edge). + // - Rounded edge, straight or both (which defaults to straight). + // - Link for edge. + + // Now, compute each edge properties. + for (int e = 0; e < axis.numEdges; e++) + { + Edge edge = axis.edges[e]; + // Does it contain round segments? + int isRound = 0; + // Does it contain straight segments? + int isStraight = 0; + // Number of upward segments. + int ups = 0; + // Number of downward segments. + int downs = 0; + + seg = edge.first; + do + { + // Check for roundness of segment. + if ((seg.flags & Segment.FLAG_EDGE_ROUND) != 0) + isRound++; + else + isStraight++; + + // Check for segment direction. + if (seg.dir == upDir) + ups += seg.maxPos - seg.minPos; + else + downs += seg.maxPos - seg.minPos; + + // Check for links. If seg.serif is set, then seg.link must + // be ignored. + boolean isSerif = seg.serif != null && seg.serif.edge != edge; + if (seg.link != null || isSerif) + { + Edge edge2 = edge.link; + Segment seg2 = seg.link; + if (isSerif) + { + seg2 = seg.serif; + edge2 = edge.serif; + } + if (edge2 != null) + { + int edgeDelta = edge.fpos - edge2.fpos; + if (edgeDelta < 0) + edgeDelta = -edgeDelta; + int segDelta = seg.pos - seg2.pos; + if (segDelta < 0) + segDelta = -segDelta; + if (segDelta < edgeDelta) + edge2 = seg2.edge; + } + else + { + edge2 = seg2.edge; + } + if (isSerif) + { + edge.serif = edge2; + edge2.flags |= Segment.FLAG_EDGE_SERIF; + } + else + { + edge.link = edge2; + } + } + seg = seg.edgeNext; + } while (seg != edge.first); + edge.flags = Segment.FLAG_EDGE_NORMAL; + if (isRound > 0 && isRound > isStraight) + edge.flags |= Segment.FLAG_EDGE_ROUND; + + // Set the edge's main direction. + edge.dir = DIR_NONE; + if (ups > downs) + edge.dir = upDir; + else if (ups < downs) + edge.dir = -upDir; + else if (ups == downs) + edge.dir = 0; + + // Gets rid of serif if link is set. This gets rid of many + // unpleasant artifacts. + if (edge.serif != null && edge.link != null) + { + edge.serif = null; + } + + // Debug: Print out all edges. + // System.err.println("edge# " + e + ": " + edge); + } + } + + private void computeBlueEdges(GlyphHints hints, LatinMetrics metrics) + { + AxisHints axis = hints.axis[DIMENSION_VERT]; + Edge[] edges = axis.edges; + int numEdges = axis.numEdges; + LatinAxis latin = metrics.axis[DIMENSION_VERT]; + int scale = latin.scale; + + // Compute which blue zones are active. I.e. have their scaled + // size < 3/4 pixels. + + // For each horizontal edge search the blue zone that is closest. + for (int e = 0; e < numEdges; e++) + { + Edge edge = edges[e]; + // System.err.println("checking edge: " + edge); + Width bestBlue = null; + int bestDist = Fixed.mul16(metrics.unitsPerEm / 40, scale); + + if (bestDist > 64 / 2) + bestDist = 64 / 2; + for (int bb = 0; bb < BLUE_MAX; bb++) + { + LatinBlue blue = latin.blues[bb]; + // System.err.println("checking blue: " + blue); + // Skip inactive blue zones, i.e. those that are too small. + if ((blue.flags & LatinBlue.FLAG_BLUE_ACTIVE) == 0) + continue; + // If it is a top zone, check for right edges. If it is a bottom + // zone, check for left edges. + boolean isTopBlue = (blue.flags & LatinBlue.FLAG_TOP) != 0; + boolean isMajorDir = edge.dir == axis.majorDir; + + // If it is a top zone, the edge must be against the major + // direction. If it is a bottom zone it must be in the major + // direction. + if (isTopBlue ^ isMajorDir) + { + int dist = edge.fpos - blue.ref.org; + if (dist < 0) + dist = -dist; + dist = Fixed.mul16(dist, scale); + if (dist < bestDist) + { + bestDist = dist; + bestBlue = blue.ref; + } + + // Now, compare it to the overshoot position if the edge is + // rounded, and if the edge is over the reference position of + // a top zone, or under the reference position of a bottom + // zone. + if ((edge.flags & Segment.FLAG_EDGE_ROUND) != 0 && dist != 0) + { + // Inversed vertical coordinates! + boolean isUnderRef = edge.fpos > blue.ref.org; + if (isTopBlue ^ isUnderRef) + { + blue = latin.blues[bb]; // Needed? + dist = edge.fpos - blue.shoot.org; + if (dist < 0) + dist = -dist; + dist = Fixed.mul16(dist, scale); + if (dist < bestDist) + { + bestDist = dist; + bestBlue = blue.shoot; + } + } + } + + } + } + if (bestBlue != null) + { + edge.blueEdge = bestBlue; + // Debug: Print out the blue edges. + // System.err.println("blue edge for: " + edge + ": " + bestBlue); + } + } + } +} diff --git a/libjava/classpath/gnu/java/awt/font/autofit/LatinAxis.java b/libjava/classpath/gnu/java/awt/font/autofit/LatinAxis.java new file mode 100644 index 000000000..9237d0ee5 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/autofit/LatinAxis.java @@ -0,0 +1,62 @@ +/* LatinAxis.java -- Axis specific data + 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.font.autofit; + +/** + * Some axis specific data. + */ +class LatinAxis +{ + + int scale; + int delta; + + int widthCount; + Width[] widths; + int edgeDistanceTreshold; + LatinBlue[] blues; + int blueCount; + int orgDelta; + int orgScale; + LatinAxis() + { + widths = new Width[Latin.MAX_WIDTHS]; + blues = new LatinBlue[Latin.BLUE_MAX]; + } +} diff --git a/libjava/classpath/gnu/java/awt/font/autofit/LatinBlue.java b/libjava/classpath/gnu/java/awt/font/autofit/LatinBlue.java new file mode 100644 index 000000000..2cf68b75c --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/autofit/LatinBlue.java @@ -0,0 +1,61 @@ +/* LatinBlue.java -- FIXME: briefly describe file purpose + 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.font.autofit; + +import gnu.java.lang.CPStringBuilder; + +public class LatinBlue +{ + static final int FLAG_BLUE_ACTIVE = 1 << 0; + static final int FLAG_TOP = 1 << 1; + static final int FLAG_ADJUSTMENT = 1 << 2; + Width ref; + Width shoot; + int flags; + public String toString() + { + CPStringBuilder s = new CPStringBuilder(); + s.append("[BlueZone]"); + s.append(" ref: "); + s.append(ref.org); + s.append(", shoot: "); + s.append(shoot.org); + return s.toString(); + } +} diff --git a/libjava/classpath/gnu/java/awt/font/autofit/LatinMetrics.java b/libjava/classpath/gnu/java/awt/font/autofit/LatinMetrics.java new file mode 100644 index 000000000..33fc63ad4 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/autofit/LatinMetrics.java @@ -0,0 +1,66 @@ +/* LatinMetrics.java -- Latin specific metrics data + 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.font.autofit; + +import gnu.java.awt.font.opentype.OpenTypeFont; + +/** + * Latin specific metrics data. + */ +class LatinMetrics + extends ScriptMetrics +{ + + LatinAxis[] axis; + + int unitsPerEm; + + LatinMetrics() + { + super(); + axis = new LatinAxis[Constants.DIMENSION_MAX]; + axis[Constants.DIMENSION_HORZ] = new LatinAxis(); + axis[Constants.DIMENSION_VERT] = new LatinAxis(); + } + LatinMetrics(OpenTypeFont face) + { + this(); + unitsPerEm = face.unitsPerEm; + } +} diff --git a/libjava/classpath/gnu/java/awt/font/autofit/Script.java b/libjava/classpath/gnu/java/awt/font/autofit/Script.java new file mode 100644 index 000000000..c223f0a26 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/autofit/Script.java @@ -0,0 +1,62 @@ +/* Script.java -- Defines script specific interface to the autofitter + 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.font.autofit; + +import gnu.java.awt.font.opentype.OpenTypeFont; +import gnu.java.awt.font.opentype.truetype.Zone; + +/** + * Defines script specific methods for the auto fitter. + */ +interface Script +{ + + /** + * Initializes the metrics. + */ + void initMetrics(ScriptMetrics metrics, OpenTypeFont face); + + void scaleMetrics(ScriptMetrics metrics , HintScaler scaler); + + void doneMetrics(ScriptMetrics metrics); + + void initHints(GlyphHints hints, ScriptMetrics metrics); + + void applyHints(GlyphHints hints, Zone outline, ScriptMetrics metrics); +} diff --git a/libjava/classpath/gnu/java/awt/font/autofit/ScriptMetrics.java b/libjava/classpath/gnu/java/awt/font/autofit/ScriptMetrics.java new file mode 100644 index 000000000..984a06dae --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/autofit/ScriptMetrics.java @@ -0,0 +1,53 @@ +/* ScriptMetrics.java -- Script specific metrics data + 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.font.autofit; + +/** + * Script specific metrics data. + */ +class ScriptMetrics +{ + + Script script; + HintScaler scaler; + ScriptMetrics() + { + scaler = new HintScaler(); + } +} diff --git a/libjava/classpath/gnu/java/awt/font/autofit/Segment.java b/libjava/classpath/gnu/java/awt/font/autofit/Segment.java new file mode 100644 index 000000000..9f9da6792 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/autofit/Segment.java @@ -0,0 +1,97 @@ +/* Segment.java -- FIXME: briefly describe file purpose + 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.font.autofit; + +import gnu.java.awt.font.opentype.truetype.Point; + +import gnu.java.lang.CPStringBuilder; + +class Segment +{ + + static final int FLAG_EDGE_NORMAL = 0; + static final int FLAG_EDGE_ROUND = 1; + static final int FLAG_EDGE_SERIF = 2; + static final int FLAG_EDGE_DONE = 4; + int dir; + int flags; + Segment link; + Segment serif; + int numLinked; + int pos; + Point first; + Point last; + Point contour; + int minPos; + int maxPos; + int score; + int len; + Segment edgeNext; + Edge edge; + + public String toString() + { + CPStringBuilder s = new CPStringBuilder(); + s.append("[Segment] id: "); + s.append(hashCode()); + s.append(", len:"); + s.append(len); + s.append(", round: "); + s.append(((flags & FLAG_EDGE_ROUND) != 0)); + s.append(", dir: "); + s.append(dir); + s.append(", pos: "); + s.append(pos); + s.append(", minPos: "); + s.append(minPos); + s.append(", maxPos: "); + s.append(maxPos); + s.append(", first: "); + s.append(first); + s.append(", last: "); + s.append(last); + s.append(", contour: "); + s.append(contour); + s.append(", link: "); + s.append(link == null ? "null" : link.hashCode()); + s.append(", serif: "); + s.append(serif == null ? "null" : serif.hashCode()); + return s.toString(); + } +} diff --git a/libjava/classpath/gnu/java/awt/font/autofit/Utils.java b/libjava/classpath/gnu/java/awt/font/autofit/Utils.java new file mode 100644 index 000000000..ca45bb2e4 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/autofit/Utils.java @@ -0,0 +1,255 @@ +/* Utils.java -- A collection of utility functions for the autofitter + 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.font.autofit; + +import gnu.java.awt.font.opentype.truetype.Fixed; + +/** + * A collection of utility methods used all around the auto fitter. + */ +class Utils + implements Constants +{ + + private static final int ATAN_BITS = 8; + private static final byte[] ATAN = new byte[] + { + 0, 0, 1, 1, 1, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 5, + 5, 5, 6, 6, 6, 7, 7, 7, + 8, 8, 8, 9, 9, 9, 10, 10, + 10, 10, 11, 11, 11, 12, 12, 12, + 13, 13, 13, 14, 14, 14, 14, 15, + 15, 15, 16, 16, 16, 17, 17, 17, + 18, 18, 18, 18, 19, 19, 19, 20, + 20, 20, 21, 21, 21, 21, 22, 22, + 22, 23, 23, 23, 24, 24, 24, 24, + 25, 25, 25, 26, 26, 26, 26, 27, + 27, 27, 28, 28, 28, 28, 29, 29, + 29, 30, 30, 30, 30, 31, 31, 31, + 31, 32, 32, 32, 33, 33, 33, 33, + 34, 34, 34, 34, 35, 35, 35, 35, + 36, 36, 36, 36, 37, 37, 37, 38, + 38, 38, 38, 39, 39, 39, 39, 40, + 40, 40, 40, 41, 41, 41, 41, 42, + 42, 42, 42, 42, 43, 43, 43, 43, + 44, 44, 44, 44, 45, 45, 45, 45, + 46, 46, 46, 46, 46, 47, 47, 47, + 47, 48, 48, 48, 48, 48, 49, 49, + 49, 49, 50, 50, 50, 50, 50, 51, + 51, 51, 51, 51, 52, 52, 52, 52, + 52, 53, 53, 53, 53, 53, 54, 54, + 54, 54, 54, 55, 55, 55, 55, 55, + 56, 56, 56, 56, 56, 57, 57, 57, + 57, 57, 57, 58, 58, 58, 58, 58, + 59, 59, 59, 59, 59, 59, 60, 60, + 60, 60, 60, 61, 61, 61, 61, 61, + 61, 62, 62, 62, 62, 62, 62, 63, + 63, 63, 63, 63, 63, 64, 64, 64 + }; + + private static final int ANGLE_PI = 256; + private static final int ANGLE_PI2 = ANGLE_PI / 2; + private static final int ANGLE_PI4 = ANGLE_PI / 4; + private static final int ANGLE_2PI = ANGLE_PI * 2; + + /** + * Computes the direction constant for the specified vector. The vector is + * given as differential value already. + * + * @param dx the x vector + * @param dy the y vector + * + * @return the direction of that vector, or DIR_NONE, if that vector is not + * approximating against one of the major axises + */ + static int computeDirection(int dx, int dy) + { + int dir = DIR_NONE; + if (dx < 0) + { + if (dy < 0) + { + if (-dx * 12 < -dy) + dir = DIR_UP; + else if (-dy * 12 < -dx) + dir = DIR_LEFT; + } + else // dy >= 0 . + { + if (-dx * 12 < dy) + dir = DIR_DOWN; + else if (dy * 12 < -dx) + dir = DIR_LEFT; + } + } + else // dx >= 0 . + { + if (dy < 0) + { + if (dx * 12 < -dy) + dir = DIR_UP; + else if (-dy * 12 < dx) + dir = DIR_RIGHT; + } + else // dy >= 0 . + { + if (dx * 12 < dy) + dir = DIR_DOWN; + else if (dy * 12 < dx) + dir = DIR_RIGHT; + } + } + return dir; + } + + public static int atan(int dx, int dy) + { + int angle; + // Trivial cases. + if (dy == 0) + { + angle = 0; + if (dx < 0) + angle = ANGLE_PI; + return angle; + } + else if (dx == 0) + { + angle = ANGLE_PI2; + if (dy < 0) + angle = - ANGLE_PI2; + return angle; + } + + + angle = 0; + if (dx < 0) + { + dx = -dx; + dy = -dy; + angle = ANGLE_PI; + } + if (dy < 0) + { + int tmp = dx; + dx = -dy; + dy = tmp; + angle -= ANGLE_PI2; + } + if (dx == 0 && dy == 0) + return 0; + + if (dx == dy) + angle += ANGLE_PI4; + else if (dx > dy) + { + angle += ATAN[Fixed.div(dy, dx) << (ATAN_BITS - 6)]; + } + else + { + angle += ANGLE_PI2 - ATAN[Fixed.div(dx, dy) << (ATAN_BITS - 6)]; + } + + if (angle > ANGLE_PI) + angle -= ANGLE_2PI; + return angle; + } + + public static int angleDiff(int ang1, int ang2) + { + int delta = ang2 - ang1; + delta %= ANGLE_2PI; + if (delta < 0) + delta += ANGLE_2PI; + if (delta > ANGLE_PI) + delta -= ANGLE_2PI; + return delta; + } + + static void sort(int num, int[] array) + { + int swap; + for (int i = 1; i < num; i++) + { + for (int j = i; j > 0; j--) + { + if (array[j] > array[j - 1]) + break; + swap = array[j]; + array[j] = array[j - 1]; + array[j - 1] = swap; + } + } + } + + static void sort(int num, Width[] array) + { + Width swap; + for (int i = 1; i < num; i++) + { + for (int j = 1; j > 0; j--) + { + if (array[j].org > array[j - 1].org) + break; + swap = array[j]; + array[j] = array[j - 1]; + array[j - 1] = swap; + } + } + } + + static int pixRound(int val) + { + return pixFloor(val + 32); + } + + static int pixFloor(int val) + { + return val & ~63; + } + + public static int mulDiv(int a, int b, int c) + { + long prod = a * b; + long div = (prod / c); + return (int) div; + } + +} diff --git a/libjava/classpath/gnu/java/awt/font/autofit/Width.java b/libjava/classpath/gnu/java/awt/font/autofit/Width.java new file mode 100644 index 000000000..079f7b396 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/autofit/Width.java @@ -0,0 +1,64 @@ +/* Width.java -- FIXME: briefly describe file purpose + 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.font.autofit; + +import gnu.java.lang.CPStringBuilder; + +public class Width +{ + int org; + int cur; + int fit; + Width(int dist) + { + org = dist; + } + + public String toString() + { + CPStringBuilder s = new CPStringBuilder(); + s.append("[Width] org: "); + s.append(org); + s.append(", cur: "); + s.append(cur); + s.append(", fit: "); + s.append(fit); + return s.toString(); + } +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/CharGlyphMap.java b/libjava/classpath/gnu/java/awt/font/opentype/CharGlyphMap.java new file mode 100644 index 000000000..8529f7e47 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/opentype/CharGlyphMap.java @@ -0,0 +1,1027 @@ +/* CharGlyphMap.java -- Manages the 'cmap' table of TrueType fonts + 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.font.opentype; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.ShortBuffer; +import java.nio.IntBuffer; + + +/** + * A mapping from Unicode codepoints to glyphs. This mapping + * does not perform any re-ordering or decomposition, so it + * is not everything that is needed to support Unicode. + * + *

This class manages the cmap table of + * OpenType and TrueType fonts. + * + * @see + * the cmap part of Adobe’ OpenType Specification + * + * @see + * the cmap section of Apple’s TrueType Reference + * Manual + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class CharGlyphMap +{ + private static final int PLATFORM_UNICODE = 0; + private static final int PLATFORM_MACINTOSH = 1; + private static final int PLATFORM_MICROSOFT = 3; + + + /** + * Determines the glyph index for a given Unicode codepoint. Users + * should be aware that the character-to-glyph mapping not not + * everything that is needed for full Unicode support. For example, + * the cmap table is not able to synthesize accented + * glyphs from the canonical decomposition sequence, even if the + * font would contain a glyph for the composed form. + * + * @param ucs4 the Unicode codepoint in UCS-4 encoding. Surrogates + * (U+D800 to U+DFFF) cannot be passed, they must be mapped to + * UCS-4 first. + * + * @return the glyph index, or 0 if the font does not contain + * a glyph for this codepoint. + */ + public abstract int getGlyph(int ucs4); + + + /** + * Reads a CharGlyphMap from an OpenType or TrueType cmap + * table. The current implementation works as follows: + * + *

  1. If the font has a type 4 cmap for the Unicode platform + * (encoding 0, 1, 2, 3 or 4), or a type 4 cmap for the Microsoft + * platform (encodings 1 or 10), that table is used to map Unicode + * codepoints to glyphs. Most recent fonts, both for Macintosh and + * Windows, should provide such a table.
  2. + * + *
  3. Otherwise, if the font has any type 0 cmap for the Macintosh + * platform, a Unicode-to-glyph mapping is synthesized from certain + * type 0 cmaps. The current implementation collects mappings from + * Roman, Icelandic, Turkish, Croatian, Romanian, Eastern European, + * Cyrillic, Greek, Hebrew, Arabic and Farsi cmaps.
  4. .
+ * + * @param buf a buffer whose position is right at the start + * of the entire cmap table, and whose limit + * is at its end. + * + * @return a concrete subclass of CharGlyphMap + * that performs the mapping. + * + * @see the cmap part of Adobe’ OpenType Specification + * + * @see the cmap section of Apple’s TrueType Reference + * Manual + */ + public static CharGlyphMap forTable(ByteBuffer buf) + { + boolean hasType0 = false; + int start4 = -1, platform4 = 0, encoding4 = 0; + int start12 = -1, platform12 = 0, encoding12 = 0; + int version; + int numTables; + int tableStart = buf.position(); + int limit = buf.limit(); + int format, platform, language, encoding, length, offset; + + version = buf.getChar(); + if (version != 0) + return null; + + numTables = buf.getChar(); + for (int i = 0; i < numTables; i++) + { + buf.limit(limit).position(tableStart + 4 + i * 8); + platform = buf.getChar(); + encoding = buf.getChar(); + offset = tableStart + buf.getInt(); + + buf.position(offset); + format = buf.getChar(); + + switch (format) + { + case 0: + hasType0 = true; + break; + + case 4: + length = buf.getChar(); + language = buf.getChar(); + if ((start4 == -1) + && Type4.isSupported(platform, language, encoding)) + { + start4 = offset; + platform4 = platform; + encoding4 = encoding; + } + break; + + case 12: + if ((start12 == -1) && Type12.isSupported(platform, encoding)) + { + start12 = offset; + platform12 = platform; + encoding12 = encoding; + } + break; + } + } + + + if (start12 >= 0) + { + try + { + buf.limit(limit).position(start12); + return new Type12(buf, platform12, encoding12); + } + catch (Exception ex) + { + ex.printStackTrace(); + } + } + + if (start4 >= 0) + { + try + { + buf.limit(limit).position(start4); + return Type4.readTable(buf, platform4, encoding4); + } + catch (Exception ex) + { + } + } + + if (hasType0) + { + try + { + buf.limit(limit).position(tableStart); + return new Type0(buf); + } + catch (Exception ex) + { + } + } + + return new Dummy(); + } + + + /** + * A dummy mapping that maps anything to the undefined glyph. + * Used if no other cmap is understood in a font. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ + private static final class Dummy + extends CharGlyphMap + { + public int getGlyph(int ucs4) + { + return 0; + } + } + + + /** + * A mapping from Unicode code points to glyph IDs through CMAP Type + * 0 tables. These tables have serious limitations: Only the first + * 256 glyphs can be addressed, and the source of the mapping is not + * Unicode, but an encoding used on the Macintosh. + * + *

However, some fonts have only a Type 0 cmap. In this case, we + * process all the Type 0 tables we understand, and establish + * a reversed glyph-to-Unicode mapping. When a glyph is requested + * for a given Unicode character, we perform a linear search on the + * reversed table to find the glyph which maps to the requested + * character. While not blazingly fast, this gives a reasonable + * fallback for old fonts. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ + private static final class Type0 + extends CharGlyphMap + { + /** + * An array whose i-th element indicates the + * Unicode code point of glyph i in the font. + */ + private char[] glyphToUCS2 = new char[256]; + + + /** + * A String whose charAt(i) is the Unicode character + * that corresponds to the codepoint i + 127 in the + * MacOS Arabic encoding. + * + * @see the Unicode mapping table for the MacOS Arabic encoding + */ + private static final String UPPER_ARABIC + = "\u007e\u0000\u00c4\u00a0\u00c7\u00c9\u00d1\u00d6\u00dc\u00e1" + + "\u00e0\u00e2\u00e4\u06ba\u00ab\u00e7\u00e9\u00e8\u00ea\u00eb" + + "\u00ed\u2026\u00ee\u00ef\u00f1\u00f3\u00bb\u00f4\u00f6\u00f7" + + "\u00fa\u00f9\u00fb\u00fc\u0020\u0021\"\u0023\u0024\u066a" + + "\u0026\u0027\u0028\u0029\u002a\u002b\u060c\u002d\u002e\u002f" + + "\u0660\u0661\u0662\u0663\u0664\u0665\u0666\u0667\u0668\u0669" + + "\u003a\u061b\u003c\u003d\u003e\u061f\u274a\u0621\u0622\u0623" + + "\u0624\u0625\u0626\u0627\u0628\u0629\u062a\u062b\u062c\u062d" + + "\u062e\u062f\u0630\u0631\u0632\u0633\u0634\u0635\u0636\u0637" + + "\u0638\u0639\u063a\u005b\\\u005d\u005e\u005f\u0640\u0641" + + "\u0642\u0643\u0644\u0645\u0646\u0647\u0648\u0649\u064a\u064b" + + "\u064c\u064d\u064e\u064f\u0650\u0651\u0652\u067e\u0679\u0686" + + "\u06d5\u06a4\u06af\u0688\u0691\u007b\u007c\u007d\u0698\u06d2"; + + + /** + * A String whose charAt(i) is the Unicode character + * that corresponds to the codepoint i + 127 in the + * MacOS East European Roman encoding. + * + * @see the Unicode mapping table for the MacOS Central European + * encoding + */ + private static final String UPPER_EAST_EUROPEAN_ROMAN + = "\u007e\u0000\u00c4\u0100\u0101\u00c9\u0104\u00d6\u00dc\u00e1" + + "\u0105\u010c\u00e4\u010d\u0106\u0107\u00e9\u0179\u017a\u010e" + + "\u00ed\u010f\u0112\u0113\u0116\u00f3\u0117\u00f4\u00f6\u00f5" + + "\u00fa\u011a\u011b\u00fc\u2020\u00b0\u0118\u00a3\u00a7\u2022" + + "\u00b6\u00df\u00ae\u00a9\u2122\u0119\u00a8\u2260\u0123\u012e" + + "\u012f\u012a\u2264\u2265\u012b\u0136\u2202\u2211\u0142\u013b" + + "\u013c\u013d\u013e\u0139\u013a\u0145\u0146\u0143\u00ac\u221a" + + "\u0144\u0147\u2206\u00ab\u00bb\u2026\u00a0\u0148\u0150\u00d5" + + "\u0151\u014c\u2013\u2014\u201c\u201d\u2018\u2019\u00f7\u25ca" + + "\u014d\u0154\u0155\u0158\u2039\u203a\u0159\u0156\u0157\u0160" + + "\u201a\u201e\u0161\u015a\u015b\u00c1\u0164\u0165\u00cd\u017d" + + "\u017e\u016a\u00d3\u00d4\u016b\u016e\u00da\u016f\u0170\u0171" + + "\u0172\u0173\u00dd\u00fd\u0137\u017b\u0141\u017c\u0122\u02c7"; + + + /** + * A String whose charAt(i) is the Unicode character + * that corresponds to the codepoint i + 127 in the + * MacOS Roman encoding for the Croatian language. + * + * @see the Unicode mapping table for the MacOS Croatian encoding + */ + private static final String UPPER_CROATIAN + = "\u007e\u0000\u00c4\u00c5\u00c7\u00c9\u00d1\u00d6\u00dc\u00e1" + + "\u00e0\u00e2\u00e4\u00e3\u00e5\u00e7\u00e9\u00e8\u00ea\u00eb" + + "\u00ed\u00ec\u00ee\u00ef\u00f1\u00f3\u00f2\u00f4\u00f6\u00f5" + + "\u00fa\u00f9\u00fb\u00fc\u2020\u00b0\u00a2\u00a3\u00a7\u2022" + + "\u00b6\u00df\u00ae\u0160\u2122\u00b4\u00a8\u2260\u017d\u00d8" + + "\u221e\u00b1\u2264\u2265\u2206\u00b5\u2202\u2211\u220f\u0161" + + "\u222b\u00aa\u00ba\u03a9\u017e\u00f8\u00bf\u00a1\u00ac\u221a" + + "\u0192\u2248\u0106\u00ab\u010c\u2026\u00a0\u00c0\u00c3\u00d5" + + "\u0152\u0153\u0110\u2014\u201c\u201d\u2018\u2019\u00f7\u25ca" + + "\uf8ff\u00a9\u2044\u20ac\u2039\u203a\u00c6\u00bb\u2013\u00b7" + + "\u201a\u201e\u2030\u00c2\u0107\u00c1\u010d\u00c8\u00cd\u00ce" + + "\u00cf\u00cc\u00d3\u00d4\u0111\u00d2\u00da\u00db\u00d9\u0131" + + "\u02c6\u02dc\u00af\u03c0\u00cb\u02da\u00b8\u00ca\u00e6\u02c7"; + + + /** + * A String whose charAt(i) is the Unicode character + * that corresponds to the codepoint i + 127 in the + * MacOS Cyrillic encoding. + * + * @see the Unicode mapping table for the MacOS Cyrillic encoding + */ + private static final String UPPER_CYRILLIC + = "\u007e\u0000\u0410\u0411\u0412\u0413\u0414\u0415\u0416\u0417" + + "\u0418\u0419\u041a\u041b\u041c\u041d\u041e\u041f\u0420\u0421" + + "\u0422\u0423\u0424\u0425\u0426\u0427\u0428\u0429\u042a\u042b" + + "\u042c\u042d\u042e\u042f\u2020\u00b0\u0490\u00a3\u00a7\u2022" + + "\u00b6\u0406\u00ae\u00a9\u2122\u0402\u0452\u2260\u0403\u0453" + + "\u221e\u00b1\u2264\u2265\u0456\u00b5\u0491\u0408\u0404\u0454" + + "\u0407\u0457\u0409\u0459\u040a\u045a\u0458\u0405\u00ac\u221a" + + "\u0192\u2248\u2206\u00ab\u00bb\u2026\u00a0\u040b\u045b\u040c" + + "\u045c\u0455\u2013\u2014\u201c\u201d\u2018\u2019\u00f7\u201e" + + "\u040e\u045e\u040f\u045f\u2116\u0401\u0451\u044f\u0430\u0431" + + "\u0432\u0433\u0434\u0435\u0436\u0437\u0438\u0439\u043a\u043b" + + "\u043c\u043d\u043e\u043f\u0440\u0441\u0442\u0443\u0444\u0445" + + "\u0446\u0447\u0448\u0449\u044a\u044b\u044c\u044d\u044e\u20ac"; + + + /** + * A String whose charAt(i) is the Unicode character + * that corresponds to the codepoint i + 127 in the + * MacOS Arabic encoding with the Farsi language. + * + * @see the Unicode mapping table for the MacOS Farsi encoding + */ + private static final String UPPER_FARSI + = "\u007e\u0000\u00c4\u00a0\u00c7\u00c9\u00d1\u00d6\u00dc\u00e1" + + "\u00e0\u00e2\u00e4\u06ba\u00ab\u00e7\u00e9\u00e8\u00ea\u00eb" + + "\u00ed\u2026\u00ee\u00ef\u00f1\u00f3\u00bb\u00f4\u00f6\u00f7" + + "\u00fa\u00f9\u00fb\u00fc\u0020\u0021\"\u0023\u0024\u066a" + + "\u0026\u0027\u0028\u0029\u002a\u002b\u060c\u002d\u002e\u002f" + + "\u06f0\u06f1\u06f2\u06f3\u06f4\u06f5\u06f6\u06f7\u06f8\u06f9" + + "\u003a\u061b\u003c\u003d\u003e\u061f\u274a\u0621\u0622\u0623" + + "\u0624\u0625\u0626\u0627\u0628\u0629\u062a\u062b\u062c\u062d" + + "\u062e\u062f\u0630\u0631\u0632\u0633\u0634\u0635\u0636\u0637" + + "\u0638\u0639\u063a\u005b\\\u005d\u005e\u005f\u0640\u0641" + + "\u0642\u0643\u0644\u0645\u0646\u0647\u0648\u0649\u064a\u064b" + + "\u064c\u064d\u064e\u064f\u0650\u0651\u0652\u067e\u0679\u0686" + + "\u06d5\u06a4\u06af\u0688\u0691\u007b\u007c\u007d\u0698\u06d2"; + + + /** + * A String whose charAt(i) is the Unicode character + * that corresponds to the codepoint i + 127 in the + * MacOS Greek encoding. + * + * @see the Unicode mapping table for the MacOS Greek encoding + */ + private static final String UPPER_GREEK + = "\u007e\u0000\u00c4\u00b9\u00b2\u00c9\u00b3\u00d6\u00dc\u0385" + + "\u00e0\u00e2\u00e4\u0384\u00a8\u00e7\u00e9\u00e8\u00ea\u00eb" + + "\u00a3\u2122\u00ee\u00ef\u2022\u00bd\u2030\u00f4\u00f6\u00a6" + + "\u20ac\u00f9\u00fb\u00fc\u2020\u0393\u0394\u0398\u039b\u039e" + + "\u03a0\u00df\u00ae\u00a9\u03a3\u03aa\u00a7\u2260\u00b0\u00b7" + + "\u0391\u00b1\u2264\u2265\u00a5\u0392\u0395\u0396\u0397\u0399" + + "\u039a\u039c\u03a6\u03ab\u03a8\u03a9\u03ac\u039d\u00ac\u039f" + + "\u03a1\u2248\u03a4\u00ab\u00bb\u2026\u00a0\u03a5\u03a7\u0386" + + "\u0388\u0153\u2013\u2015\u201c\u201d\u2018\u2019\u00f7\u0389" + + "\u038a\u038c\u038e\u03ad\u03ae\u03af\u03cc\u038f\u03cd\u03b1" + + "\u03b2\u03c8\u03b4\u03b5\u03c6\u03b3\u03b7\u03b9\u03be\u03ba" + + "\u03bb\u03bc\u03bd\u03bf\u03c0\u03ce\u03c1\u03c3\u03c4\u03b8" + + "\u03c9\u03c2\u03c7\u03c5\u03b6\u03ca\u03cb\u0390\u03b0\u00ad"; + + + /** + * A String whose charAt(i) is the Unicode character + * that corresponds to the codepoint i + 127 in the + * MacOS Hebrew encoding. + * + *

The codepoint 0x81 (HEBREW LIGATURE YIDDISH YOD YOD PATAH) + * has no composed Unicode equivalent, but is expressed as the + * sequence U+05F2 U+05B7 in Unicode. A similar situation exists + * with the codepoint 0xC0 (HEBREW LIGATURE LAMED HOLAM), which + * MacOS converts to U+F86A U+05DC U+05B9. To correctly deal + * with these sequences, we probably should synthesize a ligature + * table if a Hebrew font only provides a Type 0 CMAP. + * + * @see the Unicode mapping table for the MacOS Hebrew encoding + */ + private static final String UPPER_HEBREW + = "\u007e\u0000\u00c4\u0000\u00c7\u00c9\u00d1\u00d6\u00dc\u00e1" + + "\u00e0\u00e2\u00e4\u00e3\u00e5\u00e7\u00e9\u00e8\u00ea\u00eb" + + "\u00ed\u00ec\u00ee\u00ef\u00f1\u00f3\u00f2\u00f4\u00f6\u00f5" + + "\u00fa\u00f9\u00fb\u00fc\u0020\u0021\"\u0023\u0024\u0025" + + "\u20aa\u0027\u0029\u0028\u002a\u002b\u002c\u002d\u002e\u002f" + + "\u0030\u0031\u0032\u0033\u0034\u0035\u0036\u0037\u0038\u0039" + + "\u003a\u003b\u003c\u003d\u003e\u003f\u0000\u201e\uf89b\uf89c" + + "\uf89d\uf89e\u05bc\ufb4b\ufb35\u2026\u00a0\u05b8\u05b7\u05b5" + + "\u05b6\u05b4\u2013\u2014\u201c\u201d\u2018\u2019\ufb2a\ufb2b" + + "\u05bf\u05b0\u05b2\u05b1\u05bb\u05b9\u0000\u05b3\u05d0\u05d1" + + "\u05d2\u05d3\u05d4\u05d5\u05d6\u05d7\u05d8\u05d9\u05da\u05db" + + "\u05dc\u05dd\u05de\u05df\u05e0\u05e1\u05e2\u05e3\u05e4\u05e5" + + "\u05e6\u05e7\u05e8\u05e9\u05ea\u007d\u005d\u007b\u005b\u007c"; + + + /** + * A String whose charAt(i) is the Unicode character + * that corresponds to the codepoint i + 127 in the + * MacOS Roman encoding with the Icelandic language. + * + * @see the Unicode mapping table for the MacOS Icelandic encoding + */ + private static final String UPPER_ICELANDIC + = "\u007e\u0000\u00c4\u00c5\u00c7\u00c9\u00d1\u00d6\u00dc\u00e1" + + "\u00e0\u00e2\u00e4\u00e3\u00e5\u00e7\u00e9\u00e8\u00ea\u00eb" + + "\u00ed\u00ec\u00ee\u00ef\u00f1\u00f3\u00f2\u00f4\u00f6\u00f5" + + "\u00fa\u00f9\u00fb\u00fc\u00dd\u00b0\u00a2\u00a3\u00a7\u2022" + + "\u00b6\u00df\u00ae\u00a9\u2122\u00b4\u00a8\u2260\u00c6\u00d8" + + "\u221e\u00b1\u2264\u2265\u00a5\u00b5\u2202\u2211\u220f\u03c0" + + "\u222b\u00aa\u00ba\u03a9\u00e6\u00f8\u00bf\u00a1\u00ac\u221a" + + "\u0192\u2248\u2206\u00ab\u00bb\u2026\u00a0\u00c0\u00c3\u00d5" + + "\u0152\u0153\u2013\u2014\u201c\u201d\u2018\u2019\u00f7\u25ca" + + "\u00ff\u0178\u2044\u20ac\u00d0\u00f0\u00de\u00fe\u00fd\u00b7" + + "\u201a\u201e\u2030\u00c2\u00ca\u00c1\u00cb\u00c8\u00cd\u00ce" + + "\u00cf\u00cc\u00d3\u00d4\uf8ff\u00d2\u00da\u00db\u00d9\u0131" + + "\u02c6\u02dc\u00af\u02d8\u02d9\u02da\u00b8\u02dd\u02db\u02c7"; + + + /** + * A String whose charAt(i) is the Unicode character + * that corresponds to the codepoint i + 127 in the + * MacOS Roman encoding for most languages. Exceptions include + * Croatian, Icelandic, Romanian, and Turkish. + * + * @see the Unicode mapping table for the MacOS Roman encoding + */ + private static final String UPPER_ROMAN + = "\u007e\u0000\u00c4\u00c5\u00c7\u00c9\u00d1\u00d6\u00dc\u00e1" + + "\u00e0\u00e2\u00e4\u00e3\u00e5\u00e7\u00e9\u00e8\u00ea\u00eb" + + "\u00ed\u00ec\u00ee\u00ef\u00f1\u00f3\u00f2\u00f4\u00f6\u00f5" + + "\u00fa\u00f9\u00fb\u00fc\u2020\u00b0\u00a2\u00a3\u00a7\u2022" + + "\u00b6\u00df\u00ae\u00a9\u2122\u00b4\u00a8\u2260\u00c6\u00d8" + + "\u221e\u00b1\u2264\u2265\u00a5\u00b5\u2202\u2211\u220f\u03c0" + + "\u222b\u00aa\u00ba\u03a9\u00e6\u00f8\u00bf\u00a1\u00ac\u221a" + + "\u0192\u2248\u2206\u00ab\u00bb\u2026\u00a0\u00c0\u00c3\u00d5" + + "\u0152\u0153\u2013\u2014\u201c\u201d\u2018\u2019\u00f7\u25ca" + + "\u00ff\u0178\u2044\u20ac\u2039\u203a\ufb01\ufb02\u2021\u00b7" + + "\u201a\u201e\u2030\u00c2\u00ca\u00c1\u00cb\u00c8\u00cd\u00ce" + + "\u00cf\u00cc\u00d3\u00d4\uf8ff\u00d2\u00da\u00db\u00d9\u0131" + + "\u02c6\u02dc\u00af\u02d8\u02d9\u02da\u00b8\u02dd\u02db\u02c7"; + + + /** + * A String whose charAt(i) is the Unicode character + * that corresponds to the codepoint i + 127 in the + * MacOS Roman encoding with the Romanian language. + * + * @see the Unicode mapping table for the MacOS Romanian encoding + */ + private static final String UPPER_ROMANIAN + = "\u007e\u0000\u00c4\u00c5\u00c7\u00c9\u00d1\u00d6\u00dc\u00e1" + + "\u00e0\u00e2\u00e4\u00e3\u00e5\u00e7\u00e9\u00e8\u00ea\u00eb" + + "\u00ed\u00ec\u00ee\u00ef\u00f1\u00f3\u00f2\u00f4\u00f6\u00f5" + + "\u00fa\u00f9\u00fb\u00fc\u2020\u00b0\u00a2\u00a3\u00a7\u2022" + + "\u00b6\u00df\u00ae\u00a9\u2122\u00b4\u00a8\u2260\u0102\u0218" + + "\u221e\u00b1\u2264\u2265\u00a5\u00b5\u2202\u2211\u220f\u03c0" + + "\u222b\u00aa\u00ba\u03a9\u0103\u0219\u00bf\u00a1\u00ac\u221a" + + "\u0192\u2248\u2206\u00ab\u00bb\u2026\u00a0\u00c0\u00c3\u00d5" + + "\u0152\u0153\u2013\u2014\u201c\u201d\u2018\u2019\u00f7\u25ca" + + "\u00ff\u0178\u2044\u20ac\u2039\u203a\u021a\u021b\u2021\u00b7" + + "\u201a\u201e\u2030\u00c2\u00ca\u00c1\u00cb\u00c8\u00cd\u00ce" + + "\u00cf\u00cc\u00d3\u00d4\uf8ff\u00d2\u00da\u00db\u00d9\u0131" + + "\u02c6\u02dc\u00af\u02d8\u02d9\u02da\u00b8\u02dd\u02db\u02c7"; + + + /** + * A String whose charAt(i) is the Unicode character + * that corresponds to the codepoint i + 127 in the + * MacOS Roman encoding with the Turkish language. + * + * @see the Unicode mapping table for the MacOS Turkish encoding + */ + private static final String UPPER_TURKISH + = "\u007e\u0000\u00c4\u00c5\u00c7\u00c9\u00d1\u00d6\u00dc\u00e1" + + "\u00e0\u00e2\u00e4\u00e3\u00e5\u00e7\u00e9\u00e8\u00ea\u00eb" + + "\u00ed\u00ec\u00ee\u00ef\u00f1\u00f3\u00f2\u00f4\u00f6\u00f5" + + "\u00fa\u00f9\u00fb\u00fc\u2020\u00b0\u00a2\u00a3\u00a7\u2022" + + "\u00b6\u00df\u00ae\u00a9\u2122\u00b4\u00a8\u2260\u00c6\u00d8" + + "\u221e\u00b1\u2264\u2265\u00a5\u00b5\u2202\u2211\u220f\u03c0" + + "\u222b\u00aa\u00ba\u03a9\u00e6\u00f8\u00bf\u00a1\u00ac\u221a" + + "\u0192\u2248\u2206\u00ab\u00bb\u2026\u00a0\u00c0\u00c3\u00d5" + + "\u0152\u0153\u2013\u2014\u201c\u201d\u2018\u2019\u00f7\u25ca" + + "\u00ff\u0178\u011e\u011f\u0130\u0131\u015e\u015f\u2021\u00b7" + + "\u201a\u201e\u2030\u00c2\u00ca\u00c1\u00cb\u00c8\u00cd\u00ce" + + "\u00cf\u00cc\u00d3\u00d4\uf8ff\u00d2\u00da\u00db\u00d9\uf8a0" + + "\u02c6\u02dc\u00af\u02d8\u02d9\u02da\u00b8\u02dd\u02db\u02c7"; + + + /** + * Constructs a CharGlyphMap.Type0 from all type 0 cmaps provided + * by the font. The implementation is able to fuse multiple type + * 0 cmaps, such as the MacRoman, Turkish, Icelandic and Croatian + * encoding, into a single map from Unicode characters to glyph + * indices. + * + * @param buf a ByteBuffer whose position is right at the + * beginning of the entire cmap table of the font (not + * at some subtable). + */ + public Type0(ByteBuffer buf) + { + int numTables; + int tableStart = buf.position(); + int limit = buf.limit(); + + /* The CMAP version must be 0. */ + if (buf.getChar() != 0) + throw new IllegalStateException(); + + numTables = buf.getChar(); + for (int i = 0; i < numTables; i++) + { + buf.limit(limit).position(tableStart + 4 + i * 8); + int platform = buf.getChar(); + int encoding = buf.getChar(); + int offset = tableStart + buf.getInt(); + + buf.position(offset); + int format = buf.getChar(); + int length = buf.getChar(); + buf.limit(offset + length); + int language = buf.getChar(); + + if (format == 0) + readSingleTable(buf, platform, language, encoding); + } + } + + + /** + * Processes a CMAP Type 0 table whose platform, encoding and + * language are already known. + * + * @param buf the buffer to read the table from, positioned + * right after the language tag. + */ + private void readSingleTable(ByteBuffer buf, + int platform, int language, + int encoding) + { + String upper = getUpper129(platform, encoding, language); + if (upper == null) + return; + + /* Skip the MacOS codepoints [0 .. 31] because they do not + * correspond to any Unicode codepoint. + */ + buf.position(buf.position() + 32); + + /* Irrespective of script and language, the MacOS codepoints + * [32 .. 126] correspond to the same Unicode codepoint. + */ + for (int i = 32; i < 126; i++) + glyphToUCS2[buf.get() & 0xff] = (char) i; + + for (int i = 127; i < 256; i++) + glyphToUCS2[buf.get() & 0xff] = upper.charAt(i - 127); + + /* Glyph 0 is always the undefined character, which has + * no codepoint in Unicode. + */ + glyphToUCS2[0] = 0; + } + + + /** + * Determines the glyph index for a given Unicode codepoint. + * + * @param ucs4 the Unicode codepoint in UCS-4 encoding. + * + * @return the glyph index, or 0 if the font does not contain + * a glyph for this codepoint. + */ + public int getGlyph(int ucs4) + { + /* This linear search is not exactly super fast. However, + * only really ancient fonts have only a type 0 cmap, + * so it should not hurt in very many cases. If it shows + * to be a performance problem, one could do a binary search + * on a 256-entry table sorted by Unicode codepoint. The + * matching index of that table could then be used to look + * up the glyph ID at that position. + */ + for (int i = 0; i < 256; i++) + if (glyphToUCS2[i] == ucs4) + return i; + return 0; + } + + + /** + * Returns a String whose charAt(i) is the Unicode + * character that corresponds to the codepoint i + + * 127 in the encoding specified by the platform, script + * and language tag of a Type 0 CMAP. + * + * @param language the language tag in the cmap subtable. For the + * Macintosh platform, this is 0 to indicate language-neutral + * encoding, or the MacOS language code plus one. The + * Apple documentation does not mention that one needs to be + * added, but the Adobe OpenType specification does. + * + * @return a String for mapping the top 129 characters to + * UCS-2. If platform is not 1 + * (indicating Macintosh), or if the combination of + * script and language is not + * recognized, null will be returned. + */ + private static String getUpper129(int platform, int script, int language) + { + if (platform != PLATFORM_MACINTOSH) + return null; + + switch (script) + { + case 0: /* smRoman */ + if (language == /* langIcelandic+1 */ 16) + return UPPER_ICELANDIC; + else if (language == /* langTurkish+1 */ 18) + return UPPER_TURKISH; + else if (language == /* langCroatian+1 */ 19) + return UPPER_CROATIAN; + else if (language == /* langRomanian+1 */ 38) + return UPPER_ROMANIAN; + else if (language == /* language-neutral */ 0) + return UPPER_ROMAN; + else + return null; + + case 4: /* smArabic */ + if (language == /* langFarsi+1 */ 32) + return UPPER_FARSI; + else + return UPPER_ARABIC; + + case 5: /* smHebrew */ + return UPPER_HEBREW; + + case 6: /* smGreek */ + return UPPER_GREEK; + + case 7: /* smCyrillic */ + return UPPER_CYRILLIC; + + case 29: /* smSlavic == smEastEurRoman */ + return UPPER_EAST_EUROPEAN_ROMAN; + } + + return null; + } + } + + + /** + * A mapping from Unicode code points to glyph IDs through CMAP Type + * 4 tables. These tables are able to map two-byte encoded text + * to glyph IDs, such as Unicode Basic Multilingual Plane which + * contains U+0000 .. U+FFFE without surrogates. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ + private static final class Type4 + extends CharGlyphMap + { + /** + * Determines whether this implementation supports a combination + * of platform, language and encoding is supported for a type 4 + * cmap table. + * + *

Currently, we support the following combinations: + * + *

  • the Unicode platform in encodings 0, 1, 2, 3 and + * 4;
  • + * + *
  • the Microsoft platform in encodings 1 (Basic Multilingual + * Plane) and 10 (full Unicode).
+ * + *

Most recent Macintosh fonts provide a type 4 + * cmap for Unicode. Microsoft recommends providing a + * type 4 cmap for encoding 1 of the Microsoft + * platform. The implementation of GNU Classpath supports both + * variants. + * + *

Not supported are ShiftJIS, Big5, Wansung, Johab, and other + * non-Unicode encodings. Text can easily be converted to Unicode + * using the java.nio.charset package. + */ + static boolean isSupported(int platform, int language, int encoding) + { + switch (platform) + { + case PLATFORM_UNICODE: + return (encoding >= 0) && (encoding <= 4); + + case PLATFORM_MICROSOFT: + return (encoding == /* Basic Multilingual Plane */ 1) + || (encoding == /* Full Unicode */ 10); + } + + return false; + } + + + /** + * Processes a CMAP Type 4 table whose platform, encoding and + * language are already known. We understand the Unicode platform + * with encodings 0, 1, 2, 3 and 4, and the Microsoft platform + * with encodings 1 (Unicode BMP) and 10 (UCS-4). + * + * @param buf the buffer to read the table from, positioned at + * its beginning. + * + * @return a Type4 table, or null if the combination + * of platform and encoding is not understood. + */ + static Type4 readTable(ByteBuffer buf, + int platform, int encoding) + { + int tableStart = buf.position(); + char format = buf.getChar(); + int length = buf.getChar(); + int language = buf.getChar(); + + if ((format != 4) || !isSupported(platform, language, encoding)) + throw new IllegalArgumentException(); + + buf.limit(tableStart + length); + + int segCountX2 = buf.getChar(); + int segCount = segCountX2 / 2; + int searchRange = buf.getChar(); + int entrySelector = buf.getChar(); + int rangeShift = buf.getChar(); + + CharBuffer endCode, startCode, idRangeOffset_glyphID; + ShortBuffer idDelta; + + int pos = buf.position(); + endCode = buf.asCharBuffer(); + pos += segCountX2 + /* reservedPad */ 2; + + buf.position(pos); + startCode = buf.asCharBuffer(); + pos += segCountX2; + + buf.position(pos); + idDelta = buf.asShortBuffer(); + pos += segCountX2; + + buf.position(pos); + idRangeOffset_glyphID = buf.asCharBuffer(); + + endCode.limit(segCount); + startCode.limit(segCount); + idDelta.limit(segCount); + idRangeOffset_glyphID.limit((buf.limit() - pos) / 2); + + return new Type4(segCount, + endCode, startCode, idDelta, + idRangeOffset_glyphID); + } + + + private CharBuffer lastChar; + private CharBuffer firstChar; + private ShortBuffer idDelta; + private CharBuffer rangeID; + private int numSegments; + + private Type4(int numSegments, + CharBuffer lastChar, CharBuffer firstChar, + ShortBuffer idDelta, CharBuffer rangeID) + { + this.numSegments = numSegments; + this.lastChar = lastChar; + this.firstChar = firstChar; + this.idDelta = idDelta; + this.rangeID = rangeID; + } + + + /** + * Determines the glyph index for a given Unicode codepoint. + * + * @param ucs4 the Unicode codepoint in UCS-4 encoding. + * + * @return the glyph index, or 0 if the font does not contain + * a glyph for this codepoint. + */ + public int getGlyph(int ucs4) + { + char c, segStart; + int segment, idRangeOffset; + + if (ucs4 > 0xffff) + return 0; + + c = (char) ucs4; + segment = find(c); + segStart = firstChar.get(segment); + if ((c < segStart) || (c > lastChar.get(segment))) + return 0; + + /* + * System.out.println("seg " + segment + * + ", range=" + (int) rangeID[segment] + * + ", delta=" + delta[segment]); + */ + + idRangeOffset = rangeID.get(segment); + if (idRangeOffset == 0) + return (int) (char) (((int) c) + idDelta.get(segment)); + int result = rangeID.get((idRangeOffset >> 1) + + (c - segStart) + segment); + if (result == 0) + return 0; + return (int) (char) (result + idDelta.get(segment)); + } + + + private int find(char c) + { + int min, max, mid; + + min = 0; + max = numSegments - 1; + mid = max >> 1; + + while (min < max) + { + // System.out.println("(" + min + "," + max + ") " + mid); + char val = lastChar.get(mid); + if (val == c) + break; + else if (val < c) + min = mid + 1; + else if (val > c) + max = mid; + mid = (min + max) >> 1; + } + + return mid; + } + } + + + /** + * A mapping from Unicode code points to glyph IDs through CMAP Type + * 12 tables. These tables are able to map four-byte encoded text + * to glyph IDs, such as Unicode UCS-4. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ + private static final class Type12 + extends CharGlyphMap + { + int numGroups; + IntBuffer data; + + + /** + * Determines whether this implementation supports a combination + * of platform and encoding for a type 12 cmap table. + * + *

Currently, we support the following combinations: + * + *

  • the Unicode platform in encodings 0, 1, 2, 3 and + * 4;
  • + * + *
  • the Microsoft platform in encodings 1 (Basic Multilingual + * Plane) and 10 (full Unicode).
+ */ + static boolean isSupported(int platform, int encoding) + { + switch (platform) + { + case PLATFORM_UNICODE: + return (encoding >= 0) && (encoding <= 4); + + case PLATFORM_MICROSOFT: + return (encoding == /* Basic Multilingual Plane */ 1) + || (encoding == /* Full Unicode */ 10); + } + + return false; + } + + + /** + * Constructs a cmap type 12 table whose platform and + * encoding are already known. We understand the Unicode platform + * with encodings 0, 1, 2, 3 and 4, and the Microsoft platform + * with encodings 1 (Unicode BMP) and 10 (UCS-4). + * + * @param buf the buffer to read the table from, positioned at + * its beginning. + */ + Type12(ByteBuffer buf, int platform, int encoding) + { + int tableStart = buf.position(); + int format = buf.getChar(); + if ((format != 12) || !isSupported(platform, encoding)) + throw new IllegalStateException(); + + buf.getChar(); // skip reserved field + buf.limit(tableStart + buf.getInt()); + int language = buf.getInt(); + numGroups = buf.getInt(); + data = buf.asIntBuffer(); + } + + + /** + * Determines the glyph index for a given Unicode codepoint. Users + * should be aware that the character-to-glyph mapping not not + * everything that is needed for full Unicode support. For example, + * the cmap table is not able to synthesize accented + * glyphs from the canonical decomposition sequence, even if the + * font would contain a glyph for the composed form. + * + * @param ucs4 the Unicode codepoint in UCS-4 encoding. Surrogates + * (U+D800 to U+DFFF) cannot be passed, they must be mapped to + * UCS-4 first. + * + * @return the glyph index, or 0 if the font does not contain + * a glyph for this codepoint. + */ + public int getGlyph(int ucs4) + { + int min, max, mid, startCharCode, endCharCode; + + min = 0; + max = numGroups - 1; + mid = max >> 1; + do + { + startCharCode = data.get(3 * mid); + endCharCode = data.get(3 * mid + 1); + + + /* + System.out.println("group " + mid + " (U+" + + Integer.toHexString(startCharCode) + + " .. U+" + Integer.toHexString(endCharCode) + + "): glyph " + (int) data.get(mid*3+2)); + */ + + if ((startCharCode <= ucs4) && (ucs4 <= endCharCode)) + return ucs4 + - startCharCode + + /* startGlyphID */ data.get(mid * 3 + 2); + + if (endCharCode < ucs4) + min = mid + 1; + else + max = mid; + mid = (min + max) >> 1; + } + while (min < max); + + startCharCode = data.get(3 * mid); + endCharCode = data.get(3 * mid + 1); + if ((startCharCode <= ucs4) && (ucs4 <= endCharCode)) + return ucs4 + - startCharCode + + /* startGlyphID */ data.get(mid * 3 + 2); + + return 0; + } + } +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/GlyphNamer.java b/libjava/classpath/gnu/java/awt/font/opentype/GlyphNamer.java new file mode 100644 index 000000000..72cecb542 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/opentype/GlyphNamer.java @@ -0,0 +1,1135 @@ +/* GlyphNamer.java -- Provides glyph names. + 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.font.opentype; + +import gnu.java.lang.CPStringBuilder; + +import java.nio.ByteBuffer; +import java.nio.IntBuffer; +import java.nio.CharBuffer; + + +/** + * Provides names for glyphs, which is useful when embedding fonts + * in PostScript or PDF documents. + * + *

If the font has a Zapf table, it is used to map + * glyph IDs back to a sequence of Unicode codepoints, which then + * makes it possible to look up or synthesize a PostScript glyph name + * according to Adobe’s conventions. This allows to extract the + * original text from the generated PDF or PostScript file, which is + * important for indexing, searching and extracting. + * + *

Otherwise, glyph names are taken from the post table. All known formats (1, 2, 2.5, 3 and + * 4) are supported. + * + *

Open Tasks: The code could be cleaner structured by + * having separate sub-classes for each variant of the POST table. + * Also, the implementation should not read in all glyph names if a + * font provides them in a POST table of type 2. It would be + * sufficient to just read in the offsets and delay the String + * fetching and conversion to the time when the glyph name is actually + * requested. + * + *

Lack of Thread Safety: The GlyphNamer class is + * intentionally not safe to access from multiple concurrent + * threads. Synchronization needs to be performed externally. Usually, + * the font has already obtained a lock before calling the GlyphNamer. + * It would thus be wasteful to acquire additional locks for the + * GlyphNamer. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +final class GlyphNamer +{ + /** + * The 'post' table of the font. + */ + private ByteBuffer postTable; + + + /** + * The 'Zapf' table of the font, or null if the font has no + * such table. + */ + private ByteBuffer zapfTable; + + + /** + * The offset of each glyph relative to the Zapf table, + * or null if the font does not have a Zapf table. + */ + private IntBuffer zapfOffsets; + + + /** + * The offset from the start of the Zapf table to the start + * of the extra info area. + */ + private int zapfExtraInfo; + + + /** + * The format of the post table, a Fixed 16.16 number. + */ + private int postFormat; + + + /** + * An array of glyph names. Used for table formats 1, 2, 2.5. + */ + private String[] glyphNames; + + + /** + * An array from glyph to character codes. Similar to the + * workings of a Zapf table, but maps to CID instead of + * Unicode. Used for table format 4. + */ + private CharBuffer glyphCharacterCodes; + + + /** + * The PostScript names of the 258 standard Macintosh glyphs. Note + * that some of these glyphs are not in the Adobe Standard Glyph + * List for New Fonts, namely .notdef, .null, nonmarkingreturn, + * nonbreakingspace, apple, onesuperior, twosuperior, and + * threesuperior. + */ + private static final String[] STANDARD_POSTSCRIPT_GLYPH_NAMES = + { + ".notdef", // glyph #0 + ".null", // glyph #1 + "nonmarkingreturn", // glyph #2 + "space", // glyph #3 + "exclam", // glyph #4 + "quotedbl", // glyph #5 + "numbersign", // glyph #6 + "dollar", // glyph #7 + "percent", // glyph #8 + "ampersand", // glyph #9 + "quotesingle", // glyph #10 + "parenleft", // glyph #11 + "parenright", // glyph #12 + "asterisk", // glyph #13 + "plus", // glyph #14 + "comma", // glyph #15 + "hyphen", // glyph #16 + "period", // glyph #17 + "slash", // glyph #18 + "zero", // glyph #19 + "one", // glyph #20 + "two", // glyph #21 + "three", // glyph #22 + "four", // glyph #23 + "five", // glyph #24 + "six", // glyph #25 + "seven", // glyph #26 + "eight", // glyph #27 + "nine", // glyph #28 + "colon", // glyph #29 + "semicolon", // glyph #30 + "less", // glyph #31 + "equal", // glyph #32 + "greater", // glyph #33 + "question", // glyph #34 + "at", // glyph #35 + "A", // glyph #36 + "B", // glyph #37 + "C", // glyph #38 + "D", // glyph #39 + "E", // glyph #40 + "F", // glyph #41 + "G", // glyph #42 + "H", // glyph #43 + "I", // glyph #44 + "J", // glyph #45 + "K", // glyph #46 + "L", // glyph #47 + "M", // glyph #48 + "N", // glyph #49 + "O", // glyph #50 + "P", // glyph #51 + "Q", // glyph #52 + "R", // glyph #53 + "S", // glyph #54 + "T", // glyph #55 + "U", // glyph #56 + "V", // glyph #57 + "W", // glyph #58 + "X", // glyph #59 + "Y", // glyph #60 + "Z", // glyph #61 + "bracketleft", // glyph #62 + "backslash", // glyph #63 + "bracketright", // glyph #64 + "asciicircum", // glyph #65 + "underscore", // glyph #66 + "grave", // glyph #67 + "a", // glyph #68 + "b", // glyph #69 + "c", // glyph #70 + "d", // glyph #71 + "e", // glyph #72 + "f", // glyph #73 + "g", // glyph #74 + "h", // glyph #75 + "i", // glyph #76 + "j", // glyph #77 + "k", // glyph #78 + "l", // glyph #79 + "m", // glyph #80 + "n", // glyph #81 + "o", // glyph #82 + "p", // glyph #83 + "q", // glyph #84 + "r", // glyph #85 + "s", // glyph #86 + "t", // glyph #87 + "u", // glyph #88 + "v", // glyph #89 + "w", // glyph #90 + "x", // glyph #91 + "y", // glyph #92 + "z", // glyph #93 + "braceleft", // glyph #94 + "bar", // glyph #95 + "braceright", // glyph #96 + "asciitilde", // glyph #97 + "Adieresis", // glyph #98 + "Aring", // glyph #99 + "Ccedilla", // glyph #100 + "Eacute", // glyph #101 + "Ntilde", // glyph #102 + "Odieresis", // glyph #103 + "Udieresis", // glyph #104 + "aacute", // glyph #105 + "agrave", // glyph #106 + "acircumflex", // glyph #107 + "adieresis", // glyph #108 + "atilde", // glyph #109 + "aring", // glyph #110 + "ccedilla", // glyph #111 + "eacute", // glyph #112 + "egrave", // glyph #113 + "ecircumflex", // glyph #114 + "edieresis", // glyph #115 + "iacute", // glyph #116 + "igrave", // glyph #117 + "icircumflex", // glyph #118 + "idieresis", // glyph #119 + "ntilde", // glyph #120 + "oacute", // glyph #121 + "ograve", // glyph #122 + "ocircumflex", // glyph #123 + "odieresis", // glyph #124 + "otilde", // glyph #125 + "uacute", // glyph #126 + "ugrave", // glyph #127 + "ucircumflex", // glyph #128 + "udieresis", // glyph #129 + "dagger", // glyph #130 + "degree", // glyph #131 + "cent", // glyph #132 + "sterling", // glyph #133 + "section", // glyph #134 + "bullet", // glyph #135 + "paragraph", // glyph #136 + "germandbls", // glyph #137 + "registered", // glyph #138 + "copyright", // glyph #139 + "trademark", // glyph #140 + "acute", // glyph #141 + "dieresis", // glyph #142 + "notequal", // glyph #143 + "AE", // glyph #144 + "Oslash", // glyph #145 + "infinity", // glyph #146 + "plusminus", // glyph #147 + "lessequal", // glyph #148 + "greaterequal", // glyph #149 + "yen", // glyph #150 + "mu", // glyph #151 + "partialdiff", // glyph #152 + "summation", // glyph #153 + "product", // glyph #154 + "pi", // glyph #155 + "integral", // glyph #156 + "ordfeminine", // glyph #157 + "ordmasculine", // glyph #158 + "Omega", // glyph #159 + "ae", // glyph #160 + "oslash", // glyph #161 + "questiondown", // glyph #162 + "exclamdown", // glyph #163 + "logicalnot", // glyph #164 + "radical", // glyph #165 + "florin", // glyph #166 + "approxequal", // glyph #167 + "Delta", // glyph #168 + "guillemotleft", // glyph #169 + "guillemotright", // glyph #170 + "ellipsis", // glyph #171 + "nonbreakingspace", // glyph #172 + "Agrave", // glyph #173 + "Atilde", // glyph #174 + "Otilde", // glyph #175 + "OE", // glyph #176 + "oe", // glyph #177 + "endash", // glyph #178 + "emdash", // glyph #179 + "quotedblleft", // glyph #180 + "quotedblright", // glyph #181 + "quoteleft", // glyph #182 + "quoteright", // glyph #183 + "divide", // glyph #184 + "lozenge", // glyph #185 + "ydieresis", // glyph #186 + "Ydieresis", // glyph #187 + "fraction", // glyph #188 + "currency", // glyph #189 + "guilsinglleft", // glyph #190 + "guilsinglright", // glyph #191 + "fi", // glyph #192 + "fl", // glyph #193 + "daggerdbl", // glyph #194 + "periodcentered", // glyph #195 + "quotesinglbase", // glyph #196 + "quotedblbase", // glyph #197 + "perthousand", // glyph #198 + "Acircumflex", // glyph #199 + "Ecircumflex", // glyph #200 + "Aacute", // glyph #201 + "Edieresis", // glyph #202 + "Egrave", // glyph #203 + "Iacute", // glyph #204 + "Icircumflex", // glyph #205 + "Idieresis", // glyph #206 + "Igrave", // glyph #207 + "Oacute", // glyph #208 + "Ocircumflex", // glyph #209 + "apple", // glyph #210 + "Ograve", // glyph #211 + "Uacute", // glyph #212 + "Ucircumflex", // glyph #213 + "Ugrave", // glyph #214 + "dotlessi", // glyph #215 + "circumflex", // glyph #216 + "tilde", // glyph #217 + "macron", // glyph #218 + "breve", // glyph #219 + "dotaccent", // glyph #220 + "ring", // glyph #221 + "cedilla", // glyph #222 + "hungarumlaut", // glyph #223 + "ogonek", // glyph #224 + "caron", // glyph #225 + "Lslash", // glyph #226 + "lslash", // glyph #227 + "Scaron", // glyph #228 + "scaron", // glyph #229 + "Zcaron", // glyph #230 + "zcaron", // glyph #231 + "brokenbar", // glyph #232 + "Eth", // glyph #233 + "eth", // glyph #234 + "Yacute", // glyph #235 + "yacute", // glyph #236 + "Thorn", // glyph #237 + "thorn", // glyph #238 + "minus", // glyph #239 + "multiply", // glyph #240 + "onesuperior", // glyph #241 + "twosuperior", // glyph #242 + "threesuperior", // glyph #243 + "onehalf", // glyph #244 + "onequarter", // glyph #245 + "threequarters", // glyph #246 + "franc", // glyph #247 + "Gbreve", // glyph #248 + "gbreve", // glyph #249 + "Idotaccent", // glyph #250 + "Scedilla", // glyph #251 + "scedilla", // glyph #252 + "Cacute", // glyph #253 + "cacute", // glyph #254 + "Ccaron", // glyph #255 + "ccaron", // glyph #256 + "dcroat" // glyph #257 + }; + + + private GlyphNamer(int numGlyphs, + ByteBuffer postTable, + ByteBuffer zapfTable) + { + this.postTable = postTable; + this.zapfTable = zapfTable; + + if ((zapfTable != null) && (zapfTable.getInt(0) == 0x00010000)) + { + readZapf(numGlyphs); + return; + } + + readPost(); + } + + + /** + * Sets up the information which allows to retrieve the information + * on demand. + * + * @param numGlyphs the number of glyphs in the font. This value + * comes from the maxp table. + */ + public static GlyphNamer forTables(int numGlyphs, + ByteBuffer postTable, + ByteBuffer zapfTable) + { + return new GlyphNamer(numGlyphs, postTable, zapfTable); + } + + + /** + * Retrieves or synthesizes a PostScript name for the glyph. + * Although the code is reasonably fast, it is recommended + * to cache the results in the printer driver. + * + *

If a font provides a 'Zapf' table, the reverse mapping + * from glyph to UTF-16 sequence is performed, and a glyph + * name is synthesized following the recommendations by Adobe. + * This allows to extract the original text from the generated + * PostScript or PDF, which is a requirement for indexing + * and searching. + * + *

If a font does not provide a 'Zapf' table, the glyph name + * is taken from the 'post' table. Note that some fonts have + * wrong data in their post data, in which case the resulting + * name will be garbage. Usually, this does not hurt, unless + * the user wants to extract text from the generated PostScript + * or PDF file. The GNU implementation understands all known + * formats of the post table (1, 2, 2.5, 3 and 4). + * + * @param glyph the index of the glyph whose name is to be + * retrieved. + * + * @return the glyph name, such as A, + * gcircumflex, z_uni0302, or + * u11C42. + */ + String getGlyphName(int glyph) + { + if (zapfOffsets != null) + { + zapfTable.position(zapfOffsets.get(glyph) + 8); + int numChars = zapfTable.getChar(); + char[] chars = new char[numChars]; + for (int i = 0; i < numChars; i++) + chars[i] = zapfTable.getChar(); + return getGlyphName(chars); + } + + + /* Type 1, Type 2, Type 2.5 */ + if (glyphNames != null) + return glyphNames[glyph]; + + /* Type 4: Synthesized glyph name. */ + if (glyphCharacterCodes != null) + return "a" + glyphCharacterCodes.get(glyph); + + /* Type 3: Arbitrary, but unique name for the glyph. + * + * To find out what a good naming scheme would be, we have printed + * a document containing the character U+201C in the font + * "Hiragino Kaku Gothic Pro W3" (by Dainippon Screen Mfg. Co., + * Ltd.) on Apple MacOS X 10.1.5. This font has a type 3 'post' + * table, and its 'cmap' maps U+201C to glyph #108. The generated + * PostScript file defined a character whose name was "g108". + * + * Therefore, we use 'g' as name prefix. According to the + * TrueType/OpenType specification, it should not matter what + * prefix we use. On the other hand, it does not hurt either to be + * compatible with a good printer driver. + * + * Actually, that specific font also contains a 'Zapf' table, + * which allows to generate glyph names according to Adobe's + * conventions, so that extracting text from and searching in the + * generated PostScript or PDF becomes possible. While the Apple + * PostScript printer driver does not seem to use the 'Zapf' table + * for this purpose, we do. + */ + return "g" + glyph; + } + + + /** + * Sets up some buffers which allow to quickly read information from + * the Zapf table. + * + * @see + * Apple’s documentation of the Zapf table + */ + private void readZapf(int numGlyphs) + { + zapfExtraInfo = zapfTable.getInt(4); + zapfTable.position(8); + zapfOffsets = zapfTable.asIntBuffer(); + zapfOffsets.limit(numGlyphs); + } + + + /** + * Reads in the PostScript data from a post table of a + * TrueType or OpenType font. The implementation currently + * understands the table formats 1, 2, 2.5, 3, and 4. + */ + private void readPost() + { + int numGlyphs, nameIndex, maxNameIndex; + char[] nameIndices; + String[] names; + byte[] pascalName; + + postTable.position(0); + postFormat = postTable.getInt(); + switch (postFormat) + { + case 0x00010000: + glyphNames = STANDARD_POSTSCRIPT_GLYPH_NAMES; + return; + + case 0x00020000: + postTable.position(32); + numGlyphs = postTable.getChar(); + glyphNames = new String[numGlyphs]; + pascalName = new byte[255]; + nameIndices = new char[numGlyphs]; + maxNameIndex = 0; + for (int i = 0; i < numGlyphs; i++) + maxNameIndex = Math.max(maxNameIndex, + nameIndices[i] = postTable.getChar()); + + names = new String[Math.max(maxNameIndex - 258 + 1, 0)]; + for (int i = 258; i <= maxNameIndex; i++) + { + int nameLen = (postTable.get() & 0xff); + postTable.get(pascalName, 0, nameLen); + names[i - 258] = new String(pascalName, 0, nameLen); + } + for (int i = 0; i < numGlyphs; i++) + { + nameIndex = nameIndices[i]; + if (nameIndex < 258) + glyphNames[i] = STANDARD_POSTSCRIPT_GLYPH_NAMES[nameIndex]; + else + glyphNames[i] = names[nameIndex - 258]; + } + return; + + case 0x00025000: // in case some font has a wrong representation of 2.5 + case 0x00028000: + /* Format 2.5 is a re-ordering of the standard names. It has + * been deprecated in February 2000, but might still occasionally + * float around. Since it can be supported with so little code, + * we do so. + */ + postTable.position(32); + numGlyphs = postTable.getChar(); + glyphNames = new String[numGlyphs]; + for (int i = 0; i < numGlyphs; i++) + glyphNames[i] = STANDARD_POSTSCRIPT_GLYPH_NAMES[i + postTable.get()]; + return; + + case 0x00030000: + /* Format 3 leaves it to the printer driver to choose whatever + * name it wants to. + */ + return; + + case 0x00040000: + /* Format 4 is used by Apple for composite fonts that have + * synthetic glyph names. The name of a glyph is "a" plus + * the integer (in decimal notation) that follows the table + * after numGlyphs. + */ + postTable.position(32); + numGlyphs = postTable.getChar(); + glyphCharacterCodes = postTable.asCharBuffer(); + glyphCharacterCodes.limit(numGlyphs); + return; + } + } + + + + /* For generating the following tables, a quick-and-dirty Python + * script was used. It is unlikely that we ever need to run it + * again, but for information and convenient access, it is included + * below. Initial '#' characters need to be removed from the generated + * strings, they are present so that the lines not break in the middle + * of Java escape sequences (no, this is not very clean). + * + * import string + * + * javaEscapes = {0x22:'\\"', 0x5c:'\\\\'} + * def escape(c): + * if javaEscapes.has_key(c): + * return javaEscapes[c] + * elif 0x20 <= c <= 0x7e: + * return chr(c) + * else: + * return '\\u%04x' % c + * + * def dump(name, s, stride): + * s = ('#' * stride) + s + * print " private static final String %s" % name + * for i in range(0, len(s), 60): + * print ' + "%s"' % s[i:i+60] + * + * glyphs = {} + * for line in open('aglfn13.txt', 'r').readlines(): + * if line[0] == '#': continue + * [ucs, glyphName, desc] = line.split(';') + * glyph = int('0x' + ucs, 0) + * assert (not glyphs.has_key(glyph)) or (glyphs[glyph] == glyphName) + * glyphs[glyph] = glyphName + * del glyphs[0] # arrowvertex + * k = glyphs.keys() + * k.sort() + * numGlyphs = len(k) + * names = '' + * pos = [] + * for glyph in k: + * pos.append(len(names) + 1) + * names = names + '/' + glyphs[glyph] + * dump('AGLFN_GLYPHS', string.join(map(escape, k), ''), 5) + * dump('AGLFN_NAME_OFFSET', string.join(map(escape, pos), ''), 4) + * dump('AGLFN_NAMES', names + '/', 0) + */ + + + /** + * A String that contains the Unicode codepoint for each glyph + * in the Adobe Glyph List. The characters are in sorted order. + * + * Generated from the Adobe Glyph List for New Fonts, version 1.1 + * of 17 April 2003. + * + * @see Adobe + * Glyph List for New Fonts + */ + private static final String AGLFN_GLYPHS + = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTU" + + "VWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\u00a1\u00a2\u00a3" + + "\u00a4\u00a5\u00a6\u00a7\u00a8\u00a9\u00aa\u00ab\u00ac\u00ae" + + "\u00af\u00b0\u00b1\u00b4\u00b5\u00b6\u00b7\u00b8\u00ba\u00bb" + + "\u00bc\u00bd\u00be\u00bf\u00c0\u00c1\u00c2\u00c3\u00c4\u00c5" + + "\u00c6\u00c7\u00c8\u00c9\u00ca\u00cb\u00cc\u00cd\u00ce\u00cf" + + "\u00d0\u00d1\u00d2\u00d3\u00d4\u00d5\u00d6\u00d7\u00d8\u00d9" + + "\u00da\u00db\u00dc\u00dd\u00de\u00df\u00e0\u00e1\u00e2\u00e3" + + "\u00e4\u00e5\u00e6\u00e7\u00e8\u00e9\u00ea\u00eb\u00ec\u00ed" + + "\u00ee\u00ef\u00f0\u00f1\u00f2\u00f3\u00f4\u00f5\u00f6\u00f7" + + "\u00f8\u00f9\u00fa\u00fb\u00fc\u00fd\u00fe\u00ff\u0100\u0101" + + "\u0102\u0103\u0104\u0105\u0106\u0107\u0108\u0109\u010a\u010b" + + "\u010c\u010d\u010e\u010f\u0110\u0111\u0112\u0113\u0114\u0115" + + "\u0116\u0117\u0118\u0119\u011a\u011b\u011c\u011d\u011e\u011f" + + "\u0120\u0121\u0122\u0123\u0124\u0125\u0126\u0127\u0128\u0129" + + "\u012a\u012b\u012c\u012d\u012e\u012f\u0130\u0131\u0132\u0133" + + "\u0134\u0135\u0136\u0137\u0138\u0139\u013a\u013b\u013c\u013d" + + "\u013e\u013f\u0140\u0141\u0142\u0143\u0144\u0145\u0146\u0147" + + "\u0148\u0149\u014a\u014b\u014c\u014d\u014e\u014f\u0150\u0151" + + "\u0152\u0153\u0154\u0155\u0156\u0157\u0158\u0159\u015a\u015b" + + "\u015c\u015d\u015e\u015f\u0160\u0161\u0162\u0163\u0164\u0165" + + "\u0166\u0167\u0168\u0169\u016a\u016b\u016c\u016d\u016e\u016f" + + "\u0170\u0171\u0172\u0173\u0174\u0175\u0176\u0177\u0178\u0179" + + "\u017a\u017b\u017c\u017d\u017e\u017f\u0192\u01a0\u01a1\u01af" + + "\u01b0\u01e6\u01e7\u01fa\u01fb\u01fc\u01fd\u01fe\u01ff\u0218" + + "\u0219\u02bc\u02bd\u02c6\u02c7\u02d8\u02d9\u02da\u02db\u02dc" + + "\u02dd\u0300\u0301\u0303\u0309\u0323\u0384\u0385\u0386\u0387" + + "\u0388\u0389\u038a\u038c\u038e\u038f\u0390\u0391\u0392\u0393" + + "\u0395\u0396\u0397\u0398\u0399\u039a\u039b\u039c\u039d\u039e" + + "\u039f\u03a0\u03a1\u03a3\u03a4\u03a5\u03a6\u03a7\u03a8\u03aa" + + "\u03ab\u03ac\u03ad\u03ae\u03af\u03b0\u03b1\u03b2\u03b3\u03b4" + + "\u03b5\u03b6\u03b7\u03b8\u03b9\u03ba\u03bb\u03bd\u03be\u03bf" + + "\u03c0\u03c1\u03c2\u03c3\u03c4\u03c5\u03c6\u03c7\u03c8\u03c9" + + "\u03ca\u03cb\u03cc\u03cd\u03ce\u03d1\u03d2\u03d5\u03d6\u0401" + + "\u0402\u0403\u0404\u0405\u0406\u0407\u0408\u0409\u040a\u040b" + + "\u040c\u040e\u040f\u0410\u0411\u0412\u0413\u0414\u0415\u0416" + + "\u0417\u0418\u0419\u041a\u041b\u041c\u041d\u041e\u041f\u0420" + + "\u0421\u0422\u0423\u0424\u0425\u0426\u0427\u0428\u0429\u042a" + + "\u042b\u042c\u042d\u042e\u042f\u0430\u0431\u0432\u0433\u0434" + + "\u0435\u0436\u0437\u0438\u0439\u043a\u043b\u043c\u043d\u043e" + + "\u043f\u0440\u0441\u0442\u0443\u0444\u0445\u0446\u0447\u0448" + + "\u0449\u044a\u044b\u044c\u044d\u044e\u044f\u0451\u0452\u0453" + + "\u0454\u0455\u0456\u0457\u0458\u0459\u045a\u045b\u045c\u045e" + + "\u045f\u0462\u0463\u0472\u0473\u0474\u0475\u0490\u0491\u04d9" + + "\u05b0\u05b1\u05b2\u05b3\u05b4\u05b5\u05b6\u05b7\u05b8\u05b9" + + "\u05bb\u05bc\u05bd\u05be\u05bf\u05c0\u05c1\u05c2\u05c3\u05d0" + + "\u05d1\u05d2\u05d3\u05d4\u05d5\u05d6\u05d7\u05d8\u05d9\u05da" + + "\u05db\u05dc\u05dd\u05de\u05df\u05e0\u05e1\u05e2\u05e3\u05e4" + + "\u05e5\u05e6\u05e7\u05e8\u05e9\u05ea\u05f0\u05f1\u05f2\u060c" + + "\u061b\u061f\u0621\u0622\u0623\u0624\u0625\u0626\u0627\u0628" + + "\u0629\u062a\u062b\u062c\u062d\u062e\u062f\u0630\u0631\u0632" + + "\u0633\u0634\u0635\u0636\u0637\u0638\u0639\u063a\u0640\u0641" + + "\u0642\u0643\u0644\u0645\u0646\u0647\u0648\u0649\u064a\u064b" + + "\u064c\u064d\u064e\u064f\u0650\u0651\u0652\u0660\u0661\u0662" + + "\u0663\u0664\u0665\u0666\u0667\u0668\u0669\u066a\u066d\u0679" + + "\u067e\u0686\u0688\u0691\u0698\u06a4\u06af\u06ba\u06d2\u06d5" + + "\u1e80\u1e81\u1e82\u1e83\u1e84\u1e85\u1ef2\u1ef3\u200c\u200d" + + "\u200e\u200f\u2012\u2013\u2014\u2015\u2017\u2018\u2019\u201a" + + "\u201b\u201c\u201d\u201e\u2020\u2021\u2022\u2024\u2025\u2026" + + "\u202c\u202d\u202e\u2030\u2032\u2033\u2039\u203a\u203c\u2044" + + "\u20a1\u20a3\u20a4\u20a7\u20aa\u20ab\u20ac\u2105\u2111\u2113" + + "\u2116\u2118\u211c\u211e\u2122\u2126\u212e\u2135\u2153\u2154" + + "\u215b\u215c\u215d\u215e\u2190\u2191\u2192\u2193\u2194\u2195" + + "\u21a8\u21b5\u21d0\u21d1\u21d2\u21d3\u21d4\u2200\u2202\u2203" + + "\u2205\u2206\u2207\u2208\u2209\u220b\u220f\u2211\u2212\u2217" + + "\u221a\u221d\u221e\u221f\u2220\u2227\u2228\u2229\u222a\u222b" + + "\u2234\u223c\u2245\u2248\u2260\u2261\u2264\u2265\u2282\u2283" + + "\u2284\u2286\u2287\u2295\u2297\u22a5\u22c5\u2302\u2310\u2320" + + "\u2321\u2329\u232a\u2500\u2502\u250c\u2510\u2514\u2518\u251c" + + "\u2524\u252c\u2534\u253c\u2550\u2551\u2552\u2553\u2554\u2555" + + "\u2556\u2557\u2558\u2559\u255a\u255b\u255c\u255d\u255e\u255f" + + "\u2560\u2561\u2562\u2563\u2564\u2565\u2566\u2567\u2568\u2569" + + "\u256a\u256b\u256c\u2580\u2584\u2588\u258c\u2590\u2591\u2592" + + "\u2593\u25a0\u25a1\u25aa\u25ab\u25ac\u25b2\u25ba\u25bc\u25c4" + + "\u25ca\u25cb\u25cf\u25d8\u25d9\u25e6\u263a\u263b\u263c\u2640" + + "\u2642\u2660\u2663\u2665\u2666\u266a\u266b"; + + + /** + * The offset of each glyph name in AGLFN_NAMES. + * + * Generated from the Adobe Glyph List for New Fonts, version 1.1 + * of 17 April 2003. + * + * @see Adobe + * Glyph List for New Fonts + */ + private static final String AGLFN_NAME_OFFSET + = "\u0001\u0007\u000e\u0017\")1;GQ\\ejpw~\u0084\u0089\u008d" + + "\u0091\u0097\u009c\u00a1\u00a5\u00ab\u00b1\u00b6\u00bc\u00c6" + + "\u00cb\u00d1\u00d9\u00e2\u00e5\u00e7\u00e9\u00eb\u00ed\u00ef" + + "\u00f1\u00f3\u00f5\u00f7\u00f9\u00fb\u00fd\u00ff\u0101\u0103" + + "\u0105\u0107\u0109\u010b\u010d\u010f\u0111\u0113\u0115\u0117" + + "\u0119\u0125\u012f\u013c\u0148\u0153\u0159\u015b\u015d\u015f" + + "\u0161\u0163\u0165\u0167\u0169\u016b\u016d\u016f\u0171\u0173" + + "\u0175\u0177\u0179\u017b\u017d\u017f\u0181\u0183\u0185\u0187" + + "\u0189\u018b\u018d\u0197\u019b\u01a6\u01b1\u01bc\u01c1\u01ca" + + "\u01d3\u01d7\u01e1\u01e9\u01f2\u01fc\u0208\u0216\u0221\u022c" + + "\u0233\u023a\u0244\u024a\u024d\u0257\u0266\u026e\u027b\u028a" + + "\u0295\u029d\u02ab\u02b8\u02bf\u02c6\u02d2\u02d9\u02e3\u02e9" + + "\u02ec\u02f5\u02fc\u0303\u030f\u0319\u0320\u0327\u0333\u033d" + + "\u0341\u0348\u034f\u0356\u0362\u0369\u0373\u037c\u0383\u038a" + + "\u0391\u039d\u03a7\u03ae\u03b4\u03bf\u03c6\u03cd\u03d9\u03e0" + + "\u03ea\u03f0\u03f3\u03fc\u0403\u040a\u0416\u0420\u0427\u042e" + + "\u043a\u0444\u0448\u044f\u0456\u045d\u0469\u0470\u047a\u0481" + + "\u0488\u048f\u0496\u04a2\u04ac\u04b3\u04b9\u04c3\u04cb\u04d3" + + "\u04da\u04e1\u04e9\u04f1\u04f8\u04ff\u050b\u0517\u0522\u052d" + + "\u0534\u053b\u0542\u0549\u0550\u0557\u055f\u0567\u056e\u0575" + + "\u0580\u058b\u0593\u059b\u05a2\u05a9\u05b5\u05c1\u05c8\u05cf" + + "\u05da\u05e5\u05f2\u05ff\u060b\u0617\u061c\u0621\u0628\u062f" + + "\u0637\u063f\u0646\u064d\u0655\u065d\u0668\u0671\u0674\u0677" + + "\u0683\u068f\u069c\u06a9\u06b6\u06bd\u06c4\u06d1\u06de\u06e5" + + "\u06ec\u06f1\u06f6\u06fd\u0704\u070b\u0712\u071f\u072c\u0733" + + "\u073a\u0746\u074a\u074e\u0756\u075e\u0765\u076c\u077a\u0788" + + "\u078b\u078e\u0795\u079c\u07a9\u07b6\u07bd\u07c4\u07cb\u07d2" + + "\u07de\u07ea\u07f3\u07fc\u0803\u080a\u0817\u0824\u082b\u0832" + + "\u0837\u083c\u0843\u084a\u0852\u085a\u0861\u0868\u086e\u0874" + + "\u0882\u0890\u0898\u08a0\u08ac\u08b8\u08c4\u08d0\u08da\u08e1" + + "\u08e8\u08f3\u08fe\u0905\u090c\u0912\u0919\u091f\u0925\u092b" + + "\u0931\u0938\u093f\u094a\u0955\u095d\u0965\u0971\u097d\u098a" + + "\u0997\u09a1\u09ab\u09b6\u09bc\u09c2\u09cc\u09d1\u09d8\u09de" + + "\u09eb\u09f5\u09ff\u0a09\u0a17\u0a24\u0a2a\u0a38\u0a43\u0a4d" + + "\u0a5a\u0a63\u0a6d\u0a7a\u0a87\u0a92\u0aa4\u0aaa\u0aaf\u0ab5" + + "\u0abd\u0ac2\u0ac6\u0acc\u0ad1\u0ad7\u0ade\u0ae1\u0ae4\u0ae7" + + "\u0aef\u0af2\u0af6\u0afc\u0b00\u0b08\u0b0c\u0b10\u0b14\u0b21" + + "\u0b31\u0b3c\u0b49\u0b52\u0b5c\u0b71\u0b77\u0b7c\u0b82\u0b88" + + "\u0b90\u0b95\u0b99\u0b9f\u0ba4\u0baa\u0bb1\u0bb4\u0bb7\u0bbf" + + "\u0bc2\u0bc6\u0bcd\u0bd3\u0bd7\u0bdf\u0be3\u0be7\u0beb\u0bf1" + + "\u0bfe\u0c0e\u0c1b\u0c28\u0c33\u0c3a\u0c43\u0c48\u0c4f\u0c59" + + "\u0c63\u0c6d\u0c77\u0c81\u0c8b\u0c95\u0c9f\u0ca9\u0cb3\u0cbd" + + "\u0cc7\u0cd1\u0cdb\u0ce5\u0cef\u0cf9\u0d03\u0d0d\u0d17\u0d21" + + "\u0d2b\u0d35\u0d3f\u0d49\u0d53\u0d5d\u0d67\u0d71\u0d7b\u0d85" + + "\u0d8f\u0d99\u0da3\u0dad\u0db7\u0dc1\u0dcb\u0dd5\u0ddf\u0de9" + + "\u0df3\u0dfd\u0e07\u0e11\u0e1b\u0e25\u0e2f\u0e39\u0e43\u0e4d" + + "\u0e57\u0e61\u0e6b\u0e75\u0e7f\u0e89\u0e93\u0e9d\u0ea7\u0eb1" + + "\u0ebb\u0ec5\u0ecf\u0ed9\u0ee3\u0eed\u0ef7\u0f01\u0f0b\u0f15" + + "\u0f1f\u0f29\u0f33\u0f3d\u0f47\u0f51\u0f5b\u0f65\u0f6f\u0f79" + + "\u0f83\u0f8d\u0f97\u0fa1\u0fab\u0fb5\u0fbf\u0fc9\u0fd3\u0fdd" + + "\u0fe7\u0ff1\u0ffb\u1005\u100f\u1019\u1023\u102d\u1037\u1041" + + "\u104b\u1055\u105f\u1069\u1073\u107d\u1087\u1091\u109b\u10a5" + + "\u10af\u10b9\u10c3\u10cd\u10d7\u10e1\u10eb\u10f5\u10ff\u1109" + + "\u1113\u111d\u1127\u1131\u113b\u1145\u114f\u1159\u1163\u116d" + + "\u1177\u1181\u118b\u1195\u119f\u11a9\u11b3\u11bd\u11c7\u11d1" + + "\u11db\u11e5\u11ef\u11f9\u1203\u120d\u1217\u1221\u122b\u1235" + + "\u123f\u1249\u1253\u125d\u1267\u1271\u127b\u1285\u128f\u1299" + + "\u12a3\u12ad\u12b7\u12c1\u12cb\u12d5\u12df\u12e9\u12f3\u12fd" + + "\u1307\u1311\u131b\u1325\u132f\u1339\u1343\u134d\u1357\u1361" + + "\u136b\u1375\u137f\u1389\u1393\u139d\u13a7\u13b1\u13bb\u13c5" + + "\u13cf\u13d9\u13e3\u13ed\u13f7\u1401\u140b\u1415\u141f\u1429" + + "\u1433\u143d\u1447\u1451\u145b\u1465\u146f\u1479\u1483\u148d" + + "\u1497\u14a1\u14ab\u14b5\u14bf\u14c9\u14d3\u14dd\u14e7\u14f1" + + "\u14f8\u14ff\u1506\u150d\u1517\u1521\u1528\u152f\u1539\u1541" + + "\u1549\u1551\u155c\u1563\u156a\u1574\u1582\u158c\u1597\u15a6" + + "\u15b4\u15c1\u15cf\u15dc\u15e3\u15ed\u15f4\u1603\u1612\u161b" + + "\u1625\u162f\u1639\u1645\u164c\u1653\u1661\u1670\u167a\u1683" + + "\u1691\u1697\u169c\u16a3\u16ad\u16b2\u16b7\u16c1\u16ca\u16d4" + + "\u16de\u16ea\u16f3\u1700\u170a\u1710\u171a\u1720\u1729\u1733" + + "\u173d\u174a\u1756\u1763\u176d\u1775\u1780\u178a\u1794\u179e" + + "\u17ab\u17ba\u17c7\u17d2\u17e0\u17ed\u17fa\u1804\u1810\u181c" + + "\u1825\u182b\u1834\u183c\u1847\u1850\u1858\u1862\u1868\u1875" + + "\u187d\u188a\u1893\u189e\u18a4\u18af\u18b9\u18c6\u18cc\u18d5" + + "\u18df\u18e7\u18f1\u18fd\u1906\u1912\u191c\u1929\u1936\u1945" + + "\u194f\u195c\u196b\u1976\u1985\u1993\u199b\u19a1\u19af\u19ba" + + "\u19c5\u19cf\u19da\u19e3\u19ec\u19f5\u19fe\u1a07\u1a10\u1a19" + + "\u1a22\u1a2b\u1a34\u1a3d\u1a46\u1a4f\u1a58\u1a61\u1a6a\u1a73" + + "\u1a7c\u1a85\u1a8e\u1a97\u1aa0\u1aa9\u1ab2\u1abb\u1ac4\u1acd" + + "\u1ad6\u1adf\u1ae8\u1af1\u1afa\u1b03\u1b0c\u1b15\u1b1e\u1b27" + + "\u1b30\u1b39\u1b42\u1b4a\u1b52\u1b58\u1b60\u1b68\u1b70\u1b76" + + "\u1b7e\u1b88\u1b8f\u1b96\u1b9d\u1ba8\u1bb0\u1bb8\u1bc0\u1bc8" + + "\u1bd0\u1bd7\u1bde\u1be8\u1bf2\u1bfd\u1c07\u1c14\u1c18\u1c1f" + + "\u1c24\u1c2a\u1c2f\u1c35\u1c3d\u1c49"; + + + /** + * The name of each glyph in the Adobe Glyph List for New Fonts + * (AGLFN). The name of the n-th glyph starts at position + * AGLFN_NAME_OFFSET.charAt(n). It ends before the following + * slash (slashes cannot be part of a PostScript name, which + * is why we use it for separation). + * + *

Generated from the Adobe Glyph List for New Fonts, version 1.1 + * of 17 April 2003. + * + * @see Adobe + * Glyph List for New Fonts + */ + private static final String AGLFN_NAMES + = "/space/exclam/quotedbl/numbersign/dollar/percent/ampersand/q" + + "uotesingle/parenleft/parenright/asterisk/plus/comma/hyphen/p" + + "eriod/slash/zero/one/two/three/four/five/six/seven/eight/nin" + + "e/colon/semicolon/less/equal/greater/question/at/A/B/C/D/E/F" + + "/G/H/I/J/K/L/M/N/O/P/Q/R/S/T/U/V/W/X/Y/Z/bracketleft/backsla" + + "sh/bracketright/asciicircum/underscore/grave/a/b/c/d/e/f/g/h" + + "/i/j/k/l/m/n/o/p/q/r/s/t/u/v/w/x/y/z/braceleft/bar/bracerigh" + + "t/asciitilde/exclamdown/cent/sterling/currency/yen/brokenbar" + + "/section/dieresis/copyright/ordfeminine/guillemotleft/logica" + + "lnot/registered/macron/degree/plusminus/acute/mu/paragraph/p" + + "eriodcentered/cedilla/ordmasculine/guillemotright/onequarter" + + "/onehalf/threequarters/questiondown/Agrave/Aacute/Acircumfle" + + "x/Atilde/Adieresis/Aring/AE/Ccedilla/Egrave/Eacute/Ecircumfl" + + "ex/Edieresis/Igrave/Iacute/Icircumflex/Idieresis/Eth/Ntilde/" + + "Ograve/Oacute/Ocircumflex/Otilde/Odieresis/multiply/Oslash/U" + + "grave/Uacute/Ucircumflex/Udieresis/Yacute/Thorn/germandbls/a" + + "grave/aacute/acircumflex/atilde/adieresis/aring/ae/ccedilla/" + + "egrave/eacute/ecircumflex/edieresis/igrave/iacute/icircumfle" + + "x/idieresis/eth/ntilde/ograve/oacute/ocircumflex/otilde/odie" + + "resis/divide/oslash/ugrave/uacute/ucircumflex/udieresis/yacu" + + "te/thorn/ydieresis/Amacron/amacron/Abreve/abreve/Aogonek/aog" + + "onek/Cacute/cacute/Ccircumflex/ccircumflex/Cdotaccent/cdotac" + + "cent/Ccaron/ccaron/Dcaron/dcaron/Dcroat/dcroat/Emacron/emacr" + + "on/Ebreve/ebreve/Edotaccent/edotaccent/Eogonek/eogonek/Ecaro" + + "n/ecaron/Gcircumflex/gcircumflex/Gbreve/gbreve/Gdotaccent/gd" + + "otaccent/Gcommaaccent/gcommaaccent/Hcircumflex/hcircumflex/H" + + "bar/hbar/Itilde/itilde/Imacron/imacron/Ibreve/ibreve/Iogonek" + + "/iogonek/Idotaccent/dotlessi/IJ/ij/Jcircumflex/jcircumflex/K" + + "commaaccent/kcommaaccent/kgreenlandic/Lacute/lacute/Lcommaac" + + "cent/lcommaaccent/Lcaron/lcaron/Ldot/ldot/Lslash/lslash/Nacu" + + "te/nacute/Ncommaaccent/ncommaaccent/Ncaron/ncaron/napostroph" + + "e/Eng/eng/Omacron/omacron/Obreve/obreve/Ohungarumlaut/ohunga" + + "rumlaut/OE/oe/Racute/racute/Rcommaaccent/rcommaaccent/Rcaron" + + "/rcaron/Sacute/sacute/Scircumflex/scircumflex/Scedilla/scedi" + + "lla/Scaron/scaron/Tcommaaccent/tcommaaccent/Tcaron/tcaron/Tb" + + "ar/tbar/Utilde/utilde/Umacron/umacron/Ubreve/ubreve/Uring/ur" + + "ing/Uhungarumlaut/uhungarumlaut/Uogonek/uogonek/Wcircumflex/" + + "wcircumflex/Ycircumflex/ycircumflex/Ydieresis/Zacute/zacute/" + + "Zdotaccent/zdotaccent/Zcaron/zcaron/longs/florin/Ohorn/ohorn" + + "/Uhorn/uhorn/Gcaron/gcaron/Aringacute/aringacute/AEacute/aea" + + "cute/Oslashacute/oslashacute/Scommaaccent/scommaaccent/afii5" + + "7929/afii64937/circumflex/caron/breve/dotaccent/ring/ogonek/" + + "tilde/hungarumlaut/gravecomb/acutecomb/tildecomb/hookaboveco" + + "mb/dotbelowcomb/tonos/dieresistonos/Alphatonos/anoteleia/Eps" + + "ilontonos/Etatonos/Iotatonos/Omicrontonos/Upsilontonos/Omega" + + "tonos/iotadieresistonos/Alpha/Beta/Gamma/Epsilon/Zeta/Eta/Th" + + "eta/Iota/Kappa/Lambda/Mu/Nu/Xi/Omicron/Pi/Rho/Sigma/Tau/Upsi" + + "lon/Phi/Chi/Psi/Iotadieresis/Upsilondieresis/alphatonos/epsi" + + "lontonos/etatonos/iotatonos/upsilondieresistonos/alpha/beta/" + + "gamma/delta/epsilon/zeta/eta/theta/iota/kappa/lambda/nu/xi/o" + + "micron/pi/rho/sigma1/sigma/tau/upsilon/phi/chi/psi/omega/iot" + + "adieresis/upsilondieresis/omicrontonos/upsilontonos/omegaton" + + "os/theta1/Upsilon1/phi1/omega1/afii10023/afii10051/afii10052" + + "/afii10053/afii10054/afii10055/afii10056/afii10057/afii10058" + + "/afii10059/afii10060/afii10061/afii10062/afii10145/afii10017" + + "/afii10018/afii10019/afii10020/afii10021/afii10022/afii10024" + + "/afii10025/afii10026/afii10027/afii10028/afii10029/afii10030" + + "/afii10031/afii10032/afii10033/afii10034/afii10035/afii10036" + + "/afii10037/afii10038/afii10039/afii10040/afii10041/afii10042" + + "/afii10043/afii10044/afii10045/afii10046/afii10047/afii10048" + + "/afii10049/afii10065/afii10066/afii10067/afii10068/afii10069" + + "/afii10070/afii10072/afii10073/afii10074/afii10075/afii10076" + + "/afii10077/afii10078/afii10079/afii10080/afii10081/afii10082" + + "/afii10083/afii10084/afii10085/afii10086/afii10087/afii10088" + + "/afii10089/afii10090/afii10091/afii10092/afii10093/afii10094" + + "/afii10095/afii10096/afii10097/afii10071/afii10099/afii10100" + + "/afii10101/afii10102/afii10103/afii10104/afii10105/afii10106" + + "/afii10107/afii10108/afii10109/afii10110/afii10193/afii10146" + + "/afii10194/afii10147/afii10195/afii10148/afii10196/afii10050" + + "/afii10098/afii10846/afii57799/afii57801/afii57800/afii57802" + + "/afii57793/afii57794/afii57795/afii57798/afii57797/afii57806" + + "/afii57796/afii57807/afii57839/afii57645/afii57841/afii57842" + + "/afii57804/afii57803/afii57658/afii57664/afii57665/afii57666" + + "/afii57667/afii57668/afii57669/afii57670/afii57671/afii57672" + + "/afii57673/afii57674/afii57675/afii57676/afii57677/afii57678" + + "/afii57679/afii57680/afii57681/afii57682/afii57683/afii57684" + + "/afii57685/afii57686/afii57687/afii57688/afii57689/afii57690" + + "/afii57716/afii57717/afii57718/afii57388/afii57403/afii57407" + + "/afii57409/afii57410/afii57411/afii57412/afii57413/afii57414" + + "/afii57415/afii57416/afii57417/afii57418/afii57419/afii57420" + + "/afii57421/afii57422/afii57423/afii57424/afii57425/afii57426" + + "/afii57427/afii57428/afii57429/afii57430/afii57431/afii57432" + + "/afii57433/afii57434/afii57440/afii57441/afii57442/afii57443" + + "/afii57444/afii57445/afii57446/afii57470/afii57448/afii57449" + + "/afii57450/afii57451/afii57452/afii57453/afii57454/afii57455" + + "/afii57456/afii57457/afii57458/afii57392/afii57393/afii57394" + + "/afii57395/afii57396/afii57397/afii57398/afii57399/afii57400" + + "/afii57401/afii57381/afii63167/afii57511/afii57506/afii57507" + + "/afii57512/afii57513/afii57508/afii57505/afii57509/afii57514" + + "/afii57519/afii57534/Wgrave/wgrave/Wacute/wacute/Wdieresis/w" + + "dieresis/Ygrave/ygrave/afii61664/afii301/afii299/afii300/fig" + + "uredash/endash/emdash/afii00208/underscoredbl/quoteleft/quot" + + "eright/quotesinglbase/quotereversed/quotedblleft/quotedblrig" + + "ht/quotedblbase/dagger/daggerdbl/bullet/onedotenleader/twodo" + + "tenleader/ellipsis/afii61573/afii61574/afii61575/perthousand" + + "/minute/second/guilsinglleft/guilsinglright/exclamdbl/fracti" + + "on/colonmonetary/franc/lira/peseta/afii57636/dong/Euro/afii6" + + "1248/Ifraktur/afii61289/afii61352/weierstrass/Rfraktur/presc" + + "ription/trademark/Omega/estimated/aleph/onethird/twothirds/o" + + "neeighth/threeeighths/fiveeighths/seveneighths/arrowleft/arr" + + "owup/arrowright/arrowdown/arrowboth/arrowupdn/arrowupdnbse/c" + + "arriagereturn/arrowdblleft/arrowdblup/arrowdblright/arrowdbl" + + "down/arrowdblboth/universal/partialdiff/existential/emptyset" + + "/Delta/gradient/element/notelement/suchthat/product/summatio" + + "n/minus/asteriskmath/radical/proportional/infinity/orthogona" + + "l/angle/logicaland/logicalor/intersection/union/integral/the" + + "refore/similar/congruent/approxequal/notequal/equivalence/le" + + "ssequal/greaterequal/propersubset/propersuperset/notsubset/r" + + "eflexsubset/reflexsuperset/circleplus/circlemultiply/perpend" + + "icular/dotmath/house/revlogicalnot/integraltp/integralbt/ang" + + "leleft/angleright/SF100000/SF110000/SF010000/SF030000/SF0200" + + "00/SF040000/SF080000/SF090000/SF060000/SF070000/SF050000/SF4" + + "30000/SF240000/SF510000/SF520000/SF390000/SF220000/SF210000/" + + "SF250000/SF500000/SF490000/SF380000/SF280000/SF270000/SF2600" + + "00/SF360000/SF370000/SF420000/SF190000/SF200000/SF230000/SF4" + + "70000/SF480000/SF410000/SF450000/SF460000/SF400000/SF540000/" + + "SF530000/SF440000/upblock/dnblock/block/lfblock/rtblock/ltsh" + + "ade/shade/dkshade/filledbox/H22073/H18543/H18551/filledrect/" + + "triagup/triagrt/triagdn/triaglf/lozenge/circle/H18533/invbul" + + "let/invcircle/openbullet/smileface/invsmileface/sun/female/m" + + "ale/spade/club/heart/diamond/musicalnote/musicalnotedbl/"; + + + /** + * Determines the name of a glyph according to the Adobe Glyph List + * for New Fonts (AGLFN). Because all glyphs in AGLFN correspond to + * a precomposed Unicode codepoint, the mismatch between characters + * and glyphs is not an issue here. + * + * @param c the Unicode codepoint that corresponds to the glyph, for + * example 0x010a for LATIN CAPITAL LETTER C WITH + * DOT ABOVE. + * + * @return the glyph name, for example Cdotaccent. If + * the glyph is not in the Adobe Glyph List for New Fonts, + * null is returned. + * + * @see Adobe + * Glyph List for New Fonts (AGLFN), version 1.1 of April 17, + * 2003 + * + * @see Adobe’s guidelines related to Unicode + */ + private static String getAGLFNName(char c) + { + int min, max, mid; + char midChar; + + /* Performs a binary search in the sorted array (actually, a + * String) of glyphs in the Adobe Glyph List for New Fonts. + * + * A good compiler might be able to optimize a call to charAt for + * a static final String, but this routine is probably not that + * critical to performance. + */ + min = 0; + max = AGLFN_GLYPHS.length() - 1; + mid = max >> 1; + midChar = AGLFN_GLYPHS.charAt(mid); + do + { + if (midChar == c) + break; + else if (midChar < c) + min = mid + 1; + else + max = mid; + mid = (min + max) >> 1; + midChar = AGLFN_GLYPHS.charAt(mid); + } + while (min < max); + + if (midChar != c) + return null; + + int pos = AGLFN_NAME_OFFSET.charAt(mid); + return AGLFN_NAMES.substring(pos, AGLFN_NAMES.indexOf('/', pos)); + } + + + /** + * Returns the PostScript name of a glyph, given the sequence of + * Unicode characters that is required to produce the glyph. The + * returned name follows Adobe’s glyph naming recommendations + * in order to allow searching and indexing of the produced + * PostScript and PDF. + * + *

Some examples: + *

  • U+0041 gives A;
  • + *
  • U+011D gives gcircumflex;
  • + *
  • U+007A U+0302 gives z_uni0302;
  • + *
  • U+D807 U+DC42 (an UTF-16 escape sequence) + * gives u11C42;
  • + *
. + * + *

The routine does not bring sequences in any canonical + * form. Therefore, the result for U+0067 U+0302 (the + * decomposition of U+011D) will be + * g_uni0302, not gcircumflex. + * + * @see Unicode + * and Glyph Names and Glyph Names and Current Implementations + */ + private static String getGlyphName(char[] chars) + { + char c; + String name; + int numChars; + boolean hasSurrogates = false; + + if ((chars == null) || ((numChars = chars.length) == 0)) + return ".notdef"; + + /* The vast majority of cases will be just a single character. + * Therefore, we have a special code path for this case. + */ + if (numChars == 1) + { + c = chars[0]; + name = getAGLFNName(c); + if (name != null) + return name; + } + + CPStringBuilder buf = new CPStringBuilder(numChars * 8); + for (int i = 0; i < numChars; i++) + { + if (i > 0) + buf.append('_'); + c = chars[i]; + + /* handle surrogate pairs */ + if (c >> 10 == 0x36) // U+D800 .. U+DBFF: High surrogate + { + /* Adobe recommends using the 'u' prefix only for + * characters outside the Unicode Basic Multilingual Plane, + * because Acrobat 4 and 5 understand only the "uni" prefix. + * The 'u' prefix will be supported by Acrobat 6 and later. + * + * For further information, please refer to this page: + * http://partners.adobe.com/asn/tech/type/glyphnamelimits.jsp#3 + */ + int ucs4 = (((c & 0x3ff) << 10) | (chars[++i] & 0x3ff)) + 0x10000; + buf.append('u'); + buf.append(Integer.toHexString(ucs4).toUpperCase()); + } + else + { + /* Try the Adobe Glyph List. */ + name = getAGLFNName(c); + if (name != null) + buf.append(name); + else + { + char nibble; + buf.append("uni"); + nibble = (char) (((c >> 12) & 0xf) + 0x30); + if (nibble > 0x39) + nibble += 7; + buf.append(nibble); + nibble = (char) (((c >> 8) & 0xf) + 0x30); + if (nibble > 0x39) + nibble += 7; + buf.append(nibble); + nibble = (char) (((c >> 4) & 0xf) + 0x30); + if (nibble > 0x39) + nibble += 7; + buf.append(nibble); + nibble = (char) (((c >> 0) & 0xf) + 0x30); + if (nibble > 0x39) + nibble += 7; + buf.append(nibble); + } + } + } + return buf.toString(); + } +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/Hinter.java b/libjava/classpath/gnu/java/awt/font/opentype/Hinter.java new file mode 100644 index 000000000..9758a2896 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/opentype/Hinter.java @@ -0,0 +1,63 @@ +/* Hinter.java -- The interface to a hinting implementation + 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.font.opentype; + +import gnu.java.awt.font.opentype.truetype.Zone; + +/** + * The interface to a hinting implementation. + */ +public interface Hinter +{ + /** + * Initializes the hinter. + * + * @param face the font for which the hinter should be used + */ + void init(OpenTypeFont face); + + /** + * Hints the specified outline. + * + * @param outline the outline to hint + */ + void applyHints(Zone outline); + + void setFlags(int flags); +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/MacResourceFork.java b/libjava/classpath/gnu/java/awt/font/opentype/MacResourceFork.java new file mode 100644 index 000000000..c0f3de80e --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/opentype/MacResourceFork.java @@ -0,0 +1,235 @@ +/* MacResourceFork.java -- Parses MacOS resource forks. + 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.font.opentype; + +import java.nio.ByteBuffer; + + +/** + * A class for accessing data that is stored in the resource fork of + * Macintosh files. Writing resource forks is currently not supported. + * + *

The gnu.java.awt.font package uses this class for accessing + * fonts in the MacOS X ".dfont" format, which is is a file in the + * format of a Macintosh resource fork, but stored in the normal data + * fork of the file. + * + *

The implementation has been designed to work efficiently with + * the virtual memory subsystem. It is recommended to pass an + * instance of {@link java.nio.MappedByteBuffer} to the constructor. + * + *

Thread Safety: All access is synchronized on the ByteBuffer + * that is passed to the constructor. + * + * @see Apple’ developer documentation about the Resource File + * Format + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +final class MacResourceFork +{ + int[] types; + Resource[][] resources; + ByteBuffer buf; + + public MacResourceFork(ByteBuffer buf) + { + int typeListOffset; + int refListOffset; + int nameListOffset; + int mapOffset, mapLen; + int dataOffset, dataLen; + int numTypes; + + synchronized (buf) + { + buf = buf.duplicate(); + this.buf = buf; + buf.position(0); + dataOffset = buf.getInt(); + mapOffset = buf.getInt(); + dataLen = buf.getInt(); + mapLen = buf.getInt(); + buf.position(mapOffset + 24); + refListOffset = mapOffset + buf.getChar(); + nameListOffset = mapOffset + buf.getChar(); + numTypes = buf.getChar() + 1; + types = new int[numTypes]; + resources = new Resource[numTypes][]; + + /* Parse resource type list. */ + typeListOffset = buf.position(); + for (int i = 0; i < numTypes; i++) + { + buf.position(typeListOffset + 8 * i); + int resType = buf.getInt(); + int numRes = buf.getChar() + 1; + + types[i] = resType; + resources[i] = new Resource[numRes]; + + buf.position(refListOffset + buf.getChar()); + for (int j = 0; j < numRes; j++) + { + short resID = buf.getShort(); + int resNameOffset = nameListOffset + buf.getChar(); + int resDataOffset = buf.getInt(); + byte resAttr = (byte) (resDataOffset >> 24); + resDataOffset = dataOffset + (resDataOffset & 0x00ffffff); + buf.getInt(); /* skip four reserved bytes */ + + Resource rsrc = new Resource(buf, resType, resID, resDataOffset, + resNameOffset); + resources[i][j] = rsrc; + } + } + } + } + + + public Resource[] getResources(int type) + { + synchronized (buf) + { + for (int i = 0; i < types.length; i++) + { + if (types[i] == type) + return resources[i]; + } + } + return null; + } + + + public Resource getResource(int type, short id) + { + Resource[] res; + + synchronized (buf) + { + for (int i = 0; i < types.length; i++) + { + if (types[i] != type) + continue; + + res = resources[i]; + for (int j = 0; j < res.length; j++) + if (res[j].getID() == id) + return res[j]; + } + } + + return null; + } + + + /** + * A single resource that is contained in a resource fork. + */ + public static final class Resource + { + int type; + short id; + byte attribute; + int nameOffset; + int dataOffset; + ByteBuffer buf; + + private Resource(ByteBuffer buf, + int type, short id, int dataOffset, int nameOffset) + { + this.buf = buf; + this.type = type; + this.id = id; + this.dataOffset = dataOffset; + this.nameOffset = nameOffset; + } + + + /** + * Returns the type of this resource. + * + * @return an int encoding a four-byte type tag, + * such as 0x464f4e54 for 'FONT'. + */ + public int getType() + { + return type; + } + + + /** + * Returns the ID of this resource. + */ + public short getID() + { + return id; + } + + + /** + * Retrieves the content of the resource. Only one page of memory + * is touched, irrespective of the actual size of the resource. + */ + public ByteBuffer getContent() + { + synchronized (buf) + { + buf.limit(buf.capacity()); + int len = buf.getInt(dataOffset); + buf.position(dataOffset + 4).limit(dataOffset + 4 + len); + return buf.slice(); + } + } + + + /** + * Determines the length of the resource in bytes. + */ + public int getLength() + { + synchronized (buf) + { + return buf.getInt(dataOffset); + } + } + } +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/NameDecoder.java b/libjava/classpath/gnu/java/awt/font/opentype/NameDecoder.java new file mode 100644 index 000000000..1f1d50ac1 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/opentype/NameDecoder.java @@ -0,0 +1,702 @@ +/* NameDecoder.java -- Decodes names of OpenType and TrueType fonts. + 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.font.opentype; + +import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; +import java.util.Locale; + + +/** + * A utility class that helps with decoding the names of OpenType + * and TrueType fonts. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class NameDecoder +{ + public static final int NAME_COPYRIGHT = 0; + + + /** + * Specifies the name of the family to which a font belongs, for + * example “Univers”. + */ + public static final int NAME_FAMILY = 1; + + + /** + * Specified the name of the font inside its family, for + * example “Light”. + */ + public static final int NAME_SUBFAMILY = 2; + + + public static final int NAME_UNIQUE = 3; + + + /** + * Specifies the full human-readable name of a font, for example + * “Univers Light” + */ + public static final int NAME_FULL = 4; + + + public static final int NAME_VERSION = 5; + + + /** + * Specifies the PostScript name of a font, for example + * “Univers-Light”. + */ + public static final int NAME_POSTSCRIPT = 6; + + + public static final int NAME_TRADEMARK = 7; + public static final int NAME_MANUFACTURER = 8; + public static final int NAME_DESIGNER = 9; + public static final int NAME_DESCRIPTION = 10; + public static final int NAME_VENDOR_URL = 11; + public static final int NAME_DESIGNER_URL = 12; + public static final int NAME_LICENSE = 13; + public static final int NAME_LICENSE_URL = 14; + public static final int NAME_PREFERRED_FAMILY = 16; + public static final int NAME_PREFERRED_SUBFAMILY = 17; + public static final int NAME_FULL_MACCOMPATIBLE = 18; + public static final int NAME_SAMPLE_TEXT = 19; + public static final int NAME_POSTSCRIPT_CID = 20; + + + private static final int PLATFORM_MACINTOSH = 1; + private static final int PLATFORM_MICROSOFT = 3; + + + public static String getName(ByteBuffer nameTable, + int name, Locale locale) + { + int numRecords; + int macLanguage, msLanguage; + int offset; + int namePlatform, nameEncoding, nameLanguage, nameID, nameLen; + int nameStart; + String result; + boolean match; + + if (nameTable == null) + return null; + + nameTable.position(0); + /* We understand only format 0 of the name table. */ + if (nameTable.getShort() != 0) + return null; + + macLanguage = getMacLanguageCode(locale); + msLanguage = getMicrosoftLanguageCode(locale); + numRecords = nameTable.getShort(); + offset = nameTable.getShort(); + + for (int i = 0; i < numRecords; i++) + { + namePlatform = nameTable.getShort(); + nameEncoding = nameTable.getShort(); + nameLanguage = nameTable.getShort(); + nameID = nameTable.getShort(); + nameLen = nameTable.getShort(); + nameStart = offset + nameTable.getShort(); + + + if (nameID != name) + continue; + + // Handle PS seperately as it can be only ASCII, although + // possibly encoded as UTF-16BE + if ( name == NAME_POSTSCRIPT ) + { + if( nameTable.get(nameStart) == 0 ) // Peek at top byte + result = decodeName("UTF-16BE", nameTable, nameStart, nameLen); + else + result = decodeName("ASCII", nameTable, nameStart, nameLen); + return result; + } + + match = false; + switch (namePlatform) + { + case PLATFORM_MACINTOSH: + if ((nameLanguage == macLanguage) || (locale == null)) + match = true; + else + { + switch (macLanguage) + { + case 49: /* Azerbaijani/Cyrillic */ + match = (nameLanguage == /* Azerbaijani/Arabic */ 50) + || (nameLanguage == /* Azerbaijani/Roman */ 150); + break; + + case 57: /* Mongolian/Mongolian */ + match = (nameLanguage == /* Mongolian/Cyrillic */ 58); + break; + + case 83: /* Malay/Roman */ + match = (nameLanguage == /* Malay/Arabic */ 84); + break; + } + } + break; + + case PLATFORM_MICROSOFT: + if (((nameLanguage & 0xff) == msLanguage) || (locale == null)) + match = true; + break; + } + + + if (match) + { + result = decodeName(namePlatform, nameEncoding, nameLanguage, + nameTable, nameStart, nameLen); + if (result != null) + return result; + } + } + + return null; + } + + + /** + * The language codes used by the Macintosh operating system. MacOS + * defines numeric language identifiers in the range [0 .. 95] and + * [128 .. 150]. To map this numeric identifier into an ISO 639 + * language code, multiply it by two and take the substring at that + * position. + * + *

ISO 639 has revised the code for some languages, namely + * he for Hebrew (formerly iw), + * yi (formerly ji), and id + * for Indonesian (formerly in). In those cases, this + * table intentionally contains the older, obsolete code. The + * reason is that this is the code which + * java.util.Locale.getLanguage() is specified to return. The + * implementation of {@link #getMacLanguageCode} depends on this. + * + * @see Language Codes: ISO 639, Microsoft and Macintosh + */ + private static final String macLanguageCodes + // 0 1 2 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 + = "enfrdeitnlsvesdaptnoiwjaarfielismttrhrzhurhithkoltplhuetlv " + + // 3 4 5 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 + + "fofaruzhnlgdsqrocssksljisrmkbgukbeuzkkazazhykamokytgtkmnmnps" + + // 6 7 8 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 + + "kukssdbonesamrbnasgupaormlkntatesimykmloviintlmsmsamti sosw" + + // 9 10 11 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 + + "rwrn mgeo " + + // 12 13 14 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 + + " cyeucalaqugnayttugtsjwsuglafbriugdgvgatoelkl" + + // 15 + // 0 + + "az"; + + + /** + * The primary language IDs used by the Microsoft operating systems. + * + *

ISO 639 has revised the code for some languages, namely + * he for Hebrew (formerly iw), + * yi (formerly ji), and id + * for Indonesian (formerly in). In those cases, this + * table intentionally contains the older, obsolete code. The + * reason is that this is the code which + * java.util.Locale.getLanguage() is specified to return. The + * implementation of {@link #getMicrosoftLanguageCode} depends on + * this. + * + * @see Language Codes: ISO 639, Microsoft and Macintosh + */ + private static final String microsoftLanguageCodes + // 0 1 2 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 + = " arbgcazhcsdadeelenesfifriwhuisitjakonlnoplptrmrorushsksqsv" + + // 3 4 5 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 + + "thtrurinukbesletlvlttgfavihyazeu mk ts xhzuafkafohimt " + + // 6 7 8 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 + + "gajimskkkyswtkuzttbnpaguortateknmlasmrsamnbocykmlomygl sd" + + // 9 10 11 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 + + " si iuam ksnefypstl ha yo omtign laso"; + + + /** + * Maps a Java Locale into a MacOS language code. + * + *

For languages that are written in several script systems, + * MacOS defines multiple language codes. Java Locales have a + * variant which could be used for that purpose, but a small + * test program revealed that with Sun's JDK 1.4.1_01, only two + * of 134 available Locales have a variant tag (namely no_NO_NY + * and th_TH_TH).

+ * + *

The following cases are problematic: + * + *

  • Azerbaijani (az): The MacOS language code is 49 if + * Azerbaijani is written in the Cyrillic script; 50 if written in + * the Arabic script; 150 if written in the Roman script. This + * method will always return 49 for the Azerbaijani locale.
  • + * + *
  • Mongolian (mn): The MacOS language code is 57 if Mongolian is + * written in the Mongolian script; 58 if written in the Cyrillic + * script. This method will always return 57 for the Mongolian + * locale.
  • + * + *
  • Malay (ms): The MacOS language code is 83 if Malay is written + * in the Roman script; 84 if written in the Arabic script. This + * method will always return 83 for the Malay locale.
+ * + * @return a MacOS language code, or -1 if there is no such code for + * loc’s language. + */ + private static int getMacLanguageCode(Locale loc) + { + int code; + + if (loc == null) + return -1; + + code = findLanguageCode(loc.getLanguage(), macLanguageCodes); + switch (code) + { + case 19: + /* Traditional Chinese (MacOS language #19) and and Simplified + * Chinese (MacOS language #33) both have "zh" as their ISO 639 + * code. + */ + if (loc.equals(Locale.SIMPLIFIED_CHINESE)) + code = 33; + break; + + // Other special cases would be 49, 57 and 83, but we do not + // know what do do about them. See the method documentation for + // details. + } + + return code; + } + + + /** + * Maps a Java Locale into a Microsoft language code. + */ + private static int getMicrosoftLanguageCode(Locale locale) + { + String isoCode; + int code; + + if (locale == null) + return -1; + + isoCode = locale.getLanguage(); + code = findLanguageCode(isoCode, microsoftLanguageCodes); + if (code == -1) + { + if (isoCode.equals("hr") || isoCode.equals("sr")) + { + /* Microsoft uses code 26 for "sh" (Serbo-Croatian), + * "hr" (Croatian) and "sr" (Serbian). Our table contains + * "sh". + */ + code = 26; + } + else if (isoCode.equals("gd")) + { + /* Microsoft uses code 60 for "gd" (Scottish Gaelic) and + * "ga" (Irish Gaelic). Out table contains "ga". + */ + code = 60; + } + } + return code; + } + + + private static int findLanguageCode(String lang, String langCodes) + { + int index; + if (lang == null) + return -1; + + if (lang.length() != 2) + return -1; + + index = 0; + do + { + index = langCodes.indexOf(lang, index); + + /* The index must be even to be considered a match. Otherwise, we + * could match with the second letter of one language and the + * first of antoher one. + */ + } + while (!((index < 0) || ((index & 1) == 0))); + if (index < 0) + return -1; + + index = index / 2; + return index; + } + + + private static String decodeName(int platform, int encoding, int language, + ByteBuffer buffer, int offset, int len) + { + String charsetName = getCharsetName(platform, language, encoding); + if (charsetName == null) + return null; + + return decodeName(charsetName, buffer, offset, len); + } + + private static String decodeName(String charsetName, + ByteBuffer buffer, int offset, int len) + { + byte[] byteBuf; + int oldPosition; + + byteBuf = new byte[len]; + oldPosition = buffer.position(); + try + { + buffer.position(offset); + buffer.get(byteBuf); + try + { + return new String(byteBuf, charsetName); + } + catch (UnsupportedEncodingException uex) + { + } + } + finally + { + buffer.position(oldPosition); + } + + return null; + } + + + /** + * Maps a MacOS language code into a Java Locale. + * + * @param macLanguageCode the MacOS language code for + * the language whose Java locale is to be retrieved. + * + * @return an suitable Locale, or null if + * the mapping cannot be performed. + */ + private static Locale getMacLocale(int macLanguageCode) + { + String isoCode; + + switch (macLanguageCode) + { + case 0: return Locale.ENGLISH; + case 1: return Locale.FRENCH; + case 2: return Locale.GERMAN; + case 3: return Locale.ITALIAN; + case 11: return Locale.JAPANESE; + case 23: return Locale.KOREAN; + case 19: return Locale.TRADITIONAL_CHINESE; + case 33: return Locale.SIMPLIFIED_CHINESE; + } + + if ((macLanguageCode < 0) || (macLanguageCode > 150)) + return null; + + isoCode = macLanguageCodes.substring(macLanguageCode << 1, + (macLanguageCode + 1) << 1); + if (isoCode.charAt(0) == ' ') + return null; + + return new Locale(isoCode); + } + + + + /** + * Maps a Windows LCID into a Java Locale. + * + * @param lcid the Windows language ID whose Java locale + * is to be retrieved. + * + * @return an suitable Locale, or null if + * the mapping cannot be performed. + */ + private static Locale getWindowsLocale(int lcid) + { + /* FIXME: This is grossly incomplete. */ + switch (lcid) + { + case 0x0407: return Locale.GERMAN; + case 0x0408: return new Locale("el", "GR"); + case 0x0409: return Locale.ENGLISH; + case 0x040b: return new Locale("fi"); + case 0x040c: return Locale.FRENCH; + case 0x0416: return new Locale("pt"); + case 0x0807: return new Locale("de", "CH"); + case 0x0809: return new Locale("en", "UK"); + case 0x080c: return new Locale("fr", "BE"); + case 0x0816: return new Locale("pt", "BR"); + case 0x0c07: return new Locale("de", "AT"); + case 0x0c09: return new Locale("en", "AU"); + case 0x0c0c: return new Locale("fr", "CA"); + case 0x1007: return new Locale("de", "LU"); + case 0x1009: return new Locale("en", "CA"); + case 0x100c: return new Locale("fr", "CH"); + case 0x1407: return new Locale("de", "LI"); + case 0x1409: return new Locale("en", "NZ"); + case 0x140c: return new Locale("fr", "LU"); + case 0x1809: return new Locale("en", "IE"); + + default: + return null; + } + } + + + /** + * Maps a Macintosh Script Manager code to the name of the + * corresponding Java Charset. + * + * @param macScript a MacOS ScriptCode, for example + * 6 for smGreek. + * + * @return a String that can be used to retrieve a Java + * CharsetDecorder, for example MacGreek, or + * null if macScript has an + * unsupported value. + */ + private static String getMacCharsetName(int macScript) + { + switch (macScript) + { + case 0: return "MacRoman"; + case 1: return "MacJapanese"; + case 2: return "MacKorean"; + case 3: return "MacTradChinese"; + case 4: return "MacArabic"; + case 5: return "MacHebrew"; + case 6: return "MacGreek"; + case 7: return "MacCyrillic"; + case 8: return "MacRSymbol"; + case 9: return "MacDevanagari"; + case 10: return "MacGurmukhi"; + case 11: return "MacGujarati"; + case 12: return "MacOriya"; + case 13: return "MacBengali"; + case 14: return "MacTamil"; + case 15: return "MacTelugu"; + case 16: return "MacKannada"; + case 17: return "MacMalayalam"; + case 18: return "MacSinhalese"; + case 19: return "MacBurmese"; + case 20: return "MacKhmer"; + case 21: return "MacThai"; + case 22: return "MacLao"; + case 23: return "MacGeorgian"; + case 24: return "MacArmenian"; + case 25: return "MacSimpChinese"; + case 26: return "MacTibetan"; + case 27: return "MacMongolian"; + case 28: return "MacEthiopic"; + case 29: return "MacCentralEurope"; + case 30: return "MacVietnamese"; + case 31: return "MacExtArabic"; + + default: return null; + } + } + + + /** + * Maps a Microsoft locale ID (LCID) to the name of the + * corresponding Java Charset. + * + * @param lcid the Microsoft locale ID. + * + * @return a String that can be used to retrieve a Java + * CharsetDecorder, for example windows-1252, or + * null if lcid has an unsupported value. + */ + private static String getMicrosoftCharsetName(int lcid) + { + int lang; + char codePage = '?'; + + /* Extract the language code from the LCID. */ + lang = lcid & 0x3ff; + + /* In the majority of cases, the language alone determines the + * codepage. + */ + if (lang < 100) + codePage = (" 612D022322225022EC2202201?002A462110777 68 ?2 1 " + + " 2 2 2112 ?1 1 2 2 ") + .charAt(lang); + + /* There are a few exceptions, however, where multiple code pages + * are used for the same language. */ + if (codePage == '?') + { + switch (lcid) + { + case 0x041a: // Croatian --> Windows-1250 (Central Europe) + case 0x081a: // Serbian (Latin) --> Windows-1250 (Central Europe) + codePage = '0'; + break; + + case 0x42c: // Azeri (Latin) --> Windows-1254 (Turkish) + case 0x443: // Uzbek (Latin) --> Windows-1254 (Turkish) + codePage = '4'; + break; + + case 0x82c: // Azeri (Cyrillic) --> Windows-1251 (Cyrillic) + case 0x843: // Uzbek (Cyrillic) --> Windows-1251 (Cyrillic) + case 0xc1a: // Serbian (Cyrillic) --> Windows-1251 (Cyrillic) + codePage = '1'; + break; + } + } + + switch (codePage) + { + case '0': return "windows-1250"; // Central Europe + case '1': return "windows-1251"; // Cyrillic + case '2': return "windows-1252"; // Latin 1 + case '3': return "windows-1253"; // Greek + case '4': return "windows-1254"; // Turkish + case '5': return "windows-1255"; // Hebrew + case '6': return "windows-1256"; // Arabic + case '7': return "windows-1257"; // Baltic + case '8': return "windows-1258"; // Vietnam + case 'A': return "windows-874"; // Thai + case 'B': return "windows-936"; // Simplified Chinese, GBK + case 'C': return "windows-949"; // Korean + case 'D': return "windows-950"; // Traditional Chinese, Big5 + case 'E': return "windows-932"; // Japanese Shift-JIS + default: return null; + } + } + + + /** + * Returns the Locale of an OpenType name. + * + * @param platform the OpenType platform ID. + * + * @param language the language tag of the OpenType name. If + * platform is 1, this is the MacOS language code. + * + * @param encoding the encoding tag of the OpenType name. If + * platform is 1, this is the MacOS script code. + */ + public static Locale getLocale(int platform, int language, int encoding) + { + switch (platform) + { + case 1: /* Apple Macintosh */ + return getMacLocale(language); + + case 3: /* Microsoft Windows */ + return getWindowsLocale(language); + + default: + return null; + } + } + + + /** + * Determines the name of the charset for an OpenType font name. + * + * @param platform the OpenType platform ID. + * + * @param language the language tag of the OpenType name. If + * platform is 1, this is the MacOS language code. + * + * @param encoding the encoding tag of the OpenType name. If + * platform is 1, this is the MacOS script code. + * + * @return a charset name such as "MacRoman", + * or null if the combination is not known. + */ + public static String getCharsetName(int platform, int language, int encoding) + { + switch (platform) + { + case 1: /* Apple Macintosh */ + return getMacCharsetName(encoding); + + case 3: /* Microsoft Windows */ + return getMicrosoftCharsetName(language); + + default: + return null; + } + } +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/OpenTypeFont.java b/libjava/classpath/gnu/java/awt/font/opentype/OpenTypeFont.java new file mode 100644 index 000000000..f46addc3c --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/opentype/OpenTypeFont.java @@ -0,0 +1,882 @@ +/* OpenTypeFont.java -- Manages OpenType and TrueType fonts. + 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.font.opentype; + +import java.awt.Font; +import java.awt.FontFormatException; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.font.OpenType; +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.geom.Point2D; +import java.nio.ByteBuffer; +import java.text.CharacterIterator; +import java.util.Locale; + +import gnu.java.awt.font.FontDelegate; +import gnu.java.awt.font.GNUGlyphVector; +import gnu.java.awt.font.autofit.AutoHinter; +import gnu.java.awt.font.opentype.truetype.TrueTypeScaler; +import gnu.java.awt.font.opentype.truetype.Zone; + + +/** + * A font that takes its data from OpenType or TrueType font tables. + * + *

OpenType is an extension of the TrueType font format. In addition + * to tables for names, kerning or layout, it also stores the shapes + * of individual glyphs. Three formats are recognized for glyphs: + * Quadratic splines (classic TrueType), cubic splines (PostScript), + * and bitmaps. + * + * @see Adobe’s + * OpenType specification + * + * @see Apple’s + * TrueType specification + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public final class OpenTypeFont + implements FontDelegate +{ + static final int TAG_OTTO = 0x4f54544f; // 'OTTO' + static final int TAG_SFNT = 0x73666e74; // 'sfnt' + static final int TAG_TRUE = 0x74727565; // 'true' + static final int TAG_TTCF = 0x74746366; // 'ttcf' + static final int TAG_ZAPF = 0x5a617066; // 'Zapf' + + + /** + * A buffer containing the font data. Note that this may well be an + * instance of the subclass MappedByteBuffer, in which case the + * virtual memory subsystem can more efficiently handle requests for + * font data. This is especially recommended for large font files + * that contain many glyphs that are rarely accessed. + */ + ByteBuffer buf; + + + /** + * The number of glyphs in this font. + */ + final int numGlyphs; + + int[] tableTag, tableStart, tableLength; + + + /** + * The version of the font in 16.16 fixed-point encoding, for + * example 0x00010000 for version 1.0. There are also two special + * version IDs used by fonts for Apple Macintosh, namely 'true' + * (0x74727565) and 'typ1'. OpenType fonts sometimes have 'OTTO' as + * their version. + */ + private int version; + + + /** + * The number of font units per em. For fonts with TrueType + * outlines, this is usually a power of two (such as 2048). For + * OpenType fonts with PostScript outlines, other values are + * acceptable (such as 1000). + */ + public int unitsPerEm; + + + /** + * A factor to convert font units into ems. This value is 1 / + * unitsPerEm. + */ + private float emsPerUnit; + + + /** + * The scaler to which the actual scaling work is delegated. + */ + private Scaler scaler; + + + /** + * A delegate object for mapping Unicode UCS-4 codepoints to glyph + * IDs. + */ + private CharGlyphMap cmap; + + + /** + * A delegate object for providing a name for each glyph. + */ + private GlyphNamer glyphNamer; + + private Hinter hinter; + + /** + * Constructs an OpenType or TrueType font. + * + * @param buf a buffer with the contents of the font file. It is + * recommended to use a MappedByteBuffer for very + * large font files. + * + * @param offsetTablePosition the position of the OpenType offset + * table in the font file. The offset table of most OpenType and + * TrueType fonts starts at position 0. However, so-called TrueType + * Collections support multiple OpenType fonts in a single file, + * which allows sharing some glyphs between fonts. If many glyphs + * are shared (for example all the Kanji glyphs between multiple + * Japanese fonts), the space savings can be considerable. In that + * case, the offset table of each individual font would start at its + * own position. + * + * @throws java.awt.FontFormatException if the font data is + * not in OpenType or TrueType format. + */ + OpenTypeFont(ByteBuffer buf, int offsetTablePosition) + throws FontFormatException + { + int numTables, searchRange, entrySelector, rangeShift; + + //buf = buf.duplicate(); + this.buf = buf; + buf.limit(buf.capacity()); + buf.position(offsetTablePosition); + + /* Check that the font data is in a supported format. */ + version = buf.getInt(); + switch (version) + { + case 0x00010000: // Microsoft TrueType + case OpenType.TAG_TYP1: // Adobe PostScript embeded in Apple SFNT ('typ1') + case TAG_SFNT: // Apple TrueType + case TAG_TRUE: // Apple TrueType + case TAG_OTTO: // OpenType + break; + + default: + throw new FontFormatException("not in OpenType or TrueType format"); + } + + numTables = buf.getShort(); + searchRange = buf.getShort(); + entrySelector = buf.getShort(); + rangeShift = buf.getShort(); + + tableTag = new int[numTables]; + tableStart = new int[numTables]; + tableLength = new int[numTables]; + int lastTag = 0; + for (int i = 0; i < numTables; i++) + { + tableTag[i] = buf.getInt(); + if (lastTag >= tableTag[i]) + throw new FontFormatException("unordered OpenType table"); + + buf.getInt(); // ignore checksum + tableStart[i] = buf.getInt(); + tableLength[i] = buf.getInt(); + + //System.out.println(tagToString(tableTag[i]) + ", " + tableLength[i]); + } + + ByteBuffer head = getFontTable(OpenType.TAG_HEAD); + if ((head.getInt(0) != 0x00010000) + || (head.getInt(12) != 0x5f0f3cf5)) + throw new FontFormatException("unsupported head version"); + + unitsPerEm = head.getChar(18); + emsPerUnit = 1.0f / (float) unitsPerEm; + + + ByteBuffer maxp = getFontTable(OpenType.TAG_MAXP); + int maxpVersion = maxp.getInt(0); + switch (maxpVersion) + { + case 0x00005000: /* version 0.5, with wrong fractional part */ + numGlyphs = maxp.getChar(4); + break; + + case 0x00010000: /* version 1.0 */ + numGlyphs = maxp.getChar(4); + scaler = new TrueTypeScaler(unitsPerEm, + getFontTable(OpenType.TAG_HHEA), + getFontTable(OpenType.TAG_HMTX), + getFontTable(OpenType.TAG_VHEA), + getFontTable(OpenType.TAG_VMTX), + maxp, + getFontTable(OpenType.TAG_CVT), + getFontTable(OpenType.TAG_FPGM), + /* loca format */ head.getShort(50), + getFontTable(OpenType.TAG_LOCA), + getFontTable(OpenType.TAG_GLYF), + getFontTable(OpenType.TAG_PREP)); + break; + + default: + throw new FontFormatException("unsupported maxp version"); + } + } + + + /** + * Determines the index of a table into the offset table. The + * result can be used to find the offset and length of a table, as + * in tableStart[getTableIndex(TAG_NAME)]. + * + * @param tag the table identifier, for instance + * OpenType.TAG_NAME. + * + * @return the index of that table into the offset table, or + * -1 if the font does not contain the table specified by + * tag. + */ + private int getTableIndex(int tag) + { + /* FIXME: Since the font specification requires tableTag[] to be + * ordered, one should do binary search here. + */ + for (int i = 0; i < tableTag.length; i++) + if (tableTag[i] == tag) + return i; + return -1; + } + + + + /** + * Returns the name of the family to which this font face belongs, + * for example “Univers”. + * + * @param locale the locale for which to localize the name. + * + * @return the family name. + */ + public synchronized String getFamilyName(Locale locale) + { + String name; + + if (locale == null) + locale = Locale.getDefault(); + + name = getName(NameDecoder.NAME_FAMILY, locale); + if (name == null) + name = getName(NameDecoder.NAME_FAMILY, Locale.ENGLISH); + if (name == null) + name = getName(NameDecoder.NAME_FAMILY, /* any language */ null); + if (name == null) + name = getName(NameDecoder.NAME_FULL, locale); + if (name == null) + name = getName(NameDecoder.NAME_FULL, /* any language */ null); + return name; + } + + + /** + * Returns the name of this font face inside the family, for example + * “Light”. + * + * @param locale the locale for which to localize the name. + * + * @return the name of the face inside its family. + */ + public synchronized String getSubFamilyName(Locale locale) + { + String name; + + if (locale == null) + locale = Locale.getDefault(); + + name = getName(NameDecoder.NAME_SUBFAMILY, locale); + if (name == null) + { + name = getName(NameDecoder.NAME_SUBFAMILY, Locale.ENGLISH); + if ("Regular".equals(name)) + name = null; + } + + if (name == null) + { + String lang = locale.getLanguage(); + if ("de".equals(lang)) + name = "Standard"; + else if ("fr".equals(lang)) + name = "Standard"; + else if ("it".equals(lang)) + name = "Normale"; + else if ("nl".equals(lang)) + name = "Normaal"; + else if ("fi".equals(lang)) + name = "Normaali"; + else if ("sv".equals(lang)) + name = "Normal"; + else + name = "Regular"; + } + + return name; + } + + + + /** + * Returns the full name of this font face, for example + * “Univers Light”. + * + * @param locale the locale for which to localize the name. + * + * @return the face name. + */ + public synchronized String getFullName(Locale locale) + { + String name; + + if (locale == null) + locale = Locale.getDefault(); + + name = getName(NameDecoder.NAME_FULL, locale); + if (name == null) + name = getName(NameDecoder.NAME_FULL, Locale.ENGLISH); + if (name == null) + name = getName(NameDecoder.NAME_FULL, /* any language */ null); + + return name; + } + + + /** + * Returns the PostScript name of this font face, for example + * “Univers-Light”. + * + * @return the PostScript name, or null if the font + * does not provide a PostScript name. + */ + public synchronized String getPostScriptName() + { + return getName(NameDecoder.NAME_POSTSCRIPT, /* any language */ null); + } + + + /** + * Returns the number of glyphs in this font face. + */ + public int getNumGlyphs() + { + /* No synchronization is needed because the number of glyphs is + * set in the constructor, and it cannot change during the + * lifetime of the object. + */ + return numGlyphs; + } + + + /** + * Returns the index of the glyph which gets displayed if the font + * cannot map a Unicode code point to a glyph. Many fonts show this + * glyph as an empty box. + */ + public int getMissingGlyphCode() + { + /* No synchronization is needed because the result is constant. */ + return 0; + } + + + /** + * The font’s name table, or null if this + * table has not yet been accessed. + */ + private ByteBuffer nameTable; + + + /** + * Extracts a String from the font’s name table. + * + * @param name the numeric TrueType or OpenType name ID. + * + * @param locale the locale for which names shall be localized, or + * null if the locale does mot matter because the name + * is known to be language-independent (for example, because it is + * the PostScript name). + */ + private String getName(int name, Locale locale) + { + if (nameTable == null) + nameTable = getFontTable(OpenType.TAG_NAME); + return NameDecoder.getName(nameTable, name, locale); + } + + + /** + * Returns the version of the font. + * + * @see java.awt.font.OpenType#getVersion + * + * @return the version in 16.16 fixed-point encoding, for example + * 0x00010000 for version 1.0. + */ + public int getVersion() + { + /* No synchronization is needed because the version is set in the + * constructor, and it cannot change during the lifetime of the + * object. + */ + return version; + } + + + /** + * Creates a view buffer for an OpenType table. The caller can + * access the returned buffer without needing to synchronize access + * from multiple threads. + * + * @param tag the table identifier, for example + * OpenType.GLYF. + * + * @return a slice of the underlying buffer containing the table, or + * null if the font does not contain the requested + * table. + */ + public synchronized ByteBuffer getFontTable(int tag) + { + int index, start, len; + ByteBuffer result; + + index = getTableIndex(tag); + if (index < 0) + return null; + + start = tableStart[index]; + len = tableLength[index]; + buf.limit(start + len).position(start); + result = buf.slice(); + result.limit(len); + return result; + } + + + /** + * Returns the size of one of the tables in the font, + * or -1 if the table does not exist. + */ + public int getFontTableSize(int tag) + { + int index = getTableIndex(tag); + if (index == -1) + return index; + return tableLength[index]; + } + + + private CharGlyphMap getCharGlyphMap() + { + if (cmap != null) + return cmap; + + synchronized (this) + { + if (cmap == null) + { + int index = getTableIndex(OpenType.TAG_CMAP); + int start = tableStart[index]; + buf.limit(start + tableLength[index]).position(start); + cmap = CharGlyphMap.forTable(buf); + } + return cmap; + } + } + + + + /** + * Looks up a glyph in the font’s cmap tables, + * without performing any glyph substitution or reordering. Because + * of this limitation, this method cannot be used for script systems + * that need advanced glyph mapping, such as Arabic, Korean, or even + * Latin with exotic accents. + * + *

It is safe to call this method from any thread. + * + * @param ucs4 the Unicode codepoint in the 32-bit Unicode character + * set UCS-4. Because UTF-16 surrogates do not correspond to a single + * glyph, it does not make sense to pass them here. + * + * @return the glyph index, or zero if the font does not contain + * a glyph for the specified codepoint. + */ + public int getGlyph(int ucs4) + { + return getCharGlyphMap().getGlyph(ucs4); + } + + + /** + * Creates a GlyphVector by mapping each character in a + * CharacterIterator to the corresponding glyph. + * + *

The mapping takes only the font’s cmap + * tables into consideration. No other operations (such as glyph + * re-ordering, composition, or ligature substitution) are + * performed. This means that the resulting GlyphVector will not be + * correct for text in languages that have complex + * character-to-glyph mappings, such as Arabic, Hebrew, Hindi, or + * Thai. + * + * @param font the font object that the created GlyphVector + * will return when it gets asked for its font. This argument is + * needed because the public API works with java.awt.Font, + * not with some private delegate like OpenTypeFont. + * + * @param frc the font rendering parameters that are used for + * measuring glyphs. The exact placement of text slightly depends on + * device-specific characteristics, for instance the device + * resolution or anti-aliasing. For this reason, any measurements + * will only be accurate if the passed + * FontRenderContext correctly reflects the relevant + * parameters. Hence, frc should be obtained from the + * same Graphics2D that will be used for drawing, and + * any rendering hints should be set to the desired values before + * obtaining frc. + * + * @param ci a CharacterIterator for iterating over the + * characters to be displayed. + */ + public synchronized GlyphVector createGlyphVector(Font font, + FontRenderContext frc, + CharacterIterator ci) + { + // Initialize hinter if necessary. + checkHinter(FontDelegate.FLAG_FITTED); + + CharGlyphMap cmap; + int numGlyphs; + int[] glyphs; + int glyph; + int c; + + cmap = getCharGlyphMap(); + numGlyphs = ci.getEndIndex() - ci.getBeginIndex(); + glyphs = new int[numGlyphs]; + glyph = 0; + for (c = ci.first(); c != CharacterIterator.DONE; c = ci.next()) + { + /* handle surrogate pairs */ + if (c >> 10 == 0x36) // U+D800 .. U+DBFF: High surrogate + c = (((c & 0x3ff) << 10) | (ci.next() & 0x3ff)) + 0x10000; + glyphs[glyph] = cmap.getGlyph(c); + glyph += 1; + } + + /* If we had surrogates, the allocated array is too large. + * Because this will occur very rarely, it seems acceptable to + * re-allocate a shorter array and copy the contents around. + */ + if (glyph != numGlyphs) + { + int[] newGlyphs = new int[glyph]; + System.arraycopy(glyphs, 0, newGlyphs, 0, glyph); + glyphs = newGlyphs; + } + + return new GNUGlyphVector(this, font, frc, glyphs); + } + + /** + * Returns the glyph code for the specified character. + * + * @param c the character to map + * + * @return the glyph code + */ + public int getGlyphIndex(int c) + { + return getCharGlyphMap().getGlyph(c); + } + + /** + * Determines the advance width for a glyph. + * + * @param glyphIndex the glyph whose advance width is to be + * determined. + * + * @param pointSize the point size of the font. + * + * @param transform a transform that is applied in addition to + * scaling to the specified point size. This is often used for + * scaling according to the device resolution. Those who lack any + * aesthetic sense may also use the transform to slant or stretch + * glyphs. + * + * @param antialias true for anti-aliased rendering, + * false for normal rendering. For hinted fonts, + * this parameter may indeed affect the result. + * + * @param fractionalMetrics true for fractional metrics, + * false for rounding the result to a pixel boundary. + * + * @param horizontal true for horizontal line layout, + * false for vertical line layout. + * + * @param advance a point whose x and y + * fields will hold the advance in each direction. It is possible + * that both values are non-zero, for example if + * transform is a rotation, or in the case of Urdu + * fonts. + */ + public synchronized void getAdvance(int glyphIndex, + float pointSize, + AffineTransform transform, + boolean antialias, + boolean fractionalMetrics, + boolean horizontal, + Point2D advance) + { + /* Delegate the measurement to the scaler. The synchronization is + * needed because the scaler is not synchronized. + */ + scaler.getAdvance(glyphIndex, pointSize, transform, + antialias, fractionalMetrics, horizontal, + advance); + } + + + /** + * Returns the shape of a glyph. + * + * @param glyph the glyph whose advance width is to be determined + * + * @param pointSize the point size of the font. + * + * @param transform a transform that is applied in addition to + * scaling to the specified point size. This is often used for + * scaling according to the device resolution. Those who lack any + * aesthetic sense may also use the transform to slant or stretch + * glyphs. + * + * @param antialias true for anti-aliased rendering, + * false for normal rendering. For hinted fonts, this + * parameter may indeed affect the result. + * + * @param fractionalMetrics true for fractional + * metrics, false for rounding the result to a pixel + * boundary. + * + * @return the scaled and grid-fitted outline of the specified + * glyph, or null for bitmap fonts. + */ + public synchronized GeneralPath getGlyphOutline(int glyph, + float pointSize, + AffineTransform transform, + boolean antialias, + boolean fractionalMetrics, + int flags) + { + /* The synchronization is needed because the scaler is not + * synchronized. + */ + checkHinter(flags); + return scaler.getOutline(glyph, pointSize, transform, + antialias, fractionalMetrics, hinter, flags); + } + + /** + * Fetches the raw glyph outline for the specified glyph index. This is used + * for the autofitter only ATM and is otherwise not usable for outside code. + * + * @param glyph the glyph index to fetch + * @param transform the transform to apply + * + * @return the raw outline of that glyph + */ + public synchronized Zone getRawGlyphOutline(int glyph, + AffineTransform transform) + { + return scaler.getRawOutline(glyph, transform); + } + + /** + * Returns a name for the specified glyph. This is useful for + * generating PostScript or PDF files that embed some glyphs of a + * font. + * + *

Names are not unique: Under some rare circumstances, + * the same name can be returned for different glyphs. It is + * therefore recommended that printer drivers check whether the same + * name has already been returned for antoher glyph, and make the + * name unique by adding the string ".alt" followed by the glyph + * index.

+ * + *

This situation would occur for an OpenType or TrueType font + * that has a post table of format 3 and provides a + * mapping from glyph IDs to Unicode sequences through a + * Zapf table. If the same sequence of Unicode + * codepoints leads to different glyphs (depending on contextual + * position, for example, or on typographic sophistication level), + * the same name would get synthesized for those glyphs. + * + * @param glyphIndex the glyph whose name the caller wants to + * retrieve. + */ + public synchronized String getGlyphName(int glyphIndex) + { + if (glyphNamer == null) + glyphNamer = GlyphNamer.forTables(numGlyphs, + getFontTable(OpenType.TAG_POST), + getFontTable(TAG_ZAPF)); + + return glyphNamer.getGlyphName(glyphIndex); + } + + + /** + * Determines the distance between the base line and the highest + * ascender. + * + * @param pointSize the point size of the font. + * + * @param transform a transform that is applied in addition to + * scaling to the specified point size. This is often used for + * scaling according to the device resolution. Those who lack any + * aesthetic sense may also use the transform to slant or stretch + * glyphs. + * + * @param antialiased true for anti-aliased rendering, + * false for normal rendering. For hinted fonts, + * this parameter may indeed affect the result. + * + * @param fractionalMetrics true for fractional metrics, + * false for rounding the result to a pixel boundary. + * + * @param horizontal true for horizontal line layout, + * false for vertical line layout. + * + * @return the ascent, which usually is a positive number. + */ + public synchronized float getAscent(float pointSize, + AffineTransform transform, + boolean antialiased, + boolean fractionalMetrics, + boolean horizontal) + { + return scaler.getAscent(pointSize, transform, + antialiased, fractionalMetrics, + horizontal); + } + + + /** + * Determines the distance between the base line and the lowest + * descender. + * + * @param pointSize the point size of the font. + * + * @param transform a transform that is applied in addition to + * scaling to the specified point size. This is often used for + * scaling according to the device resolution. Those who lack any + * aesthetic sense may also use the transform to slant or stretch + * glyphs. + * + * @param antialiased true for anti-aliased rendering, + * false for normal rendering. For hinted fonts, + * this parameter may indeed affect the result. + * + * @param fractionalMetrics true for fractional metrics, + * false for rounding the result to a pixel boundary. + * + * @param horizontal true for horizontal line layout, + * false for vertical line layout. + * + * @return the descent, which usually is a nagative number. + */ + public synchronized float getDescent(float pointSize, + AffineTransform transform, + boolean antialiased, + boolean fractionalMetrics, + boolean horizontal) + { + return scaler.getDescent(pointSize, transform, + antialiased, fractionalMetrics, + horizontal); + } + + + /** + * Converts a four-byte tag identifier into a String that can be + * displayed when debugging this class. + * + * @param tag the tag as an int. + * + * @return the tag in human-readable form, for example + * name or glyf. + */ + static String tagToString(int tag) + { + char[] c = new char[4]; + c[0] = (char) ((tag >> 24) & 0xff); + c[1] = (char) ((tag >> 16) & 0xff); + c[2] = (char) ((tag >> 8) & 0xff); + c[3] = (char) (tag & 0xff); + return new String(c); + } + + /** + * Checks if a hinter is installed and installs one when not. + */ + private void checkHinter(int flags) + { + // When another hinting impl gets added (maybe a true TrueType hinter) + // then add some options here. The Hinter interface might need to be + // tweaked. + if (hinter == null) + { + try + { + hinter = new AutoHinter(); + hinter.init(this); + } + catch (Exception ex) + { + // Protect from problems inside hinter. + hinter = null; + ex.printStackTrace(); + } + } + hinter.setFlags(flags); + } +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/OpenTypeFontFactory.java b/libjava/classpath/gnu/java/awt/font/opentype/OpenTypeFontFactory.java new file mode 100644 index 000000000..32c4828c9 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/opentype/OpenTypeFontFactory.java @@ -0,0 +1,140 @@ +/* OpenTypeFontFactory.java -- Creates OpenType and TrueType fonts. + 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.font.opentype; + +import gnu.java.awt.font.FontDelegate; +import java.awt.FontFormatException; +import java.awt.font.OpenType; +import java.nio.ByteBuffer; + + +/** + * A factory for creating fonts that are stored in an + * sfnt-housed format, for example OpenType or TrueType. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public final class OpenTypeFontFactory +{ + /** + * The constructor is private so nobody can construct an instance + * of this class. + */ + private OpenTypeFontFactory() + { + } + + + /** + * Creates FontDelegate objects for the fonts in the specified + * buffer. The following font formats are currently recognized: + * + *

+ * + *

Some formats may contain more than a single font, for example + * *.ttc and *.dfont files. This is the reason why this function + * returns an array. + * + *

The implementation reads data from the buffer only when + * needed. Therefore, it greatly increases efficiency if + * buf has been obtained through mapping a file into + * the virtual address space. + * + * @throws FontFormatException if the font data is not in one of the + * known formats. + */ + public static FontDelegate[] createFonts(ByteBuffer buf) + throws FontFormatException + { + OpenTypeFont[] fonts; + int version; + + version = buf.getInt(0); + switch (version) + { + case 0x00010000: // Microsoft Windows TrueType + case OpenType.TAG_TYP1: // Apple MacOS PostScript ('typ1') + case OpenTypeFont.TAG_SFNT: // Apple MacOS TrueType ('sfnt') + case OpenTypeFont.TAG_TRUE: // Apple MacOS TrueType ('true') + case OpenTypeFont.TAG_OTTO: // OpenType + return new OpenTypeFont[] { new OpenTypeFont(buf, 0) }; + } + + + /* TrueType Collection, see "TrueType Collections" in + * http://partners.adobe.com/asn/tech/type/opentype/otff.html + */ + if (version == OpenTypeFont.TAG_TTCF) + { + // This code has never been tested. + fonts = new OpenTypeFont[buf.getInt(8)]; + for (int i = 0; i < fonts.length; i++) + fonts[i] = new OpenTypeFont(buf, buf.getInt(16 + 4 * i)); + return fonts; + } + + + /* The MacOS X .dfont format is a Macintosh resource fork in + * a normal file, contaning one or several 'sfnt' resources. + * Unfortunately, MacOS resource forks have no magic code + * that could be used for identification. Instead, we just try + * to extract at least one 'sfnt'. + */ + try + { + MacResourceFork fork = new MacResourceFork(buf); + MacResourceFork.Resource[] rsrc; + + rsrc = fork.getResources(OpenTypeFont.TAG_SFNT); + fonts = new OpenTypeFont[rsrc.length]; + for (int i = 0; i < fonts.length; i++) + fonts[i] = new OpenTypeFont(rsrc[i].getContent(), 0); + + return fonts; + } + catch (Exception ex) + { + } + + throw new FontFormatException("not in OpenType or TrueType format"); + } +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/Scaler.java b/libjava/classpath/gnu/java/awt/font/opentype/Scaler.java new file mode 100644 index 000000000..c7582b666 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/opentype/Scaler.java @@ -0,0 +1,205 @@ +/* Scaler.java -- Common superclass for font scalers. + 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.font.opentype; + +import gnu.java.awt.font.opentype.truetype.Zone; + +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.geom.Point2D; + + +/** + * An common superclass for all font scalers. The main task of font + * scaler is to retrieve a scaled and hinted outline for a glyph. + * + *

To make text more legible, high-quality fonts contain + * instructions (sometimes also called “hints”) for + * moving the scaled control points towards the coordinate grid of the + * display device. + * + *

Lack of Thread Safety: Font scalers are intentionally + * not safe to access from multiple concurrent + * threads. Synchronization needs to be performed externally. Usually, + * the font that uses this scaler already has obtained a lock before + * calling the scaler. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class Scaler +{ + /** + * Retrieves the scaled outline of a glyph, adjusting control points + * to the raster grid if necessary. + * + * @param glyph the glyph number whose outline is retrieved. + * + * @param pointSize the point size of the font. + * + * @param transform a transform that is applied in addition to + * scaling to the specified point size. This is often used for + * scaling according to the device resolution. Those who lack any + * aesthetic sense may also use the transform to slant or stretch + * glyphs. + * + * @param antialias whether or not the rasterizer will perform + * anti-aliasing on the returned path. + * + * @param fractionalMetrics false for adjusting glyph + * positions to the raster grid of device space. + * + * @return the scaled and grid-fitted outline of the specified + * glyph, or null for bitmap fonts. + */ + public abstract GeneralPath getOutline(int glyph, + float pointSize, + AffineTransform transform, + boolean antialias, + boolean fractionalMetrics, + Hinter hinter, int type); + + + /** + * Determines the advance width and height for a glyph. + * + * @param glyphIndex the glyph whose advance width is to be + * determined. + * + * @param pointSize the point size of the font. + * + * @param transform a transform that is applied in addition to + * scaling to the specified point size. This is often used for + * scaling according to the device resolution. Those who lack any + * aesthetic sense may also use the transform to slant or stretch + * glyphs. + * + * @param antialias true for anti-aliased rendering, + * false for normal rendering. For hinted fonts, + * this parameter may indeed affect the result. + * + * @param fractionalMetrics true for fractional metrics, + * false for rounding the result to a pixel boundary. + * + * @param horizontal true for horizontal line layout, + * false for vertical line layout. + * + * @param advance a point whose x and y + * fields will hold the advance in each direction. It is well + * possible that both values are non-zero, for example for rotated + * text or for Urdu fonts. + */ + public abstract void getAdvance(int glyphIndex, + float pointSize, + AffineTransform transform, + boolean antialias, + boolean fractionalMetrics, + boolean horizontal, + Point2D advance); + + + /** + * Determines the distance between the base line and the highest + * ascender. + * + * @param pointSize the point size of the font. + * + * @param transform a transform that is applied in addition to + * scaling to the specified point size. This is often used for + * scaling according to the device resolution. Those who lack any + * aesthetic sense may also use the transform to slant or stretch + * glyphs. + * + * @param antialias true for anti-aliased rendering, + * false for normal rendering. For hinted fonts, + * this parameter may indeed affect the result. + * + * @param fractionalMetrics true for fractional metrics, + * false for rounding the result to a pixel boundary. + * + * @param horizontal true for horizontal line layout, + * false for vertical line layout. + * + * @return the ascent, which usually is a positive number. + */ + public abstract float getAscent(float pointSize, + AffineTransform transform, + boolean antialias, + boolean fractionalMetrics, + boolean horizontal); + + + /** + * Determines the distance between the base line and the lowest + * descender. + * + * @param pointSize the point size of the font. + * + * @param transform a transform that is applied in addition to + * scaling to the specified point size. This is often used for + * scaling according to the device resolution. Those who lack any + * aesthetic sense may also use the transform to slant or stretch + * glyphs. + * + * @param antialiased true for anti-aliased rendering, + * false for normal rendering. For hinted fonts, + * this parameter may indeed affect the result. + * + * @param fractionalMetrics true for fractional metrics, + * false for rounding the result to a pixel boundary. + * + * @param horizontal true for horizontal line layout, + * false for vertical line layout. + * + * @return the descent, which usually is a nagative number. + */ + public abstract float getDescent(float pointSize, + AffineTransform transform, + boolean antialiased, + boolean fractionalMetrics, + boolean horizontal); + + /** + * Returns the raw outline data. This is used for the autofitter atm. + * + * @param glyph the glyph index + * @param transform the transform to apply + * + * @return the raw glyph outline + */ + public abstract Zone getRawOutline(int glyph, AffineTransform transform); +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/truetype/Fixed.java b/libjava/classpath/gnu/java/awt/font/opentype/truetype/Fixed.java new file mode 100644 index 000000000..87dfebd41 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/opentype/truetype/Fixed.java @@ -0,0 +1,176 @@ +/* Fixed.java -- Fixed-point arithmetics for TrueType coordinates. + 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.font.opentype.truetype; + +import gnu.java.lang.CPStringBuilder; + +/** + * A utility class for fixed-point arithmetics, where numbers are + * represented with 26 dot 6 digits. This representation is used by + * TrueType coordinates. + * + *

A good compiler will inline calls of methods in this class. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public final class Fixed +{ + public static final int ONE = 1<<6; + + + /** + * The constructor is private so nobody can use it. + */ + private Fixed() + { + } + + + /** + * Multiplies two fixed-point numbers. + */ + public static int mul(int a, int b) + { + return (int) ((((long) a) * b) >> 6); + } + + public static int mul16(int a, int b) + { + return (int) ((((long) a) * b) >> 16); + } + + public static int div(int a, int b) + { + return (int) ((((long) a) << 6) / b); + } + + public static int div16(int a, int b) + { + return (int) ((((long) a) << 16) / b); + } + + public static int ceil(int a) + { + return (a + 63) & -64; + } + + + public static int floor(int a) + { + return a & -64; + } + + + /** + * Calculates the length of a fixed-point vector. + */ + public static int vectorLength(int x, int y) + { + int shift; + float fx, fy; + + if (x == 0) + return Math.abs(y); + else if (y == 0) + return Math.abs(x); + + /* Use the FPU. */ + fx = ((float) x) / 64.0f; + fy = ((float) y) / 64.0f; + return (int) (Math.sqrt(fx * fx + fy * fy) * 64.0); + } + + + public static int intValue(int f) + { + return f >> 6; + } + + + public static float floatValue(int f) + { + return ((float) f) / 64; + } + public static float floatValue16(int f) + { + return ((float) f) / 65536; + } + + public static double doubleValue(int f) + { + return ((double) f) / 64; + } + + + public static int valueOf(float f) + { + return (int) (f * 64); + } + + + public static int valueOf(double d) + { + return (int) (d * 64); + } + + public static int valueOf16(double d) + { + return (int) (d * (1 << 16)); + } + + /** + * Makes a string representation of a fixed-point number. + */ + public static String toString(int f) + { + return String.valueOf(floatValue(f)); + } + + + public static String toString(int x, int y) + { + CPStringBuilder sbuf = new CPStringBuilder(40); + sbuf.append('('); + sbuf.append(((float) x) / 64); + sbuf.append(", "); + sbuf.append(((float) y) / 64); + sbuf.append(')'); + return sbuf.toString(); + } +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphLoader.java b/libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphLoader.java new file mode 100644 index 000000000..8a3c56665 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphLoader.java @@ -0,0 +1,447 @@ +/* GlyphLoader.java -- Helper for loading TrueType glyph outlines. + 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.font.opentype.truetype; + +import gnu.java.awt.font.opentype.Hinter; + +import java.awt.geom.AffineTransform; +import java.nio.ByteBuffer; + + +/** + * A class for loading scaled and hinted glyph outlines. + * + *

Lack of Thread Safety: Glyph loaders are intentionally + * not safe to access from multiple concurrent + * threads. Synchronization needs to be performed externally. Usually, + * the font has already obtained a lock before calling the scaler, + * which in turn calls the GlyphLoader. It would thus be wasteful to + * acquire additional locks for the GlyphLoader. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +final class GlyphLoader +{ + /** + * A helper object for locating glyph data. GlyphLocator is an + * abstract superclass, and there is a concretization for each glyph + * location table ('loca') format. + */ + private final GlyphLocator glyphLocator; + + + /** + * A helper object for measuring the advance width and height of a + * glyph. + */ + private final GlyphMeasurer glyphMeasurer; + + + /** + * The virtual machine for executing TrueType bytecodes. + */ + private final VirtualMachine vm; + + + /** + * The number of font units in one em. A typical value is 2048, + * but this depends on the font. + */ + private final int unitsPerEm; + + private final int[] contourEndPoints; + private final byte[] pointFlags; + + + /** + * Constructs a GlyphLoader. + */ + GlyphLoader(GlyphLocator glyphLocator, VirtualMachine vm, + int unitsPerEm, int maxContours, int maxPoints, + GlyphMeasurer glyphMeasurer) + { + this.glyphLocator = glyphLocator; + this.glyphMeasurer = glyphMeasurer; + this.unitsPerEm = unitsPerEm; + this.vm = vm; + + contourEndPoints = new int[maxContours]; + pointFlags = new byte[maxPoints]; + } + + + /** + * @param glyphIndex the number of the glyph whose outlines are to be + * retrieved. + */ + public void loadGlyph(int glyphIndex, + double pointSize, + AffineTransform transform, + boolean antialias, + Zone glyphZone, Hinter hinter) + { + glyphZone.setNumPoints(4); + loadSubGlyph(glyphIndex, pointSize, transform, antialias, glyphZone, + 0, 0, hinter); + } + + public void loadGlyph(int glyphIndex, AffineTransform transform, + Zone glyphZone, Hinter hinter) + { + loadGlyph(glyphIndex, unitsPerEm, transform, false, glyphZone, hinter); + } + + private void loadSubGlyph(int glyphIndex, + double pointSize, + AffineTransform transform, + boolean antialias, + Zone glyphZone, + int preTranslateX, + int preTranslateY, + Hinter hinter) + { + ByteBuffer glyph; + int numContours; + int xMin, yMin, xMax, yMax; + byte flag; + + glyph = glyphLocator.getGlyphData(glyphIndex); + + if (glyph == null) + { + glyphZone.setNumPoints(4); + setPhantomPoints(glyphIndex, 0, glyphZone); + glyphZone.transform(pointSize, transform, unitsPerEm, + preTranslateX, preTranslateY); + return; + } + + numContours = glyph.getShort(); + xMin = glyph.getChar(); + yMin = glyph.getChar(); + xMax = glyph.getChar(); + yMax = glyph.getChar(); + + + if (numContours >= 0) + loadSimpleGlyph(glyphIndex, pointSize, transform, antialias, + numContours, glyph, glyphZone, + preTranslateX, preTranslateY, hinter); + else + loadCompoundGlyph(glyphIndex, pointSize, transform, antialias, + glyph, glyphZone, + preTranslateX, preTranslateY, hinter); + } + + + private void loadSimpleGlyph(int glyphIndex, + double pointSize, AffineTransform transform, + boolean antialias, + int numContours, ByteBuffer glyph, + Zone glyphZone, + int preTranslateX, int preTranslateY, + Hinter hinter) + { + int numPoints; + int posInstructions, numInstructions; + boolean execInstructions; + + execInstructions = vm.setup(pointSize, transform, antialias); + + /* Load the contour end points and determine the number of + * points. + */ + for (int i = 0; i < numContours; i++) + contourEndPoints[i] = glyph.getChar(); + if (numContours > 0) + numPoints = 1 + contourEndPoints[numContours - 1]; + else + numPoints = 0; + glyphZone.setNumPoints(numPoints + 4); + + numInstructions = glyph.getChar(); + posInstructions = glyph.position(); + glyph.position(posInstructions + numInstructions); + loadFlags(numPoints, glyph); + loadCoordinates(numPoints, glyph, glyphZone); + for (int i = 0; i < numContours; i++) + glyphZone.setContourEnd(contourEndPoints[i], true); + + setPhantomPoints(glyphIndex, numPoints, glyphZone); + glyphZone.transform(pointSize, transform, unitsPerEm, + preTranslateX, preTranslateY); + + if (execInstructions && hinter != null) + { + hinter.applyHints(glyphZone); + } + } + + + private static final short ARGS_ARE_WORDS = 1; + private static final short ARGS_ARE_XY_VALUES = 2; + private static final short ROUND_XY_TO_GRID = 4; + private static final short WE_HAVE_A_SCALE = 8; + private static final short MORE_COMPONENTS = 32; + private static final short WE_HAVE_AN_X_AND_Y_SCALE = 64; + private static final short WE_HAVE_A_TWO_BY_TWO = 128; + private static final short WE_HAVE_INSTRUCTIONS = 256; + private static final short USE_MY_METRICS = 512; + private static final short OVERLAP_COMPOUND = 1024; + private static final short SCALED_COMPONENT_OFFSET = 2048; + private static final short UNSCALED_COMPONENT_OFFSET = 4096; + + private void loadCompoundGlyph(int glyphIndex, + double pointSize, + AffineTransform transform, + boolean antialias, + ByteBuffer glyph, + Zone glyphZone, + int preTranslateX, int preTranslateY, + Hinter hinter) + { + short flags; + int subGlyphIndex; + int metricsGlyphIndex; + Zone subGlyphZone = new Zone(glyphZone.getCapacity()); + int arg1, arg2; + double a, b, c, d, e, f; + AffineTransform componentTransform = new AffineTransform(); + + /* By default, use the metrics of the compound glyph. The default + * is overridden if some component glyph has the USE_MY_METRICS + * flag set. + */ + metricsGlyphIndex = glyphIndex; + + do + { + flags = glyph.getShort(); + subGlyphIndex = glyph.getChar(); + + if ((flags & USE_MY_METRICS) != 0) + metricsGlyphIndex = subGlyphIndex; + + if ((flags & ARGS_ARE_WORDS) != 0) + { + arg1 = glyph.getShort(); + arg2 = glyph.getShort(); + } + else + { + arg1 = glyph.get(); + arg2 = glyph.get(); + } + + if ((flags & WE_HAVE_A_SCALE) != 0) + { + a = d = getDouble214(glyph); + b = c = 0.0; + } + else if ((flags & WE_HAVE_AN_X_AND_Y_SCALE) != 0) + { + a = getDouble214(glyph); + d = getDouble214(glyph); + b = c = 0.0; + } + else if ((flags & WE_HAVE_A_TWO_BY_TWO) != 0) + { + a = getDouble214(glyph); + b = getDouble214(glyph); + c = getDouble214(glyph); + d = getDouble214(glyph); + } + else + { + a = d = 1.0; + b = c = 0.0; + } + + double m = Math.max(Math.abs(a), Math.abs(b)); + double n = Math.max(Math.abs(c), Math.abs(d)); + + /* The Apple TrueType specification actually says that m is + * multiplied by two if + * + * abs(abs(a) - abs(c)) <= 33/65536, + * + * but this is probably a typo. On 2003-07-23, Sascha Brawer + * wrote an e-mail message to applefonts@apple.com, asking + * whether this might possibly be an error in the specification. + */ + if (Math.abs(Math.abs(a) - Math.abs(b)) <= 33.0/65536.0) + m = m * 2; + + if (Math.abs(Math.abs(c) - Math.abs(d)) <= 33.0/65536.0) + n = n * 2; + + if ((flags & ARGS_ARE_XY_VALUES) != 0) + { + e = m * arg1; + f = n * arg2; + } + else + e = f = 0.0; + + componentTransform.setTransform(a, b, c, d, 0.0, 0.0); + + // System.out.println("componentTransform = " + componentTransform + // + ", e=" + e + ", f=" + f); + componentTransform.concatenate(transform); + + int pos = glyph.position(); + int lim = glyph.limit(); + + loadSubGlyph(subGlyphIndex, pointSize, componentTransform, + antialias, subGlyphZone, + Math.round((float) e + preTranslateX), + Math.round(-((float) f + preTranslateY)), hinter); + glyphZone.combineWithSubGlyph(subGlyphZone, 4); + glyph.limit(lim).position(pos); + } + while ((flags & MORE_COMPONENTS) != 0); + + setPhantomPoints(metricsGlyphIndex, glyphZone.getSize() - 4, glyphZone); + } + + + private double getDouble214(ByteBuffer buf) + { + return ((double) buf.getShort()) / (1 << 14); + } + + + /** + * Loads the per-point flags of a glyph into the + * pointFlags field. + */ + private void loadFlags(int numPoints, ByteBuffer glyph) + { + byte flag; + int numRepetitions; + + for (int i = 0; i < numPoints; i++) + { + pointFlags[i] = flag = glyph.get(); + if ((flag & 8) != 0) + { + numRepetitions = ((int) glyph.get()) & 0xff; + while (numRepetitions > 0) + { + pointFlags[++i] = flag; + --numRepetitions; + } + } + } + } + + + private void loadCoordinates(int numPoints, ByteBuffer glyph, + Zone glyphZone) + { + int x, y; + byte flag; + + x = 0; + for (int i = 0; i < numPoints; i++) + { + flag = pointFlags[i]; + if ((flag & 2) == 0) + { + if ((flag & 16) == 0) + x += glyph.getShort(); + } + else + { + if ((flag & 16) != 0) + x += (glyph.get() & 0xff); + else + x -= (glyph.get() & 0xff); + } + glyphZone.setOriginalX(i, x); + glyphZone.setOnCurve(i, (flag & 1) == 1); + } + + y = 0; + for (int i = 0; i < numPoints; i++) + { + flag = pointFlags[i]; + if ((flag & 4) == 0) + { + if ((flag & 32) == 0) + y += glyph.getShort(); + } + else + { + if ((flag & 32) != 0) + y += (glyph.get() & 0xff); + else + y -= (glyph.get() & 0xff); + } + glyphZone.setOriginalY(i, -y); + } + } + + + private void setPhantomPoints(int glyphIndex, int numPoints, + Zone glyphZone) + { + /* Phantom point 0: Character origin. */ + glyphZone.setOriginalX(numPoints, 0); + glyphZone.setOriginalY(numPoints, 0); + + /* Phantom point 1: Horizontal advance point. */ + glyphZone.setOriginalX(numPoints + 1, + glyphMeasurer.getAdvanceWidth(glyphIndex, true)); + glyphZone.setOriginalY(numPoints + 1, + glyphMeasurer.getAdvanceHeight(glyphIndex, true)); + + /* Phantom point 2: Vertical origin. */ + int vertX = glyphMeasurer.getAscent(/* vertical */ false); + int vertY = glyphMeasurer.getAscent(/* horizontal */ true); + glyphZone.setOriginalX(numPoints + 2, vertX); + glyphZone.setOriginalY(numPoints + 2, vertY); + + /* Phantom point 3: Vertical advance point. */ + glyphZone.setOriginalX(numPoints + 3, + vertX + glyphMeasurer.getAdvanceWidth(glyphIndex, false)); + glyphZone.setOriginalY(numPoints + 3, + vertY + glyphMeasurer.getAdvanceHeight(glyphIndex, false)); + } +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphLocator.java b/libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphLocator.java new file mode 100644 index 000000000..fc2256b15 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphLocator.java @@ -0,0 +1,187 @@ +/* GlyphLocator.java -- Locates outlines of TrueType glyphs. + 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.font.opentype.truetype; + +import java.awt.FontFormatException; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.IntBuffer; + + +/** + * Locates glyph outlines in a TrueType or OpenType glyf + * table. + * + * @see Adobe’s specification of the OpenType ‘loca’ + * table + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +abstract class GlyphLocator +{ + /** + * The actual glyph data of the font, which is contained in the + * 'glyf' table. + */ + protected ByteBuffer glyfTable; + + + /** + * Creates a new GlyphLocator for a loca table. + * + * @param format the format of the loca table. The + * value must be 0 for two-byte offsets, or 1 for four-byte + * offsets. TrueType and OpenType fonts indicate the format in the + * indexToLoc field of the font header. + * + * @param loca the loca table of the font, which + * contains the position of each glyph in the glyf + * table. + * + * @param glyf the glyf table of the font, which + * contains the outline data of each glyph. + * + * @throws FontFormatException if format is neither 0 + * nor 1. + */ + public static GlyphLocator forTable(int format, ByteBuffer loca, + ByteBuffer glyf) + throws FontFormatException + { + switch (format) + { + case 0: + return new GlyphLocator.TwoByte(loca, glyf); + + case 1: + return new GlyphLocator.FourByte(loca, glyf); + + default: + throw new FontFormatException("unsupported loca format"); + } + } + + + /** + * Locates the outline data for a glyph. + * + *

For efficiency, the glyph locator does not create a new buffer + * for each invocation. Instead, this method always returns the same + * buffer object. Therefore, the data of a glyph must have been read + * completely before another glyph of the same font gets requested + * through this method. + * + * @param glyph the number of the glyph whose outlines are to be + * retrieved. + * + * @return a buffer whose position is set to the first byte of glyph + * data, and whose limit is set to disallow accessing any data that + * does not belong to the glyph. If there is no outline data for the + * requested glyph, as would be the case for the space glyph, the + * result will be null. + */ + public abstract ByteBuffer getGlyphData(int glyph); + + + /** + * A GlyphLocator that locates glyphs using two-byte offsets, + * interpreting loca tables of format 0. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ + private final static class TwoByte + extends GlyphLocator + { + final CharBuffer indexToLoc; + + TwoByte(ByteBuffer loca, ByteBuffer glyf) + { + this.glyfTable = glyf; + indexToLoc = loca.asCharBuffer(); + } + + + public ByteBuffer getGlyphData(int glyph) + { + int offset, limit; + offset = ((int) indexToLoc.get(glyph)) << 1; + limit = ((int) indexToLoc.get(glyph + 1)) << 1; + if (offset >= limit) + return null; + + glyfTable.limit(limit).position(offset); + return glyfTable; + } + } + + + /** + * A GlyphLocator that locates glyphs using four-byte offsets, + * interpreting loca tables of format 1. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ + private final static class FourByte + extends GlyphLocator + { + final IntBuffer indexToLoc; + + FourByte(ByteBuffer loca, ByteBuffer glyf) + { + this.glyfTable = glyf; + indexToLoc = loca.asIntBuffer(); + } + + + public ByteBuffer getGlyphData(int glyph) + { + int offset, limit; + offset = indexToLoc.get(glyph); + limit = indexToLoc.get(glyph + 1); + if (offset >= limit) + return null; + + glyfTable.limit(limit).position(offset); + return glyfTable; + } + } +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphMeasurer.java b/libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphMeasurer.java new file mode 100644 index 000000000..452456d13 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphMeasurer.java @@ -0,0 +1,228 @@ +/* GlyphMeasurer.java -- Helper for measuring TrueType glyphs. + 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.font.opentype.truetype; + +import java.awt.FontFormatException; +import java.nio.ByteBuffer; +import java.nio.ShortBuffer; + + +/** + * A class for measuring TrueType and OpenType glyphs. + * + *

Lack of Thread Safety: Glyph measurers are intentionally + * not safe to access from multiple concurrent + * threads. Synchronization needs to be performed externally. Usually, + * the font has already obtained a lock before calling the scaler, + * which in turn calls the GlyphMeasurer. It would thus be wasteful to + * acquire additional locks for the GlyphMeasurer. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +final class GlyphMeasurer +{ + /** + * A view buffer that allows accessing the contents of the + * font’s hmtx table as shorts. + */ + private final ShortBuffer horizontalGlyphMetrics; + + + /** + * A view buffer that allows accessing the contents of the + * font’s vmtx table as shorts. + */ + private final ShortBuffer verticalGlyphMetrics; + + + private final int numLongHorizontalMetricsEntries; + private final int numLongVerticalMetricsEntries; + + private final int horizontalAscent; + private final int verticalAscent; + + private final int horizontalDescent; + private final int verticalDescent; + + private final int horizontalLineGap; + + + /** + * Constructs a GlyphMeasurer from TrueType/OpenType font tables. + * + * @param hhea the hhea table, which contains + * information about horizontal metrics that is common to all + * glyphs. + * + * @param hmtx the hmtx table, which contains + * glyph-specific information about horizontal metrics. + * + * @param vhea the vhea table, which contains + * information about vertical metrics that is common to all + * glyphs. If a font does not provide such a table, pass + * null. + * + * @param vmtx the vmtx table, which contains + * glyph-specific information about vertical metrics. If a font + * does not provide such a table, pass null. + */ + GlyphMeasurer(ByteBuffer hhea, ByteBuffer hmtx, + ByteBuffer vhea, ByteBuffer vmtx) + throws FontFormatException + { + if ((hhea.getInt(0) != 0x00010000) || (hhea.getInt(30) != 0)) + throw new FontFormatException("unsupported hhea format"); + + horizontalAscent = hhea.getShort(4); + horizontalDescent = hhea.getShort(6); + horizontalLineGap = hhea.getShort(8); + + numLongHorizontalMetricsEntries = hhea.getChar(34); + horizontalGlyphMetrics = hmtx.asShortBuffer(); + + if (vhea != null) + { + verticalAscent = vhea.getShort(4); + verticalDescent = vhea.getShort(6); + numLongVerticalMetricsEntries = vhea.getChar(34); + verticalGlyphMetrics = vmtx.asShortBuffer(); + } + else + { + verticalAscent = /* advanceWidthMax */ hhea.getChar(10) / 2; + verticalDescent = -verticalAscent; + numLongVerticalMetricsEntries = 0; + verticalGlyphMetrics = null; + } + } + + + /** + * Returns the distance from the baseline to the highest ascender. + * + * @param horizontal true for horizontal line layout, + * false for vertical line layout. + * + * @return the maximal ascent, in font units. + */ + public int getAscent(boolean horizontal) + { + return horizontal ? horizontalAscent : verticalAscent; + } + + + /** + * Returns the distance from the baseline to the lowest descender. + * + * @param horizontal true for horizontal line layout, + * false for vertical line layout. + * + * @return the maximal descent, in font units. + */ + public int getDescent(boolean horizontal) + { + return horizontal ? horizontalDescent : verticalDescent; + } + + + /** + * Returns the typographic line gap. + * + * @param horizontal true for horizontal line layout, + * false for vertical line layout. + * + * @return the line gap, in font units. + */ + public int getLineGap(boolean horizontal) + { + return horizontalLineGap; + } + + + /** + * Determines the advance width of a glyph, without considering + * hinting. + * + * @param glyphIndex the index of the glyph whose advance width is + * to be determined. + * + * @param horizontal true for horizontal line layout, + * false for vertical line layout. + * + * @return the advance width, in font units. + */ + public int getAdvanceWidth(int glyphIndex, boolean horizontal) + { + if (!horizontal) + return 0; + + glyphIndex = Math.min(glyphIndex, + numLongHorizontalMetricsEntries - 1); + return horizontalGlyphMetrics.get(glyphIndex << 1); + } + + + /** + * Determines the advance width of a glyph, without considering + * hinting. + * + * @param glyphIndex the index of the glyph whose advance width is + * to be determined. + * + * @param horizontal true for horizontal line layout, + * false for vertical line layout. + * + * @return the advance width, in font units. + */ + public int getAdvanceHeight(int glyphIndex, boolean horizontal) + { + if (horizontal) + return 0; + + /* If a font does not provide vertical glyph metrics, advance + * by the height of one horizontal line. + */ + if (verticalGlyphMetrics == null) + return horizontalAscent - horizontalDescent + horizontalLineGap; + + glyphIndex = Math.min(glyphIndex, + numLongVerticalMetricsEntries - 1); + return verticalGlyphMetrics.get(glyphIndex << 1); + } +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/truetype/Point.java b/libjava/classpath/gnu/java/awt/font/opentype/truetype/Point.java new file mode 100644 index 000000000..438eb6558 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/opentype/truetype/Point.java @@ -0,0 +1,287 @@ +/* Point.java -- Holds information for one point on a glyph outline + 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.font.opentype.truetype; + +import gnu.java.lang.CPStringBuilder; + +/** + * Encapsulates information regarding one point on a glyph outline. + */ +public class Point +{ + public static final short FLAG_TOUCHED_X = 1; + public static final short FLAG_TOUCHED_Y = 2; + public static final short FLAG_ON_CURVE = 4; + public static final short FLAG_CONTOUR_END = 8; + public static final short FLAG_WEAK_INTERPOLATION = 16; + public static final short FLAG_INFLECTION = 32; + public static final short FLAG_DONE_X = 64; + public static final short FLAG_DONE_Y = 128; + + /** + * Right direction. + */ + public static final int DIR_RIGHT = 1; + + /** + * Left direction. + */ + public static final int DIR_LEFT = -1; + + /** + * Up direction. + */ + public static final int DIR_UP = 2; + + /** + * Down direction. + */ + public static final int DIR_DOWN = -2; + + /** + * The original x coordinate in font units. + */ + int origX; + + /** + * The original y coordinate in font units. + */ + int origY; + + /** + * The x coordinate scaled to the target. + */ + int scaledX; + + /** + * The y coordinate scaled to the target. + */ + int scaledY; + + /** + * The final hinted and scaled x coordinate. + */ + int x; + + /** + * The final hinted and scaled y coordinate. + */ + int y; + + int u; + int v; + + /** + * The glyph flags. + */ + short flags; + + /** + * The previous point in the contour. + */ + private Point prev; + + /** + * The next point in the contour. + */ + private Point next; + + /** + * The in-direction of the point, according to the DIR_* constants of this + * class. + */ + int inDir; + + /** + * The out-direction of the point, according to the DIR_* constants of this + * class. + */ + int outDir; + + public Point getNext() + { + return next; + } + + public void setNext(Point next) + { + this.next = next; + } + + public Point getPrev() + { + return prev; + } + + public void setPrev(Point prev) + { + this.prev = prev; + } + + public int getOrigX() + { + return origX; + } + + public void setOrigX(int origX) + { + this.origX = origX; + } + + public int getOrigY() + { + return origY; + } + + public void setOrigY(int origY) + { + this.origY = origY; + } + + public int getInDir() + { + return inDir; + } + + public void setInDir(int inDir) + { + this.inDir = inDir; + } + + public int getOutDir() + { + return outDir; + } + + public void setOutDir(int outDir) + { + this.outDir = outDir; + } + + public short getFlags() + { + return flags; + } + + public void setFlags(short flags) + { + this.flags = flags; + } + + public void addFlags(short flags) + { + this.flags |= flags; + } + + public boolean isControlPoint() + { + return (flags & FLAG_ON_CURVE) == 0; + } + + public int getU() + { + return u; + } + + public void setU(int u) + { + this.u = u; + } + + public int getV() + { + return v; + } + + public void setV(int v) + { + this.v = v; + } + + public String toString() + { + CPStringBuilder s = new CPStringBuilder(); + s.append("[Point] origX: "); + s.append(origX); + s.append(", origY: "); + s.append(origY); + // TODO: Add more info when needed. + return s.toString(); + } + + public int getX() + { + return x; + } + + public void setX(int x) + { + this.x = x; + } + + public int getY() + { + return y; + } + + public void setY(int y) + { + this.y = y; + } + + public int getScaledX() + { + return scaledX; + } + + public void setScaledX(int scaledX) + { + this.scaledX = scaledX; + } + + public int getScaledY() + { + return scaledY; + } + + public void setScaledY(int scaledY) + { + this.scaledY = scaledY; + } +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/truetype/TrueTypeScaler.java b/libjava/classpath/gnu/java/awt/font/opentype/truetype/TrueTypeScaler.java new file mode 100644 index 000000000..1d5c53f9d --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/opentype/truetype/TrueTypeScaler.java @@ -0,0 +1,380 @@ +/* TrueTypeScaler.java -- Font scaler for TrueType outlines. + 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.font.opentype.truetype; + +import gnu.java.awt.font.opentype.Hinter; +import gnu.java.awt.font.opentype.Scaler; + +import java.awt.FontFormatException; +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.geom.Point2D; +import java.nio.ByteBuffer; + + +/** + * A scaler for fonts whose outlines are described in the TrueType + * format. + * + *

Lack of Thread Safety: Font scalers are intentionally + * not safe to access from multiple concurrent threads. + * Synchronization needs to be performed externally. Usually, the font + * that uses this scaler already has obtained a lock before calling + * the scaler. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public final class TrueTypeScaler + extends Scaler +{ + /** + * The TrueType or OpenType table that contains the glyph outlines. + */ + private ByteBuffer glyfTable; + + + /** + * A helper object for loading glyph outlines. + */ + private GlyphLoader glyphLoader; + + + /** + * A helper object for measuring the advance width and height of a + * glyph. + */ + private final GlyphMeasurer glyphMeasurer; + + private final Zone glyphZone; + + + /** + * The number of units per em. A typical value is 2048, but some + * font use other numbers as well. + */ + private int unitsPerEm; + + + /** + * Constructs a new TrueTypeScaler. + * + * @param unitsPerEm the number of font units per em. This value can + * be retrieved from the font’s head table. + * + * @param maxp the maxp table of the font, which + * contains various constants needed for setting up the virtual + * machine that interprets TrueType bytecodes. + * + * @param controlValueTable the cvt table of the font, + * which contains the initial values of the control value table. + * + * @param fpgm the fpgm table of the font, which + * contains a font program that is executed exactly once. The + * purpose of the font program is to define functions and to patch + * the interpreter. + * + * @param locaFormat the format of the loca table. The + * value must be 0 for two-byte offsets, or 1 for four-byte + * offsets. TrueType and OpenType fonts indicate the format in the + * indexToLoc field of the font header. + * + * @param loca the loca table of the font, which + * contains for each glyph the offset of its outline data + * in glyf. + * + * @param glyf the glyf table of the font, which + * contains the outline data for all glyphs in the font. + * + * @param preProgram the prep table of the font, which + * contains a program that is executed whenever the point size or + * the device transform have changed. This program is called + * pre-program because it gets executed before the instructions of + * the individual glyphs. If the font does not contain a + * pre-program, pass null. + * + * @throws FontFormatException if format is neither 0 + * nor 1. + */ + public TrueTypeScaler(int unitsPerEm, + ByteBuffer hhea, + ByteBuffer htmx, + ByteBuffer vhea, + ByteBuffer vtmx, + ByteBuffer maxp, + ByteBuffer controlValueTable, + ByteBuffer fpgm, + int locaFormat, ByteBuffer loca, + ByteBuffer glyf, + ByteBuffer preProgram) + throws FontFormatException + { + int maxContours, maxPoints; + VirtualMachine vm; + + maxContours = Math.max(/* maxContours */ (int) maxp.getChar(8), + /* maxCompositeContours */ (int) maxp.getChar(12)) + + /* fix for some broken fonts */ 8; + maxPoints = Math.max(/* maxPoints */ (int) maxp.getChar(6), + /* maxCompositePoints */ (int) maxp.getChar(10)) + + /* fix for some broken fonts */ 12; + + + glyphZone = new Zone(maxPoints + /* four phantom points */ 4); + this.glyfTable = glyf; + vm = new VirtualMachine(unitsPerEm, maxp, + controlValueTable, fpgm, + preProgram); + + GlyphLocator locator = GlyphLocator.forTable(locaFormat, loca, glyf); + glyphMeasurer = new GlyphMeasurer(hhea, htmx, vhea, vtmx); + glyphLoader = new GlyphLoader(locator, vm, unitsPerEm, + maxContours, maxPoints, + glyphMeasurer); + + this.unitsPerEm = unitsPerEm; + } + + + /** + * Retrieves the scaled outline of a glyph, adjusting control points + * to the raster grid if necessary. + * + * @param glyphIndex the glyph number whose outline is retrieved. + * + * @param pointSize the point size for the glyph. + * + * @param deviceTransform an affine transformation for the device. + * + * @param antialias whether or not the rasterizer will perform + * anti-aliasing on the returned path. + * + * @param fractionalMetrics false for adjusting glyph + * positions to the raster grid of device space. + */ + public GeneralPath getOutline(int glyphIndex, + float pointSize, + AffineTransform deviceTransform, + boolean antialias, + boolean fractionalMetrics, Hinter hinter, + int type) + { + glyphLoader.loadGlyph(glyphIndex, pointSize, deviceTransform, + antialias, glyphZone, hinter); + return glyphZone.getPath(type); + } + + public Zone getRawOutline(int glyphIndex, AffineTransform transform) + { + Zone zone = new Zone(glyphZone.getCapacity()); + glyphLoader.loadGlyph(glyphIndex, transform, zone, null); + return zone; + } + + /** + * Determines the advance width and height for a glyph. + * + * @param glyphIndex the glyph whose advance width and height is to + * be determined. + * + * @param pointSize the point size of the font. + * + * @param transform a transform that is applied in addition to + * scaling to the specified point size. This is often used for + * scaling according to the device resolution. Those who lack any + * aesthetic sense may also use the transform to slant or stretch + * glyphs. + * + * @param antialias true for anti-aliased rendering, + * false for normal rendering. For hinted fonts, + * this parameter may indeed affect the result. + * + * @param fractionalMetrics true for fractional metrics, + * false for rounding the result to a pixel boundary. + * + * @param horizontal true for horizontal line layout, + * false for vertical line layout. + * + * @param advance a point whose x and y + * fields will hold the advance in each direction. It is possible + * that both values are non-zero, for example if + * transform is a rotation, or in the case of Urdu + * fonts. + */ + public void getAdvance(int glyphIndex, + float pointSize, + AffineTransform transform, + boolean antialias, + boolean fractionalMetrics, + boolean horizontal, + Point2D advance) + { + double x, y; + double scaleFactor = (double) pointSize / unitsPerEm; + + /* FIXME: Should grid-fit if needed. Also, use cache if present + * in the font. + */ + advance.setLocation( + scaleFactor * glyphMeasurer.getAdvanceWidth(glyphIndex, horizontal), + scaleFactor * glyphMeasurer.getAdvanceHeight(glyphIndex, horizontal)); + + transform.transform(advance, advance); + } + + + /** + * Scales a value from font units to pixels, given the point size + * and the transform. + * + * @param pointSize the point size of the font. + * + * @param transform a transform that is applied in addition to + * scaling to the specified point size. This is often used for + * scaling according to the device resolution. + * + * @param fractionalMetrics true for fractional + * metrics, false for rounding the result to a pixel + * boundary. + * + * @param horizontal true if the funits + * value is along the x axis, false if it is along the + * y axis. + */ + private float scaleFromFUnits(int funits, + float pointSize, + AffineTransform transform, + boolean fractionalMetrics, + boolean horizontal) + { + double s; + + s = (double) pointSize / unitsPerEm; + if (transform != null) + s *= horizontal ? transform.getScaleY() : transform.getScaleX(); + s *= funits; + if (!fractionalMetrics) + s = Math.round(s); + return (float) s; + } + + + /** + * Determines the distance between the base line and the highest + * ascender. + * + * @param pointSize the point size of the font. + * + * @param transform a transform that is applied in addition to + * scaling to the specified point size. This is often used for + * scaling according to the device resolution. Those who lack any + * aesthetic sense may also use the transform to slant or stretch + * glyphs. + * + * @param antialias true for anti-aliased rendering, + * false for normal rendering. For hinted fonts, + * this parameter may indeed affect the result. + * + * @param fractionalMetrics true for fractional metrics, + * false for rounding the result to a pixel boundary. + * + * @param horizontal true for horizontal line layout, + * false for vertical line layout. + * + * @return the ascent, which usually is a positive number. + */ + public float getAscent(float pointSize, + AffineTransform transform, + boolean antialias, + boolean fractionalMetrics, + boolean horizontal) + { + /* Note that the ascent is orthogonal to the direction of line + * layout: If the line direction is horizontal, the measurement of + * ascent is along the vertical axis, and vice versa. + */ + return scaleFromFUnits(glyphMeasurer.getAscent(horizontal), + pointSize, + transform, + fractionalMetrics, + /* reverse */ !horizontal); + } + + + /** + * Determines the distance between the base line and the lowest + * descender. + * + * @param pointSize the point size of the font. + * + * @param transform a transform that is applied in addition to + * scaling to the specified point size. This is often used for + * scaling according to the device resolution. Those who lack any + * aesthetic sense may also use the transform to slant or stretch + * glyphs. + * + * @param antialiased true for anti-aliased rendering, + * false for normal rendering. For hinted fonts, + * this parameter may indeed affect the result. + * + * @param fractionalMetrics true for fractional metrics, + * false for rounding the result to a pixel boundary. + * + * @param horizontal true for horizontal line layout, + * false for vertical line layout. + * + * @return the descent, which usually is a nagative number. + */ + public float getDescent(float pointSize, + AffineTransform transform, + boolean antialiased, + boolean fractionalMetrics, + boolean horizontal) + { + /* Note that the descent is orthogonal to the direction of line + * layout: If the line direction is horizontal, the measurement of + * descent is along the vertical axis, and vice versa. + */ + return scaleFromFUnits(glyphMeasurer.getDescent(horizontal), + pointSize, + transform, + fractionalMetrics, + /* reverse */ !horizontal); + } +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/truetype/VirtualMachine.java b/libjava/classpath/gnu/java/awt/font/opentype/truetype/VirtualMachine.java new file mode 100644 index 000000000..512c39ffd --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/opentype/truetype/VirtualMachine.java @@ -0,0 +1,1815 @@ +/* VirtualMachine.java -- Virtual machine for TrueType bytecodes. + 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.font.opentype.truetype; + +import gnu.java.lang.CPStringBuilder; + +import java.awt.FontFormatException; +import java.awt.geom.AffineTransform; +import java.nio.ByteBuffer; +import java.nio.ShortBuffer; + + +/** + * A virtual machine for interpreting TrueType bytecodes. + * + *

Lack of Thread Safety: The virtual machine is + * intentionally not safe to access from multiple concurrent + * threads. Synchronization needs to be performed externally. Usually, + * the font has already obtained a lock before calling the scaler, + * which in turn calls the VM. It would be wasteful to acquire + * additional locks for the VM. + * + *

Implementation Status: The current implementation can + * execute pre-programs of fonts, but it does not yet actually move + * any points. Control flow and arithmeti instructions are + * implemented, but most geometric instructions are not working + * yet. So, the VirtualMachine class is currently a no-op. However, + * not very much is missing. You are more than welcome to complete the + * implementation. + * + *

Patents: Apple Computer holds three United States Patents + * for the mathematical algorithms that are used by TrueType + * instructions. The monopoly granted by these patents will expire in + * October 2009. Before the expiration date, a license must be + * obtained from Apple Computer to use the patented technology inside + * the United States. For other countries, different dates might + * apply, or no license might be needed. + * + *

The default build of this class does not use the patented + * algorithms. If you have obtained a license from Apple, or if the + * patent protection has expired, or if no license is required for + * your contry, you can set a flag in the source file which will + * enable the use of the patented mathematical algorithms.

+ * + *

The relevant patents are listed subsequently.

+ * + *

  1. United States Patent 5155805, Method and Apparatus + * for Moving Control Points in Displaying Digital Typeface on Raster + * Output Devices, invented by Sampo Kaasila, assigned to Apple + * Computer. Filing date: May 8, 1989. Date of patent: October 13, + * 1992.
  2. + * + *
  3. United States Patent 5159668, Method and Apparatus for + * Manipulating Outlines in Improving Digital Typeface on Raster + * Output Devices, invented by Sampo Kaasila, assigned to Apple + * Computer. Filing date: May 8, 1989. Date of patent: October 27, + * 1992.
  4. + * + *
  5. United States Patent 5325479, Method and Apparatus for + * Moving Control Points in Displaying Digital Typeface on Raster + * Output Devices, invented by Sampo Kaasila, assigned to Apple + * Computer. Filing date: May 28, 1989. Date of patent: June 28, 1994 + * (with a statement that “[t]he portion of the term of this + * patent subsequent to Oct. 13, 2009 has been + * disclaimed”).
+ * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +class VirtualMachine +{ + /** + * Indicates whether or not to perform hinting operations that are + * protected by a number of US patents, two of which will expire on + * October 13, 2009, and one of which will expire on October 27, + * 2009. + */ + private final static boolean PATENTED_HINTING = false; + + + /** + * Indicates whether the execution of the Virtual Machine is traced + * to System.out. + */ + private final static boolean TRACE_EXECUTION = false; + + + /** + * The value 1 in 2-dot-14 fixed notation. + */ + private static final short ONE_214 = 0x4000; // 1 << 14 + + + /** + * The storage area of the virtual machine. + */ + private final int[] storage; + + + /** + * The stack. The stack grows from bottom to top, so + * sp[0] gets used before sp[1]. + */ + private int[] stack; + + + /** + * The maximum number of stack elements. + */ + private final int maxStackElements; + + + /** + * The current stack pointer of the virtual machine. + */ + private int sp; + + + /** + * fdefBuffer[i] is the buffer that contains the TrueType + * instructions of function #i. Most of the time, functions are + * defined in the font program, but a font may also re-define + * functions in its CVT program. + */ + private ByteBuffer[] fdefBuffer; + + + /** + * fdefEntryPoint[i] is the position in fdefBuffer[i] where the + * first TrueType instruction after the FDEF is located. + */ + private int[] fdefEntryPoint; + + + /** + * The original Control Value Table, sometimes abbreviated as CVT. + * The table contains signed 16-bit FUnits. Some fonts have no CVT, + * in which case the field will be null. + */ + private ShortBuffer controlValueTable; + + + /** + * The scaled values inside the control value table. + */ + private int[] cvt; + + + /** + * A value that is used by rounding operations to compensate for dot + * gain. + */ + private int engineCompensation = 0; + + + /** + * The contents of the font’s fpgm table, or + * null after the font program has been executed once. + */ + private ByteBuffer fontProgram; + + + /** + * The prep table of the font, which contains a program + * that is executed whenever the point size or the device transform + * have changed. This program is called pre-program because it gets + * executed before the instructions of the individual glyphs. If + * the font does not contain a pre-program, the value of this field + * is null. + */ + private ByteBuffer preProgram; + + + /** + * The number of points in the Twilight Zone. + */ + private int numTwilightPoints; + + + /** + * The current point size of the scaled font. The value is in Fixed + * 26.6 notation. + */ + private int pointSize; // 26.6 + + private AffineTransform deviceTransform; + + private int scaleX, scaleY, shearX, shearY; // 26.6 + + + /** + * Indicates whether or not scan-line conversion will use + * anti-aliasing (with gray levels). Font programs can ask for this + * value with the GETINFO instruction, and some + * programs may behave differently according to this setting. + */ + private boolean antialiased; + + + /* Graphics State. FIXME: Move this to its own class? Some + * documentation would not hurt, either. + */ + private int cvtCutIn; // 26.6 + private int deltaBase; // uint32 + private int deltaShift; // uint32 + private short freeX; // 2.14 + private short freeY; // 2.14 + private int loop; // int + private int minimumDistance; // 26.6 + private short projX; // 2.14 + private short projY; // 2.14 + private short dualX; // 2.14 + private short dualY; // 2.14 + private int rp0, rp1, rp2; // point numbers + private boolean scanControl; + private int scanType; + private int singleWidthValue; // 26.6 + private Zone zp0, zp1, zp2; + + private Zone twilightZone; + private Zone glyphZone; + + + /** + * Indicates whether or not the instructions that are associated + * with individual glyphs shall be executed. Set as a side effect + * of executing the pre-program when the point size, device + * transform or some other relevant parameter have changed. + */ + private boolean executeGlyphInstructions; + + + /** + * Indicates whether to ignore any modifications to the control + * value table that the font’s pre-program might have + * performed. Set as a side effect of executing the pre-program + * when the point size, device transform or some other relevant + * parameter have changed. + */ + private boolean ignoreCVTProgram; + + + /** + * The length of the space between rounded values. A value + * of zero means that rounding has been switched off. + */ + private int roundPeriod; // 26.6 + + + /** + * The offset of the rounded values from multiples of + * roundPeriod. + */ + private int roundPhase; // 26.6 + + + private int roundThreshold; // 26.6 + + + /** + * A cache for the number of pixels per EM. The value is a normal + * integer, not a fixed point notation. + * + * @see #getPixelsPerEM() + */ + private int cachedPixelsPerEM; + + + /** + * The number of font units per EM. + */ + private int unitsPerEm; + + + /** + * Constructs a new Virtual Machine for executing TrueType + * instructions. + * + * @param unitsPerEm the number of font units in one typographic + * em. + * + * @param preProgram the prep table of the font, which + * contains a program that is executed whenever the point size or + * the device transform have changed. This program is called + * pre-program because it gets executed before the instructions of + * the individual glyphs. If the font does not contain a + * pre-program, pass null. + */ + VirtualMachine(int unitsPerEm, + ByteBuffer maxp, + ByteBuffer controlValueTable, + ByteBuffer fontProgram, + ByteBuffer preProgram) + throws FontFormatException + { + int maxStorage, numFunctionDefs, maxInstructionDefs; + + if (maxp.getInt(0) != 0x00010000) + throw new FontFormatException("unsupported maxp version"); + + this.unitsPerEm = unitsPerEm; + maxStorage = maxp.getChar(18); + + /* FreeType says that there exist some broken fonts (like + * "Keystrokes MT") that contain function defs, but have a zero + * value in their maxp table. + */ + numFunctionDefs = maxp.getChar(20); + if (numFunctionDefs == 0) + numFunctionDefs = 64; + fdefBuffer = new ByteBuffer[numFunctionDefs]; + fdefEntryPoint = new int[numFunctionDefs]; + + /* Read the contents of the Control Value Table. */ + if (controlValueTable != null) + this.controlValueTable = controlValueTable.asShortBuffer(); + + maxInstructionDefs = maxp.getChar(22); + maxStackElements = maxp.getChar(24); + storage = new int[maxStorage]; + this.fontProgram = fontProgram; + this.preProgram = preProgram; + numTwilightPoints = maxp.getChar(16); + } + + + /** + * Sets the graphics state to default values. + */ + private void resetGraphicsState() + { + /* The freedom, projection and dual vector default to the x axis. */ + freeX = projX = dualX = ONE_214; + freeY = projY = dualX = 0; + cachedPixelsPerEM = 0; + + cvtCutIn = 68; // 17/16 in 26.6 notation + deltaBase = 9; + deltaShift = 3; + loop = 1; + minimumDistance = Fixed.ONE; + singleWidthValue = 0; + rp0 = rp1 = rp2 = 0; + scanControl = false; + scanType = 2; + zp0 = zp1 = zp2 = getZone(1); + + setRoundingMode(Fixed.ONE, 0x48); // round to grid + } + + + /** + * Reloads the control value table and scales each entry from font + * units to pixel values. + */ + private void reloadControlValueTable() + { + /* Some TrueType fonts have no control value table. */ + if (controlValueTable == null) + return; + + /* Read in the Control Value Table. */ + if (cvt == null) + cvt = new int[controlValueTable.capacity()]; + + /* Scale the entries. */ + for (int i = 0; i < cvt.length; i++) + cvt[i] = funitsToPixels(controlValueTable.get(i)); + } + + + /** + * Scales a value from font unites to pixels. + * + * @return the scaled value. + */ + private int funitsToPixels(int funits) + { + return (int) (((long) funits * scaleY + (unitsPerEm>>1)) + / unitsPerEm); + } + + + /** + * Sets up the virtual machine for the specified parameters. If + * there is no change to the last set-up, the method will quickly + * return. Otherwise, the font’s pre-program will be + * executed. + * + * @param pointSize the point size of the scaled font. + * + * @param deviceTransform an affine transformation which gets + * applied in addition to scaling by pointSize. Font + * programs can separately inquire about the point size. For this + * reason, it is not recommended to pre-multiply the point size to + * the device transformation. + * + * @param antialiased true if the scan-line conversion + * algorithm will use gray levels to give a smoother appearance, + * false otherwise. Font programs can ask for this + * value with the GETINFO instruction, and some + * programs may behave differently according to this setting. + */ + public boolean setup(double pointSize, + AffineTransform deviceTransform, + boolean antialiased) + { + boolean changeCTM; + int pointSize_Fixed; + + if (stack == null) + stack = new int[maxStackElements]; + + if (twilightZone == null) + twilightZone = new Zone(numTwilightPoints); + + /* If the font program has not yet been executed, do so. */ + if (fontProgram != null) + { + resetGraphicsState(); + sp = -1; + execute(fontProgram, 0); + fontProgram = null; // prevent further execution + } + + /* Determine whether the transformation matrix has changed. */ + pointSize_Fixed = Fixed.valueOf(pointSize); + changeCTM = ((pointSize_Fixed != this.pointSize) + || !deviceTransform.equals(this.deviceTransform) + || (antialiased != this.antialiased)); + + if (changeCTM) + { + this.pointSize = pointSize_Fixed; + this.deviceTransform = deviceTransform; + this.antialiased = antialiased; + scaleX = (int) (deviceTransform.getScaleX() * pointSize * 64); + scaleY = (int) (deviceTransform.getScaleY() * pointSize * 64); + shearX = (int) (deviceTransform.getShearX() * pointSize * 64); + shearY = (int) (deviceTransform.getShearY() * pointSize * 64); + + resetGraphicsState(); + reloadControlValueTable(); + executeGlyphInstructions = true; + ignoreCVTProgram = false; + + if (preProgram != null) + { + sp = -1; + execute(preProgram, 0); + if (ignoreCVTProgram) + reloadControlValueTable(); + } + } + + return executeGlyphInstructions; + } + + + /** + * Executes a stream of TrueType instructions. + */ + private void execute(ByteBuffer instructions, int pos) + { + instructions.position(pos); + + // FIXME: SECURITY: Possible denial-of-service attack + // via instructions that have an endless loop. + while (instructions.hasRemaining() + && executeInstruction(instructions)) + ; + } + + + /** + * Writes a textual description of the current TrueType instruction, + * including the top stack elements, to System.out. + * This is useful for debugging. + * + * @param inst the instruction stream, positioned at the current + * instruction. + */ + private void dumpInstruction(ByteBuffer inst) + { + CPStringBuilder sbuf = new CPStringBuilder(40); + int pc = inst.position(); + int bcode = inst.get(pc) & 0xff; + int count; + int delta; + + char pcPrefix = 'c'; + for (int i = 0; i < fdefBuffer.length; i++) + { + if (fdefBuffer[i] == inst) + { + pcPrefix = 'f'; + break; + } + } + sbuf.append(pcPrefix); + + + sbuf.append(getHex((short) inst.position())); + sbuf.append(": "); + sbuf.append(getHex((byte) bcode)); + sbuf.append(" "); + sbuf.append(INST_NAME[bcode]); + + if (bcode == 0x40) // NPUSHB + { + count = inst.get(pc + 1) & 0xff; + sbuf.append(" ("); + sbuf.append(count); + sbuf.append(") "); + for (int i = 0; i < count; i++) + { + if (i > 0) + sbuf.append(" "); + sbuf.append('$'); + sbuf.append(getHex(inst.get(pc + 2 + i))); + } + } + if (bcode == 0x41) // NPUSHW + { + count = inst.get(pc + 1) & 0xff; + sbuf.append(" ("); + sbuf.append(count); + sbuf.append(") "); + for (int i = 0; i < count; i++) + { + if (i > 0) + sbuf.append(' '); + sbuf.append('$'); + sbuf.append(getHex(inst.getShort(pc + 2 + 2*i))); + } + } + else + { + count = getInstructionLength(bcode) - 1; + for (int i = 0; i < count; i++) + { + sbuf.append(" $"); + sbuf.append(getHex(inst.get(pc + 1 + i))); + } + } + + while (sbuf.length() < 30) + sbuf.append(' '); + sbuf.append('|'); + sbuf.append(sp + 1); + sbuf.append("| "); + for (int i = sp; i >= Math.max(0, sp - 5); i = i - 1) + { + if (i < sp) + sbuf.append(" "); + if ((stack[i] >> 16) != 0) + sbuf.append(getHex((short) (stack[i] >> 16))); + sbuf.append(getHex((short) stack[i])); + } + System.out.println(sbuf); + } + + + private static char getNibble(int i, int rightShift) + { + i = (i >> rightShift) & 15; + if (i < 10) + return (char) (i + '0'); + else + return (char) (i + 'a' - 10); + } + + + private static String getHex(byte b) + { + char[] a = new char[2]; + a[0] = getNibble(b, 4); + a[1] = getNibble(b, 0); + return new String(a); + } + + + private static String getHex(short b) + { + char[] a = new char[4]; + a[0] = getNibble(b, 12); + a[1] = getNibble(b, 8); + a[2] = getNibble(b, 4); + a[3] = getNibble(b, 0); + return new String(a); + } + + + /** + * Skips any instructions until the specified opcode has been + * encoutered. + * + * @param inst the current instruction stream. After the call, + * the position of inst is right after the first + * occurence of opcode. + * + * @param opcode1 the opcode for which to look. + * + * @param opcode2 another opcode for which to look. Pass -1 + * if only opcode1 would terminate skipping. + * + * @param illegalCode1 an opcode that must not be encountered + * while skipping. Pass -1 if any opcode is acceptable. + * + * @param illegalCode2 another opcode that must not be encountered + * while skipping. Pass -1 to perform no check. + * + * @param handleNestedIfClauses true to handle + * nested IF [ELSE] EIF clauses, false + * to ignore them. From the TrueType specification document, + * one would think that nested if clauses would not be valid, + * but they do appear in some fonts. + * + * @throws IllegalStateException if illegalCode1 or + * illegalCode2 has been encountered while skipping. + */ + private static void skipAfter(ByteBuffer inst, + int opcode1, int opcode2, + int illegalCode1, int illegalCode2, + boolean handleNestedIfClauses) + { + int pos = inst.position(); + int curOpcode; + int instLen; + int nestingLevel = 0; // increased inside IF [ELSE] EIF sequences + + while (true) + { + curOpcode = inst.get(pos) & 0xff; + instLen = getInstructionLength(curOpcode); + + if (false && TRACE_EXECUTION) + { + for (int i = 0; i < nestingLevel; i++) + System.out.print("--"); + System.out.print("--" + pos + "-" + INST_NAME[curOpcode]); + if (nestingLevel > 0) + System.out.print(", ifNestingLevel=" + nestingLevel); + System.out.println(); + } + + if (curOpcode == 0x40) // NPUSHB + pos += 1 + (inst.get(pos + 1) & 0xff); + else if (curOpcode == 0x41) // NPUSHW + pos += 1 + 2 * (inst.get(pos + 1) & 0xff); + else + pos += instLen; + + if ((nestingLevel == 0) + && ((curOpcode == opcode1) || (curOpcode == opcode2))) + break; + + if (handleNestedIfClauses) + { + if (curOpcode == /* IF */ 0x58) + ++nestingLevel; + else if (curOpcode == /* EIF */ 0x59) + --nestingLevel; + } + + if ((nestingLevel < 0) + || (curOpcode == illegalCode1) + || (curOpcode == illegalCode2)) + throw new IllegalStateException(); + } + + inst.position(pos); + } + + + /** + * Returns the number of bytes that a TrueType instruction occupies. + * + * @param opcode the instruction. + * + * @return the number of bytes occupied by the instructions and its + * operands. For NPUSHB and NPUSHW, where + * the instruction length depends on the first operand byte, the + * result is -1. + */ + private static int getInstructionLength(int opcode) + { + /* NPUSHB, NPUSHW --> see following byte */ + if ((opcode == 0x40) || (opcode == 0x41)) + return -1; + + /* PUSHB[0] .. PUSHB[7] --> 2, 3, 4, 5, 6, 7, 8, 9 */ + if ((opcode >= 0xb0) && (opcode <= 0xb7)) + return opcode - 0xae; + + /* PUSHW[0] .. PUSHW[7] --> 3, 5, 6, 7, 11, 13, 15, 17*/ + if ((opcode >= 0xb8) && (opcode <= 0xbf)) + return 1 + ((opcode - 0xb7) << 1); + + return 1; + } + + + /** + * Executes a single TrueType instruction. This is the core + * routine of the Virtual Machine. + * + * @return true if another instruction shall be + * executed in the same call frame; false if the + * current call frame shall be popped. + */ + private boolean executeInstruction(ByteBuffer inst) + { + if (TRACE_EXECUTION) + dumpInstruction(inst); + + int i, count, e1, e2, e3, e4, x, y; + int bcode = inst.get() & 0xff; + + switch (bcode) + { + case 0x00: // SVTCA[0], Set freedom and proj. Vectors To Coord. Axis [y] + setFreedomVector((short) 0, ONE_214); + setProjectionVector((short) 0, ONE_214); + break; + + case 0x01: // SVTCA[1], Set freedom and proj. Vectors To Coord. Axis [x] + setFreedomVector(ONE_214, (short) 0); + setProjectionVector(ONE_214, (short) 0); + break; + + case 0x02: // SPVTCA[0], Set Projection Vector To Coordinate Axis [y] + setProjectionVector((short) 0, ONE_214); + break; + + case 0x03: // SPVTCA[1], Set Projection Vector To Coordinate Axis [x] + setProjectionVector(ONE_214, (short) 0); + break; + + case 0x0c: // GPV, Get Projection Vector + stack[++sp] = projX; + stack[++sp] = projY; + break; + + case 0x0d: // GPV, Get Freedom Vector + stack[++sp] = freeX; + stack[++sp] = freeY; + break; + + case 0x0F: // ISECT, move point p to the InterSECTION of two lines + sp -= 4; + handleISECT(stack[sp], stack[sp+1], stack[sp+2], + stack[sp+3], stack[sp+4]); + break; + + case 0x10: // SRP0, Set Reference Point 0 + rp0 = stack[sp--]; + break; + + case 0x11: // SRP1, Set Reference Point 1 + rp1 = stack[sp--]; + break; + + case 0x12: // SRP2, Set Reference Point 2 + rp2 = stack[sp--]; + break; + + case 0x13: // SZP0, Set Zone Pointer 0 + zp0 = getZone(stack[sp--]); + break; + + case 0x14: // SZP1, Set Zone Pointer 1 + zp1 = getZone(stack[sp--]); + break; + + case 0x15: // SZP2, Set Zone Pointer 2 + zp2 = getZone(stack[sp--]); + break; + + case 0x16: // SZPS, Set Zone PointerS + zp0 = zp1 = zp2 = getZone(stack[sp--]); + break; + + case 0x17: // SLOOP, Set LOOP variable + loop = stack[sp--]; + break; + + case 0x18: // RTG, Round To Grid + setRoundingMode(Fixed.ONE, 0x48); + break; + + case 0x19: // RTHG, Round To Half Grid + setRoundingMode(Fixed.ONE, 0x68); + break; + + case 0x1a: // SMD, Set Minimum Distance + minimumDistance = stack[sp--]; + break; + + case 0x1B: // ELSE, ELSE clause + skipAfter(inst, + /* look for: EIF, -- */ 0x59, -1, + /* illegal: --, -- */ -1, -1, + /* handle nested if clauses */ true); + break; + + case 0x1C: // JMPR, JuMP Relative + inst.position(inst.position() - 1 + stack[sp--]); + break; + + case 0x1D: // SCVTCI, Set Control Value Table Cut-In + cvtCutIn = stack[sp--]; + break; + + case 0x1F: // SSW, Set Single Width + singleWidthValue = stack[sp--]; + break; + + case 0x20: // DUP, DUPlicate top stack element + e1 = stack[sp]; + stack[++sp] = e1; + break; + + case 0x21: // POP, POP top stack element + sp--; + break; + + case 0x22: // CLEAR, CLEAR the stack + sp = -1; + break; + + case 0x23: // SWAP, SWAP the top two elements on the stack + e1 = stack[sp--]; + e2 = stack[sp]; + stack[sp] = e1; + stack[++sp] = e2; + break; + + case 0x24: // DEPTH, DEPTH of the stack + stack[++sp] = sp + 1; + break; + + case 0x25: // CINDEX, Copy the INDEXed element to the top of the stack + stack[sp] = stack[sp - stack[sp]]; + break; + + case 0x26: // MINDEX, Move the INDEXed element to the top of the stack + i = stack[sp]; + e1 = stack[sp - i]; + System.arraycopy(/* src */ stack, /* srcPos */ sp - i + 1, + /* dest */ stack, /* destPos*/ sp - i, + /* length */ i - 1); + --sp; + stack[sp] = e1; + break; + + case 0x2a: // LOOPCALL, LOOP and CALL function + i = stack[sp--]; + count = stack[sp--]; + e1 = inst.position(); + e2 = sp; + for (int j = 0; j < count; j++) + execute(fdefBuffer[i], fdefEntryPoint[i]); + inst.position(e1); + break; + + case 0x2B: // CALL, CALL function + i = stack[sp--]; + e1 = inst.position(); + e2 = sp; + execute(fdefBuffer[i], fdefEntryPoint[i]); + inst.position(e1); + break; + + case 0x2C: // FDEF, Function DEFinition + i = stack[sp--]; + fdefBuffer[i] = inst; + fdefEntryPoint[i] = inst.position(); + skipAfter(inst, + /* look for: ENDF */ 0x2d, + /* look for: --- */ -1, + /* illegal: IDEF */ 0x89, + /* illegal: FDEF */ 0x2c, + /* do not handle nested if clauses */ false); + break; + + case 0x2D: // ENDF, END Function definition + /* Pop the current stack frame. */ + return false; + + case 0x2e: // MDAP[0], Move Direct Absolute Point + handleMDAP(stack[sp--], /* round */ false); + break; + + case 0x2f: // MDAP[1], Move Direct Absolute Point + handleMDAP(stack[sp--], /* round */ true); + break; + + case 0x39: // IP, Interpolate Point by the last relative stretch + handleIP(); + break; + + case 0x3d: // RTDG, Round To Double Grid + setRoundingMode(Fixed.ONE, 0x08); + roundThreshold = roundThreshold / 64; // period/128 + break; + + case 0x3e: // MIAP[0], Move Indirect Absolute Point + e1 = stack[sp--]; + handleMIAP(e1, stack[sp--], /* round */ false); + break; + + case 0x3f: // MIAP[1], Move Indirect Absolute Point + e1 = stack[sp--]; + handleMIAP(e1, stack[sp--], /* round */ true); + break; + + case 0x40: // NPUSHB + count = inst.get() & 0xff; + for (i = 0; i < count; i++) + stack[++sp] = inst.get() & 0xff; + break; + + case 0x41: // NPUSHW + count = inst.get() & 0xff; + for (i = 0; i < count; i++) + stack[++sp] = inst.getShort(); + break; + + case 0x42: // WS, Write Store + e1 = stack[sp--]; i = stack[sp--]; + storage[i] = e1; + break; + + case 0x43: // RS, Read Store + stack[sp] = storage[stack[sp]]; + break; + + case 0x44: // WCVTP, Write Control Value Table in Pixel units + e1 = stack[sp--]; + i = stack[sp--]; + if (i < cvt.length) + cvt[i] = e1; + break; + + case 0x45: // RCVT, Read Control Value Table entry + if (stack[sp] < cvt.length) + stack[sp] = cvt[stack[sp]]; + else + stack[sp] = 0; + break; + + case 0x46: // GC[0], Get Coordinate projected onto the projection vector + stack[sp] = getProjection(zp2, stack[sp]); + break; + + case 0x47: // GC[1], Get Coordinate projected onto the projection vector + stack[sp] = getOriginalProjection(zp2, stack[sp]); + break; + + case 0x4B: // MPPEM, Measure Pixels Per EM + stack[++sp] = getPixelsPerEM(); + break; + + case 0x4c: // MPS, Measure Point Size + /* FreeType2 returns pixels per em here, because they think that + * the point size would be irrelevant in a given font program. + * This is extremely surprising, because the appearance of good + * fonts _should_ change with point size. For example, a good + * font should be wider at small point sizes, and the holes + * inside glyphs ("Punzen" in German, I do not know the correct + * English expression) should be larger. Note that this change + * of appearance is dependent on point size, _not_ the + * resolution of the display device. + */ + stack[++sp] = pointSize; + break; + + case 0x4f: // DEBUG, DEBUG call + sp--; + break; + + case 0x50: // LT, Less Than + e1 = stack[sp--]; + stack[sp] = (stack[sp] < e1) ? 1 : 0; + break; + + case 0x51: // LTEQ, Greater Than or EQual + e1 = stack[sp--]; + stack[sp] = (stack[sp] <= e1) ? 1 : 0; + break; + + case 0x52: // GT, Greater Than + e1 = stack[sp--]; + stack[sp] = (stack[sp] > e1) ? 1 : 0; + break; + + case 0x53: // GTEQ, Greater Than or EQual + e1 = stack[sp--]; + stack[sp] = (stack[sp] >= e1) ? 1 : 0; + break; + + case 0x54: // EQ, EQual + e1 = stack[sp--]; + stack[sp] = (stack[sp] == e1) ? 1 : 0; + break; + + case 0x55: // NEQ, Not EQual + e1 = stack[sp--]; + stack[sp] = (stack[sp] != e1) ? 1 : 0; + break; + + case 0x58: // IF, IF test + if (stack[sp--] == 0) + skipAfter(inst, + /* look for: ELSE */ 0x1B, + /* look for: EIF */ 0x59, + /* illegal: -- */ -1, + /* illegal: -- */ -1, + /* handle nested if clauses */ true); + break; + + case 0x59: // EIF, End IF + // Do nothing. + break; + + case 0x5A: // AND + e1 = stack[sp--]; + stack[sp] = ((e1 != 0) && (stack[sp] != 0)) ? 1 : 0; + break; + + case 0x5B: // OR + e1 = stack[sp--]; + stack[sp] = ((e1 != 0) || (stack[sp] != 0)) ? 1 : 0; + break; + + case 0x5C: // NOT + stack[sp] = (stack[sp] != 0) ? 0 : 1; + break; + + case 0x5e: // SDB, Set Delta Base in the graphics state + deltaBase = stack[sp--]; + break; + + case 0x5f: // SDS, Set Delta Shift in the graphics state + deltaShift = stack[sp--]; + break; + + case 0x60: // ADD + e1 = stack[sp--]; + stack[sp] += e1; + break; + + case 0x61: // SUB, SUBtract + e1 = stack[sp--]; + stack[sp] -= e1; + break; + + case 0x62: // DIV, DIVide + e1 = stack[sp--]; + stack[sp] = Fixed.div(e1, stack[sp]); + break; + + case 0x63: // MUL, MULtiply + e1 = stack[sp--]; + stack[sp] = Fixed.mul(e1, stack[sp]); + break; + + case 0x64: // ABS, ABSolute value + stack[sp] = Math.abs(stack[sp]); + break; + + case 0x65: // NEG, NEGate + stack[sp] = -stack[sp]; + break; + + case 0x66: // FLOOR + stack[sp] = Fixed.floor(stack[sp]); + break; + + case 0x67: // CEILING + stack[sp] = Fixed.ceil(stack[sp]); + break; + + case 0x68: // ROUND[0] -- round grey distance + stack[sp] = round(stack[sp], /* no engine compensation */ 0); + break; + + case 0x69: // ROUND[1] -- round black distance + stack[sp] = round(stack[sp], -engineCompensation); + break; + + case 0x6a: // ROUND[2] -- round white distance + stack[sp] = round(stack[sp], engineCompensation); + break; + + case 0x6b: // ROUND[3] -- round distance (not yet defined) + stack[sp] = round(stack[sp], /* no engine compensation */ 0); + break; + + case 0x6c: // NROUND[0] -- compensate grey distance + stack[sp] = nround(stack[sp], 0); + break; + + case 0x6d: // NROUND[1] -- compensate black distance + stack[sp] = nround(stack[sp], -engineCompensation); + break; + + case 0x6e: // NROUND[2] -- compensate white distance + stack[sp] = nround(stack[sp], engineCompensation); + break; + + case 0x6f: // NROUND[3] -- compensate distance (not yet defined) + stack[sp] = nround(stack[sp], 0); + break; + + case 0x70: // WCVTF, Write Control Value Table in Funits + e1 = stack[sp--]; + cvt[stack[sp--]] = e1 * getPixelsPerEM(); + break; + + case 0x73: // DELTAC1, DELTA exception C1 + count = stack[sp--]; + sp -= 2 * count; + deltaC(stack, sp + 1, count, 0); + break; + + case 0x74: // DELTAC2, DELTA exception C2 + count = stack[sp--]; + sp -= 2 * count; + deltaC(stack, sp + 1, count, 16); + break; + + case 0x75: // DELTAC3, DELTA exception C3 + count = stack[sp--]; + sp -= 2 * count; + deltaC(stack, sp + 1, count, 32); + break; + + case 0x76: // SROUND, Super ROUND + setRoundingMode(Fixed.ONE, stack[sp--]); + break; + + case 0x77: // S45ROUND, Super ROUND 45 degrees + setRoundingMode(/* sqrt(2)/2 */ 0x2d, stack[sp--]); + break; + + case 0x78: // JROT, Jump Relative On True + e1 = stack[sp--]; + i = inst.position() - 1 + stack[sp--]; + if (e1 != 0) + inst.position(i); + break; + + case 0x79: // JROF, Jump Relative On False + e1 = stack[sp--]; + i = inst.position() - 1 + stack[sp--]; + if (e1 == 0) + inst.position(i); + break; + + case 0x7a: // ROFF, Round OFF + roundPeriod = 0; + break; + + case 0x7c: // RUTG, Round Up To Grid + setRoundingMode(Fixed.ONE, 0x40); + break; + + case 0x7d: // RDTG, Round Down To Grid + setRoundingMode(Fixed.ONE, 0x40); + roundThreshold = 0; + break; + + case 0x7e: // SANGW, Set ANGle Weight (no-op according to TrueType spec) + case 0x7f: // AA, Adjust Angle (no-op according to TrueType spec) + sp--; + break; + + case 0x85: // SCANCTRL, SCAN conversion ConTRoL + e1 = stack[sp--]; + int ppemThreshold = e1 & 255; + scanControl = false; + boolean ppemCondition = (ppemThreshold == 255) + || ((ppemThreshold != 0) && (getPixelsPerEM() > ppemThreshold)); + if (((e1 & (1<<8)) != 0) && ppemCondition) + scanControl = true; + if (((e1 & (1<<9)) != 0) && isRotated()) + scanControl = true; + if (((e1 & (1<<10)) != 0) && isStretched()) + scanControl = true; + if (((e1 & (1<<11)) != 0) && !ppemCondition) + scanControl = false; + if (((e1 & (1<<12)) != 0) && !isRotated()) + scanControl = false; + if (((e1 & (1<<13)) != 0) && !isStretched()) + scanControl = false; + break; + + case 0x88: // GETINFO, GET INFOrmation + e1 = 0; + if ((stack[sp] & 1) != 0) // ask for rasterizer version + e1 |= 35; // "Microsoft Rasterizer version 1.7" (grayscale-capable) + if (((stack[sp] & 2) != 0) && isRotated()) + e1 |= 1 << 8; // bit 8: glyph has been rotated + if (((stack[sp] & 4) != 0) && isStretched()) + e1 |= 1 << 9; // bit 9: glyph has been stretched + if (((stack[sp] & 32) != 0) && antialiased) + e1 |= 1 << 12; // bit 12: antialiasing is active + stack[sp] = e1; + break; + + case 0x8a: // ROLL, ROLL the top three stack elements + e1 = stack[sp - 2]; + stack[sp - 2] = stack[sp - 1]; + stack[sp - 1] = stack[sp]; + stack[sp] = e1; + break; + + case 0x8b: // MAX, MAXimum of top two stack elements + e1 = stack[sp--]; + stack[sp] = Math.max(e1, stack[sp]); + break; + + case 0x8c: // MIN, MINimum of top two stack elements + e1 = stack[sp--]; + stack[sp] = Math.min(e1, stack[sp]); + break; + + case 0x8d: // SCANTYPE + scanType = stack[sp--]; + break; + + case 0x8e: // INSTCTRL, INSTRuction execution ConTRoL + e1 = stack[sp--]; // selector + e2 = stack[sp--]; // value + switch (e1) + { + case 1: + executeGlyphInstructions = (e2 == 0); + break; + + case 2: + ignoreCVTProgram = (e2 != 0); + break; + } + break; + + case 0xb0: // PUSHB[0] + case 0xb1: // PUSHB[1] + case 0xb2: // PUSHB[2] + case 0xb3: // PUSHB[3] + case 0xb4: // PUSHB[4] + case 0xb5: // PUSHB[5] + case 0xb6: // PUSHB[6] + case 0xb7: // PUSHB[7] + count = bcode - 0xb0 + 1; + for (i = 0; i < count; i++) + stack[++sp] = inst.get() & 0xff; + break; + + case 0xb8: // PUSHW[0] + case 0xb9: // PUSHW[1] + case 0xba: // PUSHW[2] + case 0xbb: // PUSHW[3] + case 0xbc: // PUSHW[4] + case 0xbd: // PUSHW[5] + case 0xbe: // PUSHW[6] + case 0xbf: // PUSHW[7] + count = bcode - 0xb8 + 1; + for (i = 0; i < count; i++) + stack[++sp] = inst.getShort(); + break; + + // MIRPxxxx, Move Indirect Relative Point + case 0xe0: case 0xe1: case 0xe2: case 0xe3: + case 0xe4: case 0xe5: case 0xe6: case 0xe7: + case 0xe8: case 0xe9: case 0xea: case 0xeb: + case 0xec: case 0xed: case 0xee: case 0xef: + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: + e1 = stack[sp--]; + handleMIRP(bcode, /* point */ e1, /* cvtIndex */ stack[sp--]); + break; + + default: + throw new IllegalStateException(); + } + + return true; + } + + + /** + * Sets the rounding mode. + * + * @param period the grid period in fixed-point notation, such as + * {@link Fixed#ONE} for the SROUND instruction or + * sqrt(2)/2 for the S45ROUND instruction. + * + * @param mode a byte whose bits are set according to the TrueType + * specification for SROUND and S45ROUND parameters. + */ + private void setRoundingMode(int period, int mode) + { + /* Set the period. */ + switch ((mode & 0xc0) >> 6) + { + case 0: + roundPeriod = period / 2; + break; + + case 2: + roundPeriod = period * 2; + break; + + default: + roundPeriod = period; + break; + } + + /* Set the phase. */ + switch ((mode & 0x30) >> 4) + { + case 0: + roundPhase = 0; + break; + + case 1: + roundPhase = roundPeriod >> 2; // period/4 + break; + + case 2: + roundPhase = roundPeriod >> 1; // period/2 + break; + + case 3: + roundPhase = (roundPeriod >> 1) + (roundPeriod >> 2); // period * 3/4 + break; + } + + /* Set the threshold. */ + int threshold = mode & 0x0f; + if (threshold == 0) + roundThreshold = roundPeriod - Fixed.ONE; + else + roundThreshold = ((threshold - 4) * roundPeriod) / 8; + } + + + + /** + * Implements the DELTAC instructions. These instructions check + * whether the current number of pixels per em is contained in an + * exception table. If it is, a delta value is determined, and the + * specified entry in the Control Value Table is modified according + * to the delta. + * + * @param pairs the delta table. Because the delta table is on + * the stack, callers usually just want to pass the stack array. + * + * @param offset the offset of the first pair in pairs. + * + * @param numPairs the number of pairs. + * + * @param base 0 for DELTAC1, 16 for DELTAC2, + * or 32 for DELTAC2. + * + * @see Apple’s documentation for DELTAC1, DELTAC2, and DELTAC3 + */ + private void deltaC(int[] pairs, int offset, int numPairs, int base) + { + int arg, relativePpem; + int ppemTrigger = getPixelsPerEM() - (deltaBase + base); + int delta, cvtIndex, rightShift; + for (int i = 0; i < numPairs; i++) + { + arg = pairs[offset + 2 * i]; + relativePpem = (arg >> 4) & 15; + if (relativePpem == ppemTrigger) + { + delta = (arg & 15) - 8; + if (delta >= 0) + ++delta; + + rightShift = deltaShift - 6; + if (rightShift > 0) + delta = delta >> rightShift; + else if (rightShift < 0) + delta = delta << (-rightShift); + cvt[pairs[offset + 2 * i + 1]] += delta; + + break; + } + } + } + + + private Zone getZone(int zoneNumber) + { + return (zoneNumber == 0) ? twilightZone : glyphZone; + } + + + /** + * Projects the specified vector along the current projection + * vector. + * + * @param x the x component of the input vector, in 26.6 fixed-point + * notation. + * + * @param y the y component of the input vector, in 26.6 fixed-point + * notation. + * + * @return the projected distance, in 26.6 fixed-point notation. + */ + private int getProjection(int x, int y) + { + return (int) (((((long) x) * projX + ((long) y) * projY)) >> 14); + } + + + /** + * Projects the specified vector along the current dual projection + * vector. + * + * @param x the x component of the input vector, in 26.6 fixed-point + * notation. + * + * @param y the y component of the input vector, in 26.6 fixed-point + * notation. + * + * @return the projected distance, in 26.6 fixed-point notation. + */ + private int getDualProjection(int x, int y) + { + return (int) (((((long) x) * dualX + ((long) y) * dualY)) >> 14); + } + + + private int getProjection(Zone zone, int point) + { + return getProjection(zone.getX(point), zone.getY(point)); + } + + + private int getOriginalProjection(Zone zone, int point) + { + return getDualProjection(zone.getOriginalX(point), + zone.getOriginalY(point)); + } + + + private void handleISECT(int a0, int a1, int b0, int b1, int p) + { + System.out.println("FIXME: Unimplemented ISECT " + p); + } + + + private static int muldiv(int a, int b, int c) + { + int s; + s = a; a = Math.abs(a); + s ^= b; b = Math.abs(b); + s ^= c; c = Math.abs(c); + a = (int) ((((long) a) * b + (c>>1)) / c); + return (s < 0) ? -a : a; + } + + + private int getFreeDotProj() + { + int result; + + result = ((((int) projX) * freeX) << 2) + + ((((int) projY) * freeY) << 2); + + /* FIXME: This seems somewhat bogus. Need to contact the + * developers of FreeType. + */ + if (Math.abs(result) < 0x4000000) + result = 0x40000000; + return result; + } + + + private void movePoint(Zone zone, int point, int distance) + { + int freeDotProj = getFreeDotProj(); + int c; + + if (freeX != 0) + { + c = zone.getX(point); + c += muldiv(distance, freeX << 16, freeDotProj); + zone.setX(point, c, /* touch */ true); + } + + if (freeY != 0) + { + c = zone.getY(point); + c += muldiv(distance, freeY << 16, freeDotProj); + zone.setY(point, c, /* touch */ true); + } + + if (TRACE_EXECUTION) + { + System.out.println("point[" + point + "] moved to " + + Fixed.toString(zone.getX(point), + zone.getY(point))); + dumpVectors(); + } + } + + private void dumpVectors() + { + System.out.println(" proj=" + Fixed.toString(projX>>8, projY>>8) + + ", free=" + Fixed.toString(freeX>>8, freeY>>8)); + } + + + private void handleIP() + { + // Implementation taken from FreeType. + int p, org_a, org_b, org_x, cur_a, cur_b, cur_x, distance; + int freeDotProj; + + org_a = getOriginalProjection(zp0, rp1); + cur_a = getProjection(zp0, rp1); + + org_b = getOriginalProjection(zp1, rp2); + cur_b = getProjection(zp1, rp2); + + while (--loop >= 0) + { + p = stack[sp--]; + org_x = getOriginalProjection(zp2, p); + cur_x = getProjection(zp2, p); + + if (((org_a <= org_b) && (org_x <= org_a)) + || ((org_a > org_b) && (org_x >= org_a))) + distance = (cur_a - org_a) + (org_x - cur_x); + else if (((org_a <= org_b) && (org_x >= org_b)) + || ((org_a > org_b) && (org_x < org_b))) + distance = (cur_b - org_b) + (org_x - cur_x); + else + distance = muldiv(cur_b - cur_a, org_x - org_a, org_b - org_a) + + (cur_a - cur_x); + movePoint(zp2, p, distance); + } + loop = 1; + } + + + private void handleMDAP(int point, boolean round) + { + System.out.println("FIXME: Unimplemented MDAP: point " + + point + "/" + zp0); + } + + + private void handleMIAP(int cvtIndex, int point, boolean round) + { + int previousPos, pos; + + previousPos = getProjection(zp0, point); + pos = cvt[cvtIndex]; + + if (round) + { + if (Math.abs(pos - previousPos) > cvtCutIn) + pos = previousPos; + pos = round(pos, /* no engine compensation */ 0); + } + movePoint(zp0, point, pos - previousPos); + rp0 = rp1 = point; + } + + + private void handleMIRP(int bcode, int point, int cvtIndex) + { + System.out.println("FIXME: Unimplemented mirp " + point + ", " + cvtIndex); + } + + + + private int round(int distance, int compensation) + { + int result; + + if (roundPeriod == 0) + return nround(distance, compensation); + + if (distance >= 0) + { + result = distance + compensation - roundPhase + roundThreshold; + result &= -roundPeriod; // truncate to the next lowest periodic value + return Math.max(result, 0) + roundPhase; + } + else + { + result = compensation - roundPhase + roundThreshold - distance; + result &= -roundPeriod; + return Math.max(-result, 0) - roundPhase; + } + } + + + private static int nround(int distance, int compensation) + { + if (distance >= 0) + return Math.max(distance + compensation, 0); + else + return Math.min(distance - compensation, 0); + } + + + /** + * Determines whether the current glyph is rotated. + * + * @return false if the shearing factors for the + * x and y axes are zero; true if they + * are non-zero. + */ + private boolean isRotated() + { + return (shearX != 0) || (shearY != 0); + } + + + /** + * Determines whether the current glyph is stretched. + * + * @return false if the scaling factors for the + * x and y axes are are equal; true if + * they differ. + */ + private boolean isStretched() + { + return scaleX != scaleY; + } + + + /** + * Returns how many pixels there are per EM, in direction of the + * current projection vector. The result is a normal integer, + * not a Fixed. + */ + private int getPixelsPerEM() + { + if (cachedPixelsPerEM == 0) + { + cachedPixelsPerEM = Fixed.intValue(Fixed.vectorLength( + applyCTM_x(projX >> 8, projY >> 8), + applyCTM_y(projX >> 8, projY >> 8))); + } + + return cachedPixelsPerEM; + } + + + private void setProjectionVector(short x, short y) + { + if (PATENTED_HINTING) + { + if ((x != projX) || (y != projY)) + cachedPixelsPerEM = 0; + + projX = x; + projY = y; + } + } + + + private void setFreedomVector(short x, short y) + { + if (PATENTED_HINTING) + { + freeX = x; + freeY = y; + } + } + + + private void setDualVector(short x, short y) + { + if (PATENTED_HINTING) + { + dualX = x; + dualY = y; + } + } + + + private int applyCTM_x(int x, int y) + { + return (int) (((long) scaleX * x + (long) shearX * y) >> 6); + } + + private int applyCTM_y(int x, int y) + { + return (int) (((long) shearY * x + (long) scaleY * y) >> 6); + } + + + private static final String[] INST_NAME = + { + /* 00 */ "SVTCA[0]", "SVTCA[1]", "SPVTCA[0]", "SPVTCA[1]", + /* 04 */ "INST_04", "INST_05", "INST_06", "INST_07", + /* 08 */ "INST_08", "INST_09", "INST_0A", "INST_0B", + /* 0c */ "GPV", "GFV", "INST_0E", "ISECT", + /* 10 */ "SRP0", "SRP1", "SRP2", "SZP0", + /* 14 */ "SZP1", "SZP2", "SZPS", "SLOOP", + /* 18 */ "RTG", "RTHG", "SMD", "ELSE", + /* 1c */ "JMPR", "SCVTCI", "INST_1E", "SSW", + /* 20 */ "DUP", "POP", "CLEAR", "SWAP", + /* 24 */ "DEPTH", "CINDEX", "MINDEX", "INST_27", + /* 28 */ "INST_28", "INST_29", "LOOPCALL", "CALL", + /* 2c */ "FDEF", "ENDF", "MDAP[0]", "MDAP[1]", + /* 30 */ "IUP[0]", "IUP[1]", "SHP[0]", "SHP[1]", + /* 34 */ "INST_34", "INST_35", "INST_36", "INST_37", + /* 38 */ "INST_38", "IP", "INST_3A", "INST_3B", + /* 3c */ "INST_3C", "RTDG", "MIAP[0]", "MIAP[1]", + /* 40 */ "NPUSHB", "NPUSHW", "WS", "RS", + /* 44 */ "WCVTP", "RCVT", "GC[0]", "GC[1]", + /* 48 */ "INST_48", "INST_49", "INST_4A", "MPPEM", + /* 4c */ "MPS", "FLIPON", "FLIPOFF", "DEBUG", + /* 50 */ "LT", "LTEQ", "GT", "GTEQ", + /* 54 */ "EQ", "NEQ", "INST_56", "INST_57", + /* 58 */ "IF", "EIF", "AND", "OR", + /* 5c */ "NOT", "INST_5D", "SDB", "SDS", + /* 60 */ "ADD", "SUB", "DIV", "MUL", + /* 64 */ "ABS", "NEG", "FLOOR", "CEILING", + /* 68 */ "ROUND[0]", "ROUND[1]", "ROUND[2]", "ROUND[3]", + /* 6c */ "NROUND[0]", "NROUND[1]", "NROUND[2]", "NROUND[3]", + /* 70 */ "WCVTF", "INST_71", "INST_72", "DELTAC1", + /* 74 */ "DELTAC2", "DELTAC3", "SROUND", "S45ROUND", + /* 78 */ "JROT", "JROF", "ROFF", "INST_7B", + /* 7c */ "RUTG", "RDTG", "SANGW", "AA", + /* 80 */ "FLIPPT", "FLIPRGON", "FLIPRGOFF", "INST_83", + /* 84 */ "INST_84", "SCANCTRL", "INST_86", "INST_87", + /* 88 */ "GETINFO", "INST_89", "ROLL", "MAX", + /* 8c */ "MIN", "SCANTYPE", "INSTCTRL", "INST_8F", + /* 90 */ "INST_90", "INST_91", "INST_92", "INST_93", + /* 94 */ "INST_94", "INST_95", "INST_96", "INST_97", + /* 98 */ "INST_98", "INST_99", "INST_9A", "INST_9B", + /* 9c */ "INST_9C", "INST_9D", "INST_9E", "INST_9F", + /* a0 */ "INST_A0", "INST_A1", "INST_A2", "INST_A3", + /* a4 */ "INST_A4", "INST_A5", "INST_A6", "INST_A7", + /* a8 */ "INST_A8", "INST_A9", "INST_AA", "INST_AB", + /* ac */ "INST_AC", "INST_AD", "INST_AE", "INST_AF", + /* b0 */ "PUSHB[0]", "PUSHB[1]", "PUSHB[2]", "PUSHB[3]", + /* b4 */ "PUSHB[4]", "PUSHB[5]", "PUSHB[6]", "PUSHB[7]", + /* b8 */ "PUSHW[0]", "PUSHW[1]", "PUSHW[2]", "PUSHW[3]", + /* bc */ "PUSHW[4]", "PUSHW[5]", "PUSHW[6]", "PUSHW[7]", + /* c0 */ "INST_C0", "INST_C1", "INST_C2", "INST_C3", + /* c4 */ "INST_C4", "INST_C5", "INST_C6", "INST_C7", + /* c8 */ "INST_C8", "INST_C9", "INST_CA", "INST_CB", + /* cc */ "INST_CC", "INST_CD", "INST_CE", "INST_CF", + /* d0 */ "INST_D0", "INST_D1", "INST_D2", "INST_D3", + /* d4 */ "INST_D4", "INST_D5", "INST_D6", "INST_D7", + /* d8 */ "INST_D8", "INST_D9", "INST_DA", "INST_DB", + /* dc */ "INST_DC", "INST_DD", "INST_DE", "INST_DF", + /* e0 */ "MIRP00000", "MIRP00001", "MIRP00010", "MIRP00011", + /* e4 */ "MIRP00100", "MIRP00101", "MIRP00110", "MIRP00111", + /* e8 */ "MIRP01000", "MIRP01001", "MIRP01010", "MIRP01011", + /* ec */ "MIRP01100", "MIRP01101", "MIRP01110", "MIRP01111", + /* f0 */ "MIRP10000", "MIRP10001", "MIRP10010", "MIRP10011", + /* f4 */ "MIRP10100", "MIRP10101", "MIRP10110", "MIRP10111", + /* f8 */ "MIRP11000", "MIRP11001", "MIRP11010", "MIRP11011", + /* fc */ "MIRP11100", "MIRP11101", "MIRP11110", "MIRP11111" + }; +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/truetype/Zone.java b/libjava/classpath/gnu/java/awt/font/opentype/truetype/Zone.java new file mode 100644 index 000000000..b0559e0e3 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/opentype/truetype/Zone.java @@ -0,0 +1,291 @@ +/* Zone.java -- A collection of points with some additional information. + 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.font.opentype.truetype; + +import gnu.java.awt.font.FontDelegate; + +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.geom.PathIterator; + + +/** + * A collection of points with some additional information. + */ +public final class Zone +{ + private Point[] points; + private int numPoints; + + public double scaleX, scaleY, shearX, shearY; + + public Zone(int maxNumPoints) + { + points = new Point[maxNumPoints]; + } + + public int getCapacity() + { + return points.length; + } + + + public int getSize() + { + return numPoints; + } + + + public int getX(int point) + { + return getX(point, FontDelegate.FLAG_FITTED); + } + + public int getX(int point, int flags) + { + int x; + if ((flags & FontDelegate.FLAG_FITTED) != 0) + x = points[point].x; + else + x = points[point].scaledX; + return x; + } + + + public void setX(int point, int value, boolean touch) + { + points[point].scaledX = value; + points[point].x = value; + if (touch) + points[point].flags |= Point.FLAG_TOUCHED_X; + } + + + public void setY(int point, int value, boolean touch) + { + points[point].scaledY = value; + points[point].y = value; + if (touch) + points[point].flags |= Point.FLAG_TOUCHED_Y; + } + + public int getY(int point) + { + return getY(point, FontDelegate.FLAG_FITTED); + } + + public int getY(int point, int flags) + { + int y; + if ((flags & FontDelegate.FLAG_FITTED) != 0) + y = points[point].y; + else + y = points[point].scaledY; + return y; + } + + + public int getOriginalX(int point) + { + return points[point].origX; + } + + + public int getOriginalY(int point) + { + return points[point].origY; + } + + + public void setOriginalX(int point, int x) + { + points[point].origX = x; + } + + public void setOriginalY(int point, int y) + { + points[point].origY = y; + } + + public void setNumPoints(int numPoints) + { + for (int i = 0; i < numPoints; i++) + points[i] = new Point(); + this.numPoints = numPoints; + } + + + public boolean isOnCurve(int point) + { + return (points[point].flags & Point.FLAG_ON_CURVE) != 0; + } + + + public void setOnCurve(int point, boolean onCurve) + { + if (onCurve) + points[point].flags |= Point.FLAG_ON_CURVE; + else + points[point].flags &= ~Point.FLAG_ON_CURVE; + } + + + public boolean isContourEnd(int point) + { + return (points[point].flags & Point.FLAG_CONTOUR_END) != 0; + } + + + public void setContourEnd(int point, boolean segEnd) + { + if (segEnd) + points[point].flags |= Point.FLAG_CONTOUR_END; + else + points[point].flags &= ~Point.FLAG_CONTOUR_END; + } + + + + + void transform(double pointSize, AffineTransform deviceTransform, + int unitsPerEm, int preTranslateX, int preTranslateY) + { + double factor; + + factor = pointSize / (double) unitsPerEm; + scaleX = deviceTransform.getScaleX() * factor; + scaleY = deviceTransform.getScaleY() * factor; + shearX = deviceTransform.getShearX() * factor; + shearY = deviceTransform.getShearY() * factor; + + for (int i = 0; i < numPoints; i++) + { + int x = points[i].origX + preTranslateX; + int y = points[i].origY + preTranslateY; + + points[i].scaledX = points[i].x = Fixed.valueOf(scaleX * x + + shearX * y); + points[i].scaledY = points[i].y = Fixed.valueOf(shearY * x + + scaleY * y); + } + } + + + + void combineWithSubGlyph(Zone zone, int numPhantomPoints) + { + int offset = this.numPoints - numPhantomPoints; + int count = zone.numPoints; + System.arraycopy(zone.points, 0, this.points, offset, count); + this.numPoints += count - numPhantomPoints; + } + + + private void dump() + { + for (int i = 0; i < numPoints; i++) + { + System.out.print(" " + i + ": "); + System.out.print(Fixed.toString(points[i].scaledX, points[i].scaledY)); + System.out.print(' '); + System.out.print(Fixed.toString(points[i].origX, points[i].origY)); + System.out.print(' '); + if (isOnCurve(i)) + System.out.print('.'); + else + System.out.print('c'); + if (isContourEnd(i)) + System.out.print('E'); + System.out.println(); + if (isContourEnd(i)) + System.out.println(); + } + } + + + public PathIterator getPathIterator(int type) + { + return new ZonePathIterator(this, type); + } + + + public GeneralPath getPath(int type) + { + GeneralPath p = new GeneralPath(GeneralPath.WIND_NON_ZERO, numPoints); + p.append(getPathIterator(type), /* connect */ false); + return p; + } + + /** + * Returns the number of contours in this outline. + * + * @return the number of contours in this outline + */ + public int getNumContours() + { + int num = 0; + for (int i = 0; i < numPoints; i++) + { + if (isContourEnd(i)) + num++; + } + return num; + } + + public int getContourEnd(int n) + { + int idx = -1; + int num = 0; + for (int i = 0; i < numPoints; i++) + { + if (isContourEnd(i)) + { + idx = i; + if (num == n) + break; + num++; + } + } + return idx; + } + + public Point[] getPoints() + { + return points; + } +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/truetype/ZonePathIterator.java b/libjava/classpath/gnu/java/awt/font/opentype/truetype/ZonePathIterator.java new file mode 100644 index 000000000..f4534f36f --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/opentype/truetype/ZonePathIterator.java @@ -0,0 +1,393 @@ +/* ZonePathIterator.java -- A PathIterator over glyph zones. + 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.font.opentype.truetype; + +import java.awt.geom.PathIterator; + + +/** + * A PathIterator that enumerates the non-phantom points in a zone. + * + *

Lack of thread safety: Instances of this class are + * not safe to access from multiple concurrent threads. + * + * @see Zone + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +final class ZonePathIterator + implements PathIterator +{ + /** + * If state has this value, currentSegment + * will emit a SEG_LINETO or SEG_QUADTO segment + * to the current point. For a discussion of subtleties of on-curve + * and off-curve points, please refer to the documentation for + * {@link #getSegment}. + */ + private static final int EMIT_SEGMENT = 0; + + + /** + * If state has this value, currentSegment + * will emit a SEG_CLOSE in order to close the sub-path + * for the current contour. + */ + private static final int EMIT_CLOSE = 1; + + + /** + * If state has this value, currentSegment + * will emit a SEG_MOVETO segment to the first point in + * the current contour. If the first point is off-curve, a suitable + * on-curve point is calculated. + * + * @see #getStartSegment + */ + private static final int EMIT_MOVETO = 2; + + + /** + * The state of the iterator, which is one of + * EMIT_SEGMENT, EMIT_CLOSE, or + * EMIT_MOVETO. + */ + private int state; + + + + /** + * The zone whose segments are enumerated by this iterator. + */ + private Zone zone; + + + /** + * The total number of points in the zone, not including the four + * phantom points at its end. + */ + private int numPoints; + + + /** + * The number of the current point. + */ + private int curPoint; + + + /** + * The number of the first point in the current contour. + */ + private int contourStart; + + + private int type; + + /** + * Constructs a ZonePathIterator for the specified zone. + * + * @param zone the zone whose segments will be enumerated + * by this iterator. + */ + ZonePathIterator(Zone zone, int t) + { + this.zone = zone; + type = t; + numPoints = zone.getSize() - /* four phantom points */ 4; + + // The first segment that needs to be emitted is a SEG_MOVETO. + state = EMIT_MOVETO; + } + + + /** + * Returns the winding rule. TrueType glyphs always use the non-zero + * winding rule, so this method will always return {@link + * PathIterator#WIND_NON_ZERO}. + */ + public int getWindingRule() + { + return PathIterator.WIND_NON_ZERO; + } + + + + public boolean isDone() + { + return (state != EMIT_CLOSE) && (curPoint >= numPoints); + } + + + public void next() + { + boolean onCurve; + + /* If the current point is the end of a segment, and no SEG_CLOSE + * has been emitted yet, this will be the next segment. + */ + if (zone.isContourEnd(curPoint) && (state != EMIT_CLOSE)) + { + state = EMIT_CLOSE; + return; + } + + /* If the previously emitted segment was a SEG_CLOSE, we are now + * at the beginning of a new contour. + */ + if (state == EMIT_CLOSE) + { + contourStart = ++curPoint; + state = EMIT_MOVETO; + return; + } + + onCurve = zone.isOnCurve(curPoint); + + /* If the last segment was a moveto, and the current point + * (which is the first point in the contour) is off-curve, + * we need to emit a quadto segment for the first point. + */ + if ((state == EMIT_MOVETO) && !onCurve) + { + state = EMIT_SEGMENT; + return; + } + + + curPoint++; + + /* If the last point has been off-curve, and the now current + * point is on-curve, the last segment was a quadto that + * had the now current point at its end. In this case, we can + * skip a segment. + */ + if (!onCurve && zone.isOnCurve(curPoint)) + { + /* But if the skipped point is the end of a contour, we must not + * skip the SEG_CLOSE. An example where this matters is the 'o' + * glyph in the Helvetica font face that comes with MacOS X + * 10.1.5. + */ + if (zone.isContourEnd(curPoint)) + { + state = EMIT_CLOSE; + return; + } + + curPoint++; + } + + state = EMIT_SEGMENT; + } + + + /** + * Determines the successor of the current point in the current + * contour. The successor of the last point in a contour is the + * start of that contour. + * + * @return the number of the point that follows the current point in + * the same contour. + */ + private int getSuccessor(int p) + { + if (zone.isContourEnd(p)) + return contourStart; + else + return p + 1; + } + + + + /** + * Retrieves the current path segment using single-precision + * coordinate values. + */ + public int currentSegment(float[] coords) + { + switch (state) + { + case EMIT_CLOSE: + return PathIterator.SEG_CLOSE; + + case EMIT_MOVETO: + return getStartSegment(curPoint, coords); + + default: + return getSegment(curPoint, coords); + } + } + + + /** + * A helper array that is used by {@link + * #currentSegment(double[])}. + */ + float[] floats; + + + /** + * Retrieves the current path segment using double-precision + * coordinate values. + */ + public int currentSegment(double[] coords) + { + if (floats == null) + floats = new float[6]; + int result; + + result = currentSegment(floats); + for (int i = 0; i < 6; i++) + coords[i] = floats[i]; + return result; + } + + + /** + * Returns the segment for the specified point. + * + *

An example curve

+ * + *

If cur is an on-curve point, the returned segment + * is a straight line to cur. In the illustration, this + * would be the case for cur = 4.

+ * + *

If cur is an off-curve point, and + * cur’s successor succ is also + * off-curve, the returned segment is a quadratic Bézier + * spline whose control point is cur, and whose end + * point is located at the middle of the line connecting + * cur and succ. In the illustration, + * this would be the case for cur = 5.

+ * + *

If cur is an off-curve point, and + * cur’s successor succ is + * on-curve, the returned segment is a quadratic Bézier + * spline whose control point is cur, and whose end + * point is succ. In the illustration, this would + * be the case for cur = 6.

+ * + * @return either PathIterator.SEG_LINETO or + * PathIterator.SEG_QUADTO. + */ + private int getSegment(int cur, float[] coords) + { + int curX, curY; + int succ, succX, succY; + + curX = zone.getX(cur, type); + curY = zone.getY(cur, type); + coords[0] = Fixed.floatValue(curX); + coords[1] = Fixed.floatValue(curY); + + if (zone.isOnCurve(cur)) + return PathIterator.SEG_LINETO; + + succ = getSuccessor(cur); + succX = zone.getX(succ, type); + succY = zone.getY(succ, type); + + if (zone.isOnCurve(succ)) + { + coords[2] = Fixed.floatValue(succX); + coords[3] = Fixed.floatValue(succY); + } + else + { + coords[2] = Fixed.floatValue((curX + succX) / 2); + coords[3] = Fixed.floatValue((curY + succY) / 2); + } + return PathIterator.SEG_QUADTO; + } + + + /** + * Returns the start segment for the contour which starts + * at the specified point. + * + *

If the contour starts with an on-curve point, the returned + * segment is a SEG_MOVETO to that point.

+ * + *

If the contour starts with an off-curve point, and the contour + * ends with an on-curve point, the returned segment is a + * SEG_MOVETO to the end point.

+ * + *

If the contour starts with an off-curve point, and the contour + * also ends with an off-curve point, the returned segment is a + * SEG_MOVETO to the location at the middle between the + * start and end points of the contour.

+ * + * @return PathIterator.SEG_MOVETO. + */ + private int getStartSegment(int contourStart, float[] coords) + { + int x, y; + + if (zone.isOnCurve(contourStart)) + { + x = zone.getX(contourStart, type); + y = zone.getY(contourStart, type); + } + else + { + /* Find the last point of the current contour. */ + int contourEnd = contourStart; + while (!zone.isContourEnd(contourEnd)) + ++contourEnd; + + if (zone.isOnCurve(contourEnd)) + { + /* An example is the 'o' glyph of the Helvetica which comes + * with Apple MacOS X 10.1.5. + */ + x = zone.getX(contourEnd, type); + y = zone.getY(contourEnd, type); + } + else + { + x = (zone.getX(contourStart, type) + zone.getX(contourEnd, type)) / 2; + y = (zone.getY(contourStart, type) + zone.getY(contourEnd, type)) / 2; + } + } + + coords[0] = Fixed.floatValue(x); + coords[1] = Fixed.floatValue(y); + return PathIterator.SEG_MOVETO; + } +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/truetype/doc-files/ZonePathIterator-1.dia b/libjava/classpath/gnu/java/awt/font/opentype/truetype/doc-files/ZonePathIterator-1.dia new file mode 100644 index 000000000..b715ea02c Binary files /dev/null and b/libjava/classpath/gnu/java/awt/font/opentype/truetype/doc-files/ZonePathIterator-1.dia differ diff --git a/libjava/classpath/gnu/java/awt/font/opentype/truetype/doc-files/ZonePathIterator-1.png b/libjava/classpath/gnu/java/awt/font/opentype/truetype/doc-files/ZonePathIterator-1.png new file mode 100644 index 000000000..81d09d839 Binary files /dev/null and b/libjava/classpath/gnu/java/awt/font/opentype/truetype/doc-files/ZonePathIterator-1.png differ diff --git a/libjava/classpath/gnu/java/awt/image/AsyncImage.java b/libjava/classpath/gnu/java/awt/image/AsyncImage.java new file mode 100644 index 000000000..4fa33740e --- /dev/null +++ b/libjava/classpath/gnu/java/awt/image/AsyncImage.java @@ -0,0 +1,300 @@ +/* AsyncImage.java -- Loads images asynchronously + Copyright (C) 2008 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.image; + + +import java.awt.Graphics; +import java.awt.Image; +import java.awt.image.ImageConsumer; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.util.HashSet; +import java.util.Iterator; + +/** + * Supports asynchronous loading of images. + */ +public class AsyncImage + extends Image +{ + + /** + * The image source for AsyncImages. + */ + private class AsyncImageSource + implements ImageProducer + { + /** + * The real image source, if already present, or null + * otherwise. + */ + private ImageProducer realSource; + + public void addConsumer(ImageConsumer ic) + { + startProduction(ic); + } + + public boolean isConsumer(ImageConsumer ic) + { + return false; + } + + public void removeConsumer(ImageConsumer ic) + { + // Nothing to do here. + } + + public void requestTopDownLeftRightResend(ImageConsumer ic) + { + startProduction(ic); + } + + public void startProduction(ImageConsumer ic) + { + ImageProducer ip = getRealSource(); + if (ip == null) + { + ic.setDimensions(1, 1); + ic.imageComplete(ImageConsumer.SINGLEFRAMEDONE); + } + else + { + ip.startProduction(ic); + } + } + + /** + * Returns the real image source, if already present. Otherwise, this + * returns null. + * + * @return the real image source, or null if not present + */ + private ImageProducer getRealSource() + { + synchronized (AsyncImage.this) + { + ImageProducer source = realSource; + if (source == null) + { + Image ri = realImage; + if (ri != null) + { + realSource = source = ri.getSource(); + } + } + return source; + } + } + } + + /** + * The real image. This is null as long as the image is not complete. + */ + private volatile Image realImage; + + /** + * The image observers. + * + * This is package private to avoid accessor methods. + */ + HashSet observers; + + private volatile boolean complete = false; + + /** + * Creates a new AsyncImage. + */ + AsyncImage() + { + observers = new HashSet(); + } + + public void flush() + { + // Nothing to do here. + } + + public Graphics getGraphics() + { + Image r = realImage; + Graphics g = null; + if (r != null) + g = r.getGraphics(); // Should we return some dummy graphics instead? + return g; + } + + public boolean isComplete() { + return complete; + } + + public int getHeight(ImageObserver observer) + { + addObserver(observer); + int height = -1; + waitForImage(observer); + Image r = realImage; + if (r != null) + height = r.getHeight(observer); + return height; + } + + public Object getProperty(String name, ImageObserver observer) + { + addObserver(observer); + Image r = realImage; + Object prop = null; + if (r != null) + prop = r.getProperty(name, observer); + return prop; + } + + public ImageProducer getSource() + { + return new AsyncImageSource(); + } + + public int getWidth(ImageObserver observer) + { + addObserver(observer); + int width = -1; + waitForImage(observer); + Image r = realImage; + if (r != null) + width = r.getWidth(observer); + return width; + } + + public void addObserver(ImageObserver obs) + { + if (obs != null) + { + synchronized (this) + { + // This field gets null when image loading is complete and we don't + // need to store any more observers. + HashSet observs = observers; + if (observs != null) + { + observs.add(obs); + } + } + } + } + + public boolean prepareImage(int w, int h, ImageObserver obs) + { + addObserver(obs); + return realImage != null; + } + + public int checkImage(int w, int h, ImageObserver obs) + { + addObserver(obs); + int flags = 0; + if (realImage != null) + flags = ImageObserver.ALLBITS | ImageObserver.WIDTH + | ImageObserver.HEIGHT | ImageObserver.PROPERTIES; + return flags; + } + + public Image getRealImage() + { + return realImage; + } + + public void setRealImage(Image im) + { + realImage = im; + int status = ImageObserver.HEIGHT | ImageObserver.WIDTH; + notifyObservers(status, 0, 0, im.getWidth(null), im.getHeight(null)); + } + + public void notifyObservers(int status, int x, int y, int w, int h) + { + synchronized (this) + { + HashSet observs = observers; + if (observs != null) + { + Iterator i = observs.iterator(); + while (i.hasNext()) + { + ImageObserver obs = (ImageObserver) i.next(); + boolean complete = obs.imageUpdate(this, status, x, y, realImage.getWidth(obs), realImage.getHeight(obs)); + if (complete) // Remove completed observers. + i.remove(); + } + } + if ((status & ImageObserver.ALLBITS) != 0) + { + complete = true; + notifyAll(); + } + } + } + + /** + * Waits for the image to be loaded completely, if the image observer + * is null. Otherwise this is not necessary, because the + * image observer can be notified about later completion. + * + * @param observer the image observer + */ + public void waitForImage(ImageObserver observer) + { + if (!complete && observer == null) + { + synchronized (this) + { + while (! complete) + { + try + { + wait(); + } + catch (InterruptedException ex) + { + Thread.currentThread().interrupt(); + } + } + } + } + } +} diff --git a/libjava/classpath/gnu/java/awt/image/ImageConverter.java b/libjava/classpath/gnu/java/awt/image/ImageConverter.java new file mode 100644 index 000000000..f9c6268c3 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/image/ImageConverter.java @@ -0,0 +1,528 @@ +/* ImageConverter.java -- Loads images asynchronously + Copyright (C) 2008 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.image; + +import gnu.java.awt.image.AsyncImage; + +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.Transparency; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.ImageConsumer; +import java.awt.image.IndexColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.SinglePixelPackedSampleModel; +import java.awt.image.WritableRaster; +import java.util.Hashtable; + +/** + * Convert an Image to a BufferedImage. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class ImageConverter implements ImageConsumer +{ + + public static final String IMAGE_TRANSPARENCY_PROPERTY = + "gnu.awt.image.transparency"; + + public static final String IMAGE_PROPERTIES_PROPERTY = + "gnu.awt.image.properties"; + + private AsyncImage image; + private BufferedImage bImage; + private Hashtable imageProperties; + private int width, height; + private ColorModel colorModel; + private ColorModel targetColorModel; + + public ImageConverter() + { + width = 0; + height = 0; + image = new AsyncImage(); + } + + public void setDimensions(int w, int h) + { + width = w; + height = h; + } + + public void setProperties(Hashtable props) + { + // Ignore for now. + } + + public void setColorModel(ColorModel model) + { + colorModel = model; + } + + public void setHints(int flags) + { + // Ignore for now. + } + + public void setPixels(int x, int y, int w, int h, ColorModel model, + byte[] pixels, int offset, int scansize) + { + model = setupColorModel(model); + + if (bImage == null) + { + createImage(); + } + + Integer t = (Integer) imageProperties.get("gnu.awt.image.transparency"); + int transparency = t.intValue(); + + if(targetColorModel.equals(model)) + { + transparency = transferPixels(x, y, w, h, model, pixels, offset, + scansize, transparency); + } + else if (model instanceof IndexColorModel + && targetColorModel.equals(ColorModel.getRGBdefault())) + { + transparency = convertIndexColorModelToSRGB(x, y, w, h, + (IndexColorModel) model, + pixels, offset, scansize, + transparency); + } + else + { + transparency = convertPixels(x, y, w, h, model, pixels, offset, + scansize, transparency); + } + + imageProperties.put("gnu.awt.image.transparency", + Integer.valueOf(transparency)); + } + + public void setPixels(int x, int y, int w, int h, ColorModel model, + int[] pixels, int offset, int scansize) + { + model = setupColorModel(model); + if (bImage == null) + { + createImage(); + } + + Integer t = (Integer) imageProperties.get(IMAGE_TRANSPARENCY_PROPERTY); + int transparency= t.intValue(); + + if (targetColorModel.equals(model)) + { + transparency = transferPixels(x, y, w, h, model, pixels, offset, + scansize, transparency); + } + else if (model instanceof IndexColorModel + && targetColorModel.equals(ColorModel.getRGBdefault())) + { + transparency = convertIndexColorModelToSRGB(x, y, w, h, + (IndexColorModel) model, + pixels, offset, scansize, + transparency); + } + else + { + transparency = convertPixels(x, y, w, h, model, pixels, offset, + scansize, transparency); + } + + imageProperties.put(IMAGE_TRANSPARENCY_PROPERTY, + Integer.valueOf(transparency)); + + } + + /** + * Initialize the color model for this setPixels run:
+ * 1. if no color model was given use the hinted color model
+ * 2. if no color model was given and non was hinted use the default sRGB color model.
+ * Also:
+ * If no target color model was set use the color model of the given pixels. + * @param model + * @return + */ + private ColorModel setupColorModel(ColorModel model) + { + // If the given color model is null use the previously hinted color model. + if (model == null) + model = colorModel; + + // If no color model was given or hinted use default sRGB. + if (model == null) + model = ColorModel.getRGBdefault(); + + // If no specific color model was requested for the target use the current + // pixels model. + if (targetColorModel == null) + targetColorModel = model; + targetColorModel = ColorModel.getRGBdefault(); + return model; + } + + /** + * Creates the image instance into which the pixel data is converted. + */ + private void createImage() + { + if (imageProperties == null) + { + imageProperties = new Hashtable(); + } + + imageProperties.put(IMAGE_TRANSPARENCY_PROPERTY, + Integer.valueOf(Transparency.OPAQUE)); + imageProperties.put(IMAGE_PROPERTIES_PROPERTY, imageProperties); + + // For the sRGB case let the GraphicsEnvironment create an image for us. + if (ColorModel.getRGBdefault().equals(targetColorModel)) + { + bImage = GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice() + .getDefaultConfiguration() + .createCompatibleImage(width, height, Transparency.TRANSLUCENT); + } + else + { + WritableRaster raster = + targetColorModel.createCompatibleWritableRaster(width, height); + bImage = new BufferedImage(targetColorModel, raster, false, + imageProperties); + } + image.setRealImage(bImage); + return; + } + + /** + * Transfers pixels into a raster of the same color model. + * + * @param x the X coordinate of the source pixel rectangle + * @param y the Y coordinate of the source pixel rectangle + * @param w the width of the source pixel rectangle + * @param h the height of the source pixel rectangle + * @param model the color model of the source pixels + * @param pixels the pixel data + * @param offset the offset in the pixel array + * @param scansize the scanline size + * @param transparency the assumed transparency + * + * @return the determined transparency + */ + private int transferPixels(int x, int y, int w, int h, ColorModel model, + byte[] pixels, int offset, int scansize, + int transparency) + { + // If we have the same color model, then we can simply drop + // the pixel value into the target raster. + bImage.getRaster().setDataElements(x, y, w, h, pixels); + + for (int yy = 0; yy < h; yy++) + { + for (int xx = 0; xx < w; xx++) + { + int pixel = 0xFF & pixels[yy * scansize + xx + offset]; + int alpha = model.getAlpha(pixel); + transparency = updateTransparency(alpha, transparency); + } + } + return transparency; + } + + /** + * Transfers pixels into a raster of the same color model. + * + * @param x the X coordinate of the source pixel rectangle + * @param y the Y coordinate of the source pixel rectangle + * @param w the width of the source pixel rectangle + * @param h the height of the source pixel rectangle + * @param model the color model of the source pixels + * @param pixels the pixel data + * @param offset the offset in the pixel array + * @param scansize the scanline size + * @param transparency the assumed transparency + * + * @return the determined transparency + */ + private int transferPixels(int x, int y, int w, int h, ColorModel model, + int[] pixels, int offset, int scansize, + int transparency) + { + // If we have the same color model, then we can simply drop + // the pixel value into the target raster. + bImage.getRaster().setDataElements(x, y, w, h, pixels); + + for (int yy = 0; yy < h; yy++) + { + for (int xx = 0; xx < w; xx++) + { + int pixel = pixels[yy * scansize + xx + offset]; + int alpha = model.getAlpha(pixel); + transparency = updateTransparency(alpha, transparency); + } + } + return transparency; + } + + /** + * Converts pixel from one color model to another, and stores them in the + * target image. + * + * @param x the X coordinate of the source pixel rectangle + * @param y the Y coordinate of the source pixel rectangle + * @param w the width of the source pixel rectangle + * @param h the height of the source pixel rectangle + * @param model the color model of the source pixels + * @param pixels the pixel data + * @param offset the offset in the pixel array + * @param scansize the scanline size + * @param transparency the assumed transparency + * + * @return the determined transparency + */ + private int convertPixels(int x, int y, int w, int h, ColorModel model, + byte[] pixels, int offset, int scansize, + int transparency) + { + // If the color models are not the same, we must convert the + // pixel values from one model to the other. + Object dataEl = null; + // Convert pixels to the destination color model. + for (int yy = 0; yy < h; yy++) + { + for (int xx = 0; xx < w; xx++) + { + int pixel = 0xFF & pixels[yy * scansize + xx + offset]; + int rgb = model.getRGB(pixel); + int alpha = model.getAlpha(pixel); + transparency = updateTransparency(alpha, transparency); + dataEl = targetColorModel.getDataElements(rgb, dataEl); + bImage.getRaster().setDataElements(x + xx, y + yy, dataEl); + } + } + return transparency; + } + + /** + * Converts pixel from one color model to another, and stores them in the + * target image. + * + * @param x the X coordinate of the source pixel rectangle + * @param y the Y coordinate of the source pixel rectangle + * @param w the width of the source pixel rectangle + * @param h the height of the source pixel rectangle + * @param model the color model of the source pixels + * @param pixels the pixel data + * @param offset the offset in the pixel array + * @param scansize the scanline size + * @param transparency the assumed transparency + * + * @return the determined transparency + */ + private int convertPixels(int x, int y, int w, int h, ColorModel model, + int[] pixels, int offset, int scansize, + int transparency) + { + // If the color models are not the same, we must convert the + // pixel values from one model to the other. + Object dataEl = null; + // Convert pixels to the destination color model. + for (int yy = 0; yy < h; yy++) + { + for (int xx = 0; xx < w; xx++) + { + int pixel = pixels[yy * scansize + xx + offset]; + int rgb = model.getRGB(pixel); + int alpha = model.getAlpha(pixel); + transparency = updateTransparency(alpha, transparency); + dataEl = targetColorModel.getDataElements(rgb, dataEl); + bImage.getRaster().setDataElements(x + xx, y + yy, dataEl); + } + } + return transparency; + } + + /** + * Converts pixels from an index color model to the target image. + * + * @param x the X coordinate of the source pixel rectangle + * @param y the Y coordinate of the source pixel rectangle + * @param w the width of the source pixel rectangle + * @param h the height of the source pixel rectangle + * @param model the color model of the source pixels + * @param pixels the pixel data + * @param offset the offset in the pixel array + * @param scansize the scanline size + * @param transparency the assumed transparency + * + * @return the determined transparency + */ + private int convertIndexColorModelToSRGB(int x, int y, int w, int h, + IndexColorModel model, + byte[] pixels, int offset, + int scansize, int transparency) + { + + int mapSize = model.getMapSize(); + int[] colorMap = new int[mapSize]; + for(int i=0; i < mapSize; i++) + { + colorMap[i] = model.getRGB(i); + } + + WritableRaster raster = bImage.getRaster(); + SinglePixelPackedSampleModel sampleMode = + (SinglePixelPackedSampleModel) raster.getSampleModel(); + DataBuffer dataBuffer = (DataBuffer) raster.getDataBuffer(); + + int rasterOffset = sampleMode.getOffset(x,y)+dataBuffer.getOffset(); + int rasterScanline = sampleMode.getScanlineStride(); + + for (int yy = 0; yy < h; yy++) + { + int xoffset = offset; + for (int xx = 0; xx < w; xx++) + { + int argb = colorMap[(pixels[xoffset++] & 0xFF)]; + dataBuffer.setElem(rasterOffset+xx, argb); + int alpha = (argb >>> 24); + transparency = updateTransparency(alpha, transparency); + } + offset += scansize; + rasterOffset += rasterScanline; + } + + return transparency; + } + + /** + * Converts pixels from an index color model to the target image. + * + * @param x the X coordinate of the source pixel rectangle + * @param y the Y coordinate of the source pixel rectangle + * @param w the width of the source pixel rectangle + * @param h the height of the source pixel rectangle + * @param model the color model of the source pixels + * @param pixels the pixel data + * @param offset the offset in the pixel array + * @param scansize the scanline size + * @param transparency the assumed transparency + * + * @return the determined transparency + */ + private int convertIndexColorModelToSRGB(int x, int y, int w, int h, + IndexColorModel model, int[] pixels, + int offset, int scansize, + int transparency) + { + int mapSize = model.getMapSize(); + int[] colorMap = new int[mapSize]; + for(int i=0; i < mapSize; i++) + { + colorMap[i] = model.getRGB(i); + } + + WritableRaster raster = bImage.getRaster(); + SinglePixelPackedSampleModel sampleMode = + (SinglePixelPackedSampleModel) raster.getSampleModel(); + DataBuffer dataBuffer = (DataBuffer)raster.getDataBuffer(); + + int rasterOffset = sampleMode.getOffset(x, y) + dataBuffer.getOffset(); + int rasterScanline = sampleMode.getScanlineStride(); + + for (int yy = 0; yy < h; yy++) + { + int xoffset = offset; + for (int xx = 0; xx < w; xx++) + { + int argb = colorMap[pixels[xoffset++]]; + dataBuffer.setElem(rasterOffset + xx, argb); + int alpha = (argb >>> 24); + transparency = updateTransparency(alpha, transparency); + } + offset += scansize; + rasterOffset += rasterScanline; + } + + return transparency; + } + + /** + * Updates the transparency information according to the alpha pixel value. + * + * @param alpha the alpha pixel value + * @param transparency the old transparency + * + * @return the updated transparency + */ + private int updateTransparency(int alpha, int transparency) + { + if (alpha != 0xFF) + { + if (alpha == 0x00 && transparency <= Transparency.BITMASK) + { + transparency = Transparency.BITMASK; + } + else if (transparency < Transparency.TRANSLUCENT) + { + transparency = Transparency.TRANSLUCENT; + } + } + return transparency; + } + + public void imageComplete(int status) + { + image.notifyObservers(ImageObserver.ALLBITS, 0, 0, width, height); + } + + public void setTargetColorModel(ColorModel model) + { + targetColorModel = model; + } + + public Image getImage() + { + return image; + } +} diff --git a/libjava/classpath/gnu/java/awt/image/ImageDecoder.java b/libjava/classpath/gnu/java/awt/image/ImageDecoder.java new file mode 100644 index 000000000..a572ea33b --- /dev/null +++ b/libjava/classpath/gnu/java/awt/image/ImageDecoder.java @@ -0,0 +1,188 @@ +/* ImageDecoder.java -- + Copyright (C) 1999, 2000, 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.awt.image; + +import java.awt.image.ImageConsumer; +import java.awt.image.ImageProducer; +import java.io.ByteArrayInputStream; +import java.io.DataInput; +import java.io.EOFException; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Vector; + +public abstract class ImageDecoder implements ImageProducer +{ + Vector consumers = new Vector (); + String filename; + URL url; + byte[] data; + int offset; + int length; + InputStream input; + DataInput datainput; + + static + { + // FIXME: there was some broken code here that looked like + // it wanted to rely on this property. I don't have any idea + // what it was intended to do. + // String endian = System.getProperties ().getProperty ("gnu.cpu.endian"); + } + + public ImageDecoder (String filename) + { + this.filename = filename; + } + + public ImageDecoder (URL url) + { + this.url = url; + } + + public ImageDecoder (InputStream is) + { + this.input = is; + } + + public ImageDecoder (DataInput datainput) + { + this.datainput = datainput; + } + + public ImageDecoder (byte[] imagedata, int imageoffset, int imagelength) + { + data = imagedata; + offset = imageoffset; + length = imagelength; + } + + public void addConsumer (ImageConsumer ic) + { + consumers.addElement (ic); + } + + public boolean isConsumer (ImageConsumer ic) + { + return consumers.contains (ic); + } + + public void removeConsumer (ImageConsumer ic) + { + consumers.removeElement (ic); + } + + public void startProduction (ImageConsumer ic) + { + if (!isConsumer(ic)) + addConsumer(ic); + + Vector list = (Vector) consumers.clone (); + try + { + // Create the input stream here rather than in the + // ImageDecoder constructors so that exceptions cause + // imageComplete to be called with an appropriate error + // status. + if (input == null) + { + try + { + if (url != null) + input = url.openStream(); + else if (datainput != null) + input = new DataInputStreamWrapper(datainput); + else + { + if (filename != null) + input = new FileInputStream (filename); + else + input = new ByteArrayInputStream (data, offset, length); + } + produce (list, input); + } + finally + { + input = null; + } + } + else + { + produce (list, input); + } + } + catch (Exception e) + { + for (int i = 0; i < list.size (); i++) + { + ImageConsumer ic2 = (ImageConsumer) list.elementAt (i); + ic2.imageComplete (ImageConsumer.IMAGEERROR); + } + } + } + + public void requestTopDownLeftRightResend (ImageConsumer ic) + { + } + + public abstract void produce (Vector v, InputStream is) throws IOException; + + private static class DataInputStreamWrapper extends InputStream + { + private final DataInput datainput; + + DataInputStreamWrapper(DataInput datainput) + { + this.datainput = datainput; + } + + public int read() throws IOException + { + try + { + return datainput.readByte() & 0xFF; + } + catch (EOFException eofe) + { + return -1; + } + } + } +} diff --git a/libjava/classpath/gnu/java/awt/image/XBMDecoder.java b/libjava/classpath/gnu/java/awt/image/XBMDecoder.java new file mode 100644 index 000000000..35a3568b8 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/image/XBMDecoder.java @@ -0,0 +1,155 @@ +/* XBMDecoder.java -- Decodes X-bitmaps + Copyright (C) 1999, 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.awt.image; + +import java.awt.image.ColorModel; +import java.awt.image.ImageConsumer; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.net.URL; +import java.util.StringTokenizer; +import java.util.Vector; + +public class XBMDecoder extends ImageDecoder +{ + BufferedReader reader; + static final ColorModel cm = ColorModel.getRGBdefault (); + static final int black = 0xff000000; + static final int transparent = 0x00000000; + static final int masktable[] = { 0x01, 0x02, 0x04, 0x08, + 0x10, 0x20, 0x40, 0x80 }; + + public XBMDecoder (String filename) + { + super (filename); + } + + public XBMDecoder (URL url) + { + super (url); + } + + public void produce (Vector v, InputStream is) throws IOException + { + reader = new BufferedReader (new InputStreamReader (is)); + int width = -1, height = -1; + + for (int i = 0; i < 2; i++) + { + String line = reader.readLine (); + StringTokenizer st = new StringTokenizer (line); + + st.nextToken (); // #define + st.nextToken (); // name_[width|height] + if (i == 0) + width = Integer.parseInt (st.nextToken (), 10); + else + height = Integer.parseInt (st.nextToken (), 10); + } + + for (int i = 0; i < v.size (); i++) + { + ImageConsumer ic = (ImageConsumer) v.elementAt (i); + + ic.setDimensions (width, height); + ic.setColorModel (cm); + ic.setHints (ImageConsumer.COMPLETESCANLINES + | ImageConsumer.SINGLEFRAME + | ImageConsumer.SINGLEPASS + | ImageConsumer.TOPDOWNLEFTRIGHT); + } + + /* skip to the byte array */ + while (reader.read () != '{') { } + + /* loop through each scanline */ + for (int line = 0; line < height; line++) + { + int scanline[] = getScanline (reader, width); + + for (int i = 0; i < v.size (); i++) + { + ImageConsumer ic = (ImageConsumer) v.elementAt (i); + ic.setPixels (0, 0 + line, width, 1, cm, scanline, 0, width); + } + } + + /* tell each ImageConsumer that we're finished */ + for (int i = 0; i < v.size (); i++) + { + ImageConsumer ic = (ImageConsumer) v.elementAt (i); + ic.imageComplete (ImageConsumer.STATICIMAGEDONE); + } + } + + public static int[] getScanline (Reader in, int len) throws IOException + { + char byteStr[] = new char[2]; + int scanline[] = new int[len]; + int x = 0; + + while (x < len) + { + int ch = in.read (); + if (ch == '0') + { + in.read (); // 'x' + + byteStr[0] = (char) in.read (); + byteStr[1] = (char) in.read (); + + int byteVal = Integer.parseInt (new String (byteStr), 16); + + for (int i = 0; i < 8; i++, x++) + { + if (x == len) // condition occurs if bitmap is padded + return scanline; + + scanline[x] = ((byteVal & masktable[i]) != 0) ? + black : transparent; + } + } + } + + return scanline; + } +} diff --git a/libjava/classpath/gnu/java/awt/image/package.html b/libjava/classpath/gnu/java/awt/image/package.html new file mode 100644 index 000000000..8823367ea --- /dev/null +++ b/libjava/classpath/gnu/java/awt/image/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.awt.image + + +

+ + + diff --git a/libjava/classpath/gnu/java/awt/java2d/AbstractGraphics2D.java b/libjava/classpath/gnu/java/awt/java2d/AbstractGraphics2D.java new file mode 100644 index 000000000..1334866f2 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/java2d/AbstractGraphics2D.java @@ -0,0 +1,2094 @@ +/* AbstractGraphics2D.java -- Abstract Graphics2D implementation + 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.java2d; + +import gnu.java.util.LRUCache; + +import java.awt.AWTError; +import java.awt.AlphaComposite; +import java.awt.AWTPermission; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Composite; +import java.awt.CompositeContext; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Paint; +import java.awt.PaintContext; +import java.awt.Point; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.Toolkit; +import java.awt.RenderingHints.Key; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.awt.geom.Arc2D; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.GeneralPath; +import java.awt.geom.Line2D; +import java.awt.geom.NoninvertibleTransformException; +import java.awt.geom.RoundRectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.BufferedImageOp; +import java.awt.image.ColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.FilteredImageSource; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.image.Raster; +import java.awt.image.RenderedImage; +import java.awt.image.ReplicateScaleFilter; +import java.awt.image.SampleModel; +import java.awt.image.WritableRaster; +import java.awt.image.renderable.RenderableImage; +import java.text.AttributedCharacterIterator; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.WeakHashMap; + +/** + * This is a 100% Java implementation of the Java2D rendering pipeline. It is + * meant as a base class for Graphics2D implementations. + * + *

Backend interface

+ *

+ * The backend must at the very least provide a Raster which the the rendering + * pipeline can paint into. This must be implemented in + * {@link #getDestinationRaster()}. For some backends that might be enough, like + * when the target surface can be directly access via the raster (like in + * BufferedImages). Other targets need some way to synchronize the raster with + * the surface, which can be achieved by implementing the + * {@link #updateRaster(Raster, int, int, int, int)} method, which always gets + * called after a chunk of data got painted into the raster. + *

+ *

Alternativly the backend can provide a method for filling Shapes by + * overriding the protected method fillShape(). This can be accomplished + * by a polygon filling function of the backend. Keep in mind though that + * Shapes can be quite complex (i.e. non-convex and containing holes, etc) + * which is not supported by all polygon fillers. Also it must be noted + * that fillShape() is expected to handle painting and compositing as well as + * clipping and transformation. If your backend can't support this natively, + * then you can fallback to the implementation in this class. You'll need + * to provide a writable Raster then, see above.

+ *

Another alternative is to implement fillScanline() which only requires + * the backend to be able to draw horizontal lines in device space, + * which is usually very cheap. + * The implementation should still handle painting and compositing, + * but no more clipping and transformation is required by the backend.

+ *

The backend is free to provide implementations for the various raw* + * methods for optimized AWT 1.1 style painting of some primitives. This should + * accelerate painting of Swing greatly. When doing so, the backend must also + * keep track of the clip and translation, probably by overriding + * some clip and translate methods. Don't forget to message super in such a + * case.

+ * + *

Acceleration options

+ *

+ * The fact that it is + * pure Java makes it a little slow. However, there are several ways of + * accelerating the rendering pipeline: + *

    + *
  1. Optimization hooks for AWT 1.1 - like graphics operations. + * The most important methods from the {@link java.awt.Graphics} class + * have a corresponding raw* method, which get called when + * several optimization conditions are fullfilled. These conditions are + * described below. Subclasses can override these methods and delegate + * it directly to a native backend.
  2. + *
  3. Native PaintContexts and CompositeContext. The implementations + * for the 3 PaintContexts and AlphaCompositeContext can be accelerated + * using native code. These have proved to two of the most performance + * critical points in the rendering pipeline and cannot really be done quickly + * in plain Java because they involve lots of shuffling around with large + * arrays. In fact, you really would want to let the graphics card to the + * work, they are made for this.
  4. + *
  5. Provide an accelerated implementation for fillShape(). For instance, + * OpenGL can fill shapes very efficiently. There are some considerations + * to be made though, see above for details.
  6. + *
+ *

+ * + * @author Roman Kennke (kennke@aicas.com) + */ +public abstract class AbstractGraphics2D + extends Graphics2D + implements Cloneable, Pixelizer +{ + /** + * Caches scaled versions of an image. + * + * @see #drawImage(Image, int, int, int, int, ImageObserver) + */ + protected static final WeakHashMap> imageCache = + new WeakHashMap>(); + + /** + * Wether we use anti aliasing for rendering text by default or not. + */ + private static final boolean DEFAULT_TEXT_AA = + Boolean.getBoolean("gnu.java2d.default_text_aa"); + + /** + * The default font to use on the graphics object. + */ + private static final Font FONT = new Font("SansSerif", Font.PLAIN, 12); + + /** + * The size of the LRU cache used for caching GlyphVectors. + */ + private static final int GV_CACHE_SIZE = 50; + + /** + * Caches certain shapes to avoid massive creation of such Shapes in + * the various draw* and fill* methods. + */ + private static final ShapeCache shapeCache = new ShapeCache(); + + /** + * A pool of scanline converters. It is important to reuse scanline + * converters because they keep their datastructures in place. We pool them + * for use in multiple threads. + */ + private static final LinkedList scanlineConverters = + new LinkedList(); + + /** + * Caches glyph vectors for better drawing performance. + */ + private static final Map gvCache = + Collections.synchronizedMap(new LRUCache(GV_CACHE_SIZE)); + + /** + * This key is used to search in the gvCache without allocating a new + * key each time. + */ + private static final TextCacheKey searchTextKey = new TextCacheKey(); + + /** + * The transformation for this Graphics2D instance + */ + protected AffineTransform transform; + + /** + * The foreground. + */ + private Paint paint; + + /** + * The paint context during rendering. + */ + private PaintContext paintContext = null; + + /** + * The background. + */ + private Color background = Color.WHITE; + + /** + * Foreground color, as set by setColor. + */ + private Color foreground = Color.BLACK; + private boolean isForegroundColorNull = true; + + /** + * The current font. + */ + private Font font; + + /** + * The current composite setting. + */ + private Composite composite; + + /** + * The current stroke setting. + */ + private Stroke stroke; + + /** + * The current clip. This clip is in user coordinate space. + */ + private Shape clip; + + /** + * The rendering hints. + */ + private RenderingHints renderingHints; + + /** + * The raster of the destination surface. This is where the painting is + * performed. + */ + private WritableRaster destinationRaster; + + /** + * Indicates if certain graphics primitives can be rendered in an optimized + * fashion. This will be the case if the following conditions are met: + * - The transform may only be a translation, no rotation, shearing or + * scaling. + * - The paint must be a solid color. + * - The composite must be an AlphaComposite.SrcOver. + * - The clip must be a Rectangle. + * - The stroke must be a plain BasicStroke(). + * + * These conditions represent the standard settings of a new + * AbstractGraphics2D object and will be the most commonly used setting + * in Swing rendering and should therefore be optimized as much as possible. + */ + private boolean isOptimized = true; + + private static final BasicStroke STANDARD_STROKE = new BasicStroke(); + + private static final HashMap STANDARD_HINTS; + static + { + + HashMap hints = new HashMap(); + hints.put(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT); + hints.put(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_DEFAULT); + + STANDARD_HINTS = hints; + } + + /** + * Creates a new AbstractGraphics2D instance. + */ + protected AbstractGraphics2D() + { + transform = new AffineTransform(); + background = Color.WHITE; + composite = AlphaComposite.SrcOver; + stroke = STANDARD_STROKE; + renderingHints = new RenderingHints(STANDARD_HINTS); + } + + /** + * Draws the specified shape. The shape is passed through the current stroke + * and is then forwarded to {@link #fillShape}. + * + * @param shape the shape to draw + */ + public void draw(Shape shape) + { + // Stroke the shape. + Shape strokedShape = stroke.createStrokedShape(shape); + // Fill the stroked shape. + fillShape(strokedShape, false); + } + + + /** + * Draws the specified image and apply the transform for image space -> + * user space conversion. + * + * This method is implemented to special case RenderableImages and + * RenderedImages and delegate to + * {@link #drawRenderableImage(RenderableImage, AffineTransform)} and + * {@link #drawRenderedImage(RenderedImage, AffineTransform)} accordingly. + * Other image types are not yet handled. + * + * @param image the image to be rendered + * @param xform the transform from image space to user space + * @param obs the image observer to be notified + */ + public boolean drawImage(Image image, AffineTransform xform, + ImageObserver obs) + { + Rectangle areaOfInterest = new Rectangle(0, 0, image.getWidth(obs), + image.getHeight(obs)); + return drawImageImpl(image, xform, obs, areaOfInterest); + } + + /** + * Draws the specified image and apply the transform for image space -> + * user space conversion. This method only draw the part of the image + * specified by areaOfInterest. + * + * This method is implemented to special case RenderableImages and + * RenderedImages and delegate to + * {@link #drawRenderableImage(RenderableImage, AffineTransform)} and + * {@link #drawRenderedImage(RenderedImage, AffineTransform)} accordingly. + * Other image types are not yet handled. + * + * @param image the image to be rendered + * @param xform the transform from image space to user space + * @param obs the image observer to be notified + * @param areaOfInterest the area in image space that is rendered + */ + private boolean drawImageImpl(Image image, AffineTransform xform, + ImageObserver obs, Rectangle areaOfInterest) + { + boolean ret; + if (image == null) + { + ret = true; + } + else if (image instanceof RenderedImage) + { + // FIXME: Handle the ImageObserver. + drawRenderedImageImpl((RenderedImage) image, xform, areaOfInterest); + ret = true; + } + else if (image instanceof RenderableImage) + { + // FIXME: Handle the ImageObserver. + drawRenderableImageImpl((RenderableImage) image, xform, areaOfInterest); + ret = true; + } + else + { + // FIXME: Implement rendering of other Image types. + ret = false; + } + return ret; + } + + /** + * Renders a BufferedImage and applies the specified BufferedImageOp before + * to filter the BufferedImage somehow. The resulting BufferedImage is then + * passed on to {@link #drawRenderedImage(RenderedImage, AffineTransform)} + * to perform the final rendering. + * + * @param image the source buffered image + * @param op the filter to apply to the buffered image before rendering + * @param x the x coordinate to render the image to + * @param y the y coordinate to render the image to + */ + public void drawImage(BufferedImage image, BufferedImageOp op, int x, int y) + { + BufferedImage filtered = + op.createCompatibleDestImage(image, image.getColorModel()); + AffineTransform t = new AffineTransform(); + t.translate(x, y); + drawRenderedImage(filtered, t); + } + + /** + * Renders the specified image to the destination raster. The specified + * transform is used to convert the image into user space. The transform + * of this AbstractGraphics2D object is used to transform from user space + * to device space. + * + * The rendering is performed using the scanline algorithm that performs the + * rendering of other shapes and a custom Paint implementation, that supplies + * the pixel values of the rendered image. + * + * @param image the image to render to the destination raster + * @param xform the transform from image space to user space + */ + public void drawRenderedImage(RenderedImage image, AffineTransform xform) + { + Rectangle areaOfInterest = new Rectangle(image.getMinX(), + image.getHeight(), + image.getWidth(), + image.getHeight()); + drawRenderedImageImpl(image, xform, areaOfInterest); + } + + /** + * Renders the specified image to the destination raster. The specified + * transform is used to convert the image into user space. The transform + * of this AbstractGraphics2D object is used to transform from user space + * to device space. Only the area specified by areaOfInterest + * is finally rendered to the target. + * + * The rendering is performed using the scanline algorithm that performs the + * rendering of other shapes and a custom Paint implementation, that supplies + * the pixel values of the rendered image. + * + * @param image the image to render to the destination raster + * @param xform the transform from image space to user space + */ + private void drawRenderedImageImpl(RenderedImage image, + AffineTransform xform, + Rectangle areaOfInterest) + { + // First we compute the transformation. This is made up of 3 parts: + // 1. The areaOfInterest -> image space transform. + // 2. The image space -> user space transform. + // 3. The user space -> device space transform. + AffineTransform t = new AffineTransform(); + t.translate(- areaOfInterest.x - image.getMinX(), + - areaOfInterest.y - image.getMinY()); + t.concatenate(xform); + t.concatenate(transform); + AffineTransform it = null; + try + { + it = t.createInverse(); + } + catch (NoninvertibleTransformException ex) + { + // Ignore -- we return if the transform is not invertible. + } + if (it != null) + { + // Transform the area of interest into user space. + GeneralPath aoi = new GeneralPath(areaOfInterest); + aoi.transform(xform); + // Render the shape using the standard renderer, but with a temporary + // ImagePaint. + ImagePaint p = new ImagePaint(image, it); + Paint savedPaint = paint; + try + { + paint = p; + fillShape(aoi, false); + } + finally + { + paint = savedPaint; + } + } + } + + /** + * Renders a renderable image. This produces a RenderedImage, which is + * then passed to {@link #drawRenderedImage(RenderedImage, AffineTransform)} + * to perform the final rendering. + * + * @param image the renderable image to be rendered + * @param xform the transform from image space to user space + */ + public void drawRenderableImage(RenderableImage image, AffineTransform xform) + { + Rectangle areaOfInterest = new Rectangle((int) image.getMinX(), + (int) image.getHeight(), + (int) image.getWidth(), + (int) image.getHeight()); + drawRenderableImageImpl(image, xform, areaOfInterest); + + } + + /** + * Renders a renderable image. This produces a RenderedImage, which is + * then passed to {@link #drawRenderedImage(RenderedImage, AffineTransform)} + * to perform the final rendering. Only the area of the image specified + * by areaOfInterest is rendered. + * + * @param image the renderable image to be rendered + * @param xform the transform from image space to user space + */ + private void drawRenderableImageImpl(RenderableImage image, + AffineTransform xform, + Rectangle areaOfInterest) + { + // TODO: Maybe make more clever usage of a RenderContext here. + RenderedImage rendered = image.createDefaultRendering(); + drawRenderedImageImpl(rendered, xform, areaOfInterest); + } + + /** + * Draws the specified string at the specified location. + * + * @param text the string to draw + * @param x the x location, relative to the bounding rectangle of the text + * @param y the y location, relative to the bounding rectangle of the text + */ + public void drawString(String text, int x, int y) + { + GlyphVector gv; + synchronized (searchTextKey) + { + TextCacheKey tck = searchTextKey; + FontRenderContext frc = getFontRenderContext(); + tck.setString(text); + tck.setFont(font); + tck.setFontRenderContext(frc); + if (gvCache.containsKey(tck)) + { + gv = gvCache.get(tck); + } + else + { + gv = font.createGlyphVector(frc, text.toCharArray()); + gvCache.put(new TextCacheKey(text, font, frc), gv); + } + } + drawGlyphVector(gv, x, y); + } + + /** + * Draws the specified string at the specified location. + * + * @param text the string to draw + * @param x the x location, relative to the bounding rectangle of the text + * @param y the y location, relative to the bounding rectangle of the text + */ + public void drawString(String text, float x, float y) + { + FontRenderContext ctx = getFontRenderContext(); + GlyphVector gv = font.createGlyphVector(ctx, text.toCharArray()); + drawGlyphVector(gv, x, y); + } + + /** + * Draws the specified string (as AttributedCharacterIterator) at the + * specified location. + * + * @param iterator the string to draw + * @param x the x location, relative to the bounding rectangle of the text + * @param y the y location, relative to the bounding rectangle of the text + */ + public void drawString(AttributedCharacterIterator iterator, int x, int y) + { + FontRenderContext ctx = getFontRenderContext(); + GlyphVector gv = font.createGlyphVector(ctx, iterator); + drawGlyphVector(gv, x, y); + } + + /** + * Draws the specified string (as AttributedCharacterIterator) at the + * specified location. + * + * @param iterator the string to draw + * @param x the x location, relative to the bounding rectangle of the text + * @param y the y location, relative to the bounding rectangle of the text + */ + public void drawString(AttributedCharacterIterator iterator, float x, float y) + { + FontRenderContext ctx = getFontRenderContext(); + GlyphVector gv = font.createGlyphVector(ctx, iterator); + drawGlyphVector(gv, x, y); + } + + /** + * Fills the specified shape with the current foreground. + * + * @param shape the shape to fill + */ + public void fill(Shape shape) + { + fillShape(shape, false); + } + + public boolean hit(Rectangle rect, Shape text, boolean onStroke) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + /** + * Sets the composite. + * + * @param comp the composite to set + */ + public void setComposite(Composite comp) + { + if (! (comp instanceof AlphaComposite)) + { + // FIXME: this check is only required "if this Graphics2D + // context is drawing to a Component on the display screen". + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new AWTPermission("readDisplayPixels")); + } + + composite = comp; + if (! (comp.equals(AlphaComposite.SrcOver))) + isOptimized = false; + else + updateOptimization(); + } + + /** + * Sets the current foreground. + * + * @param p the foreground to set. + */ + public void setPaint(Paint p) + { + if (p != null) + { + paint = p; + + if (! (paint instanceof Color)) + { + isOptimized = false; + } + else + { + this.foreground = (Color) paint; + isForegroundColorNull = false; + updateOptimization(); + } + } + else + { + this.foreground = Color.BLACK; + isForegroundColorNull = true; + } + + // free resources if needed, then put the paint context to null + if (this.paintContext != null) + this.paintContext.dispose(); + + this.paintContext = null; + } + + /** + * Sets the stroke for this graphics object. + * + * @param s the stroke to set + */ + public void setStroke(Stroke s) + { + stroke = s; + if (! stroke.equals(new BasicStroke())) + isOptimized = false; + else + updateOptimization(); + } + + /** + * Sets the specified rendering hint. + * + * @param hintKey the key of the rendering hint + * @param hintValue the value + */ + public void setRenderingHint(Key hintKey, Object hintValue) + { + renderingHints.put(hintKey, hintValue); + } + + /** + * Returns the rendering hint for the specified key. + * + * @param hintKey the rendering hint key + * + * @return the rendering hint for the specified key + */ + public Object getRenderingHint(Key hintKey) + { + return renderingHints.get(hintKey); + } + + /** + * Sets the specified rendering hints. + * + * @param hints the rendering hints to set + */ + public void setRenderingHints(Map hints) + { + renderingHints.clear(); + renderingHints.putAll(hints); + } + + /** + * Adds the specified rendering hints. + * + * @param hints the rendering hints to add + */ + public void addRenderingHints(Map hints) + { + renderingHints.putAll(hints); + } + + /** + * Returns the current rendering hints. + * + * @return the current rendering hints + */ + public RenderingHints getRenderingHints() + { + return (RenderingHints) renderingHints.clone(); + } + + /** + * Translates the coordinate system by (x, y). + * + * @param x the translation X coordinate + * @param y the translation Y coordinate + */ + public void translate(int x, int y) + { + transform.translate(x, y); + + // Update the clip. We special-case rectangular clips here, because they + // are so common (e.g. in Swing). + if (clip != null) + { + if (clip instanceof Rectangle) + { + Rectangle r = (Rectangle) clip; + r.x -= x; + r.y -= y; + setClip(r); + } + else + { + AffineTransform clipTransform = new AffineTransform(); + clipTransform.translate(-x, -y); + updateClip(clipTransform); + } + } + } + + /** + * Translates the coordinate system by (tx, ty). + * + * @param tx the translation X coordinate + * @param ty the translation Y coordinate + */ + public void translate(double tx, double ty) + { + transform.translate(tx, ty); + + // Update the clip. We special-case rectangular clips here, because they + // are so common (e.g. in Swing). + if (clip != null) + { + if (clip instanceof Rectangle) + { + Rectangle r = (Rectangle) clip; + r.x -= tx; + r.y -= ty; + } + else + { + AffineTransform clipTransform = new AffineTransform(); + clipTransform.translate(-tx, -ty); + updateClip(clipTransform); + } + } + } + + /** + * Rotates the coordinate system by theta degrees. + * + * @param theta the angle be which to rotate the coordinate system + */ + public void rotate(double theta) + { + transform.rotate(theta); + if (clip != null) + { + AffineTransform clipTransform = new AffineTransform(); + clipTransform.rotate(-theta); + updateClip(clipTransform); + } + updateOptimization(); + } + + /** + * Rotates the coordinate system by theta around the point + * (x, y). + * + * @param theta the angle by which to rotate the coordinate system + * @param x the point around which to rotate, X coordinate + * @param y the point around which to rotate, Y coordinate + */ + public void rotate(double theta, double x, double y) + { + transform.rotate(theta, x, y); + if (clip != null) + { + AffineTransform clipTransform = new AffineTransform(); + clipTransform.rotate(-theta, x, y); + updateClip(clipTransform); + } + updateOptimization(); + } + + /** + * Scales the coordinate system by the factors scaleX and + * scaleY. + * + * @param scaleX the factor by which to scale the X axis + * @param scaleY the factor by which to scale the Y axis + */ + public void scale(double scaleX, double scaleY) + { + transform.scale(scaleX, scaleY); + if (clip != null) + { + AffineTransform clipTransform = new AffineTransform(); + clipTransform.scale(1 / scaleX, 1 / scaleY); + updateClip(clipTransform); + } + updateOptimization(); + } + + /** + * Shears the coordinate system by shearX and + * shearY. + * + * @param shearX the X shearing + * @param shearY the Y shearing + */ + public void shear(double shearX, double shearY) + { + transform.shear(shearX, shearY); + if (clip != null) + { + AffineTransform clipTransform = new AffineTransform(); + clipTransform.shear(-shearX, -shearY); + updateClip(clipTransform); + } + updateOptimization(); + } + + /** + * Transforms the coordinate system using the specified transform + * t. + * + * @param t the transform + */ + public void transform(AffineTransform t) + { + transform.concatenate(t); + try + { + AffineTransform clipTransform = t.createInverse(); + updateClip(clipTransform); + } + catch (NoninvertibleTransformException ex) + { + // TODO: How can we deal properly with this? + ex.printStackTrace(); + } + updateOptimization(); + } + + /** + * Sets the transformation for this Graphics object. + * + * @param t the transformation to set + */ + public void setTransform(AffineTransform t) + { + // Transform clip into target space using the old transform. + updateClip(transform); + transform.setTransform(t); + // Transform the clip back into user space using the inverse new transform. + try + { + updateClip(transform.createInverse()); + } + catch (NoninvertibleTransformException ex) + { + // TODO: How can we deal properly with this? + ex.printStackTrace(); + } + updateOptimization(); + } + + /** + * Returns the transformation of this coordinate system. + * + * @return the transformation of this coordinate system + */ + public AffineTransform getTransform() + { + return (AffineTransform) transform.clone(); + } + + /** + * Returns the current foreground. + * + * @return the current foreground + */ + public Paint getPaint() + { + return paint; + } + + + /** + * Returns the current composite. + * + * @return the current composite + */ + public Composite getComposite() + { + return composite; + } + + /** + * Sets the current background. + * + * @param color the background to set. + */ + public void setBackground(Color color) + { + background = color; + } + + /** + * Returns the current background. + * + * @return the current background + */ + public Color getBackground() + { + return background; + } + + /** + * Returns the current stroke. + * + * @return the current stroke + */ + public Stroke getStroke() + { + return stroke; + } + + /** + * Intersects the clip of this graphics object with the specified clip. + * + * @param s the clip with which the current clip should be intersected + */ + public void clip(Shape s) + { + // Initialize clip if not already present. + if (clip == null) + setClip(s); + + // This is so common, let's optimize this. + else if (clip instanceof Rectangle && s instanceof Rectangle) + { + Rectangle clipRect = (Rectangle) clip; + Rectangle r = (Rectangle) s; + computeIntersection(r.x, r.y, r.width, r.height, clipRect); + // Call setClip so that subclasses get notified. + setClip(clipRect); + } + else + { + Area current; + if (clip instanceof Area) + current = (Area) clip; + else + current = new Area(clip); + + Area intersect; + if (s instanceof Area) + intersect = (Area) s; + else + intersect = new Area(s); + + current.intersect(intersect); + clip = current; + isOptimized = false; + // Call setClip so that subclasses get notified. + setClip(clip); + } + } + + public FontRenderContext getFontRenderContext() + { + // Protect our own transform from beeing modified. + AffineTransform tf = new AffineTransform(transform); + // TODO: Determine antialias and fractionalmetrics parameters correctly. + return new FontRenderContext(tf, false, true); + } + + /** + * Draws the specified glyph vector at the specified location. + * + * @param gv the glyph vector to draw + * @param x the location, x coordinate + * @param y the location, y coordinate + */ + public void drawGlyphVector(GlyphVector gv, float x, float y) + { + translate(x, y); + fillShape(gv.getOutline(), true); + translate(-x, -y); + } + + /** + * Creates a copy of this graphics object. + * + * @return a copy of this graphics object + */ + public Graphics create() + { + AbstractGraphics2D copy = (AbstractGraphics2D) clone(); + return copy; + } + + /** + * Creates and returns a copy of this Graphics object. This should + * be overridden by subclasses if additional state must be handled when + * cloning. This is called by {@link #create()}. + * + * @return a copy of this Graphics object + */ + protected Object clone() + { + try + { + AbstractGraphics2D copy = (AbstractGraphics2D) super.clone(); + // Copy the clip. If it's a Rectangle, preserve that for optimization. + if (clip instanceof Rectangle) + copy.clip = new Rectangle((Rectangle) clip); + else if (clip != null) + copy.clip = new GeneralPath(clip); + else + copy.clip = null; + + copy.renderingHints = new RenderingHints(null); + copy.renderingHints.putAll(renderingHints); + copy.transform = new AffineTransform(transform); + // The remaining state is inmmutable and doesn't need to be copied. + return copy; + } + catch (CloneNotSupportedException ex) + { + AWTError err = new AWTError("Unexpected exception while cloning"); + err.initCause(ex); + throw err; + } + } + + /** + * Returns the current foreground. + */ + public Color getColor() + { + if (isForegroundColorNull) + return null; + + return this.foreground; + } + + /** + * Sets the current foreground. + * + * @param color the foreground to set + */ + public void setColor(Color color) + { + this.setPaint(color); + } + + public void setPaintMode() + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public void setXORMode(Color color) + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + /** + * Returns the current font. + * + * @return the current font + */ + public Font getFont() + { + return font; + } + + /** + * Sets the font on this graphics object. When f == null, the + * current setting is not changed. + * + * @param f the font to set + */ + public void setFont(Font f) + { + if (f != null) + font = f; + } + + /** + * Returns the font metrics for the specified font. + * + * @param font the font for which to fetch the font metrics + * + * @return the font metrics for the specified font + */ + public FontMetrics getFontMetrics(Font font) + { + return Toolkit.getDefaultToolkit().getFontMetrics(font); + } + + /** + * Returns the bounds of the current clip. + * + * @return the bounds of the current clip + */ + public Rectangle getClipBounds() + { + Rectangle b = null; + if (clip != null) + b = clip.getBounds(); + return b; + } + + /** + * Intersects the current clipping region with the specified rectangle. + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param width the width of the rectangle + * @param height the height of the rectangle + */ + public void clipRect(int x, int y, int width, int height) + { + clip(new Rectangle(x, y, width, height)); + } + + /** + * Sets the clip to the specified rectangle. + * + * @param x the x coordinate of the clip rectangle + * @param y the y coordinate of the clip rectangle + * @param width the width of the clip rectangle + * @param height the height of the clip rectangle + */ + public void setClip(int x, int y, int width, int height) + { + setClip(new Rectangle(x, y, width, height)); + } + + /** + * Returns the current clip. + * + * @return the current clip + */ + public Shape getClip() + { + return clip; + } + + /** + * Sets the current clipping area to clip. + * + * @param c the clip to set + */ + public void setClip(Shape c) + { + clip = c; + if (! (clip instanceof Rectangle)) + isOptimized = false; + else + updateOptimization(); + } + + public void copyArea(int x, int y, int width, int height, int dx, int dy) + { + if (isOptimized) + rawCopyArea(x, y, width, height, dx, dy); + else + copyAreaImpl(x, y, width, height, dx, dy); + } + + /** + * Draws a line from (x1, y1) to (x2, y2). + * + * This implementation transforms the coordinates and forwards the call to + * {@link #rawDrawLine}. + */ + public void drawLine(int x1, int y1, int x2, int y2) + { + if (isOptimized) + { + int tx = (int) transform.getTranslateX(); + int ty = (int) transform.getTranslateY(); + rawDrawLine(x1 + tx, y1 + ty, x2 + tx, y2 + ty); + } + else + { + ShapeCache sc = shapeCache; + if (sc.line == null) + sc.line = new Line2D.Float(); + sc.line.setLine(x1, y1, x2, y2); + draw(sc.line); + } + } + + public void drawRect(int x, int y, int w, int h) + { + if (isOptimized) + { + int tx = (int) transform.getTranslateX(); + int ty = (int) transform.getTranslateY(); + rawDrawRect(x + tx, y + ty, w, h); + } + else + { + ShapeCache sc = shapeCache; + if (sc.rect == null) + sc.rect = new Rectangle(); + sc.rect.setBounds(x, y, w, h); + draw(sc.rect); + } + } + + /** + * Fills a rectangle with the current paint. + * + * @param x the upper left corner, X coordinate + * @param y the upper left corner, Y coordinate + * @param width the width of the rectangle + * @param height the height of the rectangle + */ + public void fillRect(int x, int y, int width, int height) + { + if (isOptimized) + { + rawFillRect(x + (int) transform.getTranslateX(), + y + (int) transform.getTranslateY(), width, height); + } + else + { + ShapeCache sc = shapeCache; + if (sc.rect == null) + sc.rect = new Rectangle(); + sc.rect.setBounds(x, y, width, height); + fill(sc.rect); + } + } + + /** + * Fills a rectangle with the current background color. + * + * This implementation temporarily sets the foreground color to the + * background and forwards the call to {@link #fillRect(int, int, int, int)}. + * + * @param x the upper left corner, X coordinate + * @param y the upper left corner, Y coordinate + * @param width the width of the rectangle + * @param height the height of the rectangle + */ + public void clearRect(int x, int y, int width, int height) + { + if (isOptimized) + rawClearRect(x, y, width, height); + else + { + Paint savedForeground = getPaint(); + setPaint(getBackground()); + fillRect(x, y, width, height); + setPaint(savedForeground); + } + } + + /** + * Draws a rounded rectangle. + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param width the width of the rectangle + * @param height the height of the rectangle + * @param arcWidth the width of the arcs + * @param arcHeight the height of the arcs + */ + public void drawRoundRect(int x, int y, int width, int height, int arcWidth, + int arcHeight) + { + ShapeCache sc = shapeCache; + if (sc.roundRect == null) + sc.roundRect = new RoundRectangle2D.Float(); + sc.roundRect.setRoundRect(x, y, width, height, arcWidth, arcHeight); + draw(sc.roundRect); + } + + /** + * Fills a rounded rectangle. + * + * @param x the x coordinate of the rectangle + * @param y the y coordinate of the rectangle + * @param width the width of the rectangle + * @param height the height of the rectangle + * @param arcWidth the width of the arcs + * @param arcHeight the height of the arcs + */ + public void fillRoundRect(int x, int y, int width, int height, int arcWidth, + int arcHeight) + { + ShapeCache sc = shapeCache; + if (sc.roundRect == null) + sc.roundRect = new RoundRectangle2D.Float(); + sc.roundRect.setRoundRect(x, y, width, height, arcWidth, arcHeight); + fill(sc.roundRect); + } + + /** + * Draws the outline of an oval. + * + * @param x the upper left corner of the bounding rectangle of the ellipse + * @param y the upper left corner of the bounding rectangle of the ellipse + * @param width the width of the ellipse + * @param height the height of the ellipse + */ + public void drawOval(int x, int y, int width, int height) + { + ShapeCache sc = shapeCache; + if (sc.ellipse == null) + sc.ellipse = new Ellipse2D.Float(); + sc.ellipse.setFrame(x, y, width, height); + draw(sc.ellipse); + } + + /** + * Fills an oval. + * + * @param x the upper left corner of the bounding rectangle of the ellipse + * @param y the upper left corner of the bounding rectangle of the ellipse + * @param width the width of the ellipse + * @param height the height of the ellipse + */ + public void fillOval(int x, int y, int width, int height) + { + ShapeCache sc = shapeCache; + if (sc.ellipse == null) + sc.ellipse = new Ellipse2D.Float(); + sc.ellipse.setFrame(x, y, width, height); + fill(sc.ellipse); + } + + /** + * Draws an arc. + */ + public void drawArc(int x, int y, int width, int height, int arcStart, + int arcAngle) + { + ShapeCache sc = shapeCache; + if (sc.arc == null) + sc.arc = new Arc2D.Float(); + sc.arc.setArc(x, y, width, height, arcStart, arcAngle, Arc2D.OPEN); + draw(sc.arc); + } + + /** + * Fills an arc. + */ + public void fillArc(int x, int y, int width, int height, int arcStart, + int arcAngle) + { + ShapeCache sc = shapeCache; + if (sc.arc == null) + sc.arc = new Arc2D.Float(); + sc.arc.setArc(x, y, width, height, arcStart, arcAngle, Arc2D.PIE); + draw(sc.arc); + } + + public void drawPolyline(int[] xPoints, int[] yPoints, int npoints) + { + ShapeCache sc = shapeCache; + if (sc.polyline == null) + sc.polyline = new GeneralPath(); + GeneralPath p = sc.polyline; + p.reset(); + if (npoints > 0) + p.moveTo(xPoints[0], yPoints[0]); + for (int i = 1; i < npoints; i++) + p.lineTo(xPoints[i], yPoints[i]); + fill(p); + } + + /** + * Draws the outline of a polygon. + */ + public void drawPolygon(int[] xPoints, int[] yPoints, int npoints) + { + ShapeCache sc = shapeCache; + if (sc.polygon == null) + sc.polygon = new Polygon(); + sc.polygon.reset(); + sc.polygon.xpoints = xPoints; + sc.polygon.ypoints = yPoints; + sc.polygon.npoints = npoints; + draw(sc.polygon); + } + + /** + * Fills the outline of a polygon. + */ + public void fillPolygon(int[] xPoints, int[] yPoints, int npoints) + { + ShapeCache sc = shapeCache; + if (sc.polygon == null) + sc.polygon = new Polygon(); + sc.polygon.reset(); + sc.polygon.xpoints = xPoints; + sc.polygon.ypoints = yPoints; + sc.polygon.npoints = npoints; + fill(sc.polygon); + } + + /** + * Draws the specified image at the specified location. This forwards + * to {@link #drawImage(Image, AffineTransform, ImageObserver)}. + * + * @param image the image to render + * @param x the x location to render to + * @param y the y location to render to + * @param observer the image observer to receive notification + */ + public boolean drawImage(Image image, int x, int y, ImageObserver observer) + { + boolean ret; + if (isOptimized) + { + ret = rawDrawImage(image, x + (int) transform.getTranslateX(), + y + (int) transform.getTranslateY(), observer); + } + else + { + AffineTransform t = new AffineTransform(); + t.translate(x, y); + ret = drawImage(image, t, observer); + } + return ret; + } + + /** + * Draws the specified image at the specified location. The image + * is scaled to the specified width and height. This forwards + * to {@link #drawImage(Image, AffineTransform, ImageObserver)}. + * + * @param image the image to render + * @param x the x location to render to + * @param y the y location to render to + * @param width the target width of the image + * @param height the target height of the image + * @param observer the image observer to receive notification + */ + public boolean drawImage(Image image, int x, int y, int width, int height, + ImageObserver observer) + { + AffineTransform t = new AffineTransform(); + int imWidth = image.getWidth(observer); + int imHeight = image.getHeight(observer); + if (imWidth == width && imHeight == height) + { + // No need to scale, fall back to non-scaling loops. + return drawImage(image, x, y, observer); + } + else + { + Image scaled = prepareImage(image, width, height); + // Ideally, this should notify the observer about the scaling progress. + return drawImage(scaled, x, y, observer); + } + } + + /** + * Draws the specified image at the specified location. This forwards + * to {@link #drawImage(Image, AffineTransform, ImageObserver)}. + * + * @param image the image to render + * @param x the x location to render to + * @param y the y location to render to + * @param bgcolor the background color to use for transparent pixels + * @param observer the image observer to receive notification + */ + public boolean drawImage(Image image, int x, int y, Color bgcolor, + ImageObserver observer) + { + AffineTransform t = new AffineTransform(); + t.translate(x, y); + // TODO: Somehow implement the background option. + return drawImage(image, t, observer); + } + + /** + * Draws the specified image at the specified location. The image + * is scaled to the specified width and height. This forwards + * to {@link #drawImage(Image, AffineTransform, ImageObserver)}. + * + * @param image the image to render + * @param x the x location to render to + * @param y the y location to render to + * @param width the target width of the image + * @param height the target height of the image + * @param bgcolor the background color to use for transparent pixels + * @param observer the image observer to receive notification + */ + public boolean drawImage(Image image, int x, int y, int width, int height, + Color bgcolor, ImageObserver observer) + { + AffineTransform t = new AffineTransform(); + t.translate(x, y); + double scaleX = (double) image.getWidth(observer) / (double) width; + double scaleY = (double) image.getHeight(observer) / (double) height; + t.scale(scaleX, scaleY); + // TODO: Somehow implement the background option. + return drawImage(image, t, observer); + } + + /** + * Draws an image fragment to a rectangular area of the target. + * + * @param image the image to render + * @param dx1 the first corner of the destination rectangle + * @param dy1 the first corner of the destination rectangle + * @param dx2 the second corner of the destination rectangle + * @param dy2 the second corner of the destination rectangle + * @param sx1 the first corner of the source rectangle + * @param sy1 the first corner of the source rectangle + * @param sx2 the second corner of the source rectangle + * @param sy2 the second corner of the source rectangle + * @param observer the image observer to be notified + */ + public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, + ImageObserver observer) + { + int sx = Math.min(sx1, sx1); + int sy = Math.min(sy1, sy2); + int sw = Math.abs(sx1 - sx2); + int sh = Math.abs(sy1 - sy2); + int dx = Math.min(dx1, dx1); + int dy = Math.min(dy1, dy2); + int dw = Math.abs(dx1 - dx2); + int dh = Math.abs(dy1 - dy2); + + AffineTransform t = new AffineTransform(); + t.translate(sx - dx, sy - dy); + double scaleX = (double) sw / (double) dw; + double scaleY = (double) sh / (double) dh; + t.scale(scaleX, scaleY); + Rectangle areaOfInterest = new Rectangle(sx, sy, sw, sh); + return drawImageImpl(image, t, observer, areaOfInterest); + } + + /** + * Draws an image fragment to a rectangular area of the target. + * + * @param image the image to render + * @param dx1 the first corner of the destination rectangle + * @param dy1 the first corner of the destination rectangle + * @param dx2 the second corner of the destination rectangle + * @param dy2 the second corner of the destination rectangle + * @param sx1 the first corner of the source rectangle + * @param sy1 the first corner of the source rectangle + * @param sx2 the second corner of the source rectangle + * @param sy2 the second corner of the source rectangle + * @param bgcolor the background color to use for transparent pixels + * @param observer the image observer to be notified + */ + public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, Color bgcolor, + ImageObserver observer) + { + // FIXME: Do something with bgcolor. + return drawImage(image, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer); + } + + /** + * Disposes this graphics object. + */ + public void dispose() + { + // Nothing special to do here. + } + + /** + * Fills the specified shape. Override this if your backend can efficiently + * fill shapes. This is possible on many systems via a polygon fill + * method or something similar. But keep in mind that Shapes can be quite + * complex (non-convex, with holes etc), which is not necessarily supported + * by all polygon fillers. Also note that you must perform clipping + * before filling the shape. + * + * @param s the shape to fill + * @param isFont true if the shape is a font outline + */ + protected void fillShape(Shape s, boolean isFont) + { + // Determine if we need to antialias stuff. + boolean antialias = false; + if (isFont) + { + Object v = renderingHints.get(RenderingHints.KEY_TEXT_ANTIALIASING); + // We default to antialiasing for text rendering. + antialias = v == RenderingHints.VALUE_TEXT_ANTIALIAS_ON + || (v == RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT + && DEFAULT_TEXT_AA); + } + else + { + Object v = renderingHints.get(RenderingHints.KEY_ANTIALIASING); + antialias = (v == RenderingHints.VALUE_ANTIALIAS_ON); + } + ScanlineConverter sc = getScanlineConverter(); + int resolution = 0; + int yRes = 0; + if (antialias) + { + // Adjust resolution according to rendering hints. + resolution = 2; + yRes = 4; + } + sc.renderShape(this, s, clip, transform, resolution, yRes, renderingHints); + freeScanlineConverter(sc); + } + + /** + * Returns the color model of this Graphics object. + * + * @return the color model of this Graphics object + */ + protected abstract ColorModel getColorModel(); + + /** + * Returns the bounds of the target. + * + * @return the bounds of the target + */ + protected abstract Rectangle getDeviceBounds(); + + /** + * Draws a line in optimization mode. The implementation should respect the + * clip and translation. It can assume that the clip is a rectangle and that + * the transform is only a translating transform. + * + * @param x0 the starting point, X coordinate + * @param y0 the starting point, Y coordinate + * @param x1 the end point, X coordinate + * @param y1 the end point, Y coordinate + */ + protected void rawDrawLine(int x0, int y0, int x1, int y1) + { + ShapeCache sc = shapeCache; + if (sc.line == null) + sc.line = new Line2D.Float(); + sc.line.setLine(x0, y0, x1, y1); + draw(sc.line); + } + + protected void rawDrawRect(int x, int y, int w, int h) + { + ShapeCache sc = shapeCache; + if (sc.rect == null) + sc.rect = new Rectangle(); + sc.rect.setBounds(x, y, w, h); + draw(sc.rect); + } + + /** + * Clears a rectangle in optimization mode. The implementation should respect the + * clip and translation. It can assume that the clip is a rectangle and that + * the transform is only a translating transform. + * + * @param x the upper left corner, X coordinate + * @param y the upper left corner, Y coordinate + * @param w the width + * @param h the height + */ + protected void rawClearRect(int x, int y, int w, int h) + { + Paint savedForeground = getPaint(); + setPaint(getBackground()); + rawFillRect(x, y, w, h); + setPaint(savedForeground); + } + + /** + * Fills a rectangle in optimization mode. The implementation should respect + * the clip but can assume that it is a rectangle. + * + * @param x the upper left corner, X coordinate + * @param y the upper left corner, Y coordinate + * @param w the width + * @param h the height + */ + protected void rawFillRect(int x, int y, int w, int h) + { + ShapeCache sc = shapeCache; + if (sc.rect == null) + sc.rect = new Rectangle(); + sc.rect.setBounds(x, y, w, h); + fill(sc.rect); + } + + /** + * Draws an image in optimization mode. The implementation should respect + * the clip but can assume that it is a rectangle. + * + * @param image the image to be painted + * @param x the location, X coordinate + * @param y the location, Y coordinate + * @param obs the image observer to be notified + * + * @return true when the image is painted completely, + * false if it is still rendered + */ + protected boolean rawDrawImage(Image image, int x, int y, ImageObserver obs) + { + AffineTransform t = new AffineTransform(); + t.translate(x, y); + return drawImage(image, t, obs); + } + + /** + * Copies a rectangular region to another location. + * + * @param x the upper left corner, X coordinate + * @param y the upper left corner, Y coordinate + * @param w the width + * @param h the height + * @param dx + * @param dy + */ + protected void rawCopyArea(int x, int y, int w, int h, int dx, int dy) + { + copyAreaImpl(x, y, w, h, dx, dy); + } + + // Private implementation methods. + + /** + * Copies a rectangular area of the target raster to a different location. + */ + private void copyAreaImpl(int x, int y, int w, int h, int dx, int dy) + { + // FIXME: Implement this properly. + throw new UnsupportedOperationException("Not implemented yet."); + } + + /** + * Paints a scanline between x0 and x1. Override this when your backend + * can efficiently draw/fill horizontal lines. + * + * @param x0 the left offset + * @param x1 the right offset + * @param y the scanline + */ + public void renderScanline(int y, ScanlineCoverage c) + { + PaintContext pCtx = getPaintContext(); + + int x0 = c.getMinX(); + int x1 = c.getMaxX(); + Raster paintRaster = pCtx.getRaster(x0, y, x1 - x0, 1); + + // Do the anti aliasing thing. + float coverageAlpha = 0; + float maxCoverage = c.getMaxCoverage(); + ColorModel cm = pCtx.getColorModel(); + DataBuffer db = paintRaster.getDataBuffer(); + Point loc = new Point(paintRaster.getMinX(), paintRaster.getMinY()); + SampleModel sm = paintRaster.getSampleModel(); + WritableRaster writeRaster = Raster.createWritableRaster(sm, db, loc); + WritableRaster alphaRaster = cm.getAlphaRaster(writeRaster); + int pixel; + ScanlineCoverage.Iterator iter = c.iterate(); + while (iter.hasNext()) + { + ScanlineCoverage.Range range = iter.next(); + coverageAlpha = range.getCoverage() / maxCoverage; + if (coverageAlpha < 1.0) + { + for (int x = range.getXPos(); x < range.getXPosEnd(); x++) + { + pixel = alphaRaster.getSample(x, y, 0); + pixel = (int) (pixel * coverageAlpha); + alphaRaster.setSample(x, y, 0, pixel); + } + } + } + ColorModel paintColorModel = pCtx.getColorModel(); + CompositeContext cCtx = composite.createContext(paintColorModel, + getColorModel(), + renderingHints); + WritableRaster raster = getDestinationRaster(); + WritableRaster targetChild = raster.createWritableTranslatedChild(-x0, -y); + + cCtx.compose(paintRaster, targetChild, targetChild); + updateRaster(raster, x0, y, x1 - x0, 1); + cCtx.dispose(); + } + + + /** + * Initializes this graphics object. This must be called by subclasses in + * order to correctly initialize the state of this object. + */ + protected void init() + { + setPaint(Color.BLACK); + setFont(FONT); + isOptimized = true; + } + + /** + * Returns a WritableRaster that is used by this class to perform the + * rendering in. It is not necessary that the target surface immediately + * reflects changes in the raster. Updates to the raster are notified via + * {@link #updateRaster}. + * + * @return the destination raster + */ + protected WritableRaster getDestinationRaster() + { + // TODO: Ideally we would fetch the xdrawable's surface pixels for + // initialization of the raster. + Rectangle db = getDeviceBounds(); + if (destinationRaster == null) + { + int[] bandMasks = new int[]{ 0xFF0000, 0xFF00, 0xFF }; + destinationRaster = Raster.createPackedRaster(DataBuffer.TYPE_INT, + db.width, db.height, + bandMasks, null); + // Initialize raster with white. + int x0 = destinationRaster.getMinX(); + int x1 = destinationRaster.getWidth() + x0; + int y0 = destinationRaster.getMinY(); + int y1 = destinationRaster.getHeight() + y0; + int numBands = destinationRaster.getNumBands(); + for (int y = y0; y < y1; y++) + { + for (int x = x0; x < x1; x++) + { + for (int b = 0; b < numBands; b++) + destinationRaster.setSample(x, y, b, 255); + } + } + } + return destinationRaster; + } + + /** + * Notifies the backend that the raster has changed in the specified + * rectangular area. The raster that is provided in this method is always + * the same as the one returned in {@link #getDestinationRaster}. + * Backends that reflect changes to this raster directly don't need to do + * anything here. + * + * @param raster the updated raster, identical to the raster returned + * by {@link #getDestinationRaster()} + * @param x the upper left corner of the updated region, X coordinate + * @param y the upper lef corner of the updated region, Y coordinate + * @param w the width of the updated region + * @param h the height of the updated region + */ + protected void updateRaster(Raster raster, int x, int y, int w, int h) + { + // Nothing to do here. Backends that need to update their surface + // to reflect the change should override this method. + } + + // Some helper methods. + + /** + * Helper method to check and update the optimization conditions. + */ + private void updateOptimization() + { + int transformType = transform.getType(); + boolean optimizedTransform = false; + if (transformType == AffineTransform.TYPE_IDENTITY + || transformType == AffineTransform.TYPE_TRANSLATION) + optimizedTransform = true; + + boolean optimizedClip = (clip == null || clip instanceof Rectangle); + isOptimized = optimizedClip + && optimizedTransform && paint instanceof Color + && composite == AlphaComposite.SrcOver + && stroke.equals(new BasicStroke()); + } + + /** + * Calculates the intersection of two rectangles. The result is stored + * in rect. This is basically the same + * like {@link Rectangle#intersection(Rectangle)}, only that it does not + * create new Rectangle instances. The tradeoff is that you loose any data in + * rect. + * + * @param x upper-left x coodinate of first rectangle + * @param y upper-left y coodinate of first rectangle + * @param w width of first rectangle + * @param h height of first rectangle + * @param rect a Rectangle object of the second rectangle + * + * @throws NullPointerException if rect is null + * + * @return a rectangle corresponding to the intersection of the + * two rectangles. An empty rectangle is returned if the rectangles + * do not overlap + */ + private static Rectangle computeIntersection(int x, int y, int w, int h, + Rectangle rect) + { + int x2 = rect.x; + int y2 = rect.y; + int w2 = rect.width; + int h2 = rect.height; + + int dx = (x > x2) ? x : x2; + int dy = (y > y2) ? y : y2; + int dw = (x + w < x2 + w2) ? (x + w - dx) : (x2 + w2 - dx); + int dh = (y + h < y2 + h2) ? (y + h - dy) : (y2 + h2 - dy); + + if (dw >= 0 && dh >= 0) + rect.setBounds(dx, dy, dw, dh); + else + rect.setBounds(0, 0, 0, 0); + + return rect; + } + + /** + * Helper method to transform the clip. This is called by the various + * transformation-manipulation methods to update the clip (which is in + * userspace) accordingly. + * + * The transform usually is the inverse transform that was applied to the + * graphics object. + * + * @param t the transform to apply to the clip + */ + private void updateClip(AffineTransform t) + { + if (! (clip instanceof GeneralPath)) + clip = new GeneralPath(clip); + + GeneralPath p = (GeneralPath) clip; + p.transform(t); + } + + /** + * Returns a free scanline converter from the pool. + * + * @return a scanline converter + */ + private ScanlineConverter getScanlineConverter() + { + synchronized (scanlineConverters) + { + ScanlineConverter sc; + if (scanlineConverters.size() > 0) + { + sc = scanlineConverters.removeFirst(); + } + else + { + sc = new ScanlineConverter(); + } + return sc; + } + } + + /** + * Puts a scanline converter back in the pool. + * + * @param sc + */ + private void freeScanlineConverter(ScanlineConverter sc) + { + synchronized (scanlineConverters) + { + scanlineConverters.addLast(sc); + } + } + + private PaintContext getPaintContext() + { + if (this.paintContext == null) + { + this.paintContext = + this.foreground.createContext(getColorModel(), + getDeviceBounds(), + getClipBounds(), + getTransform(), + getRenderingHints()); + } + + return this.paintContext; + } + + /** + * Scales an image to the specified width and height. This should also + * be used to implement + * {@link Toolkit#prepareImage(Image, int, int, ImageObserver)}. + * This uses {@link Toolkit#createImage(ImageProducer)} to create the actual + * image. + * + * @param image the image to prepare + * @param w the width + * @param h the height + * + * @return the scaled image + */ + public static Image prepareImage(Image image, int w, int h) + { + // Try to find cached scaled image. + HashMap scaledTable = imageCache.get(image); + Dimension size = new Dimension(w, h); + Image scaled = null; + if (scaledTable != null) + { + scaled = scaledTable.get(size); + } + if (scaled == null) + { + // No cached scaled image. Start scaling image now. + ImageProducer source = image.getSource(); + ReplicateScaleFilter scaler = new ReplicateScaleFilter(w, h); + FilteredImageSource filteredSource = + new FilteredImageSource(source, scaler); + // Ideally, this should asynchronously scale the image. + Image scaledImage = + Toolkit.getDefaultToolkit().createImage(filteredSource); + scaled = scaledImage; + // Put scaled image in cache. + if (scaledTable == null) + { + scaledTable = new HashMap(); + imageCache.put(image, scaledTable); + } + scaledTable.put(size, scaledImage); + } + return scaled; + } + +} diff --git a/libjava/classpath/gnu/java/awt/java2d/ActiveEdges.java b/libjava/classpath/gnu/java/awt/java2d/ActiveEdges.java new file mode 100644 index 000000000..efe1966e3 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/java2d/ActiveEdges.java @@ -0,0 +1,197 @@ +/* ActiveEdges.java -- A collection of active edges for scanline conversion + 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.java2d; + +import gnu.java.lang.CPStringBuilder; + +/** + * A collection of active edges for scanline conversion. + */ +final class ActiveEdges +{ + + /** + * The active edges. This can contain null values at arbirary locations. + * The method #sort() packs this together. + */ + private PolyEdge[] activeEdges; + + /** + * The actual number of active edges. The array can be bigger than this + * number. + */ + private int numActiveEdges; + + /** + * Creates a new ActiveEdges object. + */ + ActiveEdges() + { + activeEdges = new PolyEdge[8]; + numActiveEdges = 0; + } + + /** + * Clears out all active edges. This is cheap as it simply resets the + * counter to 0. It does not release all references to PolyEdge instances. + */ + void clear() + { + numActiveEdges = 0; + } + + /** + * Adds the specified edge to the list of active edges. This does not yet + * sort the edges and therefore does destroy any order of the list. + * + * @param edge the edge to add + */ + void add(PolyEdge edge) + { + // Grow array when necessary. + int oldSize = activeEdges.length; + if (numActiveEdges >= oldSize) + { + int newSize = oldSize + oldSize / 4 + 1; + PolyEdge[] newEdges = new PolyEdge[newSize]; + System.arraycopy(activeEdges, 0, newEdges, 0, oldSize); + activeEdges = newEdges; + } + activeEdges[numActiveEdges] = edge; + numActiveEdges++; + } + + /** + * Intersects all active edges, sorts them according to their intersection + * points and packs the array to remove unneeded edges. This does also + * remove any edges that do not intersect the scanline (i.e. they end above + * of the scanline). + * + * @param y the scanline height + */ + void intersectSortAndPack(int n, int y) + { + // Intersect and pack in one go. + int last = 0; + PolyEdge tmp; + for (int i = 0; i < numActiveEdges; i++) + { + PolyEdge edge = activeEdges[i]; + // Clear out edge that ends above the scanline. + if (edge != null && edge.y1 >= y) + { + assert edge.y1 >= y && edge.y0 <= y : "edge must cross scanline"; + edge.intersect(n, y); + activeEdges[last] = edge; + last++; + + // Bubble up the added edge. + for (int j = last - 1; j > 0; j--) + { + if (activeEdges[j].xIntersection + < activeEdges[j - 1].xIntersection) + { + tmp = activeEdges[j]; + activeEdges[j] = activeEdges[j - 1]; + activeEdges[j - 1] = tmp; + } + else + { + // The beginning of the list is already sorted. + break; + } + } + } + } + numActiveEdges = last; + + } + + /** + * Returns the number of active edges. This is only reliable after a + * call to {@link #intersectSortAndPack(int, int)}. + * + * @return the number of active edges + */ + int getNumActiveEdges() + { + return numActiveEdges; + } + + /** + * Returns the active edge at the position i. + * + * @param i the index + * + * @return the active edge at the specified index + */ + PolyEdge getActiveEdge(int i) + { + return activeEdges[i]; + } + + /** + * Removes all edges that end above the specified height. + * + * @param y the cut-off height + */ + void remove(int y) + { + for (int i = 0; i < numActiveEdges; i++) + { + PolyEdge edge = activeEdges[i]; + if (edge != null && edge.y1 < y) + { + activeEdges[i] = null; + } + } + } + + public String toString() + { + CPStringBuilder s = new CPStringBuilder(); + s.append("[ActiveEdges] "); + for (int i = 0; i < numActiveEdges; i++) + { + s.append(activeEdges[i]); + s.append(','); + } + return s.toString(); + } +} diff --git a/libjava/classpath/gnu/java/awt/java2d/AlphaCompositeContext.java b/libjava/classpath/gnu/java/awt/java2d/AlphaCompositeContext.java new file mode 100644 index 000000000..f1f082abe --- /dev/null +++ b/libjava/classpath/gnu/java/awt/java2d/AlphaCompositeContext.java @@ -0,0 +1,316 @@ +/* AlphaCompositeContext.java -- CompositeContext impl for AlphaComposite + 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.java2d; + +import java.awt.AWTError; +import java.awt.AlphaComposite; +import java.awt.CompositeContext; +import java.awt.image.ColorModel; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; + +/** + * A CompositeContext implementation for {@link AlphaComposite}. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class AlphaCompositeContext + implements CompositeContext +{ + + /** + * The Composite object for which we perform compositing. + */ + private AlphaComposite composite; + + /** + * The source color model. + */ + private ColorModel srcColorModel; + + /** + * The destination color model. + */ + private ColorModel dstColorModel; + + /** + * The blending factor for the source. + */ + private float fs; + + /** + * The blending factor for the destination. + */ + private float fd; + + /** + * Creates a new AlphaCompositeContext. + * + * @param aComp the AlphaComposite object + * @param srcCM the source color model + * @param dstCM the destination color model + */ + public AlphaCompositeContext(AlphaComposite aComp, ColorModel srcCM, + ColorModel dstCM) + { + composite = aComp; + srcColorModel = srcCM; + dstColorModel = dstCM; + + + // Determine the blending factors according to the rule in the + // AlphaComposite. For some rules the factors must be determined + // dynamically because they depend on the actual pixel value. + switch (composite.getRule()) + { + case AlphaComposite.CLEAR: + fs = 0.F; + fd= 0.F; + break; + case AlphaComposite.DST: + fs = 0.F; + fd= 1.F; + break; + case AlphaComposite.DST_ATOP: + fs = 1.F; // Determined later as 1 - alpha_dst; + fd = 1.F; // Determined later as alpha_src; + break; + case AlphaComposite.DST_IN: + fs = 0.F; + fd = 0.F; // Determined later as alpha_src; + break; + case AlphaComposite.DST_OUT: + fs = 0.F; + fd = 0.F; // Determined later as 1 - alpha_src; + break; + case AlphaComposite.DST_OVER: + fs = 1.F; // Determined later as 1 - alpha_dst. + fd= 1.F; + break; + case AlphaComposite.SRC: + fs = 1.F; + fd= 0.F; + break; + case AlphaComposite.SRC_ATOP: + fs = 1.F; // Determined later as alpha_dst; + fd = 1.F; // Determined later as 1 - alpha_src; + break; + case AlphaComposite.SRC_IN: + fs = 0.F; // Determined later as alpha_dst; + fd = 0.F; + break; + case AlphaComposite.SRC_OUT: + fs = 0.F; // Determined later as 1 - alpha_dst; + fd = 0.F; + break; + case AlphaComposite.SRC_OVER: + fs = 1.F; + fd= 1.F; // Determined later as 1 - alpha_src. + break; + case AlphaComposite.XOR: + fs = 1.F; // Determined later as 1 - alpha_dst. + fd= 1.F; // Determined later as 1 - alpha_src. + break; + default: + throw new AWTError("Illegal AlphaComposite rule"); + } + + } + + /** + * Releases all resources held by this composite object. + */ + public void dispose() + { + // Nothing to do here yet. + } + + /** + * Performs compositing according to the rules specified in the + * AlphaComposite from the constructor. + */ + public void compose(Raster src, Raster dstIn, WritableRaster dstOut) + { + + // TODO: This implementation is very general and highly inefficient. There + // are two possible ways to optimize this: + // 1. Special cased implementations for common ColorModels and transfer + // types. + // 2. Native implementation. + + int x0 = src.getMinX(); + int y0 = src.getMinY(); + int width = src.getWidth(); + int height = src.getHeight(); + int x1 = x0 + width; + int y1 = y0 + height; + + Object srcPixel = null; + Object dstPixel = null; + + // Prepare the array that holds the color and alpha components of the + // source pixels. + float[] srcComponents; + int srcComponentsLength = srcColorModel.getNumComponents(); + if (! srcColorModel.hasAlpha()) + srcComponentsLength += 1; + srcComponents = new float[srcComponentsLength]; + + // Prepare the array that holds the color and alpha components of the + // destination pixels. + float[] dstComponents; + int dstComponentsLength = dstColorModel.getNumComponents(); + if (! dstColorModel.hasAlpha()) + dstComponentsLength += 1; + dstComponents = new float[dstComponentsLength]; + + if (srcComponentsLength != dstComponentsLength) + throw new AWTError("The color models of the source and destination have" + + "incompatible number of color components"); + + int srcTransferType = srcColorModel.getTransferType(); + int dstTransferType = dstColorModel.getTransferType(); + + for (int y = y0; y < y1; y++) + { + for (int x = x0; x < x1; x++) + { + // Fetch source pixel. + srcPixel = src.getDataElements(x, y, (int[]) srcPixel); + // Fetch destination pixel. + dstPixel = dstIn.getDataElements(x, y, dstPixel); + // Get normalized components. This is the only type that is + // guaranteed to be supported by all ColorModels. + srcComponents = + srcColorModel.getNormalizedComponents(srcPixel, srcComponents, 0); + if (! srcColorModel.hasAlpha()) + srcComponents[srcComponentsLength - 1] = 1.0F; + dstComponents = + dstColorModel.getNormalizedComponents(dstPixel, dstComponents, 0); + if (! dstColorModel.hasAlpha()) + dstComponents[dstComponentsLength - 1] = 1.0F; + + // Prepare the input. + float compositeAlpha = composite.getAlpha(); + srcComponents[srcComponentsLength - 1] *= compositeAlpha; + if (srcColorModel.isAlphaPremultiplied()) + { + for (int i = srcComponentsLength - 2; i >= 0; i--) + srcComponents[i] *= compositeAlpha; + } + else + { + for (int i = srcComponentsLength - 2; i >= 0; i--) + srcComponents[i] *= srcComponents[srcComponentsLength - 1]; + } + if (! dstColorModel.isAlphaPremultiplied()) + { + for (int i = dstComponentsLength - 2; i >= 0; i--) + dstComponents[i] *= dstComponents[dstComponents.length - 1]; + } + + // Determine the blending factors according to the rule in the + // AlphaComposite. For some rules the factors must be determined + // dynamically because they depend on the actual pixel value. + float srcAlpha = srcComponents[srcComponentsLength - 1]; + float dstAlpha = dstComponents[dstComponentsLength - 1]; + switch (composite.getRule()) + { + case AlphaComposite.DST_ATOP: + fs = 1.F - dstAlpha; + fd = srcAlpha; + break; + case AlphaComposite.DST_IN: + fd = srcAlpha; + break; + case AlphaComposite.DST_OUT: + fd = 1.F - srcAlpha; + break; + case AlphaComposite.DST_OVER: + fs = 1.F - dstAlpha; + break; + case AlphaComposite.SRC_ATOP: + fs = srcAlpha; + fd = 1.F - srcAlpha; + break; + case AlphaComposite.SRC_IN: + fs = dstAlpha; + break; + case AlphaComposite.SRC_OUT: + fs = 1.F - dstAlpha; + break; + case AlphaComposite.SRC_OVER: + fd= 1.F - srcAlpha; + break; + case AlphaComposite.XOR: + fs = 1.F - dstAlpha; + fd= 1.F - srcAlpha; + break; + default: + // For the other cases the factors have already been determined + // in the constructor. + } + + // Apply the blending equation to the pixels. + for (int i = 0; i < srcComponentsLength; i++) + { + dstComponents[i] = srcComponents[i] * fs + + dstComponents[i] * fd; + } + + // Convert the result back when the destination is not + // alpha-premultiplied. + dstAlpha = dstComponents[dstComponentsLength - 1]; + if (!dstColorModel.isAlphaPremultiplied() && dstAlpha != 0.F) + { + for (int i = 0; i < dstComponentsLength - 1; i++) + { + dstComponents[i] = dstComponents[i] / dstAlpha; + } + } + + // Store the result in the destination raster. + dstPixel = dstColorModel.getDataElements(dstComponents, 0, + dstPixel); + dstOut.setDataElements(x, y, dstPixel); + } // End X loop. + } // End Y loop. + } + +} diff --git a/libjava/classpath/gnu/java/awt/java2d/CubicSegment.java b/libjava/classpath/gnu/java/awt/java2d/CubicSegment.java new file mode 100644 index 000000000..8197c94c5 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/java2d/CubicSegment.java @@ -0,0 +1,184 @@ +/* CubicSegment.java -- Cubic segment used for BasicStroke + 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.java2d; + + +import java.awt.geom.CubicCurve2D; +import java.awt.geom.Point2D; + +/** + * Cubic Bezier curve segment + */ +public class CubicSegment extends Segment +{ + public Point2D cp1; // control points + public Point2D cp2; // control points + + /** + * Constructor - takes coordinates of the starting point, + * first control point, second control point and end point, + * respecively. + */ + public CubicSegment(double x1, double y1, double c1x, double c1y, + double c2x, double c2y, double x2, double y2) + { + super(); + P1 = new Point2D.Double(x1, y1); + P2 = new Point2D.Double(x2, y2); + cp1 = new Point2D.Double(c1x, c1y); + cp2 = new Point2D.Double(c2x, c2y); + } + + public CubicSegment(Point2D p1, Point2D cp1, Point2D cp2, Point2D p2) + { + super(); + P1 = p1; + P2 = p2; + this.cp1 = cp1; + this.cp2 = cp2; + } + + /** + * Clones this segment + */ + public Object clone() + { + CubicSegment segment = null; + + try + { + segment = (CubicSegment) super.clone(); + + segment.P1 = (Point2D) P1.clone(); + segment.P2 = (Point2D) P2.clone(); + segment.cp1 = (Point2D) cp1.clone(); + segment.cp2 = (Point2D) cp2.clone(); + } + catch (CloneNotSupportedException cnse) + { + InternalError ie = new InternalError(); + ie.initCause(cnse); + throw ie; + } + + return segment; + } + + /** + * Get the "top" and "bottom" segments of this segment. First array element is + * p0 + normal, second is p0 - normal. + */ + public Segment[] getDisplacedSegments(double radius) + { + // It is, apparently, impossible to derive a curve parallel to a bezier + // curve (unless it's a straight line), so we have no choice but to + // approximate the displaced segments. Similar to FlattenPathIterator. + + Segment segmentTop = null; + Segment segmentBottom = null; + this.radius = radius; + + CubicCurve2D[] curves = new CubicCurve2D[10]; + curves[0] = new CubicCurve2D.Double(P1.getX(), P1.getY(), cp1.getX(), + cp1.getY(), cp2.getX(), cp2.getY(), + P2.getX(), P2.getY()); + int numCurves = 1; + + // Hard-coded a recursion limit of 10 and flatness of 1... should we make + // this an option somewhere? + while (numCurves > 0) + { + // The curve is flat enough, or we've reached our recursion limit, + // so take the current start/end points and add it as a line segment + // to our final approximated curves + if (curves[numCurves - 1].getFlatnessSq() <= (radius / 3) || numCurves == 10) + { + Segment[] displaced = new LineSegment( + curves[numCurves - 1].getP1(), + curves[numCurves - 1].getP2()).getDisplacedSegments(radius); + if (segmentTop == null) + { + segmentTop = displaced[0]; + segmentBottom = displaced[1]; + } + else + { + segmentTop.add(displaced[0]); + segmentBottom.add(displaced[1]); + } + numCurves--; + } + + // Otherwise, subdivide again and continue + else + { + CubicCurve2D left = new CubicCurve2D.Double(); + CubicCurve2D right = new CubicCurve2D.Double(); + curves[numCurves - 1].subdivide(left, right); + curves[numCurves - 1] = right; + curves[numCurves] = left; + curves[numCurves - 1] = right; + curves[numCurves] = left; + numCurves++; + } + } + + return new Segment[] { segmentTop, segmentBottom }; + } + + public void reverse() + { + Point2D temp = P1; + P1 = P2; + P2 = temp; + temp = cp1; + cp1 = cp2; + cp2 = temp; + } + + public double[] cp1() + { + return new double[]{cp1.getX(), cp1.getY()}; + } + + public double[] cp2() + { + return new double[]{cp2.getX(), cp2.getY()}; + } +} // class CubicSegment diff --git a/libjava/classpath/gnu/java/awt/java2d/ImagePaint.java b/libjava/classpath/gnu/java/awt/java2d/ImagePaint.java new file mode 100644 index 000000000..7e5fb5638 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/java2d/ImagePaint.java @@ -0,0 +1,192 @@ +/* ImagePaint.java -- Supplies the pixels for image rendering + 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.java2d; + +import java.awt.Paint; +import java.awt.PaintContext; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Transparency; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.ColorModel; +import java.awt.image.Raster; +import java.awt.image.RenderedImage; +import java.awt.image.WritableRaster; + +/** + * This class is used as a temporary Paint object to supply the pixel values + * for image rendering using the normal scanline conversion implementation. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class ImagePaint + implements Paint +{ + + /** + * The PaintContext implementation for the ImagePaint. + */ + private class ImagePaintContext + implements PaintContext + { + + /** + * The target raster. + */ + private WritableRaster target; + + /** + * Nothing to do here. + */ + public void dispose() + { + // Nothing to do here. + } + + /** + * Returns the color model. + * + * @return the color model + */ + public ColorModel getColorModel() + { + return image.getColorModel(); + } + + /** + * Supplies the pixel to be rendered. + * + * @see PaintContext#getRaster(int, int, int, int) + */ + public Raster getRaster(int x1, int y1, int w, int h) + { + ensureRasterSize(w, h); + int x2 = x1 + w; + int y2 = y1 + h; + float[] src = new float[2]; + float[] dest = new float[2]; + Raster source = image.getData(); + int minX = source.getMinX(); + int maxX = source.getWidth() + minX; + int minY = source.getMinY(); + int maxY = source.getHeight() + minY; + Object pixel = null; + for (int y = y1; y < y2; y++) + { + for (int x = x1; x < x2; x++) + { + src[0] = x; + src[1] = y; + transform.transform(src, 0, dest, 0, 1); + int dx = (int) dest[0]; + int dy = (int) dest[1]; + // Pixels outside the source image are not of interest, skip + // them. + if (dx >= minX && dx < maxX && dy >= minY && dy < maxY) + { + pixel = source.getDataElements(dx, dy, pixel); + target.setDataElements(x - x1, y - y1, pixel); + } + } + } + return target; + } + + /** + * Ensures that the target raster exists and has at least the specified + * size. + * + * @param w the requested target width + * @param h the requested target height + */ + private void ensureRasterSize(int w, int h) + { + if (target == null || target.getWidth() < w || target.getHeight() < h) + { + Raster s = image.getData(); + target = s.createCompatibleWritableRaster(w, h); + } + } + } + + /** + * The image to render. + */ + RenderedImage image; + + /** + * The transform from image space to device space. This is the inversed + * transform of the concatenated + * transform image space -> user space -> device space transform. + */ + AffineTransform transform; + + /** + * Creates a new ImagePaint for rendering the specified image using the + * specified device space -> image space transform. This transform + * is the inversed transform of the usual image space -> user space -> device + * space transform. + * + * The ImagePaint will only render the image in the specified area of + * interest (which is specified in image space). + * + * @param i the image to render + * @param t the device space to user space transform + */ + ImagePaint(RenderedImage i, AffineTransform t) + { + image = i; + transform = t; + } + + public PaintContext createContext(ColorModel cm, Rectangle deviceBounds, + Rectangle2D userBounds, + AffineTransform xform, + RenderingHints hints) + { + return new ImagePaintContext(); + } + + public int getTransparency() + { + return Transparency.OPAQUE; + } + +} diff --git a/libjava/classpath/gnu/java/awt/java2d/LineSegment.java b/libjava/classpath/gnu/java/awt/java2d/LineSegment.java new file mode 100644 index 000000000..904037989 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/java2d/LineSegment.java @@ -0,0 +1,118 @@ +/* LineSegment.java -- Line segment used for BasicStroke + 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.java2d; + + +import java.awt.geom.Point2D; + +public class LineSegment extends Segment +{ + public LineSegment(double x1, double y1, double x2, double y2) + { + super(); + P1 = new Point2D.Double(x1, y1); + P2 = new Point2D.Double(x2, y2); + } + + public LineSegment(Point2D p1, Point2D p2) + { + super(); + P1 = (Point2D) p1.clone(); + P2 = (Point2D) p2.clone(); + } + + /** + * Clones this segment + */ + public Object clone() + { + LineSegment segment = null; + + try + { + segment = (LineSegment) super.clone(); + segment.P1 = (Point2D) P1.clone(); + segment.P2 = (Point2D) P2.clone(); + } + catch (CloneNotSupportedException cnse) + { + InternalError ie = new InternalError(); + ie.initCause(cnse); + throw ie; + } + + return segment; + } + + /** + * Get the "top" and "bottom" segments of this segment. + * First array element is p0 + normal, second is p0 - normal. + */ + public Segment[] getDisplacedSegments(double radius) + { + this.radius = radius; + double x0 = P1.getX(); + double y0 = P1.getY(); + double x1 = P2.getX(); + double y1 = P2.getY(); + double[] p = normal(x0, y0, x1, y1); + Segment s1 = (new LineSegment(x0 + p[0], y0 + p[1], + x1 + p[0], y1 + p[1] )); + Segment s2 = (new LineSegment(x0 - p[0], y0 - p[1], + x1 - p[0], y1 - p[1] )); + return new Segment[]{s1, s2}; + } + + public void reverse() + { + Point2D p = P1; + P1 = P2; + P2 = p; + } + + public double[] cp1() + { + return new double[]{P2.getX(), P2.getY()}; + } + + public double[] cp2() + { + return new double[]{P1.getX(), P1.getY()}; + } +} // class LineSegment diff --git a/libjava/classpath/gnu/java/awt/java2d/PixelCoverage.java b/libjava/classpath/gnu/java/awt/java2d/PixelCoverage.java new file mode 100644 index 000000000..356021b3d --- /dev/null +++ b/libjava/classpath/gnu/java/awt/java2d/PixelCoverage.java @@ -0,0 +1,132 @@ +package gnu.java.awt.java2d; + +/** + * Stores and handles the pixel converage for a scanline. The pixel coverage + * is stored as sorted list of buckets, each of which holds information about + * the coverage for the X and Y axis. This is utilized to compute the actual + * coverage for each pixel on the scanline and finding chunks of pixels with + * equal coverage. + */ +final class PixelCoverage +{ + + /** + * One bucket in the list. + */ + private static final class Bucket + { + /** + * The X coordinate on the scanline to which this bucket belongs. + */ + int xPos; + + /** + * The X coverage. + */ + int xCov; + + /** + * The Y coverage. + */ + int yCov; + + /** + * Implements a linked list. This points to the next element of the list. + */ + Bucket next; + + /** + * Implements a linked list. This points to the previous element of the + * list. + */ + Bucket prev; + } + + /** + * The head of the sorted list of buckets. + */ + private Bucket head; + + /** + * The current bucket. We make use of the fact that the scanline converter + * always scans the scanline (and thus this list) from left to right to + * quickly find buckets or insertion points. + */ + private Bucket current; + + /** + * The bucket after the last valid bucket. Unused buckets are not thrown + * away and garbage collected. Instead, we keep them at the tail of the list + * and reuse them when necessary. + */ + private Bucket last; + + /** + * Indicates the the next scan of the scanline begins and that the next + * request will be at the beginning of this list. This makes searching and + * sorting of this list very quick. + */ + void rewind() + { + current = head; + } + + /** + * Clears the list. This does not throw away the old buckets but only + * resets the end-pointer of the list to the first element. All buckets are + * then unused and are reused when the list is filled again. + */ + void clear() + { + last = head; + } + + /** + * This adds the specified x and y coverage to the pixel at the specified + * X position. + * + * @param x the X position + * @param xc the x coverage + * @param yc the y coverage + */ + void add(int x, int xc, int yc) + { + Bucket bucket = findOrInsert(x); + bucket.xCov += xc; + bucket.yCov += yc; + } + + /** + * Finds the bucket in the list with the specified X coordinate. + * If no such bucket is found, then a new one is fetched (either a cached + * bucket from the end of the list or a newly allocated one) inserted at the + * correct position and returned. + * + * @param x the X coordinate + * + * @return a bucket to hold the coverage data + */ + private Bucket findOrInsert(int x) + { + // First search for a matching bucket. + if (head == null) + { + // Special case: the list is still empty. + head = new Bucket(); + current = head; + return head; + } + + // This performs a linear search, starting from the current bucket. + // This is reasonably efficient because access to this list is always done + // in a linear fashion and we are not more then 1 or 2 buckets away from + // the one we're looking for. + Bucket match = current; + while (match != null && match.xPos != x) + { + + } + + return match; + } +} diff --git a/libjava/classpath/gnu/java/awt/java2d/Pixelizer.java b/libjava/classpath/gnu/java/awt/java2d/Pixelizer.java new file mode 100644 index 000000000..43e53bf63 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/java2d/Pixelizer.java @@ -0,0 +1,56 @@ +/* Pixelizer.java -- Interface for the target of the rasterizer + Copyright (C) 2007 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.java2d; + +/** + * A pixelizer is responsible for actually manipulating the pixel of a drawing + * surface after the scanline conversion process. It receives coverage + * information for a scanline and adjusts the surface pixels accordingly. + */ +public interface Pixelizer +{ + + /** + * Renders the pixel for one scanline at the Y location y + * and using the coverage information in sc. + * + * @param y the scanline Y coordinate + * @param sc the coverage information + */ + void renderScanline(int y, ScanlineCoverage sc); +} diff --git a/libjava/classpath/gnu/java/awt/java2d/PolyEdge.java b/libjava/classpath/gnu/java/awt/java2d/PolyEdge.java new file mode 100644 index 000000000..eb0cc7f8f --- /dev/null +++ b/libjava/classpath/gnu/java/awt/java2d/PolyEdge.java @@ -0,0 +1,171 @@ +/* PolyEdge.java -- An edge in a polygon, used for polygon filling + 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.java2d; + +import gnu.java.math.Fixed; + +/** + * An edge in a polygon. + * + * @author Roman Kennke (kennke@aicas.com) + */ +final class PolyEdge + implements Comparable +{ + + /** + * The start and end coordinates of the edge. y0 is always smaller or equal + * than y1. + * + * These values are stored as fixed-point decimals. + */ + public int x0, y0, x1, y1; + + /** + * The slope of the edge. This is dx / dy. + * + * This is a fixed point decimal. + */ + private int slope; + + /** + * The intersection of this edge with the current scanline. + * + * This is a fixed point decimal. + */ + int xIntersection; + + /** + * Indicates whether this edge is from the clip or from the target shape. + */ + boolean isClip; + + /** + * Implements a linked list for the edge pool. + */ + PolyEdge poolNext; + + /** + * Implements a linked list for the scanline edge lists. + */ + PolyEdge scanlineNext; + + /** + * Create an uninitialized edge. + */ + PolyEdge() + { + // Nothing to do here. + } + + /** + * Creates a new PolyEdge with the specified coordinates. + * + * @param x0 the starting point, x coordinate + * @param y0 the starting point, y coordinate + * @param x1 the end point, x coordinate + * @param y1 the end point, y coordinate + */ + PolyEdge(int n, int x0, int y0, int x1, int y1, boolean clip) + { + init(n, x0, y0, x1, y1, clip); + } + + /** + * (Re-) Initializes this edge. + * + * @param x0 + * @param y0 + * @param x1 + * @param y1 + */ + void init(int n, int x0, int y0, int x1, int y1, boolean clip) + { + isClip = clip; + if (y0 < y1) + { + this.x0 = x0; + this.y0 = y0; + this.x1 = x1; + this.y1 = y1; + } + else + { + this.x0 = x1; + this.y0 = y1; + this.x1 = x0; + this.y1 = y0; + } + slope = Fixed.div(n, this.x1 - this.x0, this.y1 - this.y0); + } + + /** + * Sorts PolyEdges by the x coordinate from the minimum x value. + */ + public int compareTo(Object o) + { + PolyEdge other = (PolyEdge) o; + int comp = 0; + if (x0 < other.x0) + comp = -1; + else if (x0 > other.x0) + comp = 1; + return comp; + } + + /** + * Intersects this edge with the scanline at height y. The result is + * stored in {@link #xIntersection}. + * + * @param y the scanline + */ + void intersect(int n, int y) + { + int dy = y - y0; + int dx = Fixed.mul(n, slope, dy); + xIntersection = x0 + dx; + } + + public String toString() + { + return "Edge: " + x0 + ", " + y0 + ", " + x1 + ", " + y1 + ", slope: " + + slope + ", xIntersection: " + xIntersection + + ", isClip: " + isClip; + } +} diff --git a/libjava/classpath/gnu/java/awt/java2d/PolyEdgeComparator.java b/libjava/classpath/gnu/java/awt/java2d/PolyEdgeComparator.java new file mode 100644 index 000000000..6706f2294 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/java2d/PolyEdgeComparator.java @@ -0,0 +1,70 @@ +/* PolyEdgeComparator.java -- Sorts PolyEdges by their current intersection + points + 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.java2d; + +import java.util.Comparator; + +/** + * Sorts {@link PolyEdge}s by their current intersection points. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class PolyEdgeComparator + implements Comparator +{ + + /** + * The current scanline. + */ + int y; + + public int compare(Object o1, Object o2) + { + PolyEdge edge1 = (PolyEdge) o1; + PolyEdge edge2 = (PolyEdge) o2; + int comp = 0; + if (edge1.xIntersection < edge2.xIntersection) + comp = -1; + else if (edge1.xIntersection > edge2.xIntersection) + comp = 1; + return comp; + } + +} diff --git a/libjava/classpath/gnu/java/awt/java2d/QuadSegment.java b/libjava/classpath/gnu/java/awt/java2d/QuadSegment.java new file mode 100644 index 000000000..b8d0ff52e --- /dev/null +++ b/libjava/classpath/gnu/java/awt/java2d/QuadSegment.java @@ -0,0 +1,260 @@ +/* QuadSegment.java -- QuadCurve segment used for BasicStroke + 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.java2d; + + +import java.awt.geom.Point2D; +import java.awt.geom.QuadCurve2D; + +/** + * Quadratic Bezier curve segment + * + * Note: Most peers don't support quadratics directly, so it might make + * sense to represent them as cubics internally and just be done with it. + * I think we should be peer-agnostic, however, and stay faithful to the + * input geometry types as far as possible. + */ +public class QuadSegment extends Segment +{ + public Point2D cp; // control point + + /** + * Constructor, takes the coordinates of the start, control, + * and end point, respectively. + */ + public QuadSegment(double x1, double y1, double cx, double cy, double x2, + double y2) + { + super(); + P1 = new Point2D.Double(x1, y1); + P2 = new Point2D.Double(x2, y2); + cp = new Point2D.Double(cx, cy); + } + + public QuadSegment(Point2D p1, Point2D cp, Point2D p2) + { + super(); + P1 = p1; + P2 = p2; + this.cp = cp; + } + + public QuadSegment(QuadCurve2D curve) + { + super(); + P1 = curve.getP1(); + P2 = curve.getP2(); + this.cp = curve.getCtrlPt(); + } + + /** + * Clones this segment + */ + public Object clone() + { + QuadSegment segment = null; + + try + { + segment = (QuadSegment) super.clone(); + + segment.P1 = (Point2D) P1.clone(); + segment.P2 = (Point2D) P2.clone(); + segment.cp = (Point2D) cp.clone(); + } + catch (CloneNotSupportedException cnse) + { + InternalError ie = new InternalError(); + ie.initCause(cnse); + throw ie; + } + + return segment; + } + + /** + * Get the "top" and "bottom" segments of a given segment. + * First array element is p0 + normal, second is p0 - normal. + */ + public Segment[] getDisplacedSegments(double radius) + { + this.radius = radius; + double x0 = P1.getX(); + double y0 = P1.getY(); + double x1 = cp.getX(); + double y1 = cp.getY(); + double x2 = P2.getX(); + double y2 = P2.getY(); + + QuadCurve2D left = new QuadCurve2D.Double(); + QuadCurve2D right = new QuadCurve2D.Double(); + QuadCurve2D orig = new QuadCurve2D.Double(x0, y0, x1, y1, x2, y2); + orig.subdivide(left, right); + + QuadSegment s1 = offsetSubdivided(left, true); + QuadSegment s2 = offsetSubdivided(left, false); + + s1.add( offsetSubdivided(right, true) ); + s2.add( offsetSubdivided(right, false) ); + + return new Segment[]{s1, s2}; + } + + private QuadSegment offsetSubdivided(QuadCurve2D curve, boolean plus) + { + double[] n1 = normal(curve.getX1(), curve.getY1(), + curve.getCtrlX(), curve.getCtrlY()); + double[] n2 = normal(curve.getCtrlX(), curve.getCtrlY(), + curve.getX2(), curve.getY2()); + + Point2D cp; + QuadSegment s; + if(!plus) + { + n1[0] = -n1[0]; + n1[1] = -n1[1]; + n2[0] = -n2[0]; + n2[1] = -n2[1]; + } + + // Handle special cases where the control point is equal to an end point + // or end points are equal (ie, straight lines) + if (curve.getP1().equals(curve.getCtrlPt())) + { + cp = curve.getCtrlPt(); + cp.setLocation(cp.getX() + n2[0], cp.getY() + n2[1]); + n1[0] = n2[0]; + n1[1] = n2[1]; + } + else if (curve.getP2().equals(curve.getCtrlPt())) + { + cp = curve.getCtrlPt(); + cp.setLocation(cp.getX() + n1[0], cp.getY() + n1[1]); + n2[0] = n1[0]; + n2[1] = n1[1]; + } + else if (curve.getP1().equals(curve.getP2())) + { + cp = curve.getCtrlPt(); + + double deltaX = curve.getX1() - curve.getCtrlX(); + double deltaY = curve.getY1() - curve.getCtrlY(); + double length = Math.sqrt((deltaX * deltaX) + (deltaY * deltaY)); + double ratio = radius / length; + deltaX *= ratio; + deltaY *= ratio; + + if (plus) + cp.setLocation(cp.getX() + deltaX, cp.getY() + deltaY); + else + cp.setLocation(cp.getX() - deltaX, cp.getY() - deltaY); + } + else if (n1[0] == n2[0] && n1[1] == n2[1]) + { + cp = curve.getCtrlPt(); + cp.setLocation(cp.getX() + n1[0], cp.getY() + n1[1]); + } + else + { + cp = lineIntersection(curve.getX1() + n1[0], + curve.getY1() + n1[1], + curve.getCtrlX() + n1[0], + curve.getCtrlY() + n1[1], + curve.getCtrlX() + n2[0], + curve.getCtrlY() + n2[1], + curve.getX2() + n2[0], + curve.getY2() + n2[1], true); + } + + s = new QuadSegment(curve.getX1() + n1[0], curve.getY1() + n1[1], + cp.getX(), cp.getY(), + curve.getX2() + n2[0], curve.getY2() + n2[1]); + + return s; + } + + private Point2D lineIntersection(double X1, double Y1, + double X2, double Y2, + double X3, double Y3, + double X4, double Y4, + boolean infinite) + { + double x1 = X1; + double y1 = Y1; + double rx = X2 - x1; + double ry = Y2 - y1; + + double x2 = X3; + double y2 = Y3; + double sx = X4 - x2; + double sy = Y4 - y2; + + double determinant = sx * ry - sy * rx; + double nom = (sx * (y2 - y1) + sy * (x1 - x2)); + + // lines can be considered parallel. + if (Math.abs(determinant) < 1E-6) + return null; + + nom = nom / determinant; + + // check if lines are within the bounds + if(!infinite && (nom > 1.0 || nom < 0.0)) + return null; + + return new Point2D.Double(x1 + nom * rx, y1 + nom * ry); + } + + public void reverse() + { + Point2D p = P1; + P1 = P2; + P2 = p; + } + + public double[] cp1() + { + return new double[]{cp.getX(), cp.getY()}; + } + + public double[] cp2() + { + return new double[]{cp.getX(), cp.getY()}; + } +} diff --git a/libjava/classpath/gnu/java/awt/java2d/RasterGraphics.java b/libjava/classpath/gnu/java/awt/java2d/RasterGraphics.java new file mode 100644 index 000000000..193ea4c7c --- /dev/null +++ b/libjava/classpath/gnu/java/awt/java2d/RasterGraphics.java @@ -0,0 +1,118 @@ +/* RasterGraphics.java -- A Graphics2D impl for Rasters + 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.java2d; + +import java.awt.GraphicsConfiguration; +import java.awt.Rectangle; +import java.awt.image.ColorModel; +import java.awt.image.WritableRaster; + +/** + * A Graphics2D implementation that operates on Raster objects. This is + * primarily used for BufferedImages, but can theoretically be used on + * arbitrary WritableRasters. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class RasterGraphics + extends AbstractGraphics2D +{ + + /** + * The raster on which we operate. + */ + private WritableRaster raster; + + /** + * The color model of this Graphics instance. + */ + private ColorModel colorModel; + + public RasterGraphics(WritableRaster r, ColorModel cm) + { + super(); + raster = r; + colorModel = cm; + init(); + } + + @Override + public void renderScanline(int y, ScanlineCoverage c) + { + if (y >= getDeviceBounds().width) + return; + + super.renderScanline(y, c); + } + + /** + * Returns the color model of this Graphics object. + * + * @return the color model of this Graphics object + */ + protected ColorModel getColorModel() + { + return colorModel; + } + + /** + * Returns a WritableRaster that is used by this class to perform the + * rendering in. It is not necessary that the target surface immediately + * reflects changes in the raster. Updates to the raster are notified via + * {@link AbstractGraphics2D#updateRaster}. + * + * @return the destination raster + */ + protected WritableRaster getDestinationRaster() + { + return raster; + } + + public GraphicsConfiguration getDeviceConfiguration() + { + // TODO Auto-generated method stub + return null; + } + + @Override + protected Rectangle getDeviceBounds() + { + return this.raster.getBounds(); + } +} diff --git a/libjava/classpath/gnu/java/awt/java2d/Scanline.java b/libjava/classpath/gnu/java/awt/java2d/Scanline.java new file mode 100644 index 000000000..24c3d34d5 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/java2d/Scanline.java @@ -0,0 +1,91 @@ +/* Scanline.java -- A scanline for the scanline converter + 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.java2d; + +/** + * Represents a scanline in the {@link ScanlineConverter}. This is basically + * a sorted list of {@link PolyEdge}s that is made for maximum reuse. + */ +class Scanline +{ + + /** + * The actual edges array. The fields can be null. + */ + private PolyEdge edges; + + /** + * Clears this scanline. This only resets the number of edges to 0. The + * actual PolyEdge objects are preserved for possible later reuse. + */ + void clear() + { + edges = null; + } + + /** + * Create a new Scanline. + */ + Scanline() + { + // Nothing to do. + } + + /** + * Inserts an edge into this scanline. This is performed in a sorted fashion, + * and so that it reuses as much existing resources as possible. + */ + void addEdge(PolyEdge edge) + { + + // Allocate PolyEdge when necessary or reuse an old one. + edge.scanlineNext = edges; + edges = edge; + } + + /** + * Returns the edges queue. + * + * @return the edges queue + */ + PolyEdge getEdges() + { + return edges; + } +} diff --git a/libjava/classpath/gnu/java/awt/java2d/ScanlineConverter.java b/libjava/classpath/gnu/java/awt/java2d/ScanlineConverter.java new file mode 100644 index 000000000..2c3481b6c --- /dev/null +++ b/libjava/classpath/gnu/java/awt/java2d/ScanlineConverter.java @@ -0,0 +1,451 @@ +/* ScanlineConverter.java -- Rasterizes Shapes + Copyright (C) 2006, 2007 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.java2d; + +import gnu.java.math.Fixed; + +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.PathIterator; + +/** + * Rasterizes {@link Shape} objects on an AbstractGraphics2D. + */ +public final class ScanlineConverter +{ + + /** + * The number of digits to use for fixed point arithmetics. + */ + private static int FIXED_DIGITS = 6; + + /** + * The fixed point constant for the number one. + */ + private static int ONE = Fixed.fixedValue(FIXED_DIGITS, 1); + + /** + * The actual number of scanlines. + */ + private int numScanlines; + + /** + * The number of scanlines. This can contain more elements than we have + * scanlines. The real number of scanlines is stored in + * {@link #numScanlines}. This can also contain null values for empty + * scanlines. + */ + private Scanline[] scanlines; + + /** + * The upper bounds which correspond to the index 0 in the scanline array. + * + * This is a fixed point value. + */ + private int upperBounds; + + /** + * The resolution of the scanline converter. + * + * This is a fixed point value. + */ + private int resolution; + + /** + * The number of significant bits for the 'Y' resolution. + */ + private int yResolution; + + /** + * One half step according to the resolution. This is stored to avoid + * unnecessary operations during rendering. + */ + private int halfStep; + + /** + * This is used in {@link #addShape(PathIterator, boolean)} to + * receive the coordinates of the path. + */ + private float[] coords; + + /** + * The active edges. + */ + private ActiveEdges activeEdges; + + private PolyEdge edgePool; + private PolyEdge edgePoolLast; + + private int minY; + private int maxY; + private int minX; + private int maxX; + + /** + * Holds and manages information about the pixel coverage. + */ + private ScanlineCoverage scanlineCoverage; + + /** + * Create a new ScanlineConverter. + */ + ScanlineConverter() + { + scanlines = new Scanline[10]; + coords = new float[6]; + activeEdges = new ActiveEdges(); + edgePool = new PolyEdge(); + edgePoolLast = edgePool; + scanlineCoverage = new ScanlineCoverage(); + } + + /** + * Renders the specified shape using the specified clip and transform. + * + * @param p the pixelizer that receives the coverage information + * @param shape the shape to render + * @param clip the clip + * @param trans the transform + */ + public void renderShape(Pixelizer p, Shape shape, Shape clip, + AffineTransform trans, int res, int yRes, + RenderingHints hints) + { + // TODO: Do something useful with the rendering hints. Like, adjusting + // the resolution. + + // Prepare resolution and upper bounds. + clear(); + setResolution(res, yRes); + + boolean haveClip = clip != null; + + // Add shapes. + float flatness = Fixed.floatValue(FIXED_DIGITS, resolution / 2); + PathIterator path = shape.getPathIterator(trans, flatness); + addShape(path, false); + if (haveClip) + { + path= clip.getPathIterator(trans, flatness); + addShape(path, true); + } + + setUpperBounds(minY); + + PolyEdge edge = edgePool; + while (edge != edgePoolLast) + { + addEdge(edge); + edge = edge.poolNext; + } + + int y = upperBounds; + int index; + activeEdges.clear(); + // The render loop... + Scanline scanline = null; + int lastRealY = Fixed.intValue(FIXED_DIGITS, y); + while (y <= maxY) + { + // First we put together our list of active edges. + index = scanlineIndex(y); + // If we go outside the scanline array we still need to render the + // remaining edges until they end. + scanline = index < scanlines.length ? scanlines[index] : null; + if (scanline != null) + { + edge = scanline.getEdges(); + while (edge != null) + { + activeEdges.add(edge); + edge = edge.scanlineNext; + } + } + + // Then we intersect all active edges with the current scanline + // and sort them according to their intersection points. + activeEdges.intersectSortAndPack(FIXED_DIGITS, y + halfStep); + + // Ok, now we can perform the actual scanlining. + int realY = Fixed.intValue(FIXED_DIGITS, y + resolution); + boolean push = lastRealY != realY; + + doScanline(p, y, push, haveClip); + + // Remove obsolete active edges. + //activeEdges.remove(y + halfStep); + // Go on with the next line... + y += resolution; + lastRealY = realY; + + } + } + + /** + * Clears all scanlines. + */ + private void clear() + { + // Reset edge pool. + edgePoolLast = edgePool; + + // Reset scanlines. + for (int i = scanlines.length - 1; i >= 0 ; i--) + { + Scanline sl = scanlines[i]; + if (sl != null) + sl.clear(); + } + + // Reset scanline coverage. + scanlineCoverage.clear(); + + // Reset bounds. + minY = Integer.MAX_VALUE; + maxY = Integer.MIN_VALUE; + minX = Integer.MAX_VALUE; + maxX = Integer.MIN_VALUE; + } + + /** + * Performs the scanlining on the current set of active edges. + * + * @param p the pixelizer to receive the pixel coverage data + * @param y the Y coordinate + * @param push true when the scanline is ready to be pushed to the + * pixelizer + * @param haveClip true when there's a clip, false otherwise + */ + private void doScanline(Pixelizer p, int y, boolean push, + boolean haveClip) + { + // First, rewind the scanline coverage. + scanlineCoverage.rewind(); + + // We begin outside the clip and outside the shape. We only draw when + // we are inside the clip AND inside the shape. + boolean inClip = ! haveClip; + boolean inShape = false; + PolyEdge lastEdge = null; + int numEdges = activeEdges.getNumActiveEdges(); + for (int i = 0; i < numEdges; i++) + { + PolyEdge edge = activeEdges.getActiveEdge(i); + if (inClip && inShape) + { + assert lastEdge != null; + int x0 = lastEdge.xIntersection; + int x1 = edge.xIntersection; + assert x0 <= x1; + + int pix0 = Fixed.intValue(FIXED_DIGITS, x0); + int pix1 = Fixed.intValue(FIXED_DIGITS, x1); + int frac0 = ONE - Fixed.trunc(FIXED_DIGITS, x0); + int frac1 = ONE - Fixed.trunc(FIXED_DIGITS, x1); + // Only keep the first 4 digits after the point. + frac0 = frac0 >> (FIXED_DIGITS - yResolution); + frac1 = frac1 >> (FIXED_DIGITS - yResolution); + scanlineCoverage.add(pix0, 1 * (1 << yResolution), frac0); + scanlineCoverage.add(pix1, -1 * (1 << yResolution), -frac1); + } + if (edge.isClip) + inClip = ! inClip; + else + inShape = ! inShape; + + lastEdge = edge; + } + + // Push out the whole scanline to the pixelizer. + if (push && ! scanlineCoverage.isEmpty()) + { + p.renderScanline(Fixed.intValue(FIXED_DIGITS, y), scanlineCoverage); + scanlineCoverage.clear(); + } + } + + + /** + * Sets the resolution. A value of 0 rasterizes the shape normally without + * anti-aliasing. Greater values renders with a resolution of 2 ^ res. + * + * @param res the resolution + */ + private void setResolution(int res, int yRes) + { + int scanlinesPerPixel = 1 << res; + int one = Fixed.fixedValue(FIXED_DIGITS, 1); + resolution = one / (scanlinesPerPixel); + halfStep = resolution / 2; + + scanlineCoverage.setMaxCoverage(scanlinesPerPixel << yResolution); + + yResolution = yRes; + } + + /** + * Sets the vertical bounds of that shape that is beeing rendered. + * + * @param y0 the upper bounds + */ + private void setUpperBounds(int y0) + { + upperBounds = fit(y0); + } + + /** + * Add a shape to the scanline converter. + * + * @param path + * @param clip + */ + private void addShape(PathIterator path, boolean clip) + { + int startX = 0; + int startY = 0; + int lastX = 0; + int lastY = 0; + while (! path.isDone()) + { + int type = path.currentSegment(coords); + switch (type) + { + case PathIterator.SEG_MOVETO: + startX = lastX = Fixed.fixedValue(FIXED_DIGITS, coords[0]); + startY = lastY = Fixed.fixedValue(FIXED_DIGITS, coords[1]); + minY = Math.min(startY, minY); + maxY = Math.max(startY, maxY); + minX = Math.min(startX, minX); + maxX = Math.max(startX, maxX); + break; + case PathIterator.SEG_LINETO: + int x = Fixed.fixedValue(FIXED_DIGITS, coords[0]); + int y = Fixed.fixedValue(FIXED_DIGITS, coords[1]); + edgePoolAdd(lastX, lastY, x, y, clip); + lastX = x; + lastY = y; + minY = Math.min(lastY, minY); + maxY = Math.max(lastY, maxY); + minX = Math.min(lastX, minX); + maxX = Math.max(lastX, maxX); + break; + case PathIterator.SEG_CLOSE: + edgePoolAdd(lastX, lastY, startX, startY, clip); + lastX = startX; + lastY = startY; + break; + case PathIterator.SEG_CUBICTO: + case PathIterator.SEG_QUADTO: + default: + assert false; + } + path.next(); + } + } + + /** + * Adds an edge into the scanline array. + */ + private void addEdge(PolyEdge edge) + { + // Determine index. + int upper = Math.min(edge.y0, edge.y1); + // Fit to raster. + int index = scanlineIndex(upper); + // Grow array when necessary. + if (index >= scanlines.length) + { + int oldSize = scanlines.length; + int newSize = Math.max(oldSize + oldSize / 2 + 1, index + 10); + Scanline[] newScanlines = new Scanline[newSize]; + System.arraycopy(scanlines, 0, newScanlines, 0, oldSize); + scanlines = newScanlines; + } + + // Add edge. + if (scanlines[index] == null) + { + scanlines[index] = new Scanline(); + } + scanlines[index].addEdge(edge); + } + + /** + * Fits an Y coordinate to the grid. + * + * @param y the Y coordinate to fit + * + * @return the fitted Y coordinate + */ + private int fit(int y) + { + int val1 = Fixed.div(FIXED_DIGITS, y, resolution); + int rounded = Fixed.round(FIXED_DIGITS, val1); + return Fixed.mul(FIXED_DIGITS, rounded, resolution); + } + + /** + * Calculates the scanline index for the specified y coordinate. + * + * @param y the y coordinate as fixed point value + * + * @return the scanline index + */ + private int scanlineIndex(int y) + { + int fitted = fit(y); + // Cleverly skip the fixed point conversions here. + return (fitted - upperBounds)/ resolution; + } + + private void edgePoolAdd(int x0, int y0, int x1, int y1, boolean clip) + { + // Don't need no horizontal edges. + if (y0 != y1) + { + edgePoolLast.init(FIXED_DIGITS, x0, y0, x1, y1, clip); + if (edgePoolLast.poolNext == null) + { + edgePoolLast.poolNext = new PolyEdge(); + } + edgePoolLast = edgePoolLast.poolNext; + } + } +} diff --git a/libjava/classpath/gnu/java/awt/java2d/ScanlineCoverage.java b/libjava/classpath/gnu/java/awt/java2d/ScanlineCoverage.java new file mode 100644 index 000000000..9ffb63e1d --- /dev/null +++ b/libjava/classpath/gnu/java/awt/java2d/ScanlineCoverage.java @@ -0,0 +1,630 @@ +/* ScanlineCoverage.java -- Manages coverage information for a scanline + Copyright (C) 2007 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.java2d; + +/** + * Stores and handles the pixel converage for a scanline. The pixel coverage + * is stored as sorted list of {@linke Covergage} entries, each of which holds + * information about the coverage for the X and Y axis. This is utilized to + * compute the actual coverage for each pixel on the scanline and finding + * chunks of pixels with equal coverage quickly. + */ +public final class ScanlineCoverage +{ + + /** + * Iterates over the coverage list and calculates the actual coverage + * ranges on a scanline. + */ + public final class Iterator + { + /** + * This instance is reused in the iteration. + */ + private Range range; + + /** + * The pointer to the current item in the iteration. + */ + private Coverage currentItem; + + /** + * The current coverage value. + */ + private int currentCoverage; + + /** + * True when the current pixel coverage has already been handled, false + * otherwise. + */ + private boolean handledPixelCoverage; + + /** + * Creates a new CoverageIterator. + */ + Iterator() + { + range = new Range(); + } + + /** + * Returns the next coverage range on the scanline. The returned object + * will always be the same object, but with different values. Keep that + * in mind when dealing with this object. + * + * @return the next coverage range on the scanline + */ + public Range next() + { + // TODO: Lump together the single-pixel coverage and the + // between-pixel coverage when the pixel coverage delta is 0. + if (handledPixelCoverage == false) + { + // Handle single pixel coverage. + range.setXPos(currentItem.xPos); + range.setLength(1); + range.setCoverage(currentCoverage + currentItem.pixelCoverage); + handledPixelCoverage = true; + } + else + { + // Handle pixel span coverage. + currentCoverage += currentItem.covDelta; + range.setCoverage(currentCoverage); + range.setXPos(currentItem.xPos + 1); + currentItem = currentItem.next; + range.setLength(currentItem.xPos - range.xPos); + handledPixelCoverage = false; + } + return range; + } + + /** + * Returns {@ true} when there are more coverage ranges to iterate, + * {@ false} otherwise. + * + * @return {@ true} when there are more coverage ranges to iterate, + * {@ false} otherwise + */ + public boolean hasNext() + { + boolean hasNext; + if (currentItem != null && handledPixelCoverage == false) + { + // We have at least one more coverage item when there's a pixel + // coverage piece left. + hasNext = true; + } + else if (currentItem == null || currentItem.next == null + || currentItem.next == last) + { + hasNext = false; + } + else + { + hasNext = true; + } + return hasNext; + } + + /** + * Resets this iterator to the start of the list. + */ + void reset() + { + currentItem = head; + currentCoverage = 0; + handledPixelCoverage = false; + } + } + + /** + * A data object that carries information about pixel coverage on a scanline. + * The data consists of a starting X position on the scanline, the + * length of the range in pixels and the actual coverage value. + **/ + public static final class Range + { + /** + * The X position on the scanline, in pixels. + */ + private int xPos; + + /** + * The length of the range, in pixels. + */ + private int length; + + /** + * The actual coverage. The relation depends on + * {@link ScanlineCoverage#maxCoverage}. + */ + private int coverage; + + /** + * Creates a new CoverageRange object. + */ + Range() + { + // Nothing to do. The values get initialized in the corresponding + // setters. + } + + /** + * Sets the X start position (left) on the scanline. This value is + * considered to be in pixels and device space. + * + * @param x the x position + */ + void setXPos(int x) + { + xPos = x; + } + + /** + * Returns the X start position (left) on the scanline. This value + * is considered to be in pixels and device space. + * + * @return the X position on the scanline + */ + public int getXPos() + { + return xPos; + } + + /** + * Sets the length of the pixel range. This is in pixel units. + * + * @param l the length of the range + */ + void setLength(int l) + { + length = l; + } + + /** + * Returns the length of the range in pixel units. + * + * @return the length of the range in pixel units + */ + public int getLength() + { + return length; + } + + /** + * Returns the first X position after the range. + * + * @return the first X position after the range + */ + public int getXPosEnd() + { + return xPos + length; + } + + /** + * Sets the coverage of the pixel range. The relation of that value + * depends on {@link ScanlineCoverage#maxCoverage}. + * + * @param cov the coverage value for the pixel range + */ + void setCoverage(int cov) + { + coverage = cov; + } + + /** + * Returns the coverage of the pixel range. The relation of this value + * depends on {@link ScanlineCoverage#getMaxCoverage()}. + * + * @return the coverage of the pixel range + */ + public int getCoverage() + { + return coverage; + } + + /** + * Returns a string representation. + */ + public String toString() + { + return "Coverage range: xPos=" + xPos + ", length=" + length + + ", coverage: " + coverage; + } + } + + /** + * One bucket in the list. + */ + private static final class Coverage + { + /** + * The X coordinate on the scanline to which this bucket belongs. + */ + int xPos; + + /** + * The coverage delta from the pixel at xPos to xPos + 1. + */ + int covDelta; + + /** + * The delta for the pixel at xPos. This is added to the pixel at xPos, + * but not to the following pixel. + */ + int pixelCoverage; + + /** + * Implements a linked list. This points to the next element of the list. + */ + Coverage next; + + /** + * Returns the X coordinate for this entry. + * + * @return the X coordinate for this entry + */ + public int getXPos() + { + return xPos; + } + + /** + * Returns the coverage delta for this entry. + * + * @return the coverage delta for this entry + */ + public int getCoverageDelta() + { + return covDelta; + } + + /** + * Returns a string representation. + * + * @return a string representation + */ + public String toString() + { + return "Coverage: xPos: " + xPos + ", covDelta: " + covDelta; + } + + /** + * Returns a string representation of this entry and all the following + * in the linked list. + * + * @return a string representation of this entry and all the following + * in the linked list + */ + public String list() + { + String str = toString(); + if (next != null) + str = str + " --> " + next.list(); + return str; + } + } + + /** + * The head of the sorted list of buckets. + */ + private Coverage head; + + /** + * The current bucket. We make use of the fact that the scanline converter + * always scans the scanline (and thus this list) from left to right to + * quickly find buckets or insertion points. + */ + private Coverage current; + + /** + * The item that is before current in the list. + */ + private Coverage currentPrev; + + /** + * The bucket after the last valid bucket. Unused buckets are not thrown + * away and garbage collected. Instead, we keep them at the tail of the list + * and reuse them when necessary. + */ + private Coverage last; + + /** + * The last valid entry. + */ + private Coverage lastPrev; + + /** + * The minimum X coordinate of this scanline. + */ + private int minX; + + /** + * The maximum X coordinate of this scanline. + */ + private int maxX; + + /** + * The maximum coverage value. + */ + private int maxCoverage; + + /** + * The iterator over the ranges of this scanline. + */ + private Iterator iterator; + + /** + * Creates a new ScanlineCoverage instance. + */ + public ScanlineCoverage() + { + iterator = new Iterator(); + } + + /** + * Indicates the the next scan of the scanline begins and that the next + * request will be at the beginning of this list. This makes searching and + * sorting of this list very quick. + */ + public void rewind() + { + current = head; + currentPrev = null; + } + + /** + * Clears the list. This does not throw away the old buckets but only + * resets the end-pointer of the list to the first element. All buckets are + * then unused and are reused when the list is filled again. + */ + public void clear() + { + last = head; + lastPrev = null; + current = head; + currentPrev = null; + minX = Integer.MAX_VALUE; + maxX = Integer.MIN_VALUE; + } + + /** + * This adds the specified coverage to the pixel at the specified + * X position. + * + * @param x the X position + * @param xc the x coverage + * @param yc the y coverage + */ + public void add(int x, int xc, int yc) + { + Coverage bucket = findOrInsert(x); + bucket.covDelta += xc; + bucket.pixelCoverage += yc; + minX = Math.min(minX, x); + maxX = Math.max(maxX, x); + } + + /** + * Returns the maximum coverage value for the scanline. + * + * @return the maximum coverage value for the scanline + */ + public int getMaxCoverage() + { + return maxCoverage; + } + + /** + * Sets the maximum coverage value for the scanline. + * + * @param maxCov the maximum coverage value for the scanline + */ + void setMaxCoverage(int maxCov) + { + maxCoverage = maxCov; + } + + /** + * Returns the maximum X coordinate of the current scanline. + * + * @return the maximum X coordinate of the current scanline + */ + public int getMaxX() + { + return maxX; + } + + /** + * Returns the minimum X coordinate of the current scanline. + * + * @return the minimum X coordinate of the current scanline + */ + public int getMinX() + { + return minX; + } + + /** + * Finds the bucket in the list with the specified X coordinate. + * If no such bucket is found, then a new one is fetched (either a cached + * bucket from the end of the list or a newly allocated one) inserted at the + * correct position and returned. + * + * @param x the X coordinate + * + * @return a bucket to hold the coverage data + */ + private Coverage findOrInsert(int x) + { + // First search for a matching bucket. + if (head == null) + { + // Special case: the list is still empty. + // Testpoint 1. + head = new Coverage(); + head.xPos = x; + current = head; + currentPrev = null; + return head; + } + + // This performs a linear search, starting from the current bucket. + // This is reasonably efficient because access to this list is always done + // in a linear fashion and we are usually not more then 1 or 2 buckets away + // from the one we're looking for. + Coverage match = current; + Coverage prev = currentPrev; + while (match != last && match.xPos < x) + { + prev = match; + match = match.next; + } + + // At this point we have either found an entry with xPos >= x, or reached + // the end of the list (match == last || match == null). + if (match == null) + { + // End of the list. No cached items to reuse. + // Testpoint 2. + match = new Coverage(); + match.xPos = x; + if (prev != null) + prev.next = match; + current = match; + currentPrev = prev; + return match; + } + else if (match == last) + { + // End of the list. Reuse this item. Expand list. + // Testpoint 3. + last = match.next; + lastPrev = match; + match.xPos = x; + match.covDelta = 0; + match.pixelCoverage = 0; + // Keep link to last element or null, indicating the end of the list. + current = match; + currentPrev = prev; + return match; + } + + if (x == match.xPos) + { + // Special case: We have another coverage entry at the same location + // as an already existing entry. Return this. + // Testpoint 4. + current = match; + currentPrev = prev; + return match; + } + else // x <= match.xPos + { + assert (x <= match.xPos); + assert (prev == null ||x > prev.xPos); + + // Create new entry, or reuse existing one. + Coverage cov; + if (last != null) + { + // Testpoint 5. + cov = last; + last = cov.next; + lastPrev.next = last; + } + else + { + // Testpoint 6. + cov = new Coverage(); + } + + cov.xPos = x; + cov.covDelta = 0; + cov.pixelCoverage = 0; + + // Insert this item in the list. + if (prev != null) + { + // Testpoint 5 & 6. + prev.next = cov; + cov.next = match; + current = cov; + currentPrev = prev; + } + else + { + // Testpoint 7. + assert (match == head); + // Insert at head. + head = cov; + head.next = match; + current = head; + currentPrev = null; + } + return cov; + } + } + + /** + * (Re-)Starts iterating the coverage values for the scanline. + * Use the returned iterator to get the consecutive coverage ranges. + * + * @return the iterator + */ + public Iterator iterate() + { + iterator.reset(); + return iterator; + } + + /** + * Returns {@ true} if this object has no entries for the current scanline, + * {@ false} otherwise. + * + * @return {@ true} if this object has no entries for the current scanline, + * {@ false} otherwise + */ + public boolean isEmpty() + { + return head == null || head == last + || head.next == null || head.next == last; + } + +} diff --git a/libjava/classpath/gnu/java/awt/java2d/Segment.java b/libjava/classpath/gnu/java/awt/java2d/Segment.java new file mode 100644 index 000000000..1d9a57001 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/java2d/Segment.java @@ -0,0 +1,158 @@ +/* Segment.java -- Abstract segment used for BasicStroke + 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.java2d; + +import java.awt.geom.Point2D; + +public abstract class Segment implements Cloneable +{ + // Start and end points of THIS segment + public Point2D P1; + public Point2D P2; + + // Segments can be linked together internally as a linked list + public Segment first; + public Segment next; + public Segment last; + + // Half the stroke width + protected double radius; + + /** + * Create a new, empty segment + */ + public Segment() + { + P1 = P2 = null; + first = this; + next = null; + last = this; + } + + /** + * Add a segment to the polygon + * @param newsegment segment to add + */ + public void add(Segment newsegment) + { + newsegment.first = first; + last.next = newsegment; + last = last.next.last; + } + + /** + * Reverses the orientation of the whole polygon + */ + public void reverseAll() + { + reverse(); + first = last; + Segment v = next; + Segment former = this; + next = null; + + while (v != null) + { + v.reverse(); + v.last = this; + Segment oldnext = v.next; + v.next = former; + + former = v; + v = oldnext; // move to the next in list + } + } + + public String toString() + { + return "Segment:"+P1+", "+P2; + } + + /** + * Get the normal vector to the slope of the line. + * @return vector of length radius, normal to the (x0,y0)-(x1,y1) vector) + */ + protected double[] normal(double x0, double y0, double x1, double y1) + { + double dx = (x1 - x0); + double dy = (y1 - y0); + if( dy == 0 ) + { + dy = radius * ((dx > 0)?1:-1); + dx = 0; + } + else if( dx == 0 ) + { + dx = radius * ((dy > 0)?-1:1); + dy = 0; + } + else + { + double N = Math.sqrt(dx * dx + dy * dy); + double odx = dx; + dx = -radius * dy / N; + dy = radius * odx / N; + } + return new double[]{ dx, dy }; + } + + /** + * Reverse the current segment + */ + public abstract void reverse(); + + /** + * Get the "top" and "bottom" segments of a segment. + * First array element is p0 + normal, second is p0 - normal. + */ + public abstract Segment[] getDisplacedSegments(double radius); + + /** + * Returns the coordinates of the first control point, or the start point + * for a line segment. + */ + public abstract double[] cp1(); + + /** + * Returns the coordinates of the second control point, or the end point + * for a line segment. + */ + public abstract double[] cp2(); + +} diff --git a/libjava/classpath/gnu/java/awt/java2d/ShapeCache.java b/libjava/classpath/gnu/java/awt/java2d/ShapeCache.java new file mode 100644 index 000000000..89a9ac4ab --- /dev/null +++ b/libjava/classpath/gnu/java/awt/java2d/ShapeCache.java @@ -0,0 +1,90 @@ +/* ShapeCache.java -- Caches certain Shapes for reuse in AbstractGraphics2D + 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.java2d; + +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.geom.Arc2D; +import java.awt.geom.Ellipse2D; +import java.awt.geom.GeneralPath; +import java.awt.geom.Line2D; +import java.awt.geom.RoundRectangle2D; + +/** + * Caches certain Shape objects for reuse in AbstractGraphics2D. This avoids + * massive creation of such objects. + */ +public class ShapeCache +{ + + /** + * A cached Line2D. + */ + public Line2D line; + + /** + * A cached Rectangle. + */ + public Rectangle rect; + + /** + * A cached RoundRectangle2D. + */ + public RoundRectangle2D roundRect; + + /** + * A cached Ellipse2D. + */ + public Ellipse2D ellipse; + + /** + * A cached Arc2D. + */ + public Arc2D arc; + + /** + * A cached Polygon. + */ + public Polygon polygon; + + /** + * A cached polyline. + */ + public GeneralPath polyline; +} diff --git a/libjava/classpath/gnu/java/awt/java2d/ShapeWrapper.java b/libjava/classpath/gnu/java/awt/java2d/ShapeWrapper.java new file mode 100644 index 000000000..f4e77f450 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/java2d/ShapeWrapper.java @@ -0,0 +1,119 @@ +/* ShapeWrapper.java -- Protects shapes by wrapping them + Copyright (C) 2007 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.java2d; + +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.PathIterator; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +/** + * Protects any other shape from beeing modified by wrapping it. + */ +public class ShapeWrapper + implements Shape +{ + + /** + * The shape to be protected. + */ + private Shape shape; + + /** + * Creates a new ShapeWrapper. + * + * @param other the shape to be protected + */ + public ShapeWrapper(Shape other) + { + shape = other; + } + + public boolean contains(double x, double y) + { + return shape.contains(x, y); + } + + public boolean contains(Point2D p) + { + return shape.contains(p); + } + + public boolean contains(double x, double y, double w, double h) + { + return shape.contains(x, y, w, h); + } + + public boolean contains(Rectangle2D r) + { + return shape.contains(r); + } + + public Rectangle getBounds() + { + return shape.getBounds(); + } + + public Rectangle2D getBounds2D() + { + return shape.getBounds2D(); + } + + public PathIterator getPathIterator(AffineTransform transform) + { + return shape.getPathIterator(transform); + } + + public PathIterator getPathIterator(AffineTransform transform, double flatness) + { + return shape.getPathIterator(transform, flatness); + } + + public boolean intersects(double x, double y, double w, double h) + { + return shape.intersects(x, y, w, h); + } + + public boolean intersects(Rectangle2D r) + { + return shape.intersects(r); + } + +} diff --git a/libjava/classpath/gnu/java/awt/java2d/TextCacheKey.java b/libjava/classpath/gnu/java/awt/java2d/TextCacheKey.java new file mode 100644 index 000000000..0a60c6226 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/java2d/TextCacheKey.java @@ -0,0 +1,153 @@ +/* TextCacheKey.java -- Key to use for caching texts with their rendered layout + Copyright (C) 2007 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.java2d; + +import java.awt.Font; +import java.awt.font.FontRenderContext; + +/** + * A key object to be used when caching pre-rendered text. + */ +public class TextCacheKey +{ + + /** + * The actual string. + */ + private String string; + + /** + * The font render context. + */ + private FontRenderContext fontRenderContext; + + /** + * The font. + */ + private Font font; + + /** + * Creates a new TextCacheKey. + * + * This is intended to be used as search key. It is important to initialize + * the values using the setter methods before using this key, otherwise + * it will throw NPEs. + */ + public TextCacheKey() + { + // No-arg constructor. + } + + /** + * Creates a new TextCacheKey with initial values. + * + * @param s the string + * @param f the font + * @param frc the font render context + */ + public TextCacheKey(String s, Font f, FontRenderContext frc) + { + string = s; + font = f; + fontRenderContext = frc; + } + + /** + * Re-sets the string. This is intented to be used in search keys only. + * + * @param s the string to set + */ + public void setString(String s) + { + string = s; + } + + /** + * Sets the font render context. + * This is intented to be used in search keys only. + * + * @param frc the new font render context + */ + public void setFontRenderContext(FontRenderContext frc) + { + fontRenderContext = frc; + } + + /** + * Sets the font. + * This is intented to be used in search keys only. + * + * @param f the font to set + */ + public void setFont(Font f) + { + font = f; + } + + /** + * Determines if two objects are equal. + * + * @see Object#equals(Object) + */ + public boolean equals(Object o) + { + boolean eq; + if (o instanceof TextCacheKey) + { + TextCacheKey other = (TextCacheKey) o; + eq = other.string.equals(string) + && other.font.equals(font) + && other.fontRenderContext.equals(fontRenderContext); + } + else + { + eq = false; + } + return eq; + } + + /** + * Computes a hashcode for this key. + * + * @see Object#hashCode() + */ + public int hashCode() + { + return string.hashCode() ^ font.hashCode() ^ fontRenderContext.hashCode(); + } +} diff --git a/libjava/classpath/gnu/java/awt/java2d/TexturePaintContext.java b/libjava/classpath/gnu/java/awt/java2d/TexturePaintContext.java new file mode 100644 index 000000000..2523d2311 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/java2d/TexturePaintContext.java @@ -0,0 +1,211 @@ +/* TexturePaintContext.java -- PaintContext impl for TexturePaint + 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.java2d; + +import java.awt.AWTError; +import java.awt.PaintContext; +import java.awt.Rectangle; +import java.awt.TexturePaint; +import java.awt.geom.AffineTransform; +import java.awt.geom.NoninvertibleTransformException; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; + +/** + * A {@link PaintContext} implementation for {@link TexturePaint}, done in + * pure Java. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class TexturePaintContext + implements PaintContext +{ + + /** + * The TexturePaint object. + */ + private BufferedImage image; + + /** + * The Raster that holds the texture. + */ + private WritableRaster paintRaster; + + /** + * The transform from userspace into device space. + */ + private AffineTransform transform; + + /** + * Creates a new TexturePaintContext for the specified TexturePaint object. + * This initializes the Raster which is returned by + * {@link #getRaster(int, int, int, int)}. + * + * @param t the texture paint object + * @param db the bounds of the target raster in device space + * @param ub the bounds of the target raster in user space + * @param xform the transformation from user space to device space + */ + public TexturePaintContext(TexturePaint t, Rectangle db, + Rectangle2D ub, AffineTransform xform) + { + image = t.getImage(); + + try + { + // Prepare transform for mapping from device space into image space. + // In order to achieve this we take the transform for userspace-> + // devicespace, append the correct scale and translation according + // to the anchor (which gives us the image->userspace->devicespace + // transform), and invert that (which gives use the device->user->image + // transform). + Rectangle2D anchor = t.getAnchorRect(); + BufferedImage image = t.getImage(); + double scaleX = anchor.getWidth() / image.getWidth(); + double scaleY = anchor.getHeight() / image.getHeight(); + transform = (AffineTransform) xform.clone(); + transform.scale(scaleX, scaleY); + transform.translate(-anchor.getMinX(), -anchor.getMinY()); + transform = transform.createInverse(); + } + catch (NoninvertibleTransformException ex) + { + AWTError err = + new AWTError("Unexpected NoninvertibleTransformException"); + err.initCause(ex); + throw err; + } + } + + /** + * Disposes the PaintContext. Nothing is to do here, since we don't use + * any native resources in that implementation. + */ + public void dispose() + { + // Nothing to do here. + } + + /** + * Returns the color model of this PaintContext. This implementation returnes + * the color model used by the BufferedImage in the TexturePaint object, + * this avoids costly color model transformations (at least at this point). + * + * @return the color model of this PaintContext + */ + public ColorModel getColorModel() + { + return image.getColorModel(); + } + + /** + * Returns the Raster that is used for painting. + * + * @param x1 the x location of the raster inside the user bounds of this paint + * context + * @param y1 the y location of the raster inside the user bounds of this paint + * context + * @param w the width + * @param h the height + * + * @return the Raster that is used for painting + * + */ + public Raster getRaster(int x1, int y1, int w, int h) + { + ensureRasterSize(w, h); + int x2 = x1 + w; + int y2 = y1 + h; + float[] src = new float[2]; + float[] dest = new float[2]; + Raster source = image.getData(); + int minX = source.getMinX(); + int width = source.getWidth(); + int minY = source.getMinY(); + int height = source.getHeight(); + Object pixel = null; + for (int y = y1; y < y2; y++) + { + for (int x = x1; x < x2; x++) + { + // Transform the coordinates from device space into image space. + src[0] = x; + src[1] = y; + transform.transform(src, 0, dest, 0, 1); + int dx = (int) dest[0]; + int dy = (int) dest[1]; + + // The modulo operation gives us the replication effect. + dx = ((dx - minX) % width) + minX; + dy = ((dy - minY) % height) + minY; + + // Handle possible negative values (replicating above the top-left) + if (dx < 0) + dx += width; + if (dy < 0) + dy += height; + + // Copy the pixel. + pixel = source.getDataElements(dx, dy, pixel); + paintRaster.setDataElements(x - x1, y - y1, pixel); + } + } + return paintRaster; + } + + /** + * Ensures that the target raster exists and has at least the specified + * size. + * + * @param w the requested target width + * @param h the requested target height + */ + private void ensureRasterSize(int w, int h) + { + if (paintRaster == null || paintRaster.getWidth() < w + || paintRaster.getHeight() < h) + { + Raster s = image.getData(); + paintRaster = s.createCompatibleWritableRaster(w, h); + } + } +} diff --git a/libjava/classpath/gnu/java/awt/package.html b/libjava/classpath/gnu/java/awt/package.html new file mode 100644 index 000000000..166168510 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.awt + + +

+ + + diff --git a/libjava/classpath/gnu/java/awt/peer/ClasspathDesktopPeer.java b/libjava/classpath/gnu/java/awt/peer/ClasspathDesktopPeer.java new file mode 100644 index 000000000..fd4f498aa --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/ClasspathDesktopPeer.java @@ -0,0 +1,301 @@ +/* ClasspathDesktopPeer.java -- Offers a concrete implementation for DesktopPeer + Copyright (C) 2006, 2007 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; + +import java.awt.AWTPermission; +import java.awt.Desktop.Action; +import java.awt.peer.DesktopPeer; + +import java.io.File; +import java.io.IOException; + +import java.net.URI; + +import java.util.prefs.Preferences; + +/** + * Offers a common implementation for the Desktop peers, that enables + * access to default system application within java processes. + * + * @author Mario Torre + */ +public class ClasspathDesktopPeer + implements DesktopPeer +{ + /** This is the fallback browser, if no desktop was detected. */ + protected static final String _DEFAULT_BROWSER = "firefox"; + + /** gnu.java.awt.peer.Desktop.html.command */ + protected static final String _BROWSE = "html"; + + /** gnu.java.awt.peer.Desktop.mail.command */ + protected static final String _MAIL = "mail"; + + /** gnu.java.awt.peer.Desktop.edit.command */ + protected static final String _EDIT = "edit"; + + /** gnu.java.awt.peer.Desktop.print.command */ + protected static final String _PRINT = "print"; + + /** gnu.java.awt.peer.Desktop.open.command */ + protected static final String _OPEN = "open"; + + /** */ + protected static final KDEDesktopPeer kde = new KDEDesktopPeer(); + + /** */ + protected static final GnomeDesktopPeer gnome = new GnomeDesktopPeer(); + + /** */ + protected static final ClasspathDesktopPeer classpath = + new ClasspathDesktopPeer(); + + /** + * Preference subsystem. Packagers and users can override the default + * behaviour of this class via preferences and system properties. + */ + protected Preferences prefs = + Preferences.userNodeForPackage(ClasspathDesktopPeer.class).node("Desktop"); + + /** + * @param target + */ + protected ClasspathDesktopPeer() + { + /* nothing to do */ + } + + public boolean isSupported(Action action) + { + String check = null; + + switch(action) + { + case BROWSE: + check = _BROWSE; + break; + + case MAIL: + check = _MAIL; + break; + + case EDIT: + check = _EDIT; + break; + + case PRINT: + check = _PRINT; + break; + + case OPEN: default: + check = _OPEN; + break; + } + + return this.supportCommand(check); + } + + public void browse(URI url) throws IOException + { + checkPermissions(); + + String browser = getCommand(_BROWSE); + + if (browser == null) + throw new UnsupportedOperationException(); + + browser = browser + " " + url.toString(); + + Runtime.getRuntime().exec(browser); + } + + public void edit(File file) throws IOException + { + checkPermissions(file, false); + + String edit = getCommand(_EDIT); + + if (edit == null) + throw new UnsupportedOperationException(); + + edit = edit + " " + file.getAbsolutePath(); + Runtime.getRuntime().exec(edit); + } + + public void mail(URI mailtoURL) throws IOException + { + checkPermissions(); + + String scheme = mailtoURL.getScheme(); + if (scheme == null || !scheme.equalsIgnoreCase("mailto")) + throw new IllegalArgumentException("URI Scheme not of type mailto"); + + String mail = getCommand(_MAIL); + + if (mail == null) + throw new UnsupportedOperationException(); + + mail = mail + " " + mailtoURL.toString(); + + Runtime.getRuntime().exec(mail); + } + + public void mail() throws IOException + { + checkPermissions(); + + String mail = getCommand(_MAIL); + + if (mail == null) + throw new UnsupportedOperationException(); + + Runtime.getRuntime().exec(mail); + } + + public void open(File file) throws IOException + { + checkPermissions(file, true); + + String open = getCommand(_OPEN); + + if (open == null) + throw new UnsupportedOperationException(); + + open = open + " " + file.getAbsolutePath(); + Runtime.getRuntime().exec(open); + } + + public void print(File file) throws IOException + { + checkPrintPermissions(file); + + String print = getCommand(_PRINT); + + if (print == null) + throw new UnsupportedOperationException(); + + print = print + " " + file.getAbsolutePath(); + Runtime.getRuntime().exec(print); + } + + protected String getCommand(String action) + { + // check if a system property exist + String command = + System.getProperty("gnu.java.awt.peer.Desktop." + action + ".command"); + + // otherwise, get it from preferences, if any + if (command == null) + { + command = prefs.node(action).get("command", null); + } + + return command; + } + + /** + * Note: Checks for AWTPermission("showWindowWithoutWarningBanner") only. + */ + protected void checkPermissions() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new AWTPermission("showWindowWithoutWarningBanner")); + } + } + + /** + * Calls checkPermissions() and checks for SecurityManager.checkRead() + * and, if readOnly is false, for SecurityManager.checkWrite() + */ + protected void checkPermissions(File file, boolean readOnly) + { + checkPermissions(); + + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkRead(file.toString()); + if (!readOnly) sm.checkWrite(file.toString()); + } + } + + /** + * Calls checkPermissions(file, true) and checks for + * SecurityManager.checkPrintJobAccess() + */ + protected void checkPrintPermissions(File file) + { + checkPermissions(file, true); + + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPrintJobAccess(); + } + } + + /** + * @param check + * @return + */ + protected boolean supportCommand(String check) + { + return ((this.getCommand(check) != null) ? true : false); + } + + /** + * @return + */ + public static DesktopPeer getDesktop() + { + // check if we are under Gnome or KDE or anything else + String desktopSession = System.getenv("GNOME_DESKTOP_SESSION_ID"); + if (desktopSession == null) + { + desktopSession = System.getenv("KDE_FULL_SESSION"); + if (desktopSession != null) + return kde; + } + else + { + return gnome; + } + + // revert to this class for default values + return classpath; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/ClasspathFontPeer.java b/libjava/classpath/gnu/java/awt/peer/ClasspathFontPeer.java new file mode 100644 index 000000000..96677a4af --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/ClasspathFontPeer.java @@ -0,0 +1,865 @@ +/* ClasspathFontPeer.java -- Font peer used by GNU Classpath. + Copyright (C) 2003, 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.awt.peer; + +import gnu.java.awt.ClasspathToolkit; + +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Toolkit; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.font.LineMetrics; +import java.awt.font.TextAttribute; +import java.awt.font.TransformAttribute; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.peer.FontPeer; +import java.text.AttributedCharacterIterator; +import java.text.CharacterIterator; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Locale; +import java.util.Map; + +/** + * A peer for fonts that are used inside Classpath. The purpose of + * this interface is to abstract from platform-specific font handling + * in the Classpath implementation of java.awt.Font and related + * classes. + * + *

State kept by the peer: a peer is generated for each Font + * object in the default implementation. If you wish to share peers between + * fonts, you will need to subclass both ClasspathFontPeer and + * {@link ClasspathToolKit}.

+ * + *

Thread Safety: Methods of this interface may be called + * from arbitrary threads at any time. Implementations of the + * ClasspathFontPeer interface are required to perform + * the necessary synchronization.

+ * + * @see java.awt.Font#getPeer + * @see java.awt.Toolkit#getFontPeer + * + * @author Sascha Brawer (brawer@dandelis.ch) + * @author Graydon Hoare (graydon@redhat.com) + */ +public abstract class ClasspathFontPeer + implements FontPeer +{ + + /*************************************************************************/ + + /* + * Instance Variables + */ + + /** + * The 3 names of this font. all fonts have 3 names, some of which + * may be equal: + * + * logical -- name the font was constructed from + * family -- a designer or brand name (Helvetica) + * face -- specific instance of a design (Helvetica Regular) + * + * @see isLogicalFontName + */ + + protected String logicalName; + protected String familyName; + protected String faceName; + + /** + * The font style, which is a combination (by OR-ing) of the font style + * constants PLAIN, BOLD and ITALIC, in this class. + */ + protected int style; + + /** + * The font point size. A point is 1/72 of an inch. + */ + protected float size; + + /** + * The affine transformation the font is currently subject to. + */ + protected AffineTransform transform; + + static class LRUCache extends LinkedHashMap + { + int max_entries; + public LRUCache(int max) + { + super(max, 0.75f, true); + max_entries = max; + } + protected boolean removeEldestEntry(Map.Entry eldest) + { + return size() > max_entries; + } + } + + private static LRUCache transCache = + new LRUCache(50); + + protected static ClasspathToolkit tk() + { + return (ClasspathToolkit)(Toolkit.getDefaultToolkit ()); + } + + /* + * Confusingly, a Logical Font is a concept unrelated to + * a Font's Logical Name. + * + * A Logical Font is one of 6 built-in, abstract font types + * which must be supported by any java environment: SansSerif, + * Serif, Monospaced, Dialog, and DialogInput. + * + * A Font's Logical Name is the name the font was constructed + * from. This might be the name of a Logical Font, or it might + * be the name of a Font Face. + */ + + protected static boolean isLogicalFontName(String name) + { + String uname = name.toUpperCase (); + return (uname.equals ("SANSSERIF") || + uname.equals ("SERIF") || + uname.equals ("MONOSPACED") || + uname.equals ("DIALOG") || + uname.equals ("DIALOGINPUT") || + uname.equals ("DEFAULT")); + } + + protected static String logicalFontNameToFaceName (String name) + { + String uname = name.toUpperCase (); + if (uname.equals("SANSSERIF")) + return "Helvetica"; + else if (uname.equals ("SERIF")) + return "Times"; + else if (uname.equals ("MONOSPACED")) + return "Courier"; + else if (uname.equals ("DIALOG")) + return "Helvetica"; + else if (uname.equals ("DIALOGINPUT")) + return "Helvetica"; + else if (uname.equals ("DEFAULT")) + return "Dialog.plain"; + else + return "Helvetica"; + } + + protected static String faceNameToFamilyName (String name) + { + return name; + } + + public static void copyStyleToAttrs (int style, Map attrs) + { + if ((style & Font.BOLD) == Font.BOLD) + attrs.put (TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD); + else + attrs.put (TextAttribute.WEIGHT, TextAttribute.WEIGHT_REGULAR); + + if ((style & Font.ITALIC) == Font.ITALIC) + attrs.put (TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE); + else + attrs.put (TextAttribute.POSTURE, TextAttribute.POSTURE_REGULAR); + } + + protected static void copyFamilyToAttrs (String fam, Map attrs) + { + if (fam != null) + attrs.put (TextAttribute.FAMILY, fam); + } + + public static void copySizeToAttrs (float size, Map attrs) + { + attrs.put (TextAttribute.SIZE, new Float (size)); + } + + protected static void copyTransformToAttrs (AffineTransform trans, Map attrs) + { + if (trans != null) + { + TransformAttribute ta; + synchronized(transCache) + { + ta = transCache.get(trans); + if (ta == null) + { + ta = new TransformAttribute(trans); + transCache.put(trans, ta); + } + } + attrs.put(TextAttribute.TRANSFORM, ta); + } + } + + + protected void setStandardAttributes (String name, String family, int style, + float size, AffineTransform trans) + { + this.logicalName = name; + + if (isLogicalFontName (name)) + this.faceName = logicalFontNameToFaceName (name); + else + this.faceName = name; + + if (family != null) + this.familyName = family; + else + this.familyName = faceNameToFamilyName (faceName); + + this.style = style; + this.size = size; + this.transform = trans; + } + + + protected void setStandardAttributes (String name, Map attribs) + { + String family = this.familyName; + AffineTransform trans = this.transform; + float size = this.size; + int style = this.style; + + if (attribs.containsKey (TextAttribute.FAMILY)) + family = (String) attribs.get (TextAttribute.FAMILY); + + if (name == null) + name = "Default"; + + if (attribs.containsKey (TextAttribute.WEIGHT)) + { + Float weight = (Float) attribs.get (TextAttribute.WEIGHT); + if (weight.floatValue () >= TextAttribute.WEIGHT_BOLD.floatValue ()) + style += Font.BOLD; + } + + if (attribs.containsKey (TextAttribute.POSTURE)) + { + Float posture = (Float) attribs.get (TextAttribute.POSTURE); + if (posture.floatValue () >= TextAttribute.POSTURE_OBLIQUE.floatValue ()) + style += Font.ITALIC; + } + + if (attribs.containsKey (TextAttribute.SIZE)) + { + Float sz = (Float) attribs.get (TextAttribute.SIZE); + size = sz.floatValue (); + + // Pango doesn't accept 0 as a font size. + if (size < 1) + size = 1; + } + else + size = 12; + + if (attribs.containsKey (TextAttribute.TRANSFORM)) + { + TransformAttribute ta = (TransformAttribute) + attribs.get(TextAttribute.TRANSFORM); + trans = ta.getTransform (); + } + + setStandardAttributes (name, family, style, size, trans); + } + + protected void getStandardAttributes (Map attrs) + { + copyFamilyToAttrs (this.familyName, attrs); + copySizeToAttrs (this.size, attrs); + copyStyleToAttrs (this.style, attrs); + copyTransformToAttrs (this.transform, attrs); + } + + + /* Begin public API */ + + public ClasspathFontPeer (String name, Map attrs) + { + setStandardAttributes (name, attrs); + } + + public ClasspathFontPeer (String name, int style, int size) + { + setStandardAttributes (name, (String)null, style, + (float)size, (AffineTransform)null); + } + + /** + * Implementation of {@link Font#getName} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public String getName (Font font) + { + return logicalName; + } + + /** + * Implementation of {@link Font#getFamily()} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public String getFamily (Font font) + { + return familyName; + } + + /** + * Implementation of {@link Font#getFamily(Locale)} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public String getFamily (Font font, Locale lc) + { + return familyName; + } + + /** + * Implementation of {@link Font#getFontName()} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public String getFontName (Font font) + { + return faceName; + } + + /** + * Implementation of {@link Font#getFontName(Locale)} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public String getFontName (Font font, Locale lc) + { + return faceName; + } + + /** + * Implementation of {@link Font#getSize} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public float getSize (Font font) + { + return size; + } + + /** + * Implementation of {@link Font#isPlain} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public boolean isPlain (Font font) + { + return style == Font.PLAIN; + } + + /** + * Implementation of {@link Font#isBold} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public boolean isBold (Font font) + { + return ((style & Font.BOLD) == Font.BOLD); + } + + /** + * Implementation of {@link Font#isItalic} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public boolean isItalic (Font font) + { + return ((style & Font.ITALIC) == Font.ITALIC); + } + + /** + * Implementation of {@link Font#deriveFont(int, float)} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public Font deriveFont (Font font, int style, float size) + { + Map attrs = new HashMap (); + getStandardAttributes (attrs); + copyStyleToAttrs (style, attrs); + copySizeToAttrs (size, attrs); + return tk().getFont (logicalName, attrs); + } + + /** + * Implementation of {@link Font#deriveFont(float)} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public Font deriveFont (Font font, float size) + { + Map attrs = new HashMap (); + getStandardAttributes (attrs); + copySizeToAttrs (size, attrs); + return tk().getFont (logicalName, attrs); + } + + /** + * Implementation of {@link Font#deriveFont(int)} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public Font deriveFont (Font font, int style) + { + Map attrs = new HashMap (); + getStandardAttributes (attrs); + copyStyleToAttrs (style, attrs); + return tk().getFont (logicalName, attrs); + } + + /** + * Implementation of {@link Font#deriveFont(int, AffineTransform)} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public Font deriveFont (Font font, int style, AffineTransform t) + { + Map attrs = new HashMap (); + getStandardAttributes (attrs); + copyStyleToAttrs (style, attrs); + copyTransformToAttrs (t, attrs); + return tk().getFont (logicalName, attrs); + } + + /** + * Implementation of {@link Font#deriveFont(AffineTransform)} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public Font deriveFont (Font font, AffineTransform t) + { + Map attrs = new HashMap (); + getStandardAttributes (attrs); + copyTransformToAttrs (t, attrs); + return tk().getFont (logicalName, attrs); + } + + /** + * Implementation of {@link Font#deriveFont(Map)} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public Font deriveFont (Font font, Map attrs) + { + return tk().getFont (logicalName, attrs); + } + + /** + * Implementation of {@link Font#getAttributes()} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public Map getAttributes (Font font) + { + HashMap h = new HashMap (); + getStandardAttributes (h); + return h; + } + + /** + * Implementation of {@link Font#getAvailableAttributes()} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public AttributedCharacterIterator.Attribute[] getAvailableAttributes(Font font) + { + AttributedCharacterIterator.Attribute a[] = + new AttributedCharacterIterator.Attribute[5]; + a[0] = TextAttribute.FAMILY; + a[1] = TextAttribute.SIZE; + a[2] = TextAttribute.POSTURE; + a[3] = TextAttribute.WEIGHT; + a[4] = TextAttribute.TRANSFORM; + return a; + } + + /** + * Implementation of {@link Font#getTransform()} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public AffineTransform getTransform (Font font) + { + if (transform == null) + transform = new AffineTransform (); + return transform; + } + + /** + * Implementation of {@link Font#isTransformed()} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public boolean isTransformed (Font font) + { + return ! transform.isIdentity (); + } + + /** + * Implementation of {@link Font#getItalicAngle()} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public float getItalicAngle (Font font) + { + if ((style & Font.ITALIC) == Font.ITALIC) + return TextAttribute.POSTURE_OBLIQUE.floatValue (); + else + return TextAttribute.POSTURE_REGULAR.floatValue (); + } + + + /** + * Implementation of {@link Font#getStyle()} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public int getStyle (Font font) + { + return style; + } + + + + + /* Remaining methods are abstract */ + + /** + * Implementation of {@link Font#canDisplay(char)} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public abstract boolean canDisplay (Font font, int c); + + /** + * Implementation of {@link Font#canDisplay(String)}, + * {@link Font#canDisplay(char [], int, int)}, and + * {@link Font#canDisplay(CharacterIterator, int, int)}. + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public abstract int canDisplayUpTo (Font font, CharacterIterator i, int start, int limit); + + + /** + * Returns the name of this font face inside the family, for example + * “Light”. + * + *

This method is currently not used by {@link Font}. However, + * this name would be needed by any serious desktop publishing + * application. + * + * @param font the font whose sub-family name is requested. + * + * @param locale the locale for which to localize the name. If + * locale is null, the returned name is + * localized to the user’s default locale. + * + * @return the name of the face inside its family, or + * null if the font does not provide a sub-family name. + */ + + public abstract String getSubFamilyName (Font font, Locale locale); + + + /** + * Implementation of {@link Font#getPSName()} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public abstract String getPostScriptName (Font font); + + + /** + * Implementation of {@link Font#getNumGlyphs()} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public abstract int getNumGlyphs (Font font); + + + /** + * Implementation of {@link Font#getMissingGlyphCode()} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public abstract int getMissingGlyphCode (Font font); + + + /** + * Implementation of {@link Font#getBaselineFor(char)} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public abstract byte getBaselineFor (Font font, char c); + + + /** + * Returns a name for the specified glyph. This is useful for + * generating PostScript or PDF files that embed some glyphs of a + * font. If the implementation follows glyph naming conventions + * specified by Adobe, search engines can extract the original text + * from the generated PostScript and PDF files. + * + *

This method is currently not used by GNU Classpath. However, + * it would be very useful for someone wishing to write a good + * PostScript or PDF stream provider for the + * javax.print package. + * + *

Names are not unique: Under some rare circumstances, + * the same name can be returned for different glyphs. It is + * therefore recommended that printer drivers check whether the same + * name has already been returned for antoher glyph, and make the + * name unique by adding the string ".alt" followed by the glyph + * index.

+ * + *

This situation would occur for an OpenType or TrueType font + * that has a post table of format 3 and provides a + * mapping from glyph IDs to Unicode sequences through a + * Zapf table. If the same sequence of Unicode + * codepoints leads to different glyphs (depending on contextual + * position, for example, or on typographic sophistication level), + * the same name would get synthesized for those glyphs. To avoid + * this, the font peer would have to go through the names of all + * glyphs, which would make this operation very inefficient with + * large fonts. + * + * @param font the font containing the glyph whose name is + * requested. + * + * @param glyphIndex the glyph whose name the caller wants to + * retrieve. + * + * @return the glyph name, or null if a font does not + * provide glyph names. + */ + + public abstract String getGlyphName (Font font, int glyphIndex); + + + /** + * Implementation of {@link + * Font#createGlyphVector(FontRenderContext, String)}, {@link + * Font#createGlyphVector(FontRenderContext, char[])}, and {@link + * Font#createGlyphVector(FontRenderContext, CharacterIterator)}. + * + * @param font the font object that the created GlyphVector will return + * when it gets asked for its font. This argument is needed because the + * public API of {@link GlyphVector} works with {@link java.awt.Font}, + * not with font peers. + */ + + public abstract GlyphVector createGlyphVector (Font font, + FontRenderContext frc, + CharacterIterator ci); + + + /** + * Implementation of {@link Font#createGlyphVector(FontRenderContext, + * int[])}. + * + * @param font the font object that the created GlyphVector will return + * when it gets asked for its font. This argument is needed because the + * public API of {@link GlyphVector} works with {@link java.awt.Font}, + * not with font peers. + */ + + public abstract GlyphVector createGlyphVector (Font font, + FontRenderContext ctx, + int[] glyphCodes); + + + /** + * Implementation of {@link Font#layoutGlyphVector(FontRenderContext, + * char[], int, int, int)}. + * + * @param font the font object that the created GlyphVector will return + * when it gets asked for its font. This argument is needed because the + * public API of {@link GlyphVector} works with {@link java.awt.Font}, + * not with font peers. + */ + + public abstract GlyphVector layoutGlyphVector (Font font, + FontRenderContext frc, + char[] chars, int start, + int limit, int flags); + + + /** + * Implementation of {@link Font#getFontMetrics()} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public abstract FontMetrics getFontMetrics (Font font); + + + /** + * Implementation of {@link Font#hasUniformLineMetrics()} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public abstract boolean hasUniformLineMetrics (Font font); + + + /** + * Implementation of {@link Font#getLineMetrics(CharacterIterator, int, + * int, FontRenderContext)} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public abstract LineMetrics getLineMetrics (Font font, + CharacterIterator ci, + int begin, int limit, + FontRenderContext rc); + + /** + * Implementation of {@link Font#getMaxCharBounds(FontRenderContext)} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public abstract Rectangle2D getMaxCharBounds (Font font, + FontRenderContext rc); + +} diff --git a/libjava/classpath/gnu/java/awt/peer/EmbeddedWindowPeer.java b/libjava/classpath/gnu/java/awt/peer/EmbeddedWindowPeer.java new file mode 100644 index 000000000..4c64a1d2d --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/EmbeddedWindowPeer.java @@ -0,0 +1,47 @@ +/* EmbeddedWindowPeer.java -- Interface for window peers that may be + embedded into other applications + Copyright (C) 2003 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; + +import java.awt.peer.FramePeer; + +public interface EmbeddedWindowPeer extends FramePeer +{ + void embed (long handle); +} diff --git a/libjava/classpath/gnu/java/awt/peer/GLightweightPeer.java b/libjava/classpath/gnu/java/awt/peer/GLightweightPeer.java new file mode 100644 index 000000000..fe128c26c --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/GLightweightPeer.java @@ -0,0 +1,461 @@ +/* GLightweightPeer.java -- + Copyright (C) 2003, 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.awt.peer; + +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.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Toolkit; +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.ContainerPeer; +import java.awt.peer.LightweightPeer; + +/** + * A stub class that implements the ComponentPeer and ContainerPeer + * interfaces using callbacks into the Component and Container + * classes. GLightweightPeer allows the Component and Container + * classes to treat lightweight and heavyweight peers in the same way. + * + * Lightweight components are painted directly onto their parent + * containers through an Image object provided by the toolkit. + */ +public class GLightweightPeer + implements LightweightPeer, ContainerPeer +{ + public GLightweightPeer() + { + // Nothing to do here. + } + + // -------- java.awt.peer.ContainerPeer implementation: + + public Insets insets() + { + // Nothing to do here for lightweights. + return null; + } + + public Insets getInsets() + { + // Nothing to do here for lightweights. + return null; + } + + public void beginValidate() + { + // Nothing to do here for lightweights. + } + + public void endValidate() + { + // Nothing to do here for lightweights. + } + + public void beginLayout() + { + // Nothing to do here for lightweights. + } + + public void endLayout() + { + // Nothing to do here for lightweights. + } + + public boolean isPaintPending() + { + // Nothing to do here for lightweights. + return false; + } + + // -------- java.awt.peer.ComponentPeer implementation: + + public int checkImage(Image img, int width, int height, ImageObserver o) + { + // Nothing to do here for lightweights. + return -1; + } + + public Image createImage(ImageProducer prod) + { + // Nothing to do here for lightweights. + return null; + } + + /* This method is not called. */ + public Image createImage(int width, int height) + { + // Nothing to do here for lightweights. + return null; + } + + public void disable() + { + // Nothing to do here for lightweights. + } + + public void dispose() + { + // Nothing to do here for lightweights. + } + + public void enable() + { + // Nothing to do here for lightweights. + } + + public GraphicsConfiguration getGraphicsConfiguration() + { + // Nothing to do here for lightweights. + return null; + } + + public FontMetrics getFontMetrics(Font f) + { + // We shouldn't end up here, but if we do we can still try do something + // reasonable. + Toolkit tk = Toolkit.getDefaultToolkit(); + return tk.getFontMetrics(f); + } + + /* Returning null here tells the Component object that called us to + * use its parent's Graphics. */ + public Graphics getGraphics() + { + // Nothing to do here for lightweights. + return null; + } + + public Point getLocationOnScreen() + { + // Nothing to do here for lightweights. + return null; + } + + public Dimension getMinimumSize() + { + return minimumSize(); + } + + public Dimension getPreferredSize() + { + return preferredSize(); + } + + /* Returning null here tells the Component object that called us to + * use its parent's Toolkit. */ + public Toolkit getToolkit() + { + // Nothing to do here for lightweights. + return null; + } + + public void handleEvent(AWTEvent e) + { + // This can only happen when an application posts a PaintEvent for + // a lightweight component directly. We still support painting for + // this case. + if (e instanceof PaintEvent) + { + PaintEvent pe = (PaintEvent) e; + Component target = (Component) e.getSource(); + if (target != null && target.isShowing()) + { + Graphics g = target.getGraphics(); + if (g != null) + { + try + { + Rectangle clip = pe.getUpdateRect(); + g.setClip(clip); + target.paint(g); + } + finally + { + g.dispose(); + } + } + } + } + } + + public void hide() + { + // Nothing to do here for lightweights. + } + + public boolean isFocusable() + { + // Nothing to do here for lightweights. + return false; + } + + public boolean isFocusTraversable() + { + // Nothing to do here for lightweights. + return false; + } + + public Dimension minimumSize() + { + return new Dimension(0, 0); + } + + public Dimension preferredSize() + { + return new Dimension(0, 0); + } + + public void paint(Graphics graphics) + { + // Nothing to do here for lightweights. + } + + public boolean prepareImage(Image img, int width, int height, + ImageObserver o) + { + // Nothing to do here for lightweights. + return false; + } + + public void print(Graphics graphics) + { + // Nothing to do here for lightweights. + } + + public void repaint(long tm, int x, int y, int width, int height) + { + // Nothing to do here for lightweights. + } + + public void requestFocus() + { + // Nothing to do here for lightweights. + } + + public boolean requestFocus(Component source, boolean bool1, boolean bool2, + long x) + { + // Nothing to do here for lightweights. + return false; + } + + public void reshape(int x, int y, int width, int height) + { + // Nothing to do here for lightweights. + } + + public void setBackground(Color color) + { + // Nothing to do here for lightweights. + } + + public void setBounds(int x, int y, int width, int height) + { + // Nothing to do here for lightweights. + } + + /** + * Sets the cursor on the heavy-weight parent peer. + * Called by the MouseListener on mouse enter. + */ + public void setCursor(Cursor cursor) + { + // Nothing to do here for lightweights. + } + + public void setEnabled(boolean enabled) + { + // Nothing to do here for lightweights. + } + + public void setEventMask(long eventMask) + { + // Nothing to do here for lightweights. + } + + public void setFont(Font font) + { + // Nothing to do here for lightweights. + } + + public void setForeground(Color color) + { + // Nothing to do here for lightweights. + } + + public void setVisible(boolean visible) + { + // Nothing to do here for lightweights. + } + + public void show() + { + // Nothing to do here for lightweights. + } + + public ColorModel getColorModel() + { + // Nothing to do here for lightweights. + return null; + } + + public boolean isObscured() + { + // Nothing to do here for lightweights. + return false; + } + + public boolean canDetermineObscurity() + { + // Nothing to do here for lightweights. + return false; + } + + public void coalescePaintEvent(PaintEvent e) + { + // Nothing to do here for lightweights. + } + + public void updateCursorImmediately() + { + // Nothing to do here for lightweights. + } + + public VolatileImage createVolatileImage(int width, int height) + { + // Nothing to do here for lightweights. + return null; + } + + public boolean handlesWheelScrolling() + { + // Nothing to do here for lightweights. + return false; + } + + public void createBuffers(int x, BufferCapabilities capabilities) + throws AWTException + { + // Nothing to do here for lightweights. + } + + public Image getBackBuffer() + { + // Nothing to do here for lightweights. + return null; + } + + public void flip(BufferCapabilities.FlipContents contents) + { + // Nothing to do here for lightweights. + } + + public void destroyBuffers() + { + // Nothing to do here for lightweights. + } + + public boolean isRestackSupported() + { + // Nothing to do here for lightweights. + return false; + } + + public void cancelPendingPaint(int x, int y, int width, int height) + { + // Nothing to do here for lightweights. + } + + public void restack() + { + // Nothing to do here for lightweights. + } + + public Rectangle getBounds() + { + // Nothing to do here for lightweights. + return null; + } + + public void reparent(ContainerPeer parent) + { + // Nothing to do here for lightweights. + } + + public void setBounds(int x, int y, int z, int width, int height) + { + // Nothing to do here for lightweights. + } + + public boolean isReparentSupported() + { + // Nothing to do here for lightweights. + return true; + } + + public void layout() + { + // Nothing to do here for lightweights. + } + + public boolean requestFocus(Component lightweightChild, boolean temporary, + boolean focusedWindowChangeAllowed, + long time, sun.awt.CausedFocusEvent.Cause cause) + { + // Always grant focus request. + return true; + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/GnomeDesktopPeer.java b/libjava/classpath/gnu/java/awt/peer/GnomeDesktopPeer.java new file mode 100644 index 000000000..2347371ad --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/GnomeDesktopPeer.java @@ -0,0 +1,155 @@ +/* GnomeDesktopPeer.java -- Offers a GNOME Desktop peer for DesktopPeer + Copyright (C) 2006, 2007 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; + +import gnu.java.lang.CPStringBuilder; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; + +/** + * @author Mario Torre + */ +public class GnomeDesktopPeer + extends ClasspathDesktopPeer +{ + /** + * Query string to use if a GNOME desktop is detected to get the name of the + * default browser. This requires gconftool-2 (part of GNOME). + */ + private static final String BROWSER_QUERY_GNOME = + "gconftool-2 -g /desktop/gnome/url-handlers/http/command"; + + protected String getCommand(String action) + { + // check if a command already exists + String command = super.getCommand(action); + + if (command == null) + { + try + { + if (action == _BROWSE) + { + command = execQuery(BROWSER_QUERY_GNOME); + } + else if (action == _PRINT) + { + command = null; + } + else + { + command = "gnome-open"; + } + } + catch (Exception e) + { + command = null; + } + } + + return command; + } + + public void browse(URI url) throws IOException + { + checkPermissions(); + + String browser = getCommand(_BROWSE); + + if (browser == null) + throw new UnsupportedOperationException(); + + browser = browser + " " + url.toString(); + + Runtime.getRuntime().exec(browser); + } + + protected boolean supportCommand(String check) + { + if (check == _PRINT) + { + return super.supportCommand(check); + } + + return true; + } + + public void mail() throws IOException + { + checkPermissions(); + + String mail = getCommand(_MAIL); + + if (mail == null) + throw new UnsupportedOperationException(); + + Runtime.getRuntime().exec(mail + " mailto:"); + } + + protected String execQuery(String command) throws IOException + { + InputStream in = null; + CPStringBuilder output = new CPStringBuilder(); + + try + { + Process process = Runtime.getRuntime().exec(command); + + // Get the input stream and read from it + in = process.getInputStream(); + int c; + while ((c = in.read()) != - 1) + { + output.append((char) c); + } + } + finally + { + if (in != null) + in.close(); + } + + // remove %s from the string, leave only the command line + int index = output.indexOf("%s"); + output.delete(index, index + 1); + + return output.toString().trim(); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/KDEDesktopPeer.java b/libjava/classpath/gnu/java/awt/peer/KDEDesktopPeer.java new file mode 100644 index 000000000..44a508435 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/KDEDesktopPeer.java @@ -0,0 +1,135 @@ +/* GnomeDesktopPeer.java -- Offers a KDE Desktop peer for DesktopPeer + Copyright (C) 2006, 2007 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; + +import gnu.java.lang.CPStringBuilder; + +import java.io.IOException; +import java.io.InputStream; + +/** + * @author Mario Torre + */ +public class KDEDesktopPeer + extends ClasspathDesktopPeer +{ + /** + * Query string to use if a GNOME desktop is detected to get the name of the + * default browser. This requires gconftool-2 (part of GNOME). + */ + private static final String BROWSER_QUERY_GNOME = + "gconftool-2 -g /desktop/gnome/url-handlers/http/command"; + + protected String getCommand(String action) + { + // check if a command already exists + String command = super.getCommand(action); + + if (command == null) + { + try + { + if (action == _MAIL) + { + command = "kfmclient exec"; + } + else if (action == _PRINT) + { + command = "kprinter"; + } + else + { + command = "kfmclient openURL"; + } + } + catch (Exception e) + { + command = null; + } + } + + return command; + } + + protected boolean supportCommand(String check) + { + return true; + } + + public void mail() throws IOException + { + checkPermissions(); + + String mail = getCommand(_MAIL); + + if (mail == null) + throw new UnsupportedOperationException(); + + Runtime.getRuntime().exec(mail + " 'mailto: '"); + } + + protected String execQuery(String command) throws IOException + { + InputStream in = null; + CPStringBuilder output = new CPStringBuilder(); + + try + { + Process process = Runtime.getRuntime().exec(command); + + // Get the input stream and read from it + in = process.getInputStream(); + int c; + while ((c = in.read()) != - 1) + { + output.append((char) c); + } + } + finally + { + if (in != null) + in.close(); + } + + // remove %s from the string, leave only the command line + int index = output.indexOf("%s"); + output.delete(index, index + 1); + + return output.toString().trim(); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/NativeEventLoopRunningEvent.java b/libjava/classpath/gnu/java/awt/peer/NativeEventLoopRunningEvent.java new file mode 100644 index 000000000..962ecd990 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/NativeEventLoopRunningEvent.java @@ -0,0 +1,58 @@ +/* NativeEventLoopRunningEvent.java -- communicates to EventQueue the + state of the native event loop + 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; + +import java.awt.AWTEvent; + +public class NativeEventLoopRunningEvent + extends AWTEvent +{ + private boolean running; + + public NativeEventLoopRunningEvent(Object source) + { + super(source, 2999); + running = ((Boolean) source).booleanValue(); + } + + public boolean isRunning() + { + return running; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/AsyncImage.java b/libjava/classpath/gnu/java/awt/peer/gtk/AsyncImage.java new file mode 100644 index 000000000..786dcf26b --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/AsyncImage.java @@ -0,0 +1,283 @@ +/* AsyncImage.java -- Loads images 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 gnu.java.awt.peer.gtk; + +import java.awt.Graphics; +import java.awt.Image; +import java.awt.image.ImageConsumer; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; + +/** + * Supports asynchronous loading of images. + */ +public class AsyncImage + extends Image +{ + + /** + * Returned as source as long as the image is not complete. + */ + private class NullImageSource + implements ImageProducer + { + private ArrayList consumers; + + NullImageSource() + { + consumers = new ArrayList(); + } + + 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 requestTopDownLeftRightResend(ImageConsumer ic) + { + startProduction(ic); + } + + public void startProduction(ImageConsumer ic) + { + consumers.add(ic); + for (int i = consumers.size() - 1; i >= 0; i--) + { + ImageConsumer c = (ImageConsumer) consumers.get(i); + c.setDimensions(1, 1); + ic.imageComplete(ImageConsumer.SINGLEFRAMEDONE); + } + } + + } + + /** + * Loads the image asynchronously. + */ + private class Loader + implements Runnable + { + private URL url; + Loader(URL u) + { + url = u; + } + + public void run() + { + Image image; + try + { + GtkImage gtkImage = new GtkImage(url); + image = CairoSurface.getBufferedImage(gtkImage); + } + catch (IllegalArgumentException iae) + { + image = null; + } + realImage = GtkToolkit.imageOrError(image); + synchronized (AsyncImage.this) + { + notifyObservers(ImageObserver.ALLBITS | ImageObserver.HEIGHT + | ImageObserver.WIDTH | ImageObserver.PROPERTIES); + observers = null; // Not needed anymore. + } + } + } + + /** + * The real image. This is null as long as the image is not complete. + */ + Image realImage; + + /** + * The image observers. + * + * This is package private to avoid accessor methods. + */ + HashSet observers; + + /** + * Creates a new AsyncImage that loads from the specified URL. + */ + AsyncImage(URL url) + { + observers = new HashSet(); + Loader l = new Loader(url); + Thread t = new Thread(l); + t.start(); + } + + public void flush() + { + // Nothing to do here. + } + + public Graphics getGraphics() + { + Image r = realImage; + Graphics g = null; + if (r != null) + g = r.getGraphics(); // Should we return some dummy graphics instead? + return g; + } + + public int getHeight(ImageObserver observer) + { + addObserver(observer); + int height = 0; + Image r = realImage; + if (r != null) + height = r.getHeight(observer); + return height; + } + + public Object getProperty(String name, ImageObserver observer) + { + addObserver(observer); + Image r = realImage; + Object prop = null; + if (r != null) + prop = r.getProperty(name, observer); + return prop; + } + + public ImageProducer getSource() + { + Image r = realImage; + ImageProducer source; + if (r == null) + source = new NullImageSource(); + else + source = r.getSource(); + return source; + } + + public int getWidth(ImageObserver observer) + { + addObserver(observer); + int width = 0; + Image r = realImage; + if (r != null) + width = r.getWidth(observer); + return width; + } + + void addObserver(ImageObserver obs) + { + if (obs != null) + { + synchronized (this) + { + // This field gets null when image loading is complete and we don't + // need to store any more observers. + HashSet observs = observers; + if (observs != null) + { + observs.add(obs); + } + else + { + // When the image is complete, notify the observer. Dunno if + // that's really needed, but to be sure. + obs.imageUpdate(this, ImageObserver.WIDTH + | ImageObserver.HEIGHT + |ImageObserver.ALLBITS + | ImageObserver.PROPERTIES, 0, 0, + realImage.getWidth(null), + realImage.getHeight(null)); + } + } + } + } + + static Image realImage(Image img, ImageObserver obs) + { + if (img instanceof AsyncImage) + { + ((AsyncImage) img).addObserver(obs); + Image r = ((AsyncImage) img).realImage; + if (r != null) + img = r; + } + return img; + } + + void notifyObservers(int status) + { + assert Thread.holdsLock(this); + // This field gets null when image loading is complete. + HashSet observs = observers; + if (observs != null) + { + Image r = realImage; + Iterator i = observs.iterator(); + while (i.hasNext()) + { + ImageObserver obs = (ImageObserver) i.next(); + obs.imageUpdate(this, status, 0, 0, r.getWidth(null), + r.getHeight(null)); + } + } + } + + int checkImage(ImageObserver obs) + { + addObserver(obs); + int flags = 0; + if (realImage != null) + flags = ImageObserver.ALLBITS | ImageObserver.WIDTH + | ImageObserver.HEIGHT | ImageObserver.PROPERTIES; + return flags; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/BufferedImageGraphics.java b/libjava/classpath/gnu/java/awt/peer/gtk/BufferedImageGraphics.java new file mode 100644 index 000000000..f9609bff6 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/BufferedImageGraphics.java @@ -0,0 +1,538 @@ +/* BufferedImageGraphics.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.java.awt.peer.gtk; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.Image; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.Toolkit; +import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.DataBufferInt; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.image.Raster; +import java.awt.image.RenderedImage; +import java.awt.image.SinglePixelPackedSampleModel; +import java.util.WeakHashMap; + +/** + * Implementation of Graphics2D on a Cairo surface. + * + * Simutanously maintains a CairoSurface and updates the + * BufferedImage from that after each drawing operation. + */ +public class BufferedImageGraphics extends CairoGraphics2D +{ + /** + * the buffered Image. + */ + private BufferedImage image, buffer; + + /** + * Image size. + */ + private int imageWidth, imageHeight; + + /** + * The cairo surface that we actually draw on. + */ + CairoSurface surface; + + /** + * Cache BufferedImageGraphics surfaces. + */ + static WeakHashMap bufferedImages + = new WeakHashMap(); + + /** + * Its corresponding cairo_t. + */ + private long cairo_t; + + private boolean hasFastCM; + private boolean hasAlpha; + + + public BufferedImageGraphics(BufferedImage bi) + { + this.image = bi; + imageWidth = bi.getWidth(); + imageHeight = bi.getHeight(); + + if (!(image.getSampleModel() instanceof SinglePixelPackedSampleModel)) + hasFastCM = false; + else if(bi.getColorModel().equals(CairoSurface.cairoCM_opaque)) + { + hasFastCM = true; + hasAlpha = false; + } + else if(bi.getColorModel().equals(CairoSurface.cairoColorModel) + || bi.getColorModel().equals(CairoSurface.cairoCM_pre)) + { + hasFastCM = true; + hasAlpha = true; + } + else + hasFastCM = false; + + // Cache surfaces. + if( bufferedImages.get( bi ) != null ) + surface = bufferedImages.get( bi ); + else + { + surface = new CairoSurface( imageWidth, imageHeight ); + bufferedImages.put(bi, surface); + } + + cairo_t = surface.newCairoContext(); + + // Get pixels out of buffered image and set in cairo surface + Raster raster = bi.getRaster(); + int[] pixels; + + if (hasFastCM) + { + SinglePixelPackedSampleModel sm = (SinglePixelPackedSampleModel)image.getSampleModel(); + int minX = image.getRaster().getSampleModelTranslateX(); + int minY = image.getRaster().getSampleModelTranslateY(); + + // Pull pixels directly out of data buffer + pixels = ((DataBufferInt)raster.getDataBuffer()).getData(); + + // Discard pixels that fall outside of the image's bounds + // (ie, this image is actually a subimage of a different image) + if (!(sm.getScanlineStride() == imageWidth && minX == 0 && minY == 0)) + { + int[] pixels2 = new int[imageWidth * imageHeight]; + int scanline = sm.getScanlineStride(); + + for (int i = 0; i < imageHeight; i++) + System.arraycopy(pixels, (i - minY) * scanline - minX, pixels2, + i * imageWidth, imageWidth); + + pixels = pixels2; + } + + // Fill the alpha channel as opaque if image does not have alpha + if( !hasAlpha ) + for(int i = 0; i < pixels.length; i++) + pixels[i] &= 0xFFFFFFFF; + } + else + { + pixels = CairoGraphics2D.findSimpleIntegerArray(image.getColorModel(), + image.getData()); + if (pixels != null) + System.arraycopy(pixels, 0, surface.getData(), + 0, pixels.length); + } + + setup( cairo_t ); + setClip(0, 0, imageWidth, imageHeight); + } + + BufferedImageGraphics(BufferedImageGraphics copyFrom) + { + image = copyFrom.image; + surface = copyFrom.surface; + cairo_t = surface.newCairoContext(); + imageWidth = copyFrom.imageWidth; + imageHeight = copyFrom.imageHeight; + + hasFastCM = copyFrom.hasFastCM; + hasAlpha = copyFrom.hasAlpha; + + copy( copyFrom, cairo_t ); + } + + /** + * Update a rectangle of the bufferedImage. This can be improved upon a lot. + */ + private void updateBufferedImage(int x, int y, int width, int height) + { + Rectangle bounds = new Rectangle(x, y, width, height); + bounds = getTransformedBounds(bounds, transform).getBounds(); + x = bounds.x; + y = bounds.y; + width = bounds.width; + height = bounds.height; + + int[] pixels = surface.getData(); + + if( x > imageWidth || y > imageHeight ) + return; + + // Deal with negative width/height. + if (height < 0) + { + y += height; + height = -height; + } + if (width < 0) + { + x += width; + width = -width; + } + + // Clip edges. + if( x < 0 ) + x = 0; + if( y < 0 ) + y = 0; + + if( x + width > imageWidth ) + width = imageWidth - x; + if( y + height > imageHeight ) + height = imageHeight - y; + + if(!hasFastCM) + { + image.setRGB(x, y, width, height, pixels, + x + y * imageWidth, imageWidth); + // The setRGB method assumes (or should assume) that pixels are NOT + // alpha-premultiplied, but Cairo stores data with premultiplication + // (thus the pixels returned in getPixels are premultiplied). + // This is ignored for consistency, however, since in + // CairoGrahpics2D.drawImage we also use non-premultiplied data + + } + else + { + int[] db = ((DataBufferInt)image.getRaster().getDataBuffer()). + getData(); + + // This should not fail, as we check the image sample model when we + // set the hasFastCM flag + SinglePixelPackedSampleModel sm = (SinglePixelPackedSampleModel)image.getSampleModel() ; + + int minX = image.getRaster().getSampleModelTranslateX(); + int minY = image.getRaster().getSampleModelTranslateY(); + + if (sm.getScanlineStride() == imageWidth && minX == 0) + { + System.arraycopy(pixels, y * imageWidth, + db, (y - minY) * imageWidth, + height * imageWidth); + } + else + { + int scanline = sm.getScanlineStride(); + for (int i = y; i < (height + y); i++) + System.arraycopy(pixels, i * imageWidth + x, db, + (i - minY) * scanline + x - minX, width); + + } + } + } + + /** + * Abstract methods. + */ + public Graphics create() + { + return new BufferedImageGraphics(this); + } + + public GraphicsConfiguration getDeviceConfiguration() + { + return null; + } + + protected Rectangle2D getRealBounds() + { + return new Rectangle2D.Double(0.0, 0.0, imageWidth, imageHeight); + } + + public void copyAreaImpl(int x, int y, int width, int height, int dx, int dy) + { + surface.copyAreaNative(x, y, width, height, dx, dy, surface.width); + updateBufferedImage(x + dx, y + dy, width, height); + } + + /** + * Overloaded methods that do actual drawing need to enter the gdk threads + * and also do certain things before and after. + */ + public void draw(Shape s) + { + // Find total bounds of shape + Rectangle r = findStrokedBounds(s); + if (shiftDrawCalls) + { + r.width++; + r.height++; + } + + // Do the drawing + if (comp == null || comp instanceof AlphaComposite) + { + super.draw(s); + updateBufferedImage(r.x, r.y, r.width, r.height); + } + else + { + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setStroke(this.getStroke()); + g2d.setColor(this.getColor()); + g2d.setTransform(transform); + g2d.draw(s); + + drawComposite(r.getBounds2D(), null); + } + } + + public void fill(Shape s) + { + if (comp == null || comp instanceof AlphaComposite) + { + super.fill(s); + Rectangle r = s.getBounds(); + updateBufferedImage(r.x, r.y, r.width, r.height); + } + else + { + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setPaint(this.getPaint()); + g2d.setColor(this.getColor()); + g2d.setTransform(transform); + g2d.fill(s); + + drawComposite(s.getBounds2D(), null); + } + } + + public void drawRenderedImage(RenderedImage image, AffineTransform xform) + { + if (comp == null || comp instanceof AlphaComposite) + { + super.drawRenderedImage(image, xform); + updateBufferedImage(0, 0, imageWidth, imageHeight); + } + else + { + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setRenderingHints(this.getRenderingHints()); + g2d.setTransform(transform); + g2d.drawRenderedImage(image, xform); + + drawComposite(buffer.getRaster().getBounds(), null); + } + + } + + protected boolean drawImage(Image img, AffineTransform xform, + Color bgcolor, ImageObserver obs) + { + if (comp == null || comp instanceof AlphaComposite) + { + boolean rv = super.drawImage(img, xform, bgcolor, obs); + updateBufferedImage(0, 0, imageWidth, imageHeight); + return rv; + } + else + { + // Get buffered image of source + if( !(img instanceof BufferedImage) ) + { + ImageProducer source = img.getSource(); + if (source == null) + return false; + img = Toolkit.getDefaultToolkit().createImage(source); + } + BufferedImage bImg = (BufferedImage) img; + + // Find translated bounds + Rectangle2D bounds = new Rectangle(bImg.getMinX(), bImg.getMinY(), + bImg.getWidth(), bImg.getHeight()); + if (xform != null) + bounds = getTransformedBounds(bounds, xform); + + // Create buffer and draw image + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setRenderingHints(this.getRenderingHints()); + g2d.drawImage(img, xform, obs); + + // Perform compositing + return drawComposite(bounds, obs); + } + } + + public void drawGlyphVector(GlyphVector gv, float x, float y) + { + // Find absolute bounds, in user-space, of this glyph vector + Rectangle2D bounds = gv.getLogicalBounds(); + bounds = new Rectangle2D.Double(x + bounds.getX(), y + bounds.getY(), + bounds.getWidth(), bounds.getHeight()); + + // Perform draw operation + if (comp == null || comp instanceof AlphaComposite) + { + super.drawGlyphVector(gv, x, y); + + // this returns an integer-based Rectangle (rather than a + // Rectangle2D), which takes care of any necessary rounding for us. + bounds = bounds.getBounds(); + + updateBufferedImage((int)bounds.getX(), (int)bounds.getY(), + (int)bounds.getWidth(), (int)bounds.getHeight()); + } + else + { + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setPaint(this.getPaint()); + g2d.setStroke(this.getStroke()); + g2d.setTransform(transform); + g2d.drawGlyphVector(gv, x, y); + + drawComposite(bounds, null); + } + } + + /** + * Perform composite drawing from the buffer onto the main image. + * + * The image to be composited should already be drawn into the buffer, in the + * proper place, after all necessary transforms have been applied. + * + * @param bounds The bounds to draw, in user-space. + * @param observer The image observer, if any (may be null). + * @return True on success, false on failure. + */ + private boolean drawComposite(Rectangle2D bounds, ImageObserver observer) + { + // Find bounds in device space + bounds = getTransformedBounds(bounds, transform); + + // Clip bounds by the stored clip, and by the internal buffer + Rectangle2D devClip = this.getClipInDevSpace(); + Rectangle2D.intersect(bounds, devClip, bounds); + devClip = new Rectangle(buffer.getMinX(), buffer.getMinY(), + buffer.getWidth(), buffer.getHeight()); + Rectangle2D.intersect(bounds, devClip, bounds); + + // Round bounds as needed, but be careful in our rounding + // (otherwise it may leave unpainted stripes) + double x = bounds.getX(); + double y = bounds.getY(); + double maxX = x + bounds.getWidth(); + double maxY = y + bounds.getHeight(); + x = Math.round(x); + y = Math.round(y); + bounds.setRect(x, y, Math.round(maxX - x), Math.round(maxY - y)); + + // Find subimage of internal buffer for updating + BufferedImage buffer2 = buffer; + if (!bounds.equals(buffer2.getRaster().getBounds())) + buffer2 = buffer2.getSubimage((int)bounds.getX(), (int)bounds.getY(), + (int)bounds.getWidth(), + (int)bounds.getHeight()); + + // Find subimage of main image for updating + BufferedImage current = image; + current = current.getSubimage((int)bounds.getX(), (int)bounds.getY(), + (int)bounds.getWidth(), + (int)bounds.getHeight()); + + // Perform actual composite operation + compCtx.compose(buffer2.getRaster(), current.getRaster(), + current.getRaster()); + + // Set cairo's composite to direct SRC, since we've already done our own + // compositing + Composite oldcomp = comp; + setComposite(AlphaComposite.Src); + + // This MUST call directly into the "action" method in CairoGraphics2D, + // not one of the wrappers, to ensure that the composite isn't processed + // more than once! + boolean rv = super.drawImage(current, + AffineTransform.getTranslateInstance(bounds.getX(), + bounds.getY()), + null, null); + setComposite(oldcomp); + updateColor(); + return rv; + } + + private void createBuffer() + { + if (buffer == null) + { + buffer = new BufferedImage(image.getWidth(), image.getHeight(), + BufferedImage.TYPE_INT_ARGB); + } + else + { + Graphics2D g2d = ((Graphics2D)buffer.getGraphics()); + + g2d.setBackground(new Color(0,0,0,0)); + g2d.clearRect(0, 0, buffer.getWidth(), buffer.getHeight()); + } + } + + protected ColorModel getNativeCM() + { + return image.getColorModel(); + } + + protected ColorModel getBufferCM() + { + return ColorModel.getRGBdefault(); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/CairoGraphics2D.java b/libjava/classpath/gnu/java/awt/peer/gtk/CairoGraphics2D.java new file mode 100644 index 000000000..05d35c573 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/CairoGraphics2D.java @@ -0,0 +1,2176 @@ +/* CairoGraphics2D.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.java.awt.peer.gtk; + +import gnu.classpath.Configuration; + +import gnu.java.awt.ClasspathToolkit; + +import java.awt.AWTPermission; +import java.awt.AlphaComposite; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Composite; +import java.awt.CompositeContext; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.GradientPaint; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.Image; +import java.awt.Paint; +import java.awt.PaintContext; +import java.awt.Point; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.TexturePaint; +import java.awt.Toolkit; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.font.TextLayout; +import java.awt.geom.AffineTransform; +import java.awt.geom.Arc2D; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.GeneralPath; +import java.awt.geom.Line2D; +import java.awt.geom.NoninvertibleTransformException; +import java.awt.geom.PathIterator; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.geom.RoundRectangle2D; +import java.awt.image.AffineTransformOp; +import java.awt.image.BufferedImage; +import java.awt.image.BufferedImageOp; +import java.awt.image.ColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferInt; +import java.awt.image.DirectColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.image.ImagingOpException; +import java.awt.image.MultiPixelPackedSampleModel; +import java.awt.image.Raster; +import java.awt.image.RenderedImage; +import java.awt.image.SampleModel; +import java.awt.image.WritableRaster; +import java.awt.image.renderable.RenderContext; +import java.awt.image.renderable.RenderableImage; +import java.text.AttributedCharacterIterator; +import java.util.HashMap; +import java.util.Map; + +/** + * This is an abstract implementation of Graphics2D on Cairo. + * + * It should be subclassed for different Cairo contexts. + * + * Note for subclassers: Apart from the constructor (see comments below), + * The following abstract methods must be implemented: + * + * Graphics create() + * GraphicsConfiguration getDeviceConfiguration() + * copyArea(int x, int y, int width, int height, int dx, int dy) + * + * Also, dispose() must be overloaded to free any native datastructures + * used by subclass and in addition call super.dispose() to free the + * native cairographics2d structure and cairo_t. + * + * @author Sven de Marothy + */ +public abstract class CairoGraphics2D extends Graphics2D +{ + static + { + if (true) // GCJ LOCAL + { + System.loadLibrary("gtkpeer"); + } + } + + /** + * Important: This is a pointer to the native cairographics2d structure + * + * DO NOT CHANGE WITHOUT CHANGING NATIVE CODE. + */ + long nativePointer; + + // Drawing state variables + /** + * The current paint + */ + Paint paint; + boolean customPaint; + + /** + * The current stroke + */ + Stroke stroke; + + /* + * Current foreground and background color. + */ + Color fg, bg; + + /** + * Current clip shape. + */ + Shape clip; + + /** + * Current transform. + */ + AffineTransform transform; + + /** + * Current font. + */ + Font font; + + /** + * The current compositing context, if any. + */ + Composite comp; + CompositeContext compCtx; + + /** + * Rendering hint map. + */ + private RenderingHints hints; + + /** + * Status of the anti-alias flag in cairo. + */ + private boolean antialias = false; + private boolean ignoreAA = false; + + /** + * Some operations (drawing rather than filling) require that their + * coords be shifted to land on 0.5-pixel boundaries, in order to land on + * "middle of pixel" coordinates and light up complete pixels. + */ + protected boolean shiftDrawCalls = false; + + /** + * Keep track if the first clip to be set, which is restored on setClip(null); + */ + private boolean firstClip = true; + private Shape originalClip; + + /** + * Stroke used for 3DRects + */ + private static BasicStroke draw3DRectStroke = new BasicStroke(); + + static ColorModel rgb32 = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF); + static ColorModel argb32 = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF, + 0xFF000000); + + /** + * Native constants for interpolation methods. + * Note, this corresponds to an enum in native/jni/gtk-peer/cairographics2d.h + */ + public static final int INTERPOLATION_NEAREST = 0, + INTERPOLATION_BILINEAR = 1, + INTERPOLATION_BICUBIC = 5, + ALPHA_INTERPOLATION_SPEED = 2, + ALPHA_INTERPOLATION_QUALITY = 3, + ALPHA_INTERPOLATION_DEFAULT = 4; + // TODO: Does ALPHA_INTERPOLATION really correspond to CAIRO_FILTER_FAST/BEST/GOOD? + + /** + * Constructor does nothing. + */ + public CairoGraphics2D() + { + } + + /** + * Sets up the default values and allocates the native cairographics2d structure + * @param cairo_t_pointer a native pointer to a cairo_t of the context. + */ + public void setup(long cairo_t_pointer) + { + nativePointer = init(cairo_t_pointer); + setRenderingHints(new RenderingHints(getDefaultHints())); + setFont(new Font("SansSerif", Font.PLAIN, 12)); + setColor(Color.black); + setBackground(Color.white); + setPaint(Color.black); + setStroke(new BasicStroke()); + setTransform(new AffineTransform()); + cairoSetAntialias(nativePointer, antialias); + } + + /** + * Same as above, but copies the state of another CairoGraphics2D. + */ + public void copy(CairoGraphics2D g, long cairo_t_pointer) + { + nativePointer = init(cairo_t_pointer); + paint = g.paint; + stroke = g.stroke; + setRenderingHints(g.hints); + + Color foreground; + + if (g.fg.getAlpha() != -1) + foreground = new Color(g.fg.getRed(), g.fg.getGreen(), g.fg.getBlue(), + g.fg.getAlpha()); + else + foreground = new Color(g.fg.getRGB()); + + if (g.bg != null) + { + if (g.bg.getAlpha() != -1) + bg = new Color(g.bg.getRed(), g.bg.getGreen(), g.bg.getBlue(), + g.bg.getAlpha()); + else + bg = new Color(g.bg.getRGB()); + } + + firstClip = g.firstClip; + originalClip = g.originalClip; + clip = g.getClip(); + + if (g.transform == null) + transform = null; + else + transform = new AffineTransform(g.transform); + + setFont(g.font); + setColor(foreground); + setBackground(bg); + setPaint(paint); + setStroke(stroke); + setTransformImpl(transform); + setClip(clip); + setComposite(comp); + + antialias = !g.antialias; + setAntialias(g.antialias); + } + + /** + * Generic destructor - call the native dispose() method. + */ + public void finalize() + { + dispose(); + } + + /** + * Disposes the native cairographics2d structure, including the + * cairo_t and any gradient stuff, if allocated. + * Subclasses should of course overload and call this if + * they have additional native structures. + */ + public void dispose() + { + disposeNative(nativePointer); + nativePointer = 0; + if (compCtx != null) + compCtx.dispose(); + } + + /** + * Allocate the cairographics2d structure and set the cairo_t pointer in it. + * @param pointer - a cairo_t pointer, casted to a long. + */ + protected native long init(long pointer); + + /** + * These are declared abstract as there may be context-specific issues. + */ + public abstract Graphics create(); + + public abstract GraphicsConfiguration getDeviceConfiguration(); + + protected abstract void copyAreaImpl(int x, int y, int width, int height, + int dx, int dy); + + + /** + * Find the bounds of this graphics context, in device space. + * + * @return the bounds in device-space + */ + protected abstract Rectangle2D getRealBounds(); + + ////// Native Methods //////////////////////////////////////////////////// + + /** + * Dispose of allocate native resouces. + */ + public native void disposeNative(long pointer); + + /** + * Draw pixels as an RGBA int matrix + * @param w - width + * @param h - height + * @param stride - stride of the array width + * @param i2u - affine transform array + */ + protected native void drawPixels(long pointer, int[] pixels, int w, int h, + int stride, double[] i2u, double alpha, + int interpolation); + + protected native void setGradient(long pointer, double x1, double y1, + double x2, double y2, + int r1, int g1, int b1, int a1, int r2, + int g2, int b2, int a2, boolean cyclic); + + protected native void setPaintPixels(long pointer, int[] pixels, int w, + int h, int stride, boolean repeat, + int x, int y); + + /** + * Set the current transform matrix + */ + protected native void cairoSetMatrix(long pointer, double[] m); + + /** + * Scaling method + */ + protected native void cairoScale(long pointer, double x, double y); + + /** + * Set the compositing operator + */ + protected native void cairoSetOperator(long pointer, int cairoOperator); + + /** + * Sets the current color in RGBA as a 0.0-1.0 double + */ + protected native void cairoSetRGBAColor(long pointer, double red, double green, + double blue, double alpha); + + /** + * Sets the current winding rule in Cairo + */ + protected native void cairoSetFillRule(long pointer, int cairoFillRule); + + /** + * Set the line style, cap, join and miter limit. + * Cap and join parameters are in the BasicStroke enumerations. + */ + protected native void cairoSetLine(long pointer, double width, int cap, + int join, double miterLimit); + + /** + * Set the dash style + */ + protected native void cairoSetDash(long pointer, double[] dashes, int ndash, + double offset); + + /* + * Draws a Glyph Vector + */ + protected native void cairoDrawGlyphVector(long pointer, GdkFontPeer font, + float x, float y, int n, + int[] codes, float[] positions, long[] fontset); + + /** + * Set the font in cairo. + */ + protected native void cairoSetFont(long pointer, GdkFontPeer font); + + /** + * Appends a rectangle to the current path + */ + protected native void cairoRectangle(long pointer, double x, double y, + double width, double height); + + /** + * Appends an arc to the current path + */ + protected native void cairoArc(long pointer, double x, double y, + double radius, double angle1, double angle2); + + /** + * Save / restore a cairo path + */ + protected native void cairoSave(long pointer); + protected native void cairoRestore(long pointer); + + /** + * New current path + */ + protected native void cairoNewPath(long pointer); + + /** + * Close current path + */ + protected native void cairoClosePath(long pointer); + + /** moveTo */ + protected native void cairoMoveTo(long pointer, double x, double y); + + /** lineTo */ + protected native void cairoLineTo(long pointer, double x, double y); + + /** Cubic curve-to */ + protected native void cairoCurveTo(long pointer, double x1, double y1, + double x2, double y2, + double x3, double y3); + + /** + * Stroke current path + */ + protected native void cairoStroke(long pointer); + + /** + * Fill current path + */ + protected native void cairoFill(long pointer, double alpha); + + /** + * Clip current path + */ + protected native void cairoClip(long pointer); + + /** + * Clear clip + */ + protected native void cairoResetClip(long pointer); + + /** + * Set antialias. + */ + protected native void cairoSetAntialias(long pointer, boolean aa); + + + ///////////////////////// TRANSFORMS /////////////////////////////////// + /** + * Set the current transform + */ + public void setTransform(AffineTransform tx) + { + // Transform clip into target space using the old transform. + updateClip(transform); + + // Update the native transform. + setTransformImpl(tx); + + // Transform the clip back into user space using the inverse new transform. + try + { + updateClip(transform.createInverse()); + } + catch (NoninvertibleTransformException ex) + { + // TODO: How can we deal properly with this? + ex.printStackTrace(); + } + + if (clip != null) + setClip(clip); + } + + private void setTransformImpl(AffineTransform tx) + { + transform = tx; + if (transform != null) + { + double[] m = new double[6]; + transform.getMatrix(m); + cairoSetMatrix(nativePointer, m); + } + } + + public void transform(AffineTransform tx) + { + if (transform == null) + transform = new AffineTransform(tx); + else + transform.concatenate(tx); + + if (clip != null) + { + try + { + AffineTransform clipTransform = tx.createInverse(); + updateClip(clipTransform); + } + catch (NoninvertibleTransformException ex) + { + // TODO: How can we deal properly with this? + ex.printStackTrace(); + } + } + + setTransformImpl(transform); + } + + public void rotate(double theta) + { + transform(AffineTransform.getRotateInstance(theta)); + } + + public void rotate(double theta, double x, double y) + { + transform(AffineTransform.getRotateInstance(theta, x, y)); + } + + public void scale(double sx, double sy) + { + transform(AffineTransform.getScaleInstance(sx, sy)); + } + + /** + * Translate the system of the co-ordinates. As translation is a frequent + * operation, it is done in an optimised way, unlike scaling and rotating. + */ + public void translate(double tx, double ty) + { + if (transform != null) + transform.translate(tx, ty); + else + transform = AffineTransform.getTranslateInstance(tx, ty); + + if (clip != null) + { + // FIXME: this should actuall try to transform the shape + // rather than degrade to bounds. + if (clip instanceof Rectangle2D) + { + Rectangle2D r = (Rectangle2D) clip; + r.setRect(r.getX() - tx, r.getY() - ty, r.getWidth(), + r.getHeight()); + } + else + { + AffineTransform clipTransform = + AffineTransform.getTranslateInstance(-tx, -ty); + updateClip(clipTransform); + } + } + + setTransformImpl(transform); + } + + public void translate(int x, int y) + { + translate((double) x, (double) y); + } + + public void shear(double shearX, double shearY) + { + transform(AffineTransform.getShearInstance(shearX, shearY)); + } + + ///////////////////////// DRAWING STATE /////////////////////////////////// + + public void clip(Shape s) + { + // Do not touch clip when s == null. + if (s == null) + { + // The spec says this should clear the clip. The reference + // implementation throws a NullPointerException instead. I think, + // in this case we should conform to the specs, as it shouldn't + // affect compatibility. + setClip(null); + return; + } + + // If the current clip is still null, initialize it. + if (clip == null) + { + clip = getRealBounds(); + } + + // This is so common, let's optimize this. + if (clip instanceof Rectangle2D && s instanceof Rectangle2D) + { + Rectangle2D clipRect = (Rectangle2D) clip; + Rectangle2D r = (Rectangle2D) s; + Rectangle2D.intersect(clipRect, r, clipRect); + setClip(clipRect); + } + else + { + Area current; + if (clip instanceof Area) + current = (Area) clip; + else + current = new Area(clip); + + Area intersect; + if (s instanceof Area) + intersect = (Area) s; + else + intersect = new Area(s); + + current.intersect(intersect); + clip = current; + // Call setClip so that the native side gets notified. + setClip(clip); + } + } + + public Paint getPaint() + { + return paint; + } + + public AffineTransform getTransform() + { + return (AffineTransform) transform.clone(); + } + + public void setPaint(Paint p) + { + if (p == null) + return; + + paint = p; + if (paint instanceof Color) + { + setColor((Color) paint); + customPaint = false; + } + + else if (paint instanceof TexturePaint) + { + TexturePaint tp = (TexturePaint) paint; + BufferedImage img = tp.getImage(); + + // map the image to the anchor rectangle + int width = (int) tp.getAnchorRect().getWidth(); + int height = (int) tp.getAnchorRect().getHeight(); + + double scaleX = width / (double) img.getWidth(); + double scaleY = height / (double) img.getHeight(); + + AffineTransform at = new AffineTransform(scaleX, 0, 0, scaleY, 0, 0); + AffineTransformOp op = new AffineTransformOp(at, getRenderingHints()); + BufferedImage texture = op.filter(img, null); + int[] pixels = texture.getRGB(0, 0, width, height, null, 0, width); + setPaintPixels(nativePointer, pixels, width, height, width, true, 0, 0); + customPaint = false; + } + + else if (paint instanceof GradientPaint) + { + GradientPaint gp = (GradientPaint) paint; + Point2D p1 = gp.getPoint1(); + Point2D p2 = gp.getPoint2(); + Color c1 = gp.getColor1(); + Color c2 = gp.getColor2(); + setGradient(nativePointer, p1.getX(), p1.getY(), p2.getX(), p2.getY(), + c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha(), + c2.getRed(), c2.getGreen(), c2.getBlue(), c2.getAlpha(), + gp.isCyclic()); + customPaint = false; + } + else + { + customPaint = true; + } + } + + /** + * Sets a custom paint + * + * @param bounds the bounding box, in user space + */ + protected void setCustomPaint(Rectangle bounds) + { + if (paint instanceof Color || paint instanceof TexturePaint + || paint instanceof GradientPaint) + return; + + int userX = bounds.x; + int userY = bounds.y; + int userWidth = bounds.width; + int userHeight = bounds.height; + + // Find bounds in device space + Rectangle2D bounds2D = getTransformedBounds(bounds, transform); + int deviceX = (int)bounds2D.getX(); + int deviceY = (int)bounds2D.getY(); + int deviceWidth = (int)Math.ceil(bounds2D.getWidth()); + int deviceHeight = (int)Math.ceil(bounds2D.getHeight()); + + // Get raster of the paint background + PaintContext pc = paint.createContext(CairoSurface.cairoColorModel, + new Rectangle(deviceX, deviceY, + deviceWidth, + deviceHeight), + bounds, + transform, hints); + + Raster raster = pc.getRaster(deviceX, deviceY, deviceWidth, + deviceHeight); + + // Clear the transform matrix in Cairo, since the raster returned by the + // PaintContext is already in device-space + AffineTransform oldTx = new AffineTransform(transform); + setTransformImpl(new AffineTransform()); + + // Set pixels in cairo, aligning the top-left of the background image + // to the top-left corner in device space + if (pc.getColorModel().equals(CairoSurface.cairoColorModel) + && raster.getSampleModel().getTransferType() == DataBuffer.TYPE_INT) + { + // Use a fast copy if the paint context can uses a Cairo-compatible + // color model + setPaintPixels(nativePointer, + (int[])raster.getDataElements(0, 0, deviceWidth, + deviceHeight, null), + deviceWidth, deviceHeight, deviceWidth, false, + deviceX, deviceY); + } + + else if (pc.getColorModel().equals(CairoSurface.cairoCM_opaque) + && raster.getSampleModel().getTransferType() == DataBuffer.TYPE_INT) + { + // We can also optimize if the context uses a similar color model + // but without an alpha channel; we just add the alpha + int[] pixels = (int[])raster.getDataElements(0, 0, deviceWidth, + deviceHeight, null); + + for (int i = 0; i < pixels.length; i++) + pixels[i] = 0xff000000 | (pixels[i] & 0x00ffffff); + + setPaintPixels(nativePointer, pixels, deviceWidth, deviceHeight, + deviceWidth, false, deviceX, deviceY); + } + + else + { + // Fall back on wrapping the raster in a BufferedImage, and + // use BufferedImage.getRGB() to do color-model conversion + WritableRaster wr = Raster.createWritableRaster(raster.getSampleModel(), + new Point(raster.getMinX(), + raster.getMinY())); + wr.setRect(raster); + + BufferedImage img2 = new BufferedImage(pc.getColorModel(), wr, + pc.getColorModel().isAlphaPremultiplied(), + null); + + setPaintPixels(nativePointer, + img2.getRGB(0, 0, deviceWidth, deviceHeight, null, 0, + deviceWidth), + deviceWidth, deviceHeight, deviceWidth, false, + deviceX, deviceY); + } + + // Restore transform + setTransformImpl(oldTx); + } + + public Stroke getStroke() + { + return stroke; + } + + public void setStroke(Stroke st) + { + stroke = st; + if (stroke instanceof BasicStroke) + { + BasicStroke bs = (BasicStroke) stroke; + cairoSetLine(nativePointer, bs.getLineWidth(), bs.getEndCap(), + bs.getLineJoin(), bs.getMiterLimit()); + + float[] dashes = bs.getDashArray(); + if (dashes != null) + { + double[] double_dashes = new double[dashes.length]; + for (int i = 0; i < dashes.length; i++) + double_dashes[i] = dashes[i]; + + cairoSetDash(nativePointer, double_dashes, double_dashes.length, + (double) bs.getDashPhase()); + } + else + cairoSetDash(nativePointer, new double[0], 0, 0.0); + } + } + + /** + * Utility method to find the bounds of a shape, including the stroke width. + * + * @param s the shape + * @return the bounds of the shape, including stroke width + */ + protected Rectangle findStrokedBounds(Shape s) + { + Rectangle r = s.getBounds(); + + if (stroke instanceof BasicStroke) + { + int strokeWidth = (int)Math.ceil(((BasicStroke)stroke).getLineWidth()); + r.x -= strokeWidth / 2; + r.y -= strokeWidth / 2; + r.height += strokeWidth; + r.width += strokeWidth; + } + else + { + Shape s2 = stroke.createStrokedShape(s); + r = s2.getBounds(); + } + + return r; + } + + public void setPaintMode() + { + setComposite(AlphaComposite.SrcOver); + } + + public void setXORMode(Color c) + { + // FIXME: implement + } + + public void setColor(Color c) + { + if (c == null) + c = Color.BLACK; + + fg = c; + paint = c; + updateColor(); + } + + /** + * Set the current fg value as the cairo color. + */ + void updateColor() + { + if (fg == null) + fg = Color.BLACK; + + cairoSetRGBAColor(nativePointer, fg.getRed() / 255.0, + fg.getGreen() / 255.0,fg.getBlue() / 255.0, + fg.getAlpha() / 255.0); + } + + public Color getColor() + { + return fg; + } + + public void clipRect(int x, int y, int width, int height) + { + if (clip == null) + setClip(new Rectangle(x, y, width, height)); + else if (clip instanceof Rectangle) + { + computeIntersection(x, y, width, height, (Rectangle) clip); + setClip(clip); + } + else + clip(new Rectangle(x, y, width, height)); + } + + public Shape getClip() + { + if (clip == null) + return null; + else if (clip instanceof Rectangle2D) + return clip.getBounds2D(); //getClipInDevSpace(); + else + { + GeneralPath p = new GeneralPath(); + PathIterator pi = clip.getPathIterator(null); + p.append(pi, false); + return p; + } + } + + public Rectangle getClipBounds() + { + if (clip == null) + return null; + else + return clip.getBounds(); + } + + protected Rectangle2D getClipInDevSpace() + { + Rectangle2D uclip = clip.getBounds2D(); + if (transform == null) + return uclip; + else + return getTransformedBounds(clip.getBounds2D(), transform); + } + + public void setClip(int x, int y, int width, int height) + { + if( width < 0 || height < 0 ) + return; + + setClip(new Rectangle2D.Double(x, y, width, height)); + } + + public void setClip(Shape s) + { + // The first time the clip is set, save it as the original clip + // to reset to on s == null. We can rely on this being non-null + // because the constructor in subclasses is expected to set the + // initial clip properly. + if( firstClip ) + { + originalClip = s; + firstClip = false; + } + + clip = s; + cairoResetClip(nativePointer); + + if (clip != null) + { + cairoNewPath(nativePointer); + if (clip instanceof Rectangle2D) + { + Rectangle2D r = (Rectangle2D) clip; + cairoRectangle(nativePointer, r.getX(), r.getY(), r.getWidth(), + r.getHeight()); + } + else + walkPath(clip.getPathIterator(null), false); + + cairoClip(nativePointer); + } + } + + public void setBackground(Color c) + { + if (c == null) + c = Color.WHITE; + bg = c; + } + + public Color getBackground() + { + return bg; + } + + /** + * Return the current composite. + */ + public Composite getComposite() + { + if (comp == null) + return AlphaComposite.SrcOver; + else + return comp; + } + + /** + * Sets the current composite context. + */ + public void setComposite(Composite comp) + { + if (this.comp == comp) + return; + + this.comp = comp; + if (compCtx != null) + compCtx.dispose(); + compCtx = null; + + if (comp instanceof AlphaComposite) + { + AlphaComposite a = (AlphaComposite) comp; + cairoSetOperator(nativePointer, a.getRule()); + } + + else + { + cairoSetOperator(nativePointer, AlphaComposite.SRC_OVER); + + if (comp != null) + { + // FIXME: this check is only required "if this Graphics2D + // context is drawing to a Component on the display screen". + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new AWTPermission("readDisplayPixels")); + + compCtx = comp.createContext(getBufferCM(), getNativeCM(), hints); + } + } + } + + /** + * Returns the Colour Model describing the native, raw image data for this + * specific peer. + * + * @return ColorModel the ColorModel of native data in this peer + */ + protected abstract ColorModel getNativeCM(); + + /** + * Returns the Color Model describing the buffer that this peer uses + * for custom composites. + * + * @return ColorModel the ColorModel of the composite buffer in this peer. + */ + protected ColorModel getBufferCM() + { + // This may be overridden by some subclasses + return getNativeCM(); + } + + ///////////////////////// DRAWING PRIMITIVES /////////////////////////////////// + + public void draw(Shape s) + { + if ((stroke != null && ! (stroke instanceof BasicStroke)) + || (comp instanceof AlphaComposite && ((AlphaComposite) comp).getAlpha() != 1.0)) + { + // Cairo doesn't support stroking with alpha, so we create the stroked + // shape and fill with alpha instead + fill(stroke.createStrokedShape(s)); + return; + } + + if (customPaint) + { + Rectangle r = findStrokedBounds(s); + setCustomPaint(r); + } + + setAntialias(!hints.get(RenderingHints.KEY_ANTIALIASING) + .equals(RenderingHints.VALUE_ANTIALIAS_OFF)); + createPath(s, true); + cairoStroke(nativePointer); + } + + public void fill(Shape s) + { + createPath(s, false); + + if (customPaint) + setCustomPaint(s.getBounds()); + + setAntialias(!hints.get(RenderingHints.KEY_ANTIALIASING) + .equals(RenderingHints.VALUE_ANTIALIAS_OFF)); + double alpha = 1.0; + if (comp instanceof AlphaComposite) + alpha = ((AlphaComposite) comp).getAlpha(); + cairoFill(nativePointer, alpha); + } + + private void createPath(Shape s, boolean isDraw) + { + cairoNewPath(nativePointer); + + // Optimize rectangles, since there is a direct Cairo function + if (s instanceof Rectangle2D) + { + Rectangle2D r = (Rectangle2D) s; + + // Pixels need to be shifted in draw operations to ensure that they + // light up entire pixels, but we also need to make sure the rectangle + // does not get distorted by this shifting operation + double x = shiftX(r.getX(),shiftDrawCalls && isDraw); + double y = shiftY(r.getY(), shiftDrawCalls && isDraw); + double w = Math.round(r.getWidth()); + double h = Math.round(r.getHeight()); + cairoRectangle(nativePointer, x, y, w, h); + } + + // Lines are easy too + else if (s instanceof Line2D) + { + Line2D l = (Line2D) s; + cairoMoveTo(nativePointer, shiftX(l.getX1(), shiftDrawCalls && isDraw), + shiftY(l.getY1(), shiftDrawCalls && isDraw)); + cairoLineTo(nativePointer, shiftX(l.getX2(), shiftDrawCalls && isDraw), + shiftY(l.getY2(), shiftDrawCalls && isDraw)); + } + + // We can optimize ellipses too; however we don't bother optimizing arcs: + // the iterator is fast enough (an ellipse requires 5 steps using the + // iterator, while most arcs are only 2-3) + else if (s instanceof Ellipse2D) + { + Ellipse2D e = (Ellipse2D) s; + + double radius = Math.min(e.getHeight(), e.getWidth()) / 2; + + // Cairo only draws circular shapes, but we can use a stretch to make + // them into ellipses + double xscale = 1, yscale = 1; + if (e.getHeight() != e.getWidth()) + { + cairoSave(nativePointer); + + if (e.getHeight() < e.getWidth()) + xscale = e.getWidth() / (radius * 2); + else + yscale = e.getHeight() / (radius * 2); + + if (xscale != 1 || yscale != 1) + cairoScale(nativePointer, xscale, yscale); + } + + cairoArc(nativePointer, + shiftX(e.getCenterX() / xscale, shiftDrawCalls && isDraw), + shiftY(e.getCenterY() / yscale, shiftDrawCalls && isDraw), + radius, 0, Math.PI * 2); + + if (xscale != 1 || yscale != 1) + cairoRestore(nativePointer); + } + + // All other shapes are broken down and drawn in steps using the + // PathIterator + else + walkPath(s.getPathIterator(null), shiftDrawCalls && isDraw); + } + + /** + * Note that the rest of the drawing methods go via fill() or draw() for the drawing, + * although subclasses may with to overload these methods where context-specific + * optimizations are possible (e.g. bitmaps and fillRect(int, int, int, int) + */ + + public void clearRect(int x, int y, int width, int height) + { + if (bg != null) + cairoSetRGBAColor(nativePointer, bg.getRed() / 255.0, + bg.getGreen() / 255.0, bg.getBlue() / 255.0, + bg.getAlpha() / 255.0); + + Composite oldcomp = comp; + setComposite(AlphaComposite.Src); + fillRect(x, y, width, height); + + setComposite(oldcomp); + updateColor(); + } + + public void draw3DRect(int x, int y, int width, int height, boolean raised) + { + Stroke tmp = stroke; + setStroke(draw3DRectStroke); + super.draw3DRect(x, y, width, height, raised); + setStroke(tmp); + } + + public void drawArc(int x, int y, int width, int height, int startAngle, + int arcAngle) + { + draw(new Arc2D.Double((double) x, (double) y, (double) width, + (double) height, (double) startAngle, + (double) arcAngle, Arc2D.OPEN)); + } + + public void drawLine(int x1, int y1, int x2, int y2) + { + // The coordinates being pairwise identical means one wants + // to draw a single pixel. This is emulated by drawing + // a one pixel sized rectangle. + if (x1 == x2 && y1 == y2) + fill(new Rectangle(x1, y1, 1, 1)); + else + draw(new Line2D.Double(x1, y1, x2, y2)); + } + + public void drawRect(int x, int y, int width, int height) + { + draw(new Rectangle(x, y, width, height)); + } + + public void fillArc(int x, int y, int width, int height, int startAngle, + int arcAngle) + { + fill(new Arc2D.Double((double) x, (double) y, (double) width, + (double) height, (double) startAngle, + (double) arcAngle, Arc2D.PIE)); + } + + public void fillRect(int x, int y, int width, int height) + { + fill (new Rectangle(x, y, width, height)); + } + + public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) + { + fill(new Polygon(xPoints, yPoints, nPoints)); + } + + public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) + { + draw(new Polygon(xPoints, yPoints, nPoints)); + } + + public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) + { + for (int i = 1; i < nPoints; i++) + draw(new Line2D.Double(xPoints[i - 1], yPoints[i - 1], + xPoints[i], yPoints[i])); + } + + public void drawOval(int x, int y, int width, int height) + { + drawArc(x, y, width, height, 0, 360); + } + + public void drawRoundRect(int x, int y, int width, int height, int arcWidth, + int arcHeight) + { + draw(new RoundRectangle2D.Double(x, y, width, height, arcWidth, arcHeight)); + } + + public void fillOval(int x, int y, int width, int height) + { + fillArc(x, y, width, height, 0, 360); + } + + public void fillRoundRect(int x, int y, int width, int height, int arcWidth, + int arcHeight) + { + fill(new RoundRectangle2D.Double(x, y, width, height, arcWidth, arcHeight)); + } + + /** + * CopyArea - performs clipping to the native surface as a convenience + * (requires getRealBounds). Then calls copyAreaImpl. + */ + public void copyArea(int ox, int oy, int owidth, int oheight, + int odx, int ody) + { + // FIXME: does this handle a rotation transform properly? + // (the width/height might not be correct) + Point2D pos = transform.transform(new Point2D.Double(ox, oy), + (Point2D) null); + Point2D dim = transform.transform(new Point2D.Double(ox + owidth, + oy + oheight), + (Point2D) null); + Point2D p2 = transform.transform(new Point2D.Double(ox + odx, oy + ody), + (Point2D) null); + int x = (int)pos.getX(); + int y = (int)pos.getY(); + int width = (int)(dim.getX() - pos.getX()); + int height = (int)(dim.getY() - pos.getY()); + int dx = (int)(p2.getX() - pos.getX()); + int dy = (int)(p2.getY() - pos.getY()); + + Rectangle2D r = getRealBounds(); + + if( width <= 0 || height <= 0 ) + return; + // Return if outside the surface + if( x + dx > r.getWidth() || y + dy > r.getHeight() ) + return; + + if( x + dx + width < r.getX() || y + dy + height < r.getY() ) + return; + + // Clip edges if necessary + if( x + dx < r.getX() ) // left + { + width = x + dx + width; + x = (int)r.getX() - dx; + } + + if( y + dy < r.getY() ) // top + { + height = y + dy + height; + y = (int)r.getY() - dy; + } + + if( x + dx + width >= r.getWidth() ) // right + width = (int)r.getWidth() - dx - x; + + if( y + dy + height >= r.getHeight() ) // bottom + height = (int)r.getHeight() - dy - y; + + copyAreaImpl(x, y, width, height, dx, dy); + } + + ///////////////////////// RENDERING HINTS /////////////////////////////////// + + public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue) + { + hints.put(hintKey, hintValue); + + shiftDrawCalls = hints.containsValue(RenderingHints.VALUE_STROKE_NORMALIZE) + || hints.containsValue(RenderingHints.VALUE_STROKE_DEFAULT); + } + + public Object getRenderingHint(RenderingHints.Key hintKey) + { + return hints.get(hintKey); + } + + public void setRenderingHints(Map hints) + { + this.hints = new RenderingHints(getDefaultHints()); + this.hints.putAll(hints); + + shiftDrawCalls = hints.containsValue(RenderingHints.VALUE_STROKE_NORMALIZE) + || hints.containsValue(RenderingHints.VALUE_STROKE_DEFAULT); + + if (compCtx != null) + { + compCtx.dispose(); + compCtx = comp.createContext(getNativeCM(), getNativeCM(), this.hints); + } + } + + public void addRenderingHints(Map hints) + { + this.hints.putAll(hints); + } + + public RenderingHints getRenderingHints() + { + return hints; + } + + private int getInterpolation() + { + if (this.hints.containsValue(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR)) + return INTERPOLATION_NEAREST; + + else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BILINEAR)) + return INTERPOLATION_BILINEAR; + + else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BICUBIC)) + return INTERPOLATION_BICUBIC; + + else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED)) + return ALPHA_INTERPOLATION_SPEED; + + else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY)) + return ALPHA_INTERPOLATION_QUALITY; + + else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT)) + return ALPHA_INTERPOLATION_DEFAULT; + + // Do bilinear interpolation as default + return INTERPOLATION_BILINEAR; + } + + /** + * Set antialias if needed. If the ignoreAA flag is set, this method will + * return without doing anything. + * + * @param needAA RenderingHints.VALUE_ANTIALIAS_ON or RenderingHints.VALUE_ANTIALIAS_OFF + */ + private void setAntialias(boolean needAA) + { + if (ignoreAA) + return; + + if (needAA != antialias) + { + antialias = !antialias; + cairoSetAntialias(nativePointer, antialias); + } + } + + ///////////////////////// IMAGE. METHODS /////////////////////////////////// + + protected boolean drawImage(Image img, AffineTransform xform, + Color bgcolor, ImageObserver obs) + { + if (img == null) + return false; + + if (xform == null) + xform = new AffineTransform(); + + // In this case, xform is an AffineTransform that transforms bounding + // box of the specified image from image space to user space. However + // when we pass this transform to cairo, cairo will use this transform + // to map "user coordinates" to "pixel" coordinates, which is the + // other way around. Therefore to get the "user -> pixel" transform + // that cairo wants from "image -> user" transform that we currently + // have, we will need to invert the transformation matrix. + AffineTransform invertedXform; + + try + { + invertedXform = xform.createInverse(); + } + catch (NoninvertibleTransformException e) + { + throw new ImagingOpException("Unable to invert transform " + + xform.toString()); + } + + // Unrecognized image - convert to a BufferedImage + // Note - this can get us in trouble when the gdk lock is re-acquired. + // for example by VolatileImage. See ComponentGraphics for how we work + // around this. + img = AsyncImage.realImage(img, obs); + if( !(img instanceof BufferedImage) ) + { + ImageProducer source = img.getSource(); + if (source == null) + return false; + img = Toolkit.getDefaultToolkit().createImage(source); + } + + BufferedImage b = (BufferedImage) img; + Raster raster; + double[] i2u = new double[6]; + int width = b.getWidth(); + int height = b.getHeight(); + + // If this BufferedImage has a BufferedImageGraphics object, + // use the cached CairoSurface that BIG is drawing onto + + if( BufferedImageGraphics.bufferedImages.get( b ) != null ) + raster = BufferedImageGraphics.bufferedImages.get( b ); + else + raster = b.getRaster(); + + invertedXform.getMatrix(i2u); + + double alpha = 1.0; + if (comp instanceof AlphaComposite) + alpha = ((AlphaComposite) comp).getAlpha(); + + if(raster instanceof CairoSurface + && ((CairoSurface)raster).sharedBuffer == true) + { + drawCairoSurface((CairoSurface)raster, xform, alpha, getInterpolation()); + updateColor(); + return true; + } + + if( bgcolor != null ) + { + Color oldColor = bg; + setBackground(bgcolor); + + Rectangle2D bounds = new Rectangle2D.Double(0, 0, width, height); + bounds = getTransformedBounds(bounds, xform); + + clearRect((int)bounds.getX(), (int)bounds.getY(), + (int)bounds.getWidth(), (int)bounds.getHeight()); + + setBackground(oldColor); + } + + int[] pixels = b.getRGB(0, 0, width, height, null, 0, width); + // FIXME: The above method returns data in the standard ARGB colorspace, + // meaning data should NOT be alpha pre-multiplied; however Cairo expects + // data to be premultiplied. + + cairoSave(nativePointer); + Rectangle2D bounds = new Rectangle2D.Double(0, 0, width, height); + bounds = getTransformedBounds(bounds, xform); + cairoRectangle(nativePointer, bounds.getX(), bounds.getY(), + bounds.getWidth(), bounds.getHeight()); + cairoClip(nativePointer); + + drawPixels(nativePointer, pixels, width, height, width, i2u, alpha, + getInterpolation()); + + cairoRestore(nativePointer); + + // Cairo seems to lose the current color which must be restored. + updateColor(); + return true; + } + + public void drawRenderedImage(RenderedImage image, AffineTransform xform) + { + drawRaster(image.getColorModel(), image.getData(), xform, null); + } + + public void drawRenderableImage(RenderableImage image, AffineTransform xform) + { + drawRenderedImage(image.createRendering(new RenderContext(xform)), xform); + } + + public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) + { + return drawImage(img, xform, null, obs); + } + + public void drawImage(BufferedImage image, BufferedImageOp op, int x, int y) + { + Image filtered = image; + if (op != null) + filtered = op.filter(image, null); + drawImage(filtered, new AffineTransform(1f, 0f, 0f, 1f, x, y), null, null); + } + + public boolean drawImage(Image img, int x, int y, ImageObserver observer) + { + return drawImage(img, new AffineTransform(1f, 0f, 0f, 1f, x, y), null, + observer); + } + + public boolean drawImage(Image img, int x, int y, Color bgcolor, + ImageObserver observer) + { + return drawImage(img, x, y, img.getWidth(observer), + img.getHeight(observer), bgcolor, observer); + } + + public boolean drawImage(Image img, int x, int y, int width, int height, + Color bgcolor, ImageObserver observer) + { + double scaleX = width / (double) img.getWidth(observer); + double scaleY = height / (double) img.getHeight(observer); + if( scaleX == 0 || scaleY == 0 ) + return true; + + return drawImage(img, new AffineTransform(scaleX, 0f, 0f, scaleY, x, y), + bgcolor, observer); + } + + public boolean drawImage(Image img, int x, int y, int width, int height, + ImageObserver observer) + { + return drawImage(img, x, y, width, height, null, observer); + } + + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, Color bgcolor, + ImageObserver observer) + { + if (img == null) + return false; + + int sourceWidth = sx2 - sx1; + int sourceHeight = sy2 - sy1; + + int destWidth = dx2 - dx1; + int destHeight = dy2 - dy1; + + if(destWidth == 0 || destHeight == 0 || sourceWidth == 0 || + sourceHeight == 0) + return true; + + double scaleX = destWidth / (double) sourceWidth; + double scaleY = destHeight / (double) sourceHeight; + + // FIXME: Avoid using an AT if possible here - it's at least twice as slow. + + Shape oldClip = getClip(); + int cx, cy, cw, ch; + if( dx1 < dx2 ) + { cx = dx1; cw = dx2 - dx1; } + else + { cx = dx2; cw = dx1 - dx2; } + if( dy1 < dy2 ) + { cy = dy1; ch = dy2 - dy1; } + else + { cy = dy2; ch = dy1 - dy2; } + + clipRect( cx, cy, cw, ch ); + + AffineTransform tx = new AffineTransform(); + tx.translate( dx1 - sx1*scaleX, dy1 - sy1*scaleY ); + tx.scale( scaleX, scaleY ); + + boolean retval = drawImage(img, tx, bgcolor, observer); + setClip( oldClip ); + return retval; + } + + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, + ImageObserver observer) + { + return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null, observer); + } + + /** + * Optimized method for drawing a CairoSurface onto this graphics context. + * + * @param surface The surface to draw. + * @param tx The transformation matrix (cannot be null). + * @param alpha The alpha value to paint with ( 0 <= alpha <= 1). + * @param interpolation The interpolation type. + */ + protected void drawCairoSurface(CairoSurface surface, AffineTransform tx, + double alpha, int interpolation) + { + // Find offset required if this surface is a sub-raster, and append offset + // to transformation. + if (surface.getSampleModelTranslateX() != 0 + || surface.getSampleModelTranslateY() != 0) + { + Point2D origin = new Point2D.Double(0, 0); + Point2D offset = new Point2D.Double(surface.getSampleModelTranslateX(), + surface.getSampleModelTranslateY()); + + tx.transform(origin, origin); + tx.transform(offset, offset); + + tx.translate(offset.getX() - origin.getX(), + offset.getY() - origin.getY()); + } + + // Find dimensions of this surface relative to the root parent surface + Rectangle bounds = new Rectangle(-surface.getSampleModelTranslateX(), + -surface.getSampleModelTranslateY(), + surface.width, surface.height); + + // Clip to the translated image + // We use direct cairo methods to avoid the overhead of maintaining a + // java copy of the clip, since we will be reverting it immediately + // after drawing + Shape newBounds = tx.createTransformedShape(bounds); + cairoSave(nativePointer); + walkPath(newBounds.getPathIterator(null), false); + cairoClip(nativePointer); + + // Draw the surface + try + { + double[] i2u = new double[6]; + tx.createInverse().getMatrix(i2u); + surface.nativeDrawSurface(surface.surfacePointer, nativePointer, i2u, + alpha, interpolation); + } + catch (NoninvertibleTransformException ex) + { + // This should never happen(?), so we don't need to do anything here. + ; + } + + // Restore clip + cairoRestore(nativePointer); + } + + + ///////////////////////// TEXT METHODS //////////////////////////////////// + + public void drawString(String str, float x, float y) + { + if (str == null || str.length() == 0) + return; + GdkFontPeer fontPeer = (GdkFontPeer) font.getPeer(); + TextLayout tl = (TextLayout) fontPeer.textLayoutCache.get(str); + if (tl == null) + { + tl = new TextLayout( str, getFont(), getFontRenderContext() ); + fontPeer.textLayoutCache.put(str, tl); + } + + // Set antialias to text_antialiasing, and set the ignoreAA flag so that + // the setting doesn't get overridden in a draw() or fill() call. + setAntialias(!hints.get(RenderingHints.KEY_TEXT_ANTIALIASING) + .equals(RenderingHints.VALUE_TEXT_ANTIALIAS_OFF)); + ignoreAA = true; + + tl.draw(this, x, y); + ignoreAA = false; + } + + public void drawString(String str, int x, int y) + { + drawString (str, (float) x, (float) y); + } + + public void drawString(AttributedCharacterIterator ci, int x, int y) + { + drawString (ci, (float) x, (float) y); + } + + public void drawGlyphVector(GlyphVector gv, float x, float y) + { + double alpha = 1.0; + + if( gv.getNumGlyphs() <= 0 ) + return; + + if (customPaint) + setCustomPaint(gv.getOutline().getBounds()); + + if (comp instanceof AlphaComposite) + alpha = ((AlphaComposite) comp).getAlpha(); + + setAntialias(!hints.get(RenderingHints.KEY_TEXT_ANTIALIASING) + .equals(RenderingHints.VALUE_TEXT_ANTIALIAS_OFF)); + ignoreAA = true; + + if (gv instanceof FreetypeGlyphVector && alpha == 1.0 + && !((FreetypeGlyphVector)gv).hasTransforms()) + { + int n = gv.getNumGlyphs (); + int[] codes = gv.getGlyphCodes (0, n, null); + long[] fontset = ((FreetypeGlyphVector)gv).getGlyphFonts (0, n, null); + float[] positions = gv.getGlyphPositions (0, n, null); + + setFont (gv.getFont ()); + GdkFontPeer fontPeer = (GdkFontPeer) font.getPeer(); + synchronized (fontPeer) + { + cairoDrawGlyphVector(nativePointer, fontPeer, + x, y, n, codes, positions, fontset); + } + } + else + { + translate(x, y); + fill(gv.getOutline()); + translate(-x, -y); + } + + ignoreAA = false; + } + + public void drawString(AttributedCharacterIterator ci, float x, float y) + { + GlyphVector gv = getFont().createGlyphVector(getFontRenderContext(), ci); + drawGlyphVector(gv, x, y); + } + + /** + * Should perhaps be contexct dependent, but this is left for now as an + * overloadable default implementation. + */ + public FontRenderContext getFontRenderContext() + { + return new FontRenderContext(transform, true, true); + } + + // Until such time as pango is happy to talk directly to cairo, we + // actually need to redirect some calls from the GtkFontPeer and + // GtkFontMetrics into the drawing kit and ask cairo ourselves. + + public FontMetrics getFontMetrics() + { + return getFontMetrics(getFont()); + } + + public FontMetrics getFontMetrics(Font f) + { + return ((GdkFontPeer) f.getPeer()).getFontMetrics(f); + } + + public void setFont(Font f) + { + // Sun's JDK does not throw NPEs, instead it leaves the current setting + // unchanged. So do we. + if (f == null) + return; + + if (f.getPeer() instanceof GdkFontPeer) + font = f; + else + font = + ((ClasspathToolkit)(Toolkit.getDefaultToolkit())) + .getFont(f.getName(), f.getAttributes()); + + GdkFontPeer fontpeer = (GdkFontPeer) getFont().getPeer(); + synchronized (fontpeer) + { + cairoSetFont(nativePointer, fontpeer); + } + } + + public Font getFont() + { + if (font == null) + return new Font("SansSerif", Font.PLAIN, 12); + return font; + } + + /////////////////////// MISC. PUBLIC METHODS ///////////////////////////////// + + public boolean hit(Rectangle rect, Shape s, boolean onStroke) + { + if( onStroke ) + { + Shape stroked = stroke.createStrokedShape( s ); + return stroked.intersects( (double)rect.x, (double)rect.y, + (double)rect.width, (double)rect.height ); + } + return s.intersects( (double)rect.x, (double)rect.y, + (double)rect.width, (double)rect.height ); + } + + public String toString() + { + return (getClass().getName() + + "[font=" + getFont().toString() + + ",color=" + fg.toString() + + "]"); + } + + ///////////////////////// PRIVATE METHODS /////////////////////////////////// + + /** + * All the drawImage() methods eventually get delegated here if the image + * is not a Cairo surface. + * + * @param bgcolor - if non-null draws the background color before + * drawing the image. + */ + private boolean drawRaster(ColorModel cm, Raster r, + AffineTransform imageToUser, Color bgcolor) + { + if (r == null) + return false; + + SampleModel sm = r.getSampleModel(); + DataBuffer db = r.getDataBuffer(); + + if (db == null || sm == null) + return false; + + if (cm == null) + cm = ColorModel.getRGBdefault(); + + double[] i2u = new double[6]; + if (imageToUser != null) + imageToUser.getMatrix(i2u); + else + { + i2u[0] = 1; + i2u[1] = 0; + i2u[2] = 0; + i2u[3] = 1; + i2u[4] = 0; + i2u[5] = 0; + } + + int[] pixels = findSimpleIntegerArray(cm, r); + + if (pixels == null) + { + // FIXME: I don't think this code will work correctly with a non-RGB + // MultiPixelPackedSampleModel. Although this entire method should + // probably be rewritten to better utilize Cairo's different supported + // data formats. + if (sm instanceof MultiPixelPackedSampleModel) + { + pixels = r.getPixels(0, 0, r.getWidth(), r.getHeight(), pixels); + for (int i = 0; i < pixels.length; i++) + pixels[i] = cm.getRGB(pixels[i]); + } + else + { + pixels = new int[r.getWidth() * r.getHeight()]; + for (int i = 0; i < pixels.length; i++) + pixels[i] = cm.getRGB(db.getElem(i)); + } + } + + // Change all transparent pixels in the image to the specified bgcolor, + // or (if there's no alpha) fill in an alpha channel so that it paints + // correctly. + if (cm.hasAlpha()) + { + if (bgcolor != null && cm.hasAlpha()) + for (int i = 0; i < pixels.length; i++) + { + if (cm.getAlpha(pixels[i]) == 0) + pixels[i] = bgcolor.getRGB(); + } + } + else + for (int i = 0; i < pixels.length; i++) + pixels[i] |= 0xFF000000; + + double alpha = 1.0; + if (comp instanceof AlphaComposite) + alpha = ((AlphaComposite) comp).getAlpha(); + + drawPixels(nativePointer, pixels, r.getWidth(), r.getHeight(), + r.getWidth(), i2u, alpha, getInterpolation()); + + // Cairo seems to lose the current color which must be restored. + updateColor(); + + return true; + } + + /** + * Shifts an x-coordinate by 0.5 in device space. + */ + private double shiftX(double coord, boolean doShift) + { + if (doShift) + { + double shift = 0.5; + if (!transform.isIdentity()) + shift /= transform.getScaleX(); + return (coord + shift); + } + else + return coord; + } + + /** + * Shifts a y-coordinate by 0.5 in device space. + */ + private double shiftY(double coord, boolean doShift) + { + if (doShift) + { + double shift = 0.5; + if (!transform.isIdentity()) + shift /= transform.getScaleY(); + return (coord + shift); + } + else + return coord; + } + + /** + * Adds a pathIterator to the current Cairo path, also sets the cairo winding rule. + */ + private void walkPath(PathIterator p, boolean doShift) + { + double x = 0; + double y = 0; + double[] coords = new double[6]; + + cairoSetFillRule(nativePointer, p.getWindingRule()); + for (; ! p.isDone(); p.next()) + { + int seg = p.currentSegment(coords); + switch (seg) + { + case PathIterator.SEG_MOVETO: + x = shiftX(coords[0], doShift); + y = shiftY(coords[1], doShift); + cairoMoveTo(nativePointer, x, y); + break; + case PathIterator.SEG_LINETO: + x = shiftX(coords[0], doShift); + y = shiftY(coords[1], doShift); + cairoLineTo(nativePointer, x, y); + break; + case PathIterator.SEG_QUADTO: + // splitting a quadratic bezier into a cubic: + // see: http://pfaedit.sourceforge.net/bezier.html + double x1 = x + (2.0 / 3.0) * (shiftX(coords[0], doShift) - x); + double y1 = y + (2.0 / 3.0) * (shiftY(coords[1], doShift) - y); + + double x2 = x1 + (1.0 / 3.0) * (shiftX(coords[2], doShift) - x); + double y2 = y1 + (1.0 / 3.0) * (shiftY(coords[3], doShift) - y); + + x = shiftX(coords[2], doShift); + y = shiftY(coords[3], doShift); + cairoCurveTo(nativePointer, x1, y1, x2, y2, x, y); + break; + case PathIterator.SEG_CUBICTO: + x = shiftX(coords[4], doShift); + y = shiftY(coords[5], doShift); + cairoCurveTo(nativePointer, shiftX(coords[0], doShift), + shiftY(coords[1], doShift), + shiftX(coords[2], doShift), + shiftY(coords[3], doShift), x, y); + break; + case PathIterator.SEG_CLOSE: + cairoClosePath(nativePointer); + break; + } + } + } + + /** + * Used by setRenderingHints() + */ + private Map getDefaultHints() + { + HashMap defaultHints = + new HashMap(); + + defaultHints.put(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT); + + defaultHints.put(RenderingHints.KEY_STROKE_CONTROL, + RenderingHints.VALUE_STROKE_DEFAULT); + + defaultHints.put(RenderingHints.KEY_FRACTIONALMETRICS, + RenderingHints.VALUE_FRACTIONALMETRICS_OFF); + + defaultHints.put(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_OFF); + + defaultHints.put(RenderingHints.KEY_RENDERING, + RenderingHints.VALUE_RENDER_DEFAULT); + + return defaultHints; + } + + /** + * Used by drawRaster and GdkPixbufDecoder + */ + public static int[] findSimpleIntegerArray (ColorModel cm, Raster raster) + { + if (cm == null || raster == null) + return null; + + if (! cm.getColorSpace().isCS_sRGB()) + return null; + + if (! (cm instanceof DirectColorModel)) + return null; + + DirectColorModel dcm = (DirectColorModel) cm; + + if (dcm.getRedMask() != 0x00FF0000 || dcm.getGreenMask() != 0x0000FF00 + || dcm.getBlueMask() != 0x000000FF) + return null; + + if (! (raster instanceof WritableRaster)) + return null; + + if (raster.getSampleModel().getDataType() != DataBuffer.TYPE_INT) + return null; + + if (! (raster.getDataBuffer() instanceof DataBufferInt)) + return null; + + DataBufferInt db = (DataBufferInt) raster.getDataBuffer(); + + if (db.getNumBanks() != 1) + return null; + + // Finally, we have determined that this is a single bank, [A]RGB-int + // buffer in sRGB space. It's worth checking all this, because it means + // that cairo can paint directly into the data buffer, which is very + // fast compared to all the normal copying and converting. + + return db.getData(); + } + + /** + * Helper method to transform the clip. This is called by the various + * transformation-manipulation methods to update the clip (which is in + * userspace) accordingly. + * + * The transform usually is the inverse transform that was applied to the + * graphics object. + * + * @param t the transform to apply to the clip + */ + private void updateClip(AffineTransform t) + { + if (clip == null) + return; + + // If the clip is a rectangle, and the transformation preserves the shape + // (translate/stretch only), then keep the clip as a rectangle + double[] matrix = new double[4]; + t.getMatrix(matrix); + if (clip instanceof Rectangle2D && matrix[1] == 0 && matrix[2] == 0) + { + Rectangle2D rect = (Rectangle2D)clip; + double[] origin = new double[] {rect.getX(), rect.getY()}; + double[] dimensions = new double[] {rect.getWidth(), rect.getHeight()}; + t.transform(origin, 0, origin, 0, 1); + t.deltaTransform(dimensions, 0, dimensions, 0, 1); + rect.setRect(origin[0], origin[1], dimensions[0], dimensions[1]); + } + else + { + if (! (clip instanceof GeneralPath)) + clip = new GeneralPath(clip); + + GeneralPath p = (GeneralPath) clip; + p.transform(t); + } + } + + private static Rectangle computeIntersection(int x, int y, int w, int h, + Rectangle rect) + { + int x2 = rect.x; + int y2 = rect.y; + int w2 = rect.width; + int h2 = rect.height; + + int dx = (x > x2) ? x : x2; + int dy = (y > y2) ? y : y2; + int dw = (x + w < x2 + w2) ? (x + w - dx) : (x2 + w2 - dx); + int dh = (y + h < y2 + h2) ? (y + h - dy) : (y2 + h2 - dy); + + if (dw >= 0 && dh >= 0) + rect.setBounds(dx, dy, dw, dh); + else + rect.setBounds(0, 0, 0, 0); + + return rect; + } + + static Rectangle2D getTransformedBounds(Rectangle2D bounds, AffineTransform tx) + { + double x1 = bounds.getX(); + double x2 = bounds.getX() + bounds.getWidth(); + double x3 = x1; + double x4 = x2; + double y1 = bounds.getY(); + double y2 = y1; + double y3 = bounds.getY() + bounds.getHeight(); + double y4 = y3; + + double[] points = new double[] {x1, y1, x2, y2, x3, y3, x4, y4}; + tx.transform(points, 0, points, 0, 4); + + double minX = points[0]; + double maxX = minX; + double minY = points[1]; + double maxY = minY; + for (int i = 0; i < 8; i++) + { + if (points[i] < minX) + minX = points[i]; + if (points[i] > maxX) + maxX = points[i]; + i++; + + if (points[i] < minY) + minY = points[i]; + if (points[i] > maxY) + maxY = points[i]; + } + + return new Rectangle2D.Double(minX, minY, (maxX - minX), (maxY - minY)); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurface.java b/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurface.java new file mode 100644 index 000000000..71f6638e4 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurface.java @@ -0,0 +1,428 @@ +/* CairoSurface.java + Copyright (C) 2006, 2007 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.gtk; + +import gnu.java.awt.Buffers; + +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.color.ColorSpace; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferInt; +import java.awt.image.DirectColorModel; +import java.awt.image.Raster; +import java.awt.image.RasterFormatException; +import java.awt.image.SampleModel; +import java.awt.image.SinglePixelPackedSampleModel; +import java.awt.image.WritableRaster; +import java.nio.ByteOrder; +import java.util.Arrays; +import java.util.Hashtable; + +/** + * CairoSurface - wraps a Cairo surface. + * + * @author Sven de Marothy + */ +public class CairoSurface extends WritableRaster +{ + int width = -1, height = -1; + + /** + * The native pointer to the Cairo surface. + */ + long surfacePointer; + + /** + * Whether the data buffer is shared between java and cairo. + */ + boolean sharedBuffer; + + // FIXME: use only the cairoCM_pre colormodel + // since that's what Cairo really uses (is there a way to do this cheaply? + // we use a non-multiplied model most of the time to avoid costly coercion + // operations...) + static ColorModel cairoColorModel = new DirectColorModel(32, 0x00FF0000, + 0x0000FF00, + 0x000000FF, + 0xFF000000); + + static ColorModel cairoCM_pre = new DirectColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), + 32, 0x00FF0000, + 0x0000FF00, + 0x000000FF, + 0xFF000000, + true, + Buffers.smallestAppropriateTransferType(32)); + + // This CM corresponds to the CAIRO_FORMAT_RGB24 type in Cairo + static ColorModel cairoCM_opaque = new DirectColorModel(24, 0x00FF0000, + 0x0000FF00, + 0x000000FF); + /** + * Allocates and clears the buffer and creates the cairo surface. + * @param width - the image size + * @param height - the image size + * @param stride - the buffer row stride. (in ints) + */ + private native void create(int width, int height, int stride, int[] buf); + + /** + * Destroys the cairo surface and frees the buffer. + */ + private native void destroy(long surfacePointer, int[] buf); + + /** + * Draws this image to a given CairoGraphics context, + * with an affine transform given by i2u. + */ + public native void nativeDrawSurface(long surfacePointer, long contextPointer, + double[] i2u, double alpha, + int interpolation); + + /** + * Synchronizes the image's data buffers, copying any changes made in the + * Java array into the native array. + * + * This method should only be called if (sharedBuffers == false). + */ + native void syncNativeToJava(long surfacePointer, int[] buffer); + + /** + * Synchronizes the image's data buffers, copying any changes made in the + * native array into the Java array. + * + * This method should only be called if (sharedBuffers == false). + */ + native void syncJavaToNative(long surfacePointer, int[] buffer); + + /** + * Return the buffer, with the sample values of each pixel reversed + * (ie, in ABGR instead of ARGB). + * + * @return A pointer to a flipped buffer. The memory is allocated in native + * code, and must be explicitly freed when it is no longer needed. + */ + native long getFlippedBuffer(long surfacePointer); + + /** + * Create a cairo_surface_t with specified width and height. + * The format will be ARGB32 with premultiplied alpha and native bit + * and word ordering. + */ + public CairoSurface(int width, int height) + { + this(0, 0, width, height); + } + + public CairoSurface(int x, int y, int width, int height) + { + super(createCairoSampleModel(width, height), null, new Point(x, y)); + + if(width <= 0 || height <= 0) + throw new IllegalArgumentException("Image must be at least 1x1 pixels."); + + this.width = width; + this.height = height; + dataBuffer = new DataBufferInt(width * height); + create(width, height, width, getData()); + + if(surfacePointer == 0) + throw new Error("Could not allocate bitmap."); + } + + /** + * Create a Cairo Surface that is a subimage of another Cairo Surface + */ + public CairoSurface(SampleModel sm, CairoSurface parent, Rectangle bounds, + Point origin) + { + super(sm, parent.dataBuffer, bounds, origin, parent); + + this.width = super.width; + this.height = super.height; + this.surfacePointer = parent.surfacePointer; + this.sharedBuffer = parent.sharedBuffer; + this.dataBuffer = parent.dataBuffer; + } + + /** + * Create a cairo_surface_t from a GtkImage instance. + * (data is copied, not shared) + */ + CairoSurface(GtkImage image) + { + this(image.width, image.height); + + // Copy the pixel data from the GtkImage. + int[] data = image.getPixels(); + + // Swap ordering from GdkPixbuf to Cairo + if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) + { + for (int i = 0; i < data.length; i++ ) + { + // On a big endian system we get a RRGGBBAA data array. + int alpha = data[i] & 0xFF; + if( alpha == 0 ) // I do not know why we need this, but it works. + data[i] = 0; + else + { + // Cairo needs a ARGB32 native array. + data[i] = (data[i] >>> 8) | (alpha << 24); + } + } + } + else + { + for (int i = 0; i < data.length; i++ ) + { + // On a little endian system we get a AABBGGRR data array. + int alpha = data[i] & 0xFF000000; + if( alpha == 0 ) // I do not know why we need this, but it works. + data[i] = 0; + else + { + int b = (data[i] & 0xFF0000) >> 16; + int g = (data[i] & 0xFF00); + int r = (data[i] & 0xFF) << 16; + // Cairo needs a ARGB32 native array. + data[i] = alpha | r | g | b; + } + } + } + + System.arraycopy(data, 0, getData(), 0, data.length); + } + + /** + * Dispose of the native data. + */ + public void dispose() + { + if(surfacePointer != 0 && parent == null) + destroy(surfacePointer, getData()); + } + + /** + * Call dispose() to clean up any native resources allocated. + */ + protected void finalize() + { + dispose(); + } + + /** + * Return a GtkImage from this Cairo surface. + */ + public GtkImage getGtkImage() + { + return new GtkImage(width, height, getFlippedBuffer(surfacePointer)); + } + + /** + * Convenience method to quickly grab the data array backing this Raster. + * + * @return The array behind the databuffer. + */ + public int[] getData() + { + return ((DataBufferInt)dataBuffer).getData(); + } + + /** + * Returns a BufferedImage backed by a Cairo surface. + */ + public static BufferedImage getBufferedImage(int width, int height) + { + return getBufferedImage(new CairoSurface(width, height)); + } + + /** + * Returns a BufferedImage backed by a Cairo surface, + * created from a GtkImage. + */ + public static BufferedImage getBufferedImage(GtkImage image) + { + return getBufferedImage(new CairoSurface(image)); + } + + /** + * Returns a BufferedImage backed by a Cairo surface. + */ + public static BufferedImage getBufferedImage(CairoSurface surface) + { + return new BufferedImage(cairoColorModel, surface, + cairoColorModel.isAlphaPremultiplied(), + new Hashtable()); + } + + /** + * Return a Graphics2D drawing to the CairoSurface. + */ + public Graphics2D getGraphics() + { + return new CairoSurfaceGraphics(this); + } + + ///// Methods used by CairoSurfaceGraphics ///// + /** + * Creates a cairo_t drawing context, returns the pointer as a long. + * Used by CairoSurfaceGraphics. + */ + native long nativeNewCairoContext(long surfacePointer); + + public long newCairoContext() + { + return nativeNewCairoContext(surfacePointer); + } + + /** + * Copy a portion of this surface to another area on the surface. The given + * parameters must be within bounds - count on a segfault otherwise. + * + * @param x The x coordinate of the area to be copied from. + * @param y The y coordinate of the area to be copied from. + * @param width The width of the area to be copied. + * @param height The height of the area to be copied. + * @param dx The destination x coordinate. + * @param dy The destination y coordinate. + * @param stride The scanline stride. + */ + public void copyAreaNative(int x, int y, int width, + int height, int dx, int dy, int stride) + { + copyAreaNative2(surfacePointer, x, y, width, height, dx, dy, stride); + } + native void copyAreaNative2(long surfacePointer, + int x, int y, int width, int height, + int dx, int dy, int stride); + + /** + * Creates a SampleModel that matches Cairo's native format + */ + protected static SampleModel createCairoSampleModel(int w, int h) + { + return new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT, w, h, + new int[]{0x00FF0000, 0x0000FF00, + 0x000000FF, 0xFF000000}); + } + + /** + * Returns whether this ColorModel is compatible with Cairo's native types. + * + * @param cm The color model to check. + * @return Whether it is compatible. + */ + public static boolean isCompatibleColorModel(ColorModel cm) + { + return (cm.equals(cairoCM_pre) || cm.equals(cairoCM_opaque) || + cm.equals(cairoColorModel)); + } + + /** + * Returns whether this SampleModel is compatible with Cairo's native types. + * + * @param sm The sample model to check. + * @return Whether it is compatible. + */ + public static boolean isCompatibleSampleModel(SampleModel sm) + { + return (sm instanceof SinglePixelPackedSampleModel + && sm.getDataType() == DataBuffer.TYPE_INT + && Arrays.equals(((SinglePixelPackedSampleModel)sm).getBitMasks(), + new int[]{0x00FF0000, 0x0000FF00, + 0x000000FF, 0xFF000000})); + } + + ///// Methods interhited from Raster and WritableRaster ///// + public Raster createChild(int parentX, int parentY, int width, int height, + int childMinX, int childMinY, int[] bandList) + { + return createWritableChild(parentX, parentY, width, height, + childMinX, childMinY, bandList); + } + + public WritableRaster createCompatibleWritableRaster() + { + return new CairoSurface(width, height); + } + + public WritableRaster createCompatibleWritableRaster (int x, int y, + int w, int h) + { + return new CairoSurface(x, y, w, h); + } + + public Raster createTranslatedChild(int childMinX, int childMinY) + { + return createWritableTranslatedChild(childMinX, childMinY); + } + + public WritableRaster createWritableChild(int parentX, int parentY, + int w, int h, int childMinX, + int childMinY, int[] bandList) + { + if (parentX < minX || parentX + w > minX + width + || parentY < minY || parentY + h > minY + height) + throw new RasterFormatException("Child raster extends beyond parent"); + + SampleModel sm = (bandList == null) ? + sampleModel : + sampleModel.createSubsetSampleModel(bandList); + + return new CairoSurface(sm, this, + new Rectangle(childMinX, childMinY, w, h), + new Point(sampleModelTranslateX + childMinX - parentX, + sampleModelTranslateY + childMinY - parentY)); + } + + public WritableRaster createWritableTranslatedChild(int x, int y) + { + int tcx = sampleModelTranslateX - minX + x; + int tcy = sampleModelTranslateY - minY + y; + + return new CairoSurface(sampleModel, this, + new Rectangle(x, y, width, height), + new Point(tcx, tcy)); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java b/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java new file mode 100644 index 000000000..a0c6caa9a --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java @@ -0,0 +1,355 @@ +/* CairoSurfaceGraphics.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.java.awt.peer.gtk; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.Toolkit; +import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.image.RenderedImage; +import java.util.Hashtable; + +/** + * Implementation of Graphics2D on a Cairo surface. + */ +public class CairoSurfaceGraphics extends CairoGraphics2D +{ + protected CairoSurface surface; + private BufferedImage buffer; + private long cairo_t; + + /** + * Create a graphics context from a cairo surface + */ + public CairoSurfaceGraphics(CairoSurface surface) + { + this.surface = surface; + cairo_t = surface.newCairoContext(); + setup( cairo_t ); + setClip(0, 0, surface.width, surface.height); + } + + /** + * Creates another context from a surface. + * Used by create(). + */ + private CairoSurfaceGraphics(CairoSurfaceGraphics copyFrom) + { + surface = copyFrom.surface; + cairo_t = surface.newCairoContext(); + copy( copyFrom, cairo_t ); + } + + public Graphics create() + { + return new CairoSurfaceGraphics(this); + } + + public GraphicsConfiguration getDeviceConfiguration() + { + return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration(); + } + + protected Rectangle2D getRealBounds() + { + return new Rectangle2D.Double(0.0, 0.0, surface.width, surface.height); + } + + public void copyAreaImpl(int x, int y, int width, int height, int dx, int dy) + { + surface.copyAreaNative(x, y, width, height, dx, dy, surface.width); + } + + /** + * Overloaded methods that do actual drawing need to account for custom + * composites + */ + public void draw(Shape s) + { + if (!surface.sharedBuffer) + surface.syncJavaToNative(surface.surfacePointer, surface.getData()); + + // Find total bounds of shape + Rectangle r = findStrokedBounds(s); + if (shiftDrawCalls) + { + r.width++; + r.height++; + } + + // Do the drawing + if (comp == null || comp instanceof AlphaComposite) + super.draw(s); + + else + { + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setStroke(this.getStroke()); + g2d.setColor(this.getColor()); + g2d.setTransform(transform); + g2d.draw(s); + + drawComposite(r.getBounds2D(), null); + } + + if (!surface.sharedBuffer) + surface.syncNativeToJava(surface.surfacePointer, surface.getData()); + } + + public void fill(Shape s) + { + if (!surface.sharedBuffer) + surface.syncJavaToNative(surface.surfacePointer, surface.getData()); + + if (comp == null || comp instanceof AlphaComposite) + super.fill(s); + + else + { + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setPaint(this.getPaint()); + g2d.setColor(this.getColor()); + g2d.setTransform(transform); + g2d.fill(s); + + drawComposite(s.getBounds2D(), null); + } + + if (!surface.sharedBuffer) + surface.syncNativeToJava(surface.surfacePointer, surface.getData()); + } + + public void drawRenderedImage(RenderedImage image, AffineTransform xform) + { + if (!surface.sharedBuffer) + surface.syncJavaToNative(surface.surfacePointer, surface.getData()); + + if (comp == null || comp instanceof AlphaComposite) + super.drawRenderedImage(image, xform); + + else + { + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setRenderingHints(this.getRenderingHints()); + g2d.setTransform(transform); + g2d.drawRenderedImage(image, xform); + + drawComposite(buffer.getRaster().getBounds(), null); + } + + if (!surface.sharedBuffer) + surface.syncNativeToJava(surface.surfacePointer, surface.getData()); + } + + protected boolean drawImage(Image img, AffineTransform xform, + Color bgcolor, ImageObserver obs) + { + if (!surface.sharedBuffer) + surface.syncJavaToNative(surface.surfacePointer, surface.getData()); + + boolean ret; + if (comp == null || comp instanceof AlphaComposite) + ret = super.drawImage(img, xform, bgcolor, obs); + + else + { + // Get buffered image of source + if( !(img instanceof BufferedImage) ) + { + ImageProducer source = img.getSource(); + if (source == null) + return false; + img = Toolkit.getDefaultToolkit().createImage(source); + } + BufferedImage bImg = (BufferedImage) img; + + // Find translated bounds + Rectangle2D bounds = new Rectangle(bImg.getMinX(), bImg.getMinY(), + bImg.getWidth(), bImg.getHeight()); + if (xform != null) + bounds = getTransformedBounds(bounds, xform); + + // Create buffer and draw image + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setRenderingHints(this.getRenderingHints()); + g2d.drawImage(img, xform, obs); + + // Perform compositing + ret = drawComposite(bounds, obs); + } + + if (!surface.sharedBuffer) + surface.syncNativeToJava(surface.surfacePointer, surface.getData()); + + return ret; + } + + public void drawGlyphVector(GlyphVector gv, float x, float y) + { + if (!surface.sharedBuffer) + surface.syncJavaToNative(surface.surfacePointer, surface.getData()); + + if (comp == null || comp instanceof AlphaComposite) + super.drawGlyphVector(gv, x, y); + + else + { + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setPaint(this.getPaint()); + g2d.setStroke(this.getStroke()); + g2d.drawGlyphVector(gv, x, y); + + Rectangle2D bounds = gv.getLogicalBounds(); + bounds = new Rectangle2D.Double(x + bounds.getX(), y + bounds.getY(), + bounds.getWidth(), bounds.getHeight()); + drawComposite(bounds, null); + } + + if (!surface.sharedBuffer) + surface.syncNativeToJava(surface.surfacePointer, surface.getData()); + } + + private boolean drawComposite(Rectangle2D bounds, ImageObserver observer) + { + // Find bounds in device space + bounds = getTransformedBounds(bounds, transform); + + // Clip bounds by the stored clip, and by the internal buffer + Rectangle2D devClip = this.getClipInDevSpace(); + Rectangle2D.intersect(bounds, devClip, bounds); + devClip = new Rectangle(buffer.getMinX(), buffer.getMinY(), + buffer.getWidth(), buffer.getHeight()); + Rectangle2D.intersect(bounds, devClip, bounds); + + // Round bounds as needed, but be careful in our rounding + // (otherwise it may leave unpainted stripes) + double x = bounds.getX(); + double y = bounds.getY(); + double maxX = x + bounds.getWidth(); + double maxY = y + bounds.getHeight(); + x = Math.round(x); + y = Math.round(y); + bounds.setRect(x, y, Math.round(maxX - x), Math.round(maxY - y)); + + // Find subimage of internal buffer for updating + BufferedImage buffer2 = buffer; + if (!bounds.equals(buffer2.getRaster().getBounds())) + buffer2 = buffer2.getSubimage((int)bounds.getX(), (int)bounds.getY(), + (int)bounds.getWidth(), + (int)bounds.getHeight()); + + // Find subimage of main image for updating + BufferedImage current = CairoSurface.getBufferedImage(surface); + current = current.getSubimage((int)bounds.getX(), (int)bounds.getY(), + (int)bounds.getWidth(), + (int)bounds.getHeight()); + + // Perform actual composite operation + compCtx.compose(buffer2.getRaster(), current.getRaster(), + buffer2.getRaster()); + + // Set cairo's composite to direct SRC, since we've already done our own + // compositing + Composite oldcomp = comp; + setComposite(AlphaComposite.Src); + + // This MUST call directly into the "action" method in CairoGraphics2D, + // not one of the wrappers, to ensure that the composite isn't processed + // more than once! + boolean rv = super.drawImage(buffer2, + AffineTransform.getTranslateInstance(bounds.getX(), + bounds.getY()), + null, null); + setComposite(oldcomp); + updateColor(); + return rv; + } + + private void createBuffer() + { + if (buffer == null) + { + buffer = new BufferedImage(getBufferCM(), + surface.createCompatibleWritableRaster(), + getBufferCM().isAlphaPremultiplied(), + new Hashtable()); + } + else + { + Graphics2D g2d = ((Graphics2D)buffer.getGraphics()); + + g2d.setBackground(new Color(0,0,0,0)); + g2d.clearRect(0, 0, buffer.getWidth(), buffer.getHeight()); + } + } + + protected ColorModel getNativeCM() + { + return CairoSurface.cairoCM_pre; + } + + protected ColorModel getBufferCM() + { + return CairoSurface.cairoColorModel; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/ComponentGraphics.java b/libjava/classpath/gnu/java/awt/peer/gtk/ComponentGraphics.java new file mode 100644 index 000000000..50161b2b7 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/ComponentGraphics.java @@ -0,0 +1,941 @@ +/* ComponentGraphics.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.java.awt.peer.gtk; + +import gnu.classpath.Pointer; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.Image; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.Toolkit; +import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.image.Raster; +import java.awt.image.RenderedImage; +import java.awt.image.WritableRaster; +import java.util.Hashtable; + +/** + * ComponentGraphics - context for drawing directly to a component, + * as this is an X drawable, it requires that we use GTK locks. + * + * This context draws directly to the drawable and requires xrender. + */ +public class ComponentGraphics extends CairoGraphics2D +{ + private static final boolean hasXRenderExtension = hasXRender(); + + private GtkComponentPeer component; + protected long cairo_t; + private BufferedImage buffer, componentBuffer; + + private static ThreadLocal hasLock = new ThreadLocal(); + private static Integer ONE = Integer.valueOf(1); + + ComponentGraphics() + { + } + + private ComponentGraphics(GtkComponentPeer component) + { + this.component = component; + cairo_t = initState(component); + setup( cairo_t ); + Rectangle bounds = component.awtComponent.getBounds(); + setClip( new Rectangle( 0, 0, bounds.width, bounds.height) ); + setBackground(component.awtComponent.getBackground()); + setColor(component.awtComponent.getForeground()); + } + + private ComponentGraphics(ComponentGraphics cg) + { + component = cg.component; + cairo_t = initState(component); + copy( cg, cairo_t ); + Rectangle bounds = component.awtComponent.getBounds(); + setClip( new Rectangle( 0, 0, bounds.width, bounds.height) ); + setBackground(component.awtComponent.getBackground()); + setColor(component.awtComponent.getForeground()); + } + + /** + * Creates a cairo_t for the component surface and return it. + */ + private native long initState(GtkComponentPeer component); + + /** + * Obtain and hold a GDK lock, which is required for all drawing operations + * in this graphics context (since it is backed by an X surface). + * + * This method causes the GDK locking behaviour to be re-entrant. No race + * conditions are caused since a ThreadLocal is used and each thread has its + * own lock counter. + */ + private void lock() + { + Integer i = hasLock.get(); + if (i == null) + { + start_gdk_drawing(); + hasLock.set(ONE); + } + else + hasLock.set(Integer.valueOf(i.intValue() + 1)); + } + + /** + * Release the re-entrant GDK lock. + */ + private void unlock() + { + Integer i = hasLock.get(); + if (i == null) + throw new IllegalStateException(); + if (i == ONE) + { + hasLock.set(null); + end_gdk_drawing(); + } + else if (i.intValue() == 2) + hasLock.set(ONE); + else + hasLock.set(Integer.valueOf(i.intValue() - 1)); + } + + /** + * Creates a cairo_t for a volatile image + */ + protected native long initFromVolatile( long pixmapPtr); + + /** + * Grab lock + */ + private native void start_gdk_drawing(); + + /** + * Release lock + */ + private native void end_gdk_drawing(); + + /** + * Query if the system has the XRender extension. + */ + public static native boolean hasXRender(); + + /** + * This is a utility method (used by GtkComponentPeer) for grabbing the + * image of a component. + */ + private static native Pointer nativeGrab(GtkComponentPeer component); + + private native void copyAreaNative(GtkComponentPeer component, int x, int y, + int width, int height, int dx, int dy); + + private native void drawVolatile(GtkComponentPeer component, + long vimg, int x, int y, + int width, int height, int cx, int cy, + int cw, int ch); + + /** + * Not really related (moveme?). Utility method used by GtkComponent. + */ + public static GtkImage grab( GtkComponentPeer component ) + { + return new GtkImage( nativeGrab( component ) ); + } + + /** + * Returns a Graphics2D object for a component, either an instance of this + * class (if xrender is supported), or a context which copies. + */ + public static Graphics2D getComponentGraphics(GtkComponentPeer component) + { + if( hasXRenderExtension ) + return new ComponentGraphics(component); + + Rectangle r = component.awtComponent.getBounds(); + return new ComponentGraphicsCopy(r.width, r.height, component); + } + + public GraphicsConfiguration getDeviceConfiguration() + { + return component.getGraphicsConfiguration(); + } + + public Graphics create() + { + return new ComponentGraphics(this); + } + + protected Rectangle2D getRealBounds() + { + return component.awtComponent.getBounds(); + } + + public void copyAreaImpl(int x, int y, int width, int height, int dx, int dy) + { + copyAreaNative(component, x, y, width, height, dx, dy); + } + + /** + * Overloaded methods that do actual drawing need to enter the gdk threads + * and also do certain things before and after. + */ + public void draw(Shape s) + { + if (comp == null || comp instanceof AlphaComposite) + super.draw(s); + + else + { + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setStroke(this.getStroke()); + g2d.setColor(this.getColor()); + g2d.draw(s); + + drawComposite(s.getBounds2D(), null); + } + } + + public void fill(Shape s) + { + if (comp == null || comp instanceof AlphaComposite) + super.fill(s); + + else + { + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setPaint(this.getPaint()); + g2d.setColor(this.getColor()); + g2d.fill(s); + + drawComposite(s.getBounds2D(), null); + } + } + + public void drawRenderedImage(RenderedImage image, AffineTransform xform) + { + if (comp == null || comp instanceof AlphaComposite) + super.drawRenderedImage(image, xform); + + else + { + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setRenderingHints(this.getRenderingHints()); + g2d.drawRenderedImage(image, xform); + + drawComposite(buffer.getRaster().getBounds(), null); + } + } + + protected boolean drawImage(Image img, AffineTransform xform, + Color bgcolor, ImageObserver obs) + { + boolean rv; + if (comp == null || comp instanceof AlphaComposite) + rv = super.drawImage(img, xform, bgcolor, obs); + + else + { + // Get buffered image of source + if( !(img instanceof BufferedImage) ) + { + ImageProducer source = img.getSource(); + if (source == null) + return false; + img = Toolkit.getDefaultToolkit().createImage(source); + } + BufferedImage bImg = (BufferedImage) img; + + // Find translated bounds + Point2D origin = new Point2D.Double(bImg.getMinX(), bImg.getMinY()); + Point2D pt = new Point2D.Double(bImg.getWidth() + bImg.getMinX(), + bImg.getHeight() + bImg.getMinY()); + if (xform != null) + { + origin = xform.transform(origin, origin); + pt = xform.transform(pt, pt); + } + + // Create buffer and draw image + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setRenderingHints(this.getRenderingHints()); + g2d.drawImage(img, xform, obs); + + // Perform compositing + rv = drawComposite(new Rectangle2D.Double(origin.getX(), + origin.getY(), + pt.getX(), pt.getY()), + obs); + } + return rv; + } + + public void drawGlyphVector(GlyphVector gv, float x, float y) + { + if (comp == null || comp instanceof AlphaComposite) + super.drawGlyphVector(gv, x, y); + + else + { + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setPaint(this.getPaint()); + g2d.setStroke(this.getStroke()); + g2d.drawGlyphVector(gv, x, y); + + Rectangle2D bounds = gv.getLogicalBounds(); + bounds = new Rectangle2D.Double(x + bounds.getX(), y + bounds.getY(), + bounds.getWidth(), bounds.getHeight()); + drawComposite(bounds, null); + } + } + + public boolean drawImage(Image img, int x, int y, ImageObserver observer) + { + // If it is a GtkVolatileImage with an "easy" transform then + // draw directly. Always pass a BufferedImage to super to avoid + // deadlock (see Note in CairoGraphics.drawImage()). + if (img instanceof GtkVolatileImage) + { + GtkVolatileImage vimg = (GtkVolatileImage) img; + int type = transform.getType(); + if ((type == AffineTransform.TYPE_IDENTITY + || type == AffineTransform.TYPE_TRANSLATION) + && (clip == null || clip instanceof Rectangle2D)) + { + Rectangle2D r = (Rectangle2D) clip; + if (r == null) + r = getRealBounds(); + x += transform.getTranslateX(); + y += transform.getTranslateY(); + drawVolatile(component, vimg.nativePointer, + x, y, vimg.width, vimg.height, + (int) (r.getX() + transform.getTranslateX()), + (int) (r.getY() + transform.getTranslateY()), + (int) r.getWidth(), + (int) r.getHeight()); + return true; + } + else + return super.drawImage(vimg.getSnapshot(), x, y, observer); + } + + BufferedImage bimg; + if (img instanceof BufferedImage) + bimg = (BufferedImage) img; + else + { + ImageProducer source = img.getSource(); + if (source == null) + return false; + bimg = (BufferedImage) Toolkit.getDefaultToolkit().createImage(source); + } + return super.drawImage(bimg, x, y, observer); + } + + public boolean drawImage(Image img, int x, int y, int width, int height, + ImageObserver observer) + { + // If it is a GtkVolatileImage with an "easy" transform then + // draw directly. Always pass a BufferedImage to super to avoid + // deadlock (see Note in CairoGraphics.drawImage()). + if (img instanceof GtkVolatileImage + && (clip == null || clip instanceof Rectangle2D)) + { + GtkVolatileImage vimg = (GtkVolatileImage) img; + int type = transform.getType(); + if ((type == AffineTransform.TYPE_IDENTITY + || type == AffineTransform.TYPE_TRANSLATION) + && (clip == null || clip instanceof Rectangle2D)) + { + Rectangle2D r = (Rectangle2D) clip; + if (r == null) + r = getRealBounds(); + x += transform.getTranslateX(); + y += transform.getTranslateY(); + drawVolatile(component, vimg.nativePointer, + x, y, width, height, + (int) (r.getX() + transform.getTranslateX()), + (int) (r.getY() + transform.getTranslateY()), + (int) r.getWidth(), + (int) r.getHeight()); + return true; + } + else + return super.drawImage(vimg.getSnapshot(), x, y, + width, height, observer); + } + + BufferedImage bimg; + img = AsyncImage.realImage(img, observer); + if (img instanceof BufferedImage) + bimg = (BufferedImage) img; + else + { + ImageProducer source = img.getSource(); + if (source == null) + return false; + bimg = (BufferedImage) Toolkit.getDefaultToolkit().createImage(source); + } + return super.drawImage(bimg, x, y, width, height, observer); + } + + private boolean drawComposite(Rectangle2D bounds, ImageObserver observer) + { + // Clip source to visible areas that need updating + Rectangle2D clip = this.getClipBounds(); + Rectangle2D.intersect(bounds, clip, bounds); + clip = new Rectangle(buffer.getMinX(), buffer.getMinY(), + buffer.getWidth(), buffer.getHeight()); + Rectangle2D.intersect(bounds, clip, bounds); + + BufferedImage buffer2 = buffer; + if (!bounds.equals(buffer2.getRaster().getBounds())) + buffer2 = buffer2.getSubimage((int)bounds.getX(), (int)bounds.getY(), + (int)bounds.getWidth(), + (int)bounds.getHeight()); + + // Get destination clip to bounds + double[] points = new double[] {bounds.getX(), bounds.getY(), + bounds.getMaxX(), bounds.getMaxY()}; + transform.transform(points, 0, points, 0, 2); + + Rectangle2D deviceBounds = new Rectangle2D.Double(points[0], points[1], + points[2] - points[0], + points[3] - points[1]); + + Rectangle2D.intersect(deviceBounds, this.getClipInDevSpace(), deviceBounds); + + // Get current image on the component + GtkImage img = grab(component); + Graphics gr = componentBuffer.createGraphics(); + gr.drawImage(img, 0, 0, null); + gr.dispose(); + + BufferedImage cBuffer = componentBuffer; + if (!deviceBounds.equals(cBuffer.getRaster().getBounds())) + cBuffer = cBuffer.getSubimage((int)deviceBounds.getX(), + (int)deviceBounds.getY(), + (int)deviceBounds.getWidth(), + (int)deviceBounds.getHeight()); + + // Perform actual composite operation + compCtx.compose(buffer2.getRaster(), cBuffer.getRaster(), + cBuffer.getRaster()); + + // This MUST call directly into the "action" method in CairoGraphics2D, + // not one of the wrappers, to ensure that the composite isn't processed + // more than once! + boolean rv = super.drawImage(cBuffer, + AffineTransform.getTranslateInstance(bounds.getX(), + bounds.getY()), + null, null); + return rv; + } + + private void createBuffer() + { + if (buffer == null) + { + WritableRaster rst; + rst = Raster.createWritableRaster(GtkVolatileImage.createGdkSampleModel(component.awtComponent.getWidth(), + component.awtComponent.getHeight()), + new Point(0,0)); + + buffer = new BufferedImage(GtkVolatileImage.gdkColorModel, rst, + GtkVolatileImage.gdkColorModel.isAlphaPremultiplied(), + new Hashtable()); + } + else + { + Graphics2D g2d = ((Graphics2D)buffer.getGraphics()); + + g2d.setBackground(new Color(0,0,0,0)); + g2d.clearRect(0, 0, buffer.getWidth(), buffer.getHeight()); + } + + if (componentBuffer == null) + { + WritableRaster rst; + rst = Raster.createWritableRaster(GtkVolatileImage.createGdkSampleModel(component.awtComponent.getWidth(), + component.awtComponent.getHeight()), + new Point(0,0)); + + componentBuffer = new BufferedImage(GtkVolatileImage.gdkColorModel, rst, + GtkVolatileImage.gdkColorModel.isAlphaPremultiplied(), + new Hashtable()); + } + } + + protected ColorModel getNativeCM() + { + return GtkVolatileImage.gdkColorModel; + } + + /* --- START OVERRIDDEN NATIVE METHODS ---- + * All native methods in CairoGraphics2D should be overridden here and + * enclosed in locks, since the cairo surface is backed by an X surface + * in this graphics context and the X surface requires external locking. + * + * We lock everything "just in case", since it's difficult to know which + * calls are and aren't thread-safe. Overriding and locking the native + * methods allows superclass code in CairoGraphics2D to execute properly, + * without the need to override every single method. + * + * CAVEAT: if native code obtains a lock (using gdk_threads_enter(), not the + * lock() method provided here) and then calls back into Java and one of these + * methods ends up being called, we will deadlock. The lock is only reentrant + * when called via our lock() method. + */ + + /* These methods are already locked in the superclass CairoGraphics2D + * so they do not need to be overridden: + * + * public void disposeNative + * + * protected void cairoDrawGlyphVector + * + * protected void cairoSetFont + */ + + @Override + protected long init(long pointer) + { + long ret; + + try + { + lock(); + ret = super.init(pointer); + } + finally + { + unlock(); + } + + return ret; + } + + @Override + protected void drawPixels(long pointer, int[] pixels, int w, int h, + int stride, double[] i2u, double alpha, + int interpolation) + { + try + { + lock(); + super.drawPixels(pointer, pixels, w, h, stride, i2u, alpha, + interpolation); + } + finally + { + unlock(); + } + } + + @Override + protected void setGradient(long pointer, double x1, double y1, + double x2, double y2, + int r1, int g1, int b1, int a1, + int r2, int g2, int b2, int a2, boolean cyclic) + { + try + { + lock(); + super.setGradient(pointer, x1, y1, x2, y2, r1, g1, b1, a1, r2, g2, b2, a2, + cyclic); + } + finally + { + unlock(); + } + } + + @Override + protected void setPaintPixels(long pointer, int[] pixels, int w, int h, + int stride, boolean repeat, int x, int y) + { + try + { + lock(); + super.setPaintPixels(pointer, pixels, w, h, stride, repeat, x, y); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoSetMatrix(long pointer, double[] m) + { + try + { + lock(); + super.cairoSetMatrix(pointer, m); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoScale(long pointer, double x, double y) + { + try + { + lock(); + super.cairoScale(pointer, x, y); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoSetOperator(long pointer, int cairoOperator) + { + try + { + lock(); + super.cairoSetOperator(pointer, cairoOperator); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoSetRGBAColor(long pointer, double red, double green, + double blue, double alpha) + { + try + { + lock(); + super.cairoSetRGBAColor(pointer, red, green, blue, alpha); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoSetFillRule(long pointer, int cairoFillRule) + { + try + { + lock(); + super.cairoSetFillRule(pointer, cairoFillRule); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoSetLine(long pointer, double width, int cap, int join, + double miterLimit) + { + try + { + lock(); + super.cairoSetLine(pointer, width, cap, join, miterLimit); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoSetDash(long pointer, double[] dashes, int ndash, + double offset) + { + try + { + lock(); + super.cairoSetDash(pointer, dashes, ndash, offset); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoRectangle(long pointer, double x, double y, + double width, double height) + { + try + { + lock(); + super.cairoRectangle(pointer, x, y, width, height); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoArc(long pointer, double x, double y, + double radius, double angle1, double angle2) + { + try + { + lock(); + super.cairoArc(pointer, x, y, radius, angle1, angle2); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoSave(long pointer) + { + try + { + lock(); + super.cairoSave(pointer); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoRestore(long pointer) + { + try + { + lock(); + super.cairoRestore(pointer); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoNewPath(long pointer) + { + try + { + lock(); + super.cairoNewPath(pointer); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoClosePath(long pointer) + { + try + { + lock(); + super.cairoClosePath(pointer); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoMoveTo(long pointer, double x, double y) + { + try + { + lock(); + super.cairoMoveTo(pointer, x, y); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoLineTo(long pointer, double x, double y) + { + try + { + lock(); + super.cairoLineTo(pointer, x, y); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoCurveTo(long pointer, double x1, double y1, double x2, + double y2, double x3, double y3) + { + try + { + lock(); + super.cairoCurveTo(pointer, x1, y1, x2, y2, x3, y3); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoStroke(long pointer) + { + try + { + lock(); + super.cairoStroke(pointer); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoFill(long pointer, double alpha) + { + try + { + lock(); + super.cairoFill(pointer, alpha); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoClip(long pointer) + { + try + { + lock(); + super.cairoClip(pointer); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoResetClip(long pointer) + { + try + { + lock(); + super.cairoResetClip(pointer); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoSetAntialias(long pointer, boolean aa) + { + try + { + lock(); + super.cairoSetAntialias(pointer, aa); + } + finally + { + unlock(); + } + } + + @Override + protected void drawCairoSurface(CairoSurface surface, AffineTransform tx, + double alpha, int interpolation) + { + try + { + lock(); + super.drawCairoSurface(surface, tx, alpha, interpolation); + } + finally + { + unlock(); + } + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/ComponentGraphicsCopy.java b/libjava/classpath/gnu/java/awt/peer/gtk/ComponentGraphicsCopy.java new file mode 100644 index 000000000..a73012d9f --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/ComponentGraphicsCopy.java @@ -0,0 +1,122 @@ +/* ComponentGraphicsCopy.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.java.awt.peer.gtk; + +import java.awt.Color; +import java.awt.Image; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.awt.image.RenderedImage; +import java.awt.image.ImageObserver; + +/** + * Implementation of Graphics2D for Components for servers which + * do not have xrender. + * + * A mirrored GtkImage of the component is stored in memory + * and copied back. Yay. + */ +public class ComponentGraphicsCopy extends CairoSurfaceGraphics +{ + private GtkComponentPeer component; + + /** + * GtkImage sharing its data buffer with this Cairo surface. + */ + private GtkImage gtkimage; + + private int width, height; + + native void getPixbuf( GtkComponentPeer component, GtkImage image ); + + native void copyPixbuf( GtkComponentPeer component, GtkImage image, + int x, int y, int w, int h ); + + public ComponentGraphicsCopy(int width, int height, + GtkComponentPeer component) + { + super( new CairoSurface( width, height ) ); + this.component = component; + this.width = width; + this.height = height; + gtkimage = surface.getGtkImage(); + getPixbuf( component, gtkimage ); + } + + /** + * Overloaded methods that do actual drawing need to enter the gdk threads + * and also do certain things before and after. + */ + public void draw(Shape s) + { + super.draw(s); + Rectangle r = s.getBounds(); + copyPixbuf(component, gtkimage, r.x, r.y, r.width, r.height); + } + + public void fill(Shape s) + { + super.fill(s); + Rectangle r = s.getBounds(); + copyPixbuf(component, gtkimage, r.x, r.y, r.width, r.height); + } + + public void drawRenderedImage(RenderedImage image, AffineTransform xform) + { + super.drawRenderedImage(image, xform); + copyPixbuf(component, gtkimage, 0, 0, width, height); + } + + protected boolean drawImage(Image img, AffineTransform xform, + Color bgcolor, ImageObserver obs) + { + boolean rv = super.drawImage(img, xform, bgcolor, obs); + copyPixbuf(component, gtkimage, 0, 0, width, height); + return rv; + } + + public void drawGlyphVector(GlyphVector gv, float x, float y) + { + super.drawGlyphVector(gv, x, y); + Rectangle r = gv.getPixelBounds(getFontRenderContext(), x , y); + copyPixbuf(component, gtkimage, r.x, r.y, r.width, r.height); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java b/libjava/classpath/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java new file mode 100644 index 000000000..8fd734799 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java @@ -0,0 +1,630 @@ +/* FreetypeGlyphVector.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.java.awt.peer.gtk; + +import java.awt.Font; +import java.awt.Shape; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphJustificationInfo; +import java.awt.font.GlyphMetrics; +import java.awt.font.GlyphVector; +import java.awt.font.TextAttribute; +import java.awt.font.TransformAttribute; +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.util.Arrays; + +public class FreetypeGlyphVector extends GlyphVector +{ + /** + * The associated font and its peer. + */ + private Font font; + private GdkFontPeer peer; // ATTN: Accessed from native code. + + private Rectangle2D logicalBounds; + + private float[] glyphPositions; + /** + * The string represented by this GlyphVector. + */ + private String s; + + /** + * The font render context + */ + private FontRenderContext frc; + + /** + * The total # of glyphs. + */ + private int nGlyphs; + + /** + * The glyph codes + */ + private int[] glyphCodes; + + /** + * The set of fonts used in this glyph vector. + */ + private long[] fontSet = null; + + /** + * Glyph transforms. Supports all transform operations. + * + * The identity transform should not be stored in this array; use a null + * instead (will result in performance improvements). + */ + private AffineTransform[] glyphTransforms; + + private GlyphMetrics[] metricsCache; + + private native void dispose(long[] fonts); + + /** + * Returns a pointer to the native PangoFcFont object. + * + * The object will be referenced with g_object_ref n times before being + * returned, and must be unreferenced a corresponding number of times. + * + * @param n Number of times to reference the object. + * @return Pointer to the native default font. + */ + private native long getNativeFontPointer(int n); + + /** + * Create a glyphvector from a given (Freetype) font and a String. + */ + public FreetypeGlyphVector(Font f, String s, FontRenderContext frc) + { + this(f, s.toCharArray(), 0, s.length(), frc, Font.LAYOUT_LEFT_TO_RIGHT); + } + + /** + * Create a glyphvector from a given (Freetype) font and a String. + */ + public FreetypeGlyphVector(Font f, char[] chars, int start, int len, + FontRenderContext frc, int flags) + { + this.s = new String(chars, start, len); + + this.font = f; + this.frc = frc; + if( !(font.getPeer() instanceof GdkFontPeer ) ) + throw new IllegalArgumentException("Not a valid font."); + peer = (GdkFontPeer)font.getPeer(); + + getGlyphs(); + if( flags == Font.LAYOUT_RIGHT_TO_LEFT ) + { + // reverse the glyph ordering. + int[] temp = new int[ nGlyphs ]; + for(int i = 0; i < nGlyphs; i++) + temp[i] = glyphCodes[nGlyphs - i - 1]; + glyphCodes = temp; + } + performDefaultLayout(); + } + + /** + * Create a glyphvector from a given set of glyph codes. + */ + public FreetypeGlyphVector(Font f, int[] codes, FontRenderContext frc) + { + this.font = f; + this.frc = frc; + if( !(font.getPeer() instanceof GdkFontPeer ) ) + throw new IllegalArgumentException("Not a valid font."); + peer = (GdkFontPeer)font.getPeer(); + + glyphCodes = new int[ codes.length ]; + System.arraycopy(codes, 0, glyphCodes, 0, codes.length); + nGlyphs = glyphCodes.length; + + if (fontSet == null) + { + fontSet = new long[nGlyphs]; + Arrays.fill(fontSet, getNativeFontPointer(nGlyphs)); + } + + performDefaultLayout(); + } + + /** + * Cloning constructor + */ + private FreetypeGlyphVector( FreetypeGlyphVector gv ) + { + font = gv.font; + peer = gv.peer; + frc = gv.frc; + s = gv.s; + nGlyphs = gv.nGlyphs; + logicalBounds = gv.logicalBounds.getBounds2D(); + + if( gv.metricsCache != null ) + { + metricsCache = new GlyphMetrics[ nGlyphs ]; + System.arraycopy(gv.metricsCache, 0, metricsCache, 0, nGlyphs); + } + + glyphCodes = new int[ nGlyphs ]; + fontSet = new long[nGlyphs]; + glyphPositions = new float[(nGlyphs + 1) * 2]; + glyphTransforms = new AffineTransform[ nGlyphs ]; + Arrays.fill(glyphTransforms, null); + + for(int i = 0; i < nGlyphs; i++ ) + { + if (gv.glyphTransforms[i] != null) + glyphTransforms[ i ] = new AffineTransform(gv.glyphTransforms[i]); + glyphCodes[i] = gv.glyphCodes[ i ]; + } + System.arraycopy(gv.glyphPositions, 0, glyphPositions, 0, + glyphPositions.length); + System.arraycopy(gv.glyphCodes, 0, glyphCodes, 0, nGlyphs); + System.arraycopy(gv.fontSet, 0, fontSet, 0, nGlyphs); + } + + public void finalize() + { + dispose(fontSet); + } + + /** + * Create the array of glyph codes. + */ + private void getGlyphs() + { + nGlyphs = s.codePointCount( 0, s.length() ); + glyphCodes = new int[ nGlyphs ]; + fontSet = new long[ nGlyphs ]; + int[] codePoints = new int[ nGlyphs ]; + int stringIndex = 0; + + for(int i = 0; i < nGlyphs; i++) + { + codePoints[i] = s.codePointAt( stringIndex ); + // UTF32 surrogate handling + if( codePoints[i] != (int)s.charAt( stringIndex ) ) + stringIndex ++; + stringIndex ++; + + if (Character.isISOControl(codePoints[i])) + { + // Replace with 'hair space'. Should better be 'zero-width space' + // but that doesn't seem to be supported by default font. + codePoints[i] = 8202; + } + } + + getGlyphs( codePoints, glyphCodes, fontSet ); + } + + /** + * Returns the glyph code within the font for a given character + */ + public native void getGlyphs(int[] codepoints, int[] glyphs, long[] fonts); + + /** + * Returns the kerning of a glyph pair + */ + private native void getKerning(int leftGlyph, int rightGlyph, long font, + float[] p); + + private native double[] getMetricsNative(int glyphCode, long font); + + private native GeneralPath getGlyphOutlineNative(int glyphIndex, long font); + + + public Object clone() + { + return new FreetypeGlyphVector( this ); + } + + /** + * Duh, compares two instances. + */ + public boolean equals(GlyphVector gv) + { + if( ! (gv instanceof FreetypeGlyphVector) ) + return false; + + return (((FreetypeGlyphVector)gv).font.equals(font) && + ((FreetypeGlyphVector)gv).frc.equals(frc) + && ((FreetypeGlyphVector)gv).s.equals(s)); + } + + /** + * Returns the associated Font + */ + public Font getFont() + { + return font; + } + + /** + * Returns the associated FontRenderContext + */ + public FontRenderContext getFontRenderContext() + { + return frc; + } + + /** + * Layout the glyphs. + */ + public void performDefaultLayout() + { + logicalBounds = null; // invalidate caches. + glyphTransforms = new AffineTransform[nGlyphs]; + Arrays.fill(glyphTransforms, null); + glyphPositions = new float[(nGlyphs + 1) * 2]; + + GlyphMetrics gm = null; + float x = 0; + float y = 0; + float[] p = {0.0f, 0.0f}; + for(int i = 0; i < nGlyphs; i++) + { + gm = getGlyphMetrics( i ); + glyphPositions[i*2] = x; + glyphPositions[i*2 + 1] = y; + + x += gm.getAdvanceX(); + y += gm.getAdvanceY(); + + // Get the kerning only if it's not the last glyph, and the two glyphs are + // using the same font + if (i != nGlyphs-1 && fontSet[i] == fontSet[i+1]) + { + getKerning(glyphCodes[i], glyphCodes[i + 1], fontSet[i], p); + x += p[0]; + y += p[1]; + } + } + glyphPositions[nGlyphs * 2] = x; + glyphPositions[nGlyphs * 2 + 1] = y; + + // Apply any transform that may be in the font's attributes + TransformAttribute ta; + ta = (TransformAttribute)font.getAttributes().get(TextAttribute.TRANSFORM); + if (ta != null) + { + AffineTransform tx = ta.getTransform(); + + // Transform glyph positions + tx.transform(glyphPositions, 0, glyphPositions, 0, + glyphPositions.length / 2); + + // Also store per-glyph scale/shear/rotate (but not translation) + double[] matrix = new double[4]; + tx.getMatrix(matrix); + AffineTransform deltaTx = new AffineTransform(matrix); + if (!deltaTx.isIdentity()) + Arrays.fill(glyphTransforms, deltaTx); + } + } + + /** + * Returns the code of the glyph at glyphIndex; + */ + public int getGlyphCode(int glyphIndex) + { + return glyphCodes[ glyphIndex ]; + } + + /** + * Returns multiple glyphcodes. + */ + public int[] getGlyphCodes(int beginGlyphIndex, int numEntries, + int[] codeReturn) + { + int[] rval; + + if( codeReturn == null || codeReturn.length < numEntries) + rval = new int[ numEntries ]; + else + rval = codeReturn; + + System.arraycopy(glyphCodes, beginGlyphIndex, rval, 0, numEntries); + + return rval; + } + + /** + * Returns pointers to the fonts used in this glyph vector. + * + * The array index matches that of the glyph vector itself. + */ + protected long[] getGlyphFonts(int beginGlyphIndex, int numEntries, + long[] codeReturn) + { + long[] rval; + + if( codeReturn == null || codeReturn.length < numEntries) + rval = new long[ numEntries ]; + else + rval = codeReturn; + + System.arraycopy(fontSet, beginGlyphIndex, rval, 0, numEntries); + + return rval; + } + + public Shape getGlyphLogicalBounds(int glyphIndex) + { + GlyphMetrics gm = getGlyphMetrics( glyphIndex ); + if( gm == null ) + return null; + Rectangle2D r = gm.getBounds2D(); + Point2D p = getGlyphPosition( glyphIndex ); + + double[] bounds = new double[] {p.getX() + r.getX() - gm.getLSB(), + p.getY() + r.getY(), + p.getX() + r.getX() - gm.getLSB() + gm.getAdvanceX(), + p.getY() + r.getY() + r.getHeight()}; + + if (glyphTransforms[glyphIndex] != null) + glyphTransforms[glyphIndex].transform(bounds, 0, bounds, 0, 2); + + return new Rectangle2D.Double(bounds[0], bounds[1], bounds[2] - bounds[0], + bounds[3] - bounds[1]); + } + + /* + * FIXME: Not all glyph types are supported. + * (The JDK doesn't really seem to do so either) + */ + public void setupGlyphMetrics() + { + metricsCache = new GlyphMetrics[ nGlyphs ]; + + for(int i = 0; i < nGlyphs; i++) + { + GlyphMetrics gm = (GlyphMetrics)peer.getGlyphMetrics(glyphCodes[i]); + if( gm == null ) + { + double[] val = getMetricsNative(glyphCodes[i], fontSet[i]); + if( val == null ) + gm = null; + else + { + gm = new GlyphMetrics(true, + (float)val[1], + (float)val[2], + new Rectangle2D.Double(val[3], val[4], + val[5], val[6] ), + GlyphMetrics.STANDARD ); + peer.putGlyphMetrics( glyphCodes[ i ], gm ); + } + } + metricsCache[ i ] = gm; + } + } + + /** + * Returns the metrics of a single glyph. + */ + public GlyphMetrics getGlyphMetrics(int glyphIndex) + { + if( metricsCache == null ) + setupGlyphMetrics(); + + return metricsCache[ glyphIndex ]; + } + + /** + * Returns the outline of a single glyph. + * + * Despite what the Sun API says, this method returns the glyph relative to + * the origin of the *entire string*, not each individual glyph. + */ + public Shape getGlyphOutline(int glyphIndex) + { + GeneralPath gp = getGlyphOutlineNative(glyphCodes[glyphIndex], + fontSet[glyphIndex]); + + AffineTransform tx = AffineTransform.getTranslateInstance(glyphPositions[glyphIndex*2], + glyphPositions[glyphIndex*2+1]); + if (glyphTransforms[glyphIndex] != null) + tx.concatenate( glyphTransforms[glyphIndex]); + + gp.transform(tx); + return gp; + } + + /** + * Returns the position of a single glyph. + */ + public Point2D getGlyphPosition(int glyphIndex) + { + return new Point2D.Float(glyphPositions[glyphIndex*2], + glyphPositions[glyphIndex*2 + 1]); + } + + /** + * Returns the positions of multiple glyphs. + */ + public float[] getGlyphPositions(int beginGlyphIndex, int numEntries, + float[] positionReturn) + { + if (positionReturn == null || positionReturn.length < (numEntries * 2)) + positionReturn = new float[numEntries*2]; + + System.arraycopy(glyphPositions, beginGlyphIndex*2, positionReturn, 0, + numEntries*2); + return positionReturn; + } + + /** + * Returns the transform of a glyph. + */ + public AffineTransform getGlyphTransform(int glyphIndex) + { + return glyphTransforms[glyphIndex]; + } + + /** + * Checks whether any transform has been set on any glyphs. + */ + protected boolean hasTransforms() + { + for (int i = 0; i < glyphTransforms.length; i++) + if (glyphTransforms[i] != null) + return true; + + return false; + } + + /** + * Returns the visual bounds of a glyph + * May be off by a pixel or two due to hinting/rasterization. + */ + public Shape getGlyphVisualBounds(int glyphIndex) + { + return getGlyphOutline( glyphIndex ).getBounds2D(); + } + + /** + * Return the logical bounds of the whole thing. + */ + public Rectangle2D getLogicalBounds() + { + if( nGlyphs == 0 ) + return new Rectangle2D.Double(0, 0, 0, 0); + if( logicalBounds != null ) + return logicalBounds; + + Rectangle2D rect = (Rectangle2D)getGlyphLogicalBounds( 0 ); + for( int i = 1; i < nGlyphs; i++ ) + { + Rectangle2D r2 = (Rectangle2D)getGlyphLogicalBounds( i ); + + rect = rect.createUnion( r2 ); + } + + logicalBounds = rect; + return rect; + } + + /** + * Returns the number of glyphs. + */ + public int getNumGlyphs() + { + return glyphCodes.length; + } + + /** + * Returns the outline of the entire GlyphVector. + */ + public Shape getOutline() + { + GeneralPath path = new GeneralPath(); + for( int i = 0; i < getNumGlyphs(); i++ ) + path.append(getGlyphOutline(i), false); + return path; + } + + /** + * TODO: + * FreeType does not currently have an API for the JSTF table. We should + * probably get the table ourselves from FT and pass it to some parser + * which the native font peers will need. + */ + public GlyphJustificationInfo getGlyphJustificationInfo(int glyphIndex) + { + return null; + } + + /** + * Returns the outline of the entire vector, drawn at (x,y). + */ + public Shape getOutline(float x, float y) + { + AffineTransform tx = AffineTransform.getTranslateInstance( x, y ); + GeneralPath gp = (GeneralPath)getOutline(); + gp.transform( tx ); + return gp; + } + + /** + * Returns the visual bounds of the entire GlyphVector. + * May be off by a pixel or two due to hinting/rasterization. + */ + public Rectangle2D getVisualBounds() + { + return getOutline().getBounds2D(); + } + + /** + * Sets the position of a glyph. + */ + public void setGlyphPosition(int glyphIndex, Point2D newPos) + { + glyphPositions[glyphIndex*2] = (float)(newPos.getX()); + glyphPositions[glyphIndex*2 + 1] = (float)(newPos.getY()); + logicalBounds = null; + } + + /** + * Sets the transform of a single glyph. + */ + public void setGlyphTransform(int glyphIndex, AffineTransform newTX) + { + // The identity transform should never be in the glyphTransforms array; + // using and checking for nulls can be much faster. + if (newTX != null && newTX.isIdentity()) + newTX = null; + + // If the old and new transforms are identical, bail + if (glyphTransforms[glyphIndex] == null && newTX == null) + return; + + if (newTX != null && newTX.equals(glyphTransforms[glyphIndex])) + return; + + // Invalidate bounds cache and set new transform + logicalBounds = null; + glyphTransforms[glyphIndex] = newTX; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkFontPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkFontPeer.java new file mode 100644 index 000000000..6b099063f --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkFontPeer.java @@ -0,0 +1,545 @@ +/* GdkFontPeer.java -- Implements FontPeer with GTK+ + Copyright (C) 1999, 2004, 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.java.awt.peer.gtk; + +import gnu.classpath.Configuration; +import gnu.classpath.Pointer; + +import gnu.java.awt.ClasspathToolkit; +import gnu.java.awt.peer.ClasspathFontPeer; +import gnu.java.awt.font.opentype.NameDecoder; + +import gnu.java.lang.CPStringBuilder; + +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Toolkit; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.font.GlyphMetrics; +import java.awt.font.LineMetrics; +import java.awt.font.TextLayout; +import java.awt.geom.Rectangle2D; +import java.text.CharacterIterator; +import java.util.Locale; +import java.util.Map; +import java.nio.ByteBuffer; +import java.util.HashMap; + +public class GdkFontPeer extends ClasspathFontPeer +{ + static final FontRenderContext DEFAULT_CTX = + new FontRenderContext(null, false, false); + + /** + * Caches TextLayout instances for use in charsWidth() and drawString(). + * The size of the cache has been chosen so that relativly large GUIs with + * text documents are still efficient. + */ + HashMap textLayoutCache = new GtkToolkit.LRUCache(500); + + private class GdkFontMetrics extends FontMetrics + { + + public GdkFontMetrics (Font font) + { + super(initFont(font)); + } + + public int stringWidth (String str) + { + TextLayout tl = textLayoutCache.get(str); + if (tl == null) + { + tl = new TextLayout(str, font, DEFAULT_CTX); + textLayoutCache.put(str, tl); + } + return (int) tl.getAdvance(); + } + + public int charWidth (char ch) + { + return stringWidth (new String (new char[] { ch })); + } + + public int charsWidth (char data[], int off, int len) + { + return stringWidth (new String (data, off, len)); + } + + public int getHeight() + { + return (int) height; + } + + public int getLeading () + { + return (int) (height - (ascent + descent)); + } + + public int getAscent () + { + return (int) ascent; + } + + public int getMaxAscent () + { + return (int) ascent; + } + + public int getDescent () + { + return (int) descent; + } + + public int getMaxDescent () + { + return (int) maxDescent; + } + + public int getMaxAdvance () + { + return (int) maxAdvance; + } + } + + static native void initStaticState(); + private final int native_state = GtkGenericPeer.getUniqueInteger (); + + /** + * Cache GlyphMetrics objects. + */ + private HashMap metricsCache; + + private static final int FONT_METRICS_ASCENT = 0; + private static final int FONT_METRICS_MAX_ASCENT = 1; + private static final int FONT_METRICS_DESCENT = 2; + private static final int FONT_METRICS_MAX_DESCENT = 3; + private static final int FONT_METRICS_MAX_ADVANCE = 4; + private static final int FONT_METRICS_HEIGHT = 5; + private static final int FONT_METRICS_UNDERLINE_OFFSET = 6; + private static final int FONT_METRICS_UNDERLINE_THICKNESS = 7; + + float ascent; + float descent; + float maxAscent; + float maxDescent; + float maxAdvance; + float height; + float underlineOffset; + float underlineThickness; + + GdkFontMetrics metrics; + + static + { + if (true) // GCJ LOCAL + { + System.loadLibrary("gtkpeer"); + } + + initStaticState (); + + } + + private ByteBuffer nameTable = null; + + /** + * The pointer to the native font data. + * + * This field is manipulated by native code. Don't change or remove + * without adjusting the native code. + */ + private Pointer nativeFont; + + private native void initState (); + private native void dispose (); + private native void setFont (String family, int style, int size); + + native synchronized void getFontMetrics(double [] metrics); + native synchronized void getTextMetrics(String str, double [] metrics); + + native void releasePeerGraphicsResource(); + + + protected void finalize () + { + releasePeerGraphicsResource(); + dispose (); + } + + /* + * Helpers for the 3-way overloading that this class seems to suffer + * from. Remove them if you feel like they're a performance bottleneck, + * for the time being I prefer my code not be written and debugged in + * triplicate. + */ + + private String buildString(CharacterIterator iter) + { + CPStringBuilder sb = new CPStringBuilder(); + for(char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) + sb.append(c); + return sb.toString(); + } + + private String buildString(CharacterIterator iter, int begin, int limit) + { + CPStringBuilder sb = new CPStringBuilder(); + int i = 0; + for(char c = iter.first(); c != CharacterIterator.DONE; c = iter.next(), i++) + { + if (begin <= i) + sb.append(c); + if (limit <= i) + break; + } + return sb.toString(); + } + + private String buildString(char[] chars, int begin, int limit) + { + return new String(chars, begin, limit - begin); + } + + /* Public API */ + + public GdkFontPeer (String name, int style) + { + // All fonts get a default size of 12 if size is not specified. + this(name, style, 12); + } + + public GdkFontPeer (String name, int style, int size) + { + super(name, style, size); + initState (); + setFont (this.familyName, this.style, (int)this.size); + metricsCache = new HashMap(); + setupMetrics(); + } + + public GdkFontPeer (String name, Map attributes) + { + super(name, attributes); + initState (); + setFont (this.familyName, this.style, (int)this.size); + metricsCache = new HashMap(); + setupMetrics(); + } + + + /** + * Makes sure to return a Font based on the given Font that has as + * peer a GdkFontPeer. Used in the initializer. + */ + static Font initFont(Font font) + { + if (font == null) + return new Font("Dialog", Font.PLAIN, 12); + else if (font.getPeer() instanceof GdkFontPeer) + return font; + else + { + ClasspathToolkit toolkit; + toolkit = (ClasspathToolkit) Toolkit.getDefaultToolkit(); + return toolkit.getFont(font.getName(), font.getAttributes()); + } + } + + private void setupMetrics() + { + double [] hires = new double[8]; + getFontMetrics(hires); + ascent = (float) hires[FONT_METRICS_ASCENT]; + maxAscent = (float) hires[FONT_METRICS_MAX_ASCENT]; + descent = (float) hires[FONT_METRICS_DESCENT]; + maxDescent = (float) hires[FONT_METRICS_MAX_DESCENT]; + maxAdvance = (float) hires[FONT_METRICS_MAX_ADVANCE]; + height = (float) hires[FONT_METRICS_HEIGHT]; + underlineOffset = (float) hires[FONT_METRICS_UNDERLINE_OFFSET]; + underlineThickness = (float) hires[FONT_METRICS_UNDERLINE_THICKNESS]; + } + + /** + * Unneeded, but implemented anyway. + */ + public String getSubFamilyName(Font font, Locale locale) + { + String name; + + if (locale == null) + locale = Locale.getDefault(); + + name = getName(NameDecoder.NAME_SUBFAMILY, locale); + if (name == null) + { + name = getName(NameDecoder.NAME_SUBFAMILY, Locale.ENGLISH); + if ("Regular".equals(name)) + name = null; + } + + return name; + } + + /** + * Returns the bytes belonging to a TrueType/OpenType table, + * Parameters n,a,m,e identify the 4-byte ASCII tag of the table. + * + * Returns null if the font is not TT, the table is nonexistant, + * or if some other unexpected error occured. + * + */ + private native byte[] getTrueTypeTable(byte n, byte a, byte m, byte e); + + /** + * Returns the PostScript name of the font, defaults to the familyName if + * a PS name could not be retrieved. + */ + public String getPostScriptName(Font font) + { + String name = getName(NameDecoder.NAME_POSTSCRIPT, + /* any language */ null); + if( name == null ) + return this.familyName; + + return name; + } + + /** + * Extracts a String from the font’s name table. + * + * @param name the numeric TrueType or OpenType name ID. + * + * @param locale the locale for which names shall be localized, or + * null if the locale does mot matter because the name + * is known to be language-independent (for example, because it is + * the PostScript name). + */ + private String getName(int name, Locale locale) + { + if (nameTable == null) + { + byte[] data = getTrueTypeTable((byte)'n', (byte) 'a', + (byte) 'm', (byte) 'e'); + if( data == null ) + return null; + + nameTable = ByteBuffer.wrap( data ); + } + + return NameDecoder.getName(nameTable, name, locale); + } + + public boolean canDisplay (Font font, int c) + { + // FIXME: inquire with pango + return true; + } + + public int canDisplayUpTo (Font font, CharacterIterator i, int start, int limit) + { + // FIXME: inquire with pango + return -1; + } + + public GlyphVector createGlyphVector (Font font, + FontRenderContext ctx, + CharacterIterator i) + { + return new FreetypeGlyphVector(font, buildString (i), ctx); + } + + public GlyphVector createGlyphVector (Font font, + FontRenderContext ctx, + int[] glyphCodes) + { + return new FreetypeGlyphVector(font, glyphCodes, ctx); + } + + public byte getBaselineFor (Font font, char c) + { + // FIXME: Actually check. + return Font.ROMAN_BASELINE; + } + + private class GdkFontLineMetrics extends LineMetrics + { + private int nchars; + public GdkFontLineMetrics (GdkFontPeer fp, int n) + { + nchars = n; + } + + public float getAscent() + { + return ascent; + } + + public int getBaselineIndex() + { + // FIXME + return Font.ROMAN_BASELINE; + } + + public float[] getBaselineOffsets() + { + return new float[3]; + } + + public float getDescent() + { + return descent; + } + + public float getHeight() + { + return height; + } + + public float getLeading() + { + return height - (ascent + descent); + } + + public int getNumChars() + { + return nchars; + } + + public float getStrikethroughOffset() + { + // FreeType doesn't seem to provide a value here. + return ascent / 2; + } + + public float getStrikethroughThickness() + { + // FreeType doesn't seem to provide a value here. + return 1.f; + } + + public float getUnderlineOffset() + { + return underlineOffset; + } + + public float getUnderlineThickness() + { + return underlineThickness; + } + + } + + public LineMetrics getLineMetrics (Font font, CharacterIterator ci, + int begin, int limit, FontRenderContext rc) + { + return new GdkFontLineMetrics (this, limit - begin); + } + + public Rectangle2D getMaxCharBounds (Font font, FontRenderContext rc) + { + throw new UnsupportedOperationException (); + } + + public int getMissingGlyphCode (Font font) + { + throw new UnsupportedOperationException (); + } + + public String getGlyphName (Font font, int glyphIndex) + { + throw new UnsupportedOperationException (); + } + + public int getNumGlyphs (Font font) + { + byte[] data = getTrueTypeTable((byte)'m', (byte) 'a', + (byte)'x', (byte) 'p'); + if( data == null ) + return -1; + + ByteBuffer buf = ByteBuffer.wrap( data ); + return buf.getShort(4); + } + + public boolean hasUniformLineMetrics (Font font) + { + return true; + } + + public GlyphVector layoutGlyphVector (Font font, FontRenderContext frc, + char[] chars, int start, int limit, + int flags) + { + return new FreetypeGlyphVector(font, chars, start, limit - start, + frc, flags); + } + + public LineMetrics getLineMetrics (Font font, String str, + FontRenderContext frc) + { + return new GdkFontLineMetrics (this, str.length ()); + } + + public FontMetrics getFontMetrics (Font font) + { + if (metrics == null) + metrics = new GdkFontMetrics(font); + return metrics; + } + + /** + * Returns a cached GlyphMetrics object for a given glyphcode, + * or null if it doesn't exist in the cache. + */ + GlyphMetrics getGlyphMetrics( int glyphCode ) + { + return metricsCache.get(new Integer(glyphCode)); + } + + /** + * Put a GlyphMetrics object in the cache. + */ + void putGlyphMetrics( int glyphCode, GlyphMetrics metrics ) + { + metricsCache.put( new Integer( glyphCode ), metrics ); + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsConfiguration.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsConfiguration.java new file mode 100644 index 000000000..40474ff3b --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsConfiguration.java @@ -0,0 +1,156 @@ +/* GdkGraphicsConfiguration.java -- describes characteristics of graphics + Copyright (C) 2000, 2001, 2002, 2003, 2004, 2006 Free Software Foundation + +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.gtk; + +import java.awt.BufferCapabilities; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.ImageCapabilities; +import java.awt.Rectangle; +import java.awt.Transparency; + +import java.awt.geom.AffineTransform; + +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.DirectColorModel; +import java.awt.image.VolatileImage; + +public class GdkGraphicsConfiguration + extends GraphicsConfiguration +{ + GdkScreenGraphicsDevice gdkScreenGraphicsDevice; + + ColorModel opaqueColorModel; + + ColorModel bitmaskColorModel; + + ColorModel translucentColorModel; + + public GdkGraphicsConfiguration(GdkScreenGraphicsDevice dev) + { + gdkScreenGraphicsDevice = dev; + + opaqueColorModel = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF, 0); + bitmaskColorModel = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF, 0x1000000); + translucentColorModel = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF, 0xFF000000); + } + + public GraphicsDevice getDevice() + { + return gdkScreenGraphicsDevice; + } + + public BufferedImage createCompatibleImage(int w, int h) + { + return new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); + } + + public BufferedImage createCompatibleImage(int w, int h, + int transparency) + { + return createCompatibleImage(w, h); + } + + public VolatileImage createCompatibleVolatileImage(int w, int h) + { + return new GtkVolatileImage(w, h); + } + + public VolatileImage createCompatibleVolatileImage(int w, int h, + ImageCapabilities caps) + throws java.awt.AWTException + { + return new GtkVolatileImage(w, h, caps); + } + + public ColorModel getColorModel() + { + return opaqueColorModel; + } + + public ColorModel getColorModel(int transparency) + { + switch (transparency) + { + case Transparency.OPAQUE: + return opaqueColorModel; + case Transparency.BITMASK: + return bitmaskColorModel; + default: + case Transparency.TRANSLUCENT: + return translucentColorModel; + } + } + + public AffineTransform getDefaultTransform() + { + // FIXME: extract the GDK DPI information here. + return new AffineTransform(); + } + + public AffineTransform getNormalizingTransform() + { + // FIXME: extract the GDK DPI information here. + return new AffineTransform(); + } + + public Rectangle getBounds() + { + return gdkScreenGraphicsDevice.getBounds(); + } + + public BufferCapabilities getBufferCapabilities() + { + return new BufferCapabilities(getImageCapabilities(), + getImageCapabilities(), + BufferCapabilities.FlipContents.UNDEFINED); + } + + public ImageCapabilities getImageCapabilities() + { + return new ImageCapabilities(false); + } + + public VolatileImage createCompatibleVolatileImage(int width, int height, int transparency) + { + // FIXME: support the transparency argument + return new GtkVolatileImage(width, height); + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java new file mode 100644 index 000000000..d931f4419 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java @@ -0,0 +1,172 @@ +/* GdkGraphicsEnvironment.java -- information about the graphics environment + Copyright (C) 2004, 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.java.awt.peer.gtk; + +import gnu.classpath.Configuration; +import gnu.java.awt.ClasspathGraphicsEnvironment; + +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.HeadlessException; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.Raster; +import java.awt.image.SampleModel; +import java.awt.image.WritableRaster; +import java.util.Locale; + +import gnu.classpath.Pointer; + +public class GdkGraphicsEnvironment extends ClasspathGraphicsEnvironment +{ + private final int native_state = GtkGenericPeer.getUniqueInteger (); + + private GdkScreenGraphicsDevice defaultDevice; + + private GdkScreenGraphicsDevice[] devices; + + /** + * The pointer to the native display resource. + * + * This field is manipulated by native code. Don't change or remove + * without adjusting the native code. + */ + private Pointer display; + + static + { + if (true) // GCJ LOCAL + { + System.loadLibrary("gtkpeer"); + } + + GtkToolkit.initializeGlobalIDs(); + initIDs(); + } + + private static native void initIDs(); + + public GdkGraphicsEnvironment () + { + nativeInitState(); + } + + native void nativeInitState(); + + public GraphicsDevice[] getScreenDevices () + { + if (devices == null) + { + devices = nativeGetScreenDevices(); + } + + return (GraphicsDevice[]) devices.clone(); + } + + private native GdkScreenGraphicsDevice[] nativeGetScreenDevices(); + + public GraphicsDevice getDefaultScreenDevice () + { + if (GraphicsEnvironment.isHeadless ()) + throw new HeadlessException (); + + synchronized (GdkGraphicsEnvironment.class) + { + if (defaultDevice == null) + { + defaultDevice = nativeGetDefaultScreenDevice(); + } + } + + return defaultDevice; + } + + private native GdkScreenGraphicsDevice nativeGetDefaultScreenDevice(); + + public Graphics2D createGraphics (BufferedImage image) + { + Raster raster = image.getRaster(); + if(raster instanceof CairoSurface) + return ((CairoSurface)raster).getGraphics(); + + return new BufferedImageGraphics( image ); + } + + private native int nativeGetNumFontFamilies(); + private native void nativeGetFontFamilies(String[] family_names); + + public Font[] getAllFonts () + { + throw new java.lang.UnsupportedOperationException (); + } + + public String[] getAvailableFontFamilyNames () + { + String[] family_names; + int array_size; + + array_size = nativeGetNumFontFamilies(); + family_names = new String[array_size]; + + nativeGetFontFamilies(family_names); + return family_names; + } + + public String[] getAvailableFontFamilyNames (Locale l) + { + throw new java.lang.UnsupportedOperationException (); + } + + /** + * Used by GtkMouseInfoPeer. + */ + native int[] getMouseCoordinates(); + native boolean isWindowUnderMouse(GtkWindowPeer windowPeer); + + public WritableRaster createRaster(ColorModel cm, SampleModel sm) + { + if (CairoSurface.isCompatibleSampleModel(sm) + && CairoSurface.isCompatibleColorModel(cm)) + return new CairoSurface(sm.getWidth(), sm.getHeight()); + else + return null; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java new file mode 100644 index 000000000..1b247c6eb --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java @@ -0,0 +1,785 @@ +/* GdkPixbufDecoder.java -- Image data decoding object + Copyright (C) 2003, 2004, 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.java.awt.peer.gtk; + +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.DirectColorModel; +import java.awt.image.ImageConsumer; +import java.awt.image.Raster; +import java.awt.image.RenderedImage; +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Locale; +import java.util.Vector; + +import javax.imageio.IIOImage; +import javax.imageio.ImageReadParam; +import javax.imageio.ImageReader; +import javax.imageio.ImageTypeSpecifier; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.spi.IIORegistry; +import javax.imageio.spi.ImageReaderSpi; +import javax.imageio.spi.ImageWriterSpi; +import javax.imageio.stream.ImageInputStream; +import javax.imageio.stream.ImageOutputStream; + +import gnu.classpath.Configuration; +import gnu.classpath.Pointer; + +public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder +{ + static + { + if (true) // GCJ LOCAL + { + System.loadLibrary("gtkpeer"); + } + + initStaticState (); + } + + /** + * Lock that should be held for all gdkpixbuf operations. We don't use + * the global gdk_threads_enter/leave functions since gdkpixbuf + * operations can be done in parallel to drawing and manipulating gtk + * widgets. + */ + static Object pixbufLock = new Object(); + + static native void initStaticState(); + private final int native_state = GtkGenericPeer.getUniqueInteger (); + + // initState() has been called, but pumpDone() has not yet been called. + private boolean needsClose = false; + + // the current set of ImageConsumers for this decoder + Vector curr; + + /** + * The pointer to the native pixbuf loader. + * + * This field is manipulated by native code. Don't change or remove + * without adjusting the native code. + */ + private Pointer nativeDecoder; + + // interface to GdkPixbuf + // These native functions should be called with the pixbufLock held. + native void initState (); + native void pumpBytes (byte[] bytes, int len) throws IOException; + native void pumpDone () throws IOException; + native void finish (boolean needsClose); + + /** + * Converts given image to bytes. + * Will call the GdkPixbufWriter for each chunk. + */ + static native void streamImage(int[] bytes, String format, + int width, int height, + boolean hasAlpha, GdkPixbufWriter writer); + + // gdk-pixbuf provids data in RGBA format + static final ColorModel cm = new DirectColorModel (32, 0xff000000, + 0x00ff0000, + 0x0000ff00, + 0x000000ff); + public GdkPixbufDecoder (DataInput datainput) + { + super (datainput); + } + + public GdkPixbufDecoder (InputStream in) + { + super (in); + } + + public GdkPixbufDecoder (String filename) + { + super (filename); + } + + public GdkPixbufDecoder (URL url) + { + super (url); + } + + public GdkPixbufDecoder (byte[] imagedata, int imageoffset, int imagelength) + { + super (imagedata, imageoffset, imagelength); + } + + // called back by native side: area_prepared_cb + void areaPrepared (int width, int height) + { + + if (curr == null) + return; + + for (int i = 0; i < curr.size (); i++) + { + ImageConsumer ic = (ImageConsumer) curr.elementAt (i); + ic.setDimensions (width, height); + ic.setColorModel (cm); + ic.setHints (ImageConsumer.RANDOMPIXELORDER); + } + } + + // called back by native side: area_updated_cb + void areaUpdated (int x, int y, int width, int height, + int pixels[], int scansize) + { + if (curr == null) + return; + + for (int i = 0; i < curr.size (); i++) + { + ImageConsumer ic = (ImageConsumer) curr.elementAt (i); + ic.setPixels (x, y, width, height, cm, pixels, 0, scansize); + } + } + + // called from an async image loader of one sort or another, this method + // repeatedly reads bytes from the input stream and passes them through a + // GdkPixbufLoader using the native method pumpBytes. pumpBytes in turn + // decodes the image data and calls back areaPrepared and areaUpdated on + // this object, feeding back decoded pixel blocks, which we pass to each + // of the ImageConsumers in the provided Vector. + + public void produce (Vector v, InputStream is) throws IOException + { + curr = v; + + byte bytes[] = new byte[4096]; + int len = 0; + synchronized(pixbufLock) + { + initState(); + } + needsClose = true; + + // Note: We don't want the pixbufLock while reading from the InputStream. + while ((len = is.read (bytes)) != -1) + { + synchronized(pixbufLock) + { + pumpBytes (bytes, len); + } + } + + synchronized(pixbufLock) + { + pumpDone(); + } + + needsClose = false; + + for (int i = 0; i < curr.size (); i++) + { + ImageConsumer ic = (ImageConsumer) curr.elementAt (i); + ic.imageComplete (ImageConsumer.STATICIMAGEDONE); + } + + curr = null; + } + + public void finalize() + { + synchronized(pixbufLock) + { + finish(needsClose); + } + } + + + public static class ImageFormatSpec + { + public String name; + public boolean writable = false; + public ArrayList mimeTypes = new ArrayList(); + public ArrayList extensions = new ArrayList(); + + public ImageFormatSpec(String name, boolean writable) + { + this.name = name; + this.writable = writable; + } + + public synchronized void addMimeType(String m) + { + mimeTypes.add(m); + } + + public synchronized void addExtension(String e) + { + extensions.add(e); + } + } + + static ArrayList imageFormatSpecs; + + public static ImageFormatSpec registerFormat(String name, boolean writable) + { + ImageFormatSpec ifs = new ImageFormatSpec(name, writable); + synchronized(GdkPixbufDecoder.class) + { + if (imageFormatSpecs == null) + imageFormatSpecs = new ArrayList(); + imageFormatSpecs.add(ifs); + } + return ifs; + } + + static String[] getFormatNames(boolean writable) + { + ArrayList names = new ArrayList(); + synchronized (imageFormatSpecs) + { + Iterator i = imageFormatSpecs.iterator(); + while (i.hasNext()) + { + ImageFormatSpec ifs = i.next(); + if (writable && !ifs.writable) + continue; + names.add(ifs.name); + + /* + * In order to make the filtering code work, we need to register + * this type under every "format name" likely to be used as a synonym. + * This generally means "all the extensions people might use". + */ + + Iterator j = ifs.extensions.iterator(); + while (j.hasNext()) + names.add(j.next()); + } + } + return names.toArray(new String[names.size()]); + } + + static String[] getFormatExtensions(boolean writable) + { + ArrayList extensions = new ArrayList(); + synchronized (imageFormatSpecs) + { + Iterator i = imageFormatSpecs.iterator(); + while (i.hasNext()) + { + ImageFormatSpec ifs = i.next(); + if (writable && !ifs.writable) + continue; + Iterator j = ifs.extensions.iterator(); + while (j.hasNext()) + extensions.add(j.next()); + } + } + return extensions.toArray(new String[extensions.size()]); + } + + static String[] getFormatMimeTypes(boolean writable) + { + ArrayList mimeTypes = new ArrayList(); + synchronized (imageFormatSpecs) + { + Iterator i = imageFormatSpecs.iterator(); + while (i.hasNext()) + { + ImageFormatSpec ifs = i.next(); + if (writable && !ifs.writable) + continue; + Iterator j = ifs.mimeTypes.iterator(); + while (j.hasNext()) + mimeTypes.add(j.next()); + } + } + return mimeTypes.toArray(new String[mimeTypes.size()]); + } + + + static String findFormatName(Object ext, boolean needWritable) + { + if (ext == null) + return null; + + if (!(ext instanceof String)) + throw new IllegalArgumentException("extension is not a string"); + + String str = (String) ext; + + Iterator i = imageFormatSpecs.iterator(); + while (i.hasNext()) + { + ImageFormatSpec ifs = i.next(); + + if (needWritable && !ifs.writable) + continue; + + if (ifs.name.equals(str)) + return str; + + Iterator j = ifs.extensions.iterator(); + while (j.hasNext()) + { + String extension = j.next(); + if (extension.equals(str)) + return ifs.name; + } + + j = ifs.mimeTypes.iterator(); + while (j.hasNext()) + { + String mimeType = j.next(); + if (mimeType.equals(str)) + return ifs.name; + } + } + throw new IllegalArgumentException("unknown extension '" + str + "'"); + } + + private static GdkPixbufReaderSpi readerSpi; + private static GdkPixbufWriterSpi writerSpi; + + public static synchronized GdkPixbufReaderSpi getReaderSpi() + { + if (readerSpi == null) + readerSpi = new GdkPixbufReaderSpi(); + return readerSpi; + } + + public static synchronized GdkPixbufWriterSpi getWriterSpi() + { + if (writerSpi == null) + writerSpi = new GdkPixbufWriterSpi(); + return writerSpi; + } + + public static void registerSpis(IIORegistry reg) + { + reg.registerServiceProvider(getReaderSpi(), ImageReaderSpi.class); + reg.registerServiceProvider(getWriterSpi(), ImageWriterSpi.class); + } + + public static class GdkPixbufWriterSpi extends ImageWriterSpi + { + public GdkPixbufWriterSpi() + { + super("GdkPixbuf", "2.x", + GdkPixbufDecoder.getFormatNames(true), + GdkPixbufDecoder.getFormatExtensions(true), + GdkPixbufDecoder.getFormatMimeTypes(true), + "gnu.java.awt.peer.gtk.GdkPixbufDecoder$GdkPixbufWriter", + new Class[] { ImageOutputStream.class }, + new String[] { "gnu.java.awt.peer.gtk.GdkPixbufDecoder$GdkPixbufReaderSpi" }, + false, null, null, null, null, + false, null, null, null, null); + } + + public boolean canEncodeImage(ImageTypeSpecifier ts) + { + return true; + } + + public ImageWriter createWriterInstance(Object ext) + { + return new GdkPixbufWriter(this, ext); + } + + public String getDescription(java.util.Locale loc) + { + return "GdkPixbuf Writer SPI"; + } + + } + + public static class GdkPixbufReaderSpi extends ImageReaderSpi + { + public GdkPixbufReaderSpi() + { + super("GdkPixbuf", "2.x", + GdkPixbufDecoder.getFormatNames(false), + GdkPixbufDecoder.getFormatExtensions(false), + GdkPixbufDecoder.getFormatMimeTypes(false), + "gnu.java.awt.peer.gtk.GdkPixbufDecoder$GdkPixbufReader", + new Class[] { ImageInputStream.class }, + new String[] { "gnu.java.awt.peer.gtk.GdkPixbufDecoder$GdkPixbufWriterSpi" }, + false, null, null, null, null, + false, null, null, null, null); + } + + public boolean canDecodeInput(Object obj) + { + return true; + } + + public ImageReader createReaderInstance(Object ext) + { + return new GdkPixbufReader(this, ext); + } + + public String getDescription(Locale loc) + { + return "GdkPixbuf Reader SPI"; + } + } + + private static class GdkPixbufWriter + extends ImageWriter implements Runnable + { + String ext; + public GdkPixbufWriter(GdkPixbufWriterSpi ownerSpi, Object ext) + { + super(ownerSpi); + this.ext = findFormatName(ext, true); + } + + public IIOMetadata convertImageMetadata (IIOMetadata inData, + ImageTypeSpecifier imageType, + ImageWriteParam param) + { + return null; + } + + public IIOMetadata convertStreamMetadata (IIOMetadata inData, + ImageWriteParam param) + { + return null; + } + + public IIOMetadata getDefaultImageMetadata (ImageTypeSpecifier imageType, + ImageWriteParam param) + { + return null; + } + + public IIOMetadata getDefaultStreamMetadata (ImageWriteParam param) + { + return null; + } + + public void write (IIOMetadata streamMetadata, IIOImage i, ImageWriteParam param) + throws IOException + { + RenderedImage image = i.getRenderedImage(); + Raster ras = image.getData(); + int width = ras.getWidth(); + int height = ras.getHeight(); + ColorModel model = image.getColorModel(); + int[] pixels = CairoGraphics2D.findSimpleIntegerArray (image.getColorModel(), ras); + + if (pixels == null) + { + BufferedImage img; + if(model != null && model.hasAlpha()) + img = CairoSurface.getBufferedImage(width, height); + img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + int[] pix = new int[4]; + for (int y = 0; y < height; ++y) + for (int x = 0; x < width; ++x) + img.setRGB(x, y, model.getRGB(ras.getPixel(x, y, pix))); + pixels = CairoGraphics2D.findSimpleIntegerArray (img.getColorModel(), + img.getRaster()); + model = img.getColorModel(); + } + + Thread workerThread = new Thread(this, "GdkPixbufWriter"); + workerThread.start(); + processImageStarted(1); + synchronized(pixbufLock) + { + streamImage(pixels, this.ext, width, height, model.hasAlpha(), + this); + } + synchronized(data) + { + data.add(DATADONE); + data.notifyAll(); + } + + while (workerThread.isAlive()) + { + try + { + workerThread.join(); + } + catch (InterruptedException ioe) + { + // Ignored. + } + } + + if (exception != null) + throw exception; + + processImageComplete(); + } + + /** + * Object marking end of data from native streamImage code. + */ + private static final Object DATADONE = new Object(); + + /** + * Holds the data gotten from the native streamImage code. + * A worker thread will pull data out. + * Needs to be synchronized for access. + * The special object DATADONE is added when all data has been delivered. + */ + private ArrayList data = new ArrayList(); + + /** + * Holds any IOException thrown by the run method that needs + * to be rethrown by the write method. + */ + private IOException exception; + + /** Callback for streamImage native code. **/ + private void write(byte[] bs) + { + synchronized(data) + { + data.add(bs); + data.notifyAll(); + } + } + + public void run() + { + boolean done = false; + while (!done) + { + synchronized(data) + { + while (data.isEmpty()) + { + try + { + data.wait(); + } + catch (InterruptedException ie) + { + /* ignore */ + } + } + + Object o = data.remove(0); + if (o == DATADONE) + done = true; + else + { + DataOutput out = (DataOutput) getOutput(); + try + { + out.write((byte[]) o); + } + catch (IOException ioe) + { + // We are only interested in the first exception. + if (exception == null) + exception = ioe; + } + } + } + } + } + } + + private static class GdkPixbufReader + extends ImageReader + implements ImageConsumer + { + // ImageConsumer parts + GdkPixbufDecoder dec; + BufferedImage bufferedImage; + ColorModel defaultModel; + int width; + int height; + String ext; + + public GdkPixbufReader(GdkPixbufReaderSpi ownerSpi, Object ext) + { + super(ownerSpi); + this.ext = findFormatName(ext, false); + } + + public GdkPixbufReader(GdkPixbufReaderSpi ownerSpi, Object ext, + GdkPixbufDecoder d) + { + this(ownerSpi, ext); + dec = d; + } + + public void setDimensions(int w, int h) + { + processImageStarted(1); + width = w; + height = h; + } + + public void setProperties(Hashtable props) {} + + public void setColorModel(ColorModel model) + { + defaultModel = model; + } + + public void setHints(int flags) {} + + public void setPixels(int x, int y, int w, int h, + ColorModel model, byte[] pixels, + int offset, int scansize) + { + } + + public void setPixels(int x, int y, int w, int h, + ColorModel model, int[] pixels, + int offset, int scansize) + { + if (model == null) + model = defaultModel; + + if (bufferedImage == null) + { + if(model != null && model.hasAlpha()) + bufferedImage = new BufferedImage (width, height, + BufferedImage.TYPE_INT_ARGB); + else + bufferedImage = new BufferedImage (width, height, + BufferedImage.TYPE_INT_RGB); + } + + int pixels2[]; + if (model != null) + { + pixels2 = new int[pixels.length]; + for (int yy = 0; yy < h; yy++) + for (int xx = 0; xx < w; xx++) + { + int i = yy * scansize + xx; + pixels2[i] = model.getRGB (pixels[i]); + } + } + else + pixels2 = pixels; + + bufferedImage.setRGB (x, y, w, h, pixels2, offset, scansize); + processImageProgress(y / (height == 0 ? 1 : height)); + } + + public void imageComplete(int status) + { + processImageComplete(); + } + + public BufferedImage getBufferedImage() + { + if (bufferedImage == null && dec != null) + dec.startProduction (this); + return bufferedImage; + } + + // ImageReader parts + + public int getNumImages(boolean allowSearch) + throws IOException + { + return 1; + } + + public IIOMetadata getImageMetadata(int i) + { + return null; + } + + public IIOMetadata getStreamMetadata() + throws IOException + { + return null; + } + + public Iterator getImageTypes(int imageIndex) + throws IOException + { + BufferedImage img = getBufferedImage(); + Vector vec = new Vector(); + vec.add(new ImageTypeSpecifier(img)); + return vec.iterator(); + } + + public int getHeight(int imageIndex) + throws IOException + { + return getBufferedImage().getHeight(); + } + + public int getWidth(int imageIndex) + throws IOException + { + return getBufferedImage().getWidth(); + } + + public void setInput(Object input, + boolean seekForwardOnly, + boolean ignoreMetadata) + { + super.setInput(input, seekForwardOnly, ignoreMetadata); + Object get = getInput(); + if (get instanceof InputStream) + dec = new GdkPixbufDecoder((InputStream) get); + else if (get instanceof DataInput) + dec = new GdkPixbufDecoder((DataInput) get); + else + throw new IllegalArgumentException("input object not supported: " + + get); + } + + public BufferedImage read(int imageIndex, ImageReadParam param) + throws IOException + { + return getBufferedImage (); + } + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkRobotPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkRobotPeer.java new file mode 100644 index 000000000..2609bad09 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkRobotPeer.java @@ -0,0 +1,99 @@ +/* GdkRobot.java -- an XTest implementation of RobotPeer + Copyright (C) 2004, 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.java.awt.peer.gtk; + +import java.awt.AWTException; +import java.awt.GraphicsDevice; +import java.awt.Rectangle; +import java.awt.image.ColorModel; +import java.awt.image.DirectColorModel; +import java.awt.peer.RobotPeer; + +/** + * Implements the RobotPeer interface using the XTest extension. + * + * @author Thomas Fitzsimmons + */ +public class GdkRobotPeer implements RobotPeer +{ + // gdk-pixbuf provides data in RGBA format + static final ColorModel cm = new DirectColorModel (32, 0xff000000, + 0x00ff0000, + 0x0000ff00, + 0x000000ff); + + public GdkRobotPeer (GraphicsDevice screen) throws AWTException + { + // FIXME: make use of screen parameter when GraphicsDevice is + // implemented. + if (!initXTest ()) + throw new AWTException ("XTest extension not supported"); + } + + native boolean initXTest (); + + // RobotPeer methods + public native void mouseMove (int x, int y); + public native void mousePress (int buttons); + public native void mouseRelease (int buttons); + public native void mouseWheel (int wheelAmt); + public native void keyPress (int keycode); + public native void keyRelease (int keycode); + native int[] nativeGetRGBPixels (int x, int y, int width, int height); + + public int getRGBPixel (int x, int y) + { + return cm.getRGB (nativeGetRGBPixels (x, y, 1, 1)[0]); + } + + public int[] getRGBPixels (Rectangle r) + { + int[] gdk_pixels = nativeGetRGBPixels (r.x, r.y, r.width, r.height); + int[] pixels = new int[r.width * r.height]; + + for (int i = 0; i < r.width * r.height; i++) + pixels[i] = cm.getRGB (gdk_pixels[i]); + + return pixels; + } + + public void dispose() + { + // Nothing to do here yet. + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkScreenGraphicsDevice.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkScreenGraphicsDevice.java new file mode 100644 index 000000000..1c849dfc0 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkScreenGraphicsDevice.java @@ -0,0 +1,362 @@ +/* GdkScreenGraphicsDevice.java -- information about a screen device + Copyright (C) 2004, 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.java.awt.peer.gtk; + +import java.awt.DisplayMode; +import java.awt.Frame; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.Rectangle; +import java.awt.Window; +import java.util.ArrayList; + +import gnu.classpath.Configuration; +import gnu.classpath.Pointer; + +class GdkScreenGraphicsDevice extends GraphicsDevice +{ + private final int native_state = GtkGenericPeer.getUniqueInteger (); + + private Window fullscreenWindow; + + private boolean oldWindowDecorationState; + + private Rectangle oldWindowBounds; + + private Rectangle bounds; + + private GdkGraphicsConfiguration[] configurations; + + /** The GdkGraphicsEnvironment instance that created this + * GdkScreenGraphicsDevice. This is only needed for native + * methods which need to access the 'native_state' field storing a pointer + * to a GdkDisplay object. + */ + GdkGraphicsEnvironment env; + + /** An identifier that is created by Gdk + */ + String idString; + + /** The display modes supported by this GdkScreenGraphicsDevice. + * If the array is null nativeGetDisplayModes has + * to be called. + */ + X11DisplayMode[] displayModes; + + /** The non-changeable display mode of this GdkScreenGraphicsDevice + * . This field gets initialized by the {@link #init()} method. If it + * is still null afterwards, the XRandR extension is available + * and display mode changes are possible. If it is non-null XRandR is not + * available, no display mode changes are possible and no other native + * method must be called. + */ + DisplayMode fixedDisplayMode; + + /** + * The pointer to the native screen resource. + * + * This field is manipulated by native code. Don't change or remove + * without adjusting the native code. + */ + private Pointer screen; + + static + { + if (true) // GCJ LOCAL + { + System.loadLibrary("gtkpeer"); + } + + GtkToolkit.initializeGlobalIDs(); + initIDs(); + } + + static native void initIDs(); + + GdkScreenGraphicsDevice (GdkGraphicsEnvironment e) + { + super(); + env = e; + + configurations = new GdkGraphicsConfiguration[1]; + configurations[0] = new GdkGraphicsConfiguration(this); + } + + /** This method is called from the native side immediately after + * the constructor is run. + */ + void init() + { + fixedDisplayMode = nativeGetFixedDisplayMode(env); + } + + /** Depending on the availability of the XRandR extension the method returns + * the screens' non-changeable display mode or null, meaning that XRandR can + * handle display mode changes. + */ + native DisplayMode nativeGetFixedDisplayMode(GdkGraphicsEnvironment env); + + public int getType () + { + // Gdk manages only raster screens. + return GraphicsDevice.TYPE_RASTER_SCREEN; + } + + public String getIDstring () + { + if (idString == null) + idString = nativeGetIDString(); + + return idString; + } + + private native String nativeGetIDString(); + + public GraphicsConfiguration[] getConfigurations () + { + return (GraphicsConfiguration[]) configurations.clone(); + } + + public GraphicsConfiguration getDefaultConfiguration () + { + return configurations[0]; + } + + + /** + * Returns the current display mode of this device, or null if unknown. + * + * @return the current display mode + * @see #setDisplayMode(DisplayMode) + * @see #getDisplayModes() + * @since 1.4 + */ + public DisplayMode getDisplayMode() + { + if (fixedDisplayMode != null) + return fixedDisplayMode; + + synchronized (this) + { + if (displayModes == null) + displayModes = nativeGetDisplayModes(env); + } + + int index = nativeGetDisplayModeIndex(env); + int rate = nativeGetDisplayModeRate(env); + + return new DisplayMode(displayModes[index].width, + displayModes[index].height, + DisplayMode.BIT_DEPTH_MULTI, + rate); + } + + native int nativeGetDisplayModeIndex(GdkGraphicsEnvironment env); + + native int nativeGetDisplayModeRate(GdkGraphicsEnvironment env); + + public DisplayMode[] getDisplayModes() + { + if (fixedDisplayMode != null) + return new DisplayMode[] { fixedDisplayMode }; + + synchronized (this) + { + if (displayModes == null) + displayModes = nativeGetDisplayModes(env); + } + + ArrayList list = new ArrayList(); + for(int i=0;ifalse + * @since 1.4 + */ + public boolean isFullScreenSupported() + { + return true; + } + + public boolean isDisplayChangeSupported() + { + return fixedDisplayMode == null; + } + + public void setDisplayMode(DisplayMode dm) + { + if (fixedDisplayMode != null) + throw new UnsupportedOperationException("Cannnot change display mode."); + + if (dm == null) + throw new IllegalArgumentException("DisplayMode must not be null."); + + synchronized (this) + { + if (displayModes == null) + displayModes = nativeGetDisplayModes(env); + } + + for (int i=0; i groupMap + = new WeakHashMap(); + + public native void createCheckButton (); + public native void createRadioButton (long groupPointer); + + public native void addToGroup (long groupPointer); + public native void removeFromGroup (); + public native void switchToGroup (long groupPointer); + + public native void connectSignals (); + + /** + * 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); + + public GtkCheckboxPeer (Checkbox c) + { + super (c); + } + + public void create () + { + Checkbox checkbox = (Checkbox) awtComponent; + current_group = checkbox.getCheckboxGroup (); + if (current_group == null) + { + // Initially we're not part of a group so we're backed by a + // GtkCheckButton. + createCheckButton(); + } + else + { + // Initially we're part of a group. + + // See if this group is already stored in our map. + Long groupPointer = null; + synchronized (groupMap) + { + groupPointer = groupMap.get(current_group); + } + + if (groupPointer == null) + { + // We don't know about this group. Create a new native + // group pointer for this group and store it in our map. + createRadioButton(0); + } + else + { + // We already know about this group. Pass the + // corresponding native group pointer value to the native + // create method. + createRadioButton(groupPointer.longValue()); + } + } + currentState = checkbox.getState(); + gtkToggleButtonSetActive(currentState); + + String label = checkbox.getLabel(); + if (label != null) + gtkButtonSetLabel(label); + } + + /** + * 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. + */ + public synchronized void setState (boolean state) + { + if (currentState != state) + { + currentState = state; + gtkToggleButtonSetActive(state); + } + } + + public void setLabel (String label) + { + gtkButtonSetLabel (label); + } + + public void setCheckboxGroup (CheckboxGroup group) + { + if (current_group == null && group != null) + { + // This peer's owner is currently not in a group, and now + // we're adding it to a group. This means that the backing + // GtkWidget will change from a GtkCheckButton to a + // GtkRadioButton. + + current_group = group; + + // See if the new group is already stored in our map. + Long groupPointer = null; + synchronized (groupMap) + { + groupPointer = groupMap.get(current_group); + } + + if (groupPointer == null) + { + // We don't know about this group. Create a new native + // group pointer for this group and store it in our map. + addToGroup(0); + } + else + { + // We already know about this group. Pass the + // corresponding native group pointer value to the native + // create method. + addToGroup(groupPointer.longValue()); + } + } + else if (current_group != null && group == null) + { + // This peer's owner is currently in a group, and now we're + // removing it from a group. This means that the backing + // GtkWidget will change from a GtkRadioButton to a + // GtkCheckButton. + removeFromGroup(); + current_group = null; + } + else if (current_group == null && group == null) + { + // This peer's owner is currently not in a group, and we're + // not adding it to a group, so simply return. + return; + } + else if (current_group != group) + { + // This peer's owner is currently in a group, and now we're + // putting it in another group. This means that we must + // remove the backing GtkRadioButton from one group and add it + // to the other group. + + current_group = group; + + // See if the new group is already stored in our map. + Long groupPointer = null; + synchronized (groupMap) + { + groupPointer = groupMap.get(current_group); + } + + if (groupPointer == null) + { + // We don't know about this group. Create a new native + // group pointer for this group and store it in our map. + switchToGroup(0); + } + else + { + // We already know about this group. Pass the + // corresponding native group pointer value to the native + // create method. + switchToGroup(groupPointer.longValue()); + } + } + } + + // Override the superclass postItemEvent so that the peer doesn't + // need information that we have. + // called back by native side: item_toggled_cb + public synchronized void postItemEvent(Object item, boolean state) + { + // Only fire event is state actually changed. + if (currentState != state) + { + currentState = state; + super.postItemEvent(awtComponent, + state ? ItemEvent.SELECTED : ItemEvent.DESELECTED); + } + } + + public void addToGroupMap(long groupPointer) + { + synchronized (groupMap) + { + groupMap.put(current_group, new Long (groupPointer)); + } + } + + public void dispose () + { + groupMap.clear(); + current_group = null; + currentState = false; + super.dispose (); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkChoicePeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkChoicePeer.java new file mode 100644 index 000000000..59cacf0b6 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkChoicePeer.java @@ -0,0 +1,142 @@ +/* GtkChoicePeer.java -- Implements ChoicePeer with GTK + Copyright (C) 1998, 1999, 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.java.awt.peer.gtk; + +import java.awt.Choice; +import java.awt.AWTEvent; +import java.awt.event.ItemEvent; +import java.awt.peer.ChoicePeer; + +public class GtkChoicePeer extends GtkComponentPeer + implements ChoicePeer +{ + private int selected; + + public GtkChoicePeer (Choice c) + { + super (c); + + int count = c.getItemCount (); + if (count > 0) + { + for (int i = 0; i < count; i++) + add(c.getItem(i), i); + + selected = c.getSelectedIndex(); + if (selected >= 0) + select( selected ); + } + else + selected = -1; + } + + native void create (); + + native int nativeGetSelected (); + + native void connectSignals (); + + native void selectNative (int position); + + native void selectNativeUnlocked (int position); + + public native void add (String item, int index); + + native void nativeRemove(int index); + + native void nativeRemoveAll(); + + public void select (int position) + { + if (Thread.currentThread() == GtkMainThread.mainThread) + selectNativeUnlocked (position); + else + selectNative (position); + } + + public void remove( int index ) + { + // Ensure the triggering of an event when removing item zero if zero is the + // selected item, even though the selected index doesn't change. + if( index == 0 && selected == 0 ) + selected = -1; + nativeRemove( index ); + } + + public void removeAll() + { + selected = -1; // we do not want to trigger a select event here. + nativeRemoveAll(); + } + + public void addItem (String item, int position) + { + add (item, position); + } + + /** + * Callback from the native side on an item-select event, + * which posts an event. The event is only posted if it represents an actual + * change. Selected is set to the peer's state initially, so that the + * first call to select(int) from the constructor will not trigger an event. + * (it should not) + */ + protected void postChoiceItemEvent ( int index ) + { + if( selected != index ) + { + selected = index; + postItemEvent (((Choice) awtComponent).getItem( selected ), + ItemEvent.SELECTED); + } + } + + /** + * Catches the event and calls Choice.select() if the component state + * needs updating. + */ + public void handleEvent (AWTEvent event) + { + super.handleEvent (event); + if (event instanceof ItemEvent) + if (((ItemEvent)event).getItemSelectable() == awtComponent + && ((ItemEvent)event).getStateChange() == ItemEvent.SELECTED) + ((Choice)awtComponent).select( selected ); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkClipboard.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkClipboard.java new file mode 100644 index 000000000..4250cabaa --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkClipboard.java @@ -0,0 +1,436 @@ +/* GtkClipboard.java + Copyright (C) 1999, 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.java.awt.peer.gtk; + +import gnu.java.lang.CPStringBuilder; + +import java.awt.Image; + +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.ClipboardOwner; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.StringSelection; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.InputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.Reader; +import java.io.Serializable; +import java.io.UnsupportedEncodingException; + +import java.util.List; +import java.util.Iterator; + +public class GtkClipboard extends Clipboard +{ + /** + * The one and only gtk+ clipboard instance for the CLIPBOARD selection. + */ + final static GtkClipboard clipboard = new GtkClipboard("System Clipboard"); + + /** + * The one and only gtk+ clipboard instance for the PRIMARY selection. + */ + final static GtkClipboard selection = new GtkClipboard("System Selection"); + + // Given to the native side so it can signal special targets that + // can be converted to one of the special predefined DataFlavors. + static final String stringMimeType + = DataFlavor.stringFlavor.getMimeType(); + static final String imageMimeType + = DataFlavor.imageFlavor.getMimeType(); + static final String filesMimeType + = DataFlavor.javaFileListFlavor.getMimeType(); + + // Indicates whether the results of the clipboard selection can be + // cached by GtkSelection. True if + // gdk_display_supports_selection_notification. + static final boolean canCache = initNativeState(clipboard, selection, + stringMimeType, + imageMimeType, + filesMimeType); + + /** + * Creates the clipboard and sets the initial contents to the + * current gtk+ selection. + */ + private GtkClipboard(String name) + { + super(name); + setContents(new GtkSelection(this), null); + } + + /** + * Returns the one and only GtkClipboard instance for the CLIPBOARD + * selection. + */ + static GtkClipboard getClipboardInstance() + { + return clipboard; + } + + /** + * Returns the one and only GtkClipboard instance for the PRIMARY + * selection. + */ + static GtkClipboard getSelectionInstance() + { + return selection; + } + + /** + * Sets the GtkSelection facade as new contents of the clipboard. + * Called from gtk+ when another application grabs the clipboard and + * we loose ownership. + * + * @param cleared If true this is a clear event (someone takes the + * clipboard from us) otherwise it is an owner changed event. + */ + private synchronized void setSystemContents(boolean cleared) + { + // We need to notify clipboard owner listeners when we were the + // owner (the selection was explictly set) and someone takes the + // clipboard away from us and asks us the clear any held storage, + // or if we weren't the owner of the clipboard to begin with, but + // the clipboard contents changed. We could refine this and check + // whether the actual available formats did in fact change, but we + // assume listeners will check for that anyway (and if possible we + // ask to cache the available formats so even if multiple + // listeners check after a notification the overhead should be + // minimal). + boolean owner = ! (contents instanceof GtkSelection); + boolean needNotification = (cleared && owner) || (! cleared && ! owner); + if (needNotification) + GtkClipboardNotifier.announce(this); + } + + /** + * Sets the new contents and advertises the available flavors to the + * gtk+ clipboard. + */ + public synchronized void setContents(Transferable contents, + ClipboardOwner owner) + { + super.setContents(contents, owner); + + if (contents == null) + { + advertiseContent(null, false, false, false); + return; + } + + // We don't need to do anything for a GtkSelection facade. + if (contents instanceof GtkSelection) + return; + + boolean text = false; + boolean images = false; + boolean files = false; + + if (contents instanceof StringSelection + || contents.isDataFlavorSupported(DataFlavor.stringFlavor) + || contents.isDataFlavorSupported(DataFlavor.plainTextFlavor) + || contents.isDataFlavorSupported(DataFlavor.getTextPlainUnicodeFlavor())) + text = true; + + DataFlavor[] flavors = contents.getTransferDataFlavors(); + String[] mimeTargets = new String[flavors.length]; + for (int i = 0; i < flavors.length; i++) + { + DataFlavor flavor = flavors[i]; + String mimeType = flavor.getMimeType(); + mimeTargets[i] = mimeType; + + if (! text) + if ("text".equals(flavor.getPrimaryType()) + || flavor.isRepresentationClassReader()) + text = true; + + if (! images && flavors[i].equals(DataFlavor.imageFlavor)) + { + try + { + Object o = contents.getTransferData(DataFlavor.imageFlavor); + if (o instanceof Image) + images = true; + } + catch (UnsupportedFlavorException ufe) + { + } + catch (IOException ioe) + { + } + catch (ClassCastException cce) + { + } + } + + if (flavors[i].equals(DataFlavor.javaFileListFlavor)) + files = true; + } + + advertiseContent(mimeTargets, text, images, files); + } + + /** + * Advertises new contents to the gtk+ clipboard given a string + * array of (mime-type) targets. When the boolean flags text, images + * and/or files are set then gtk+ is asked to also advertise the + * availability of any text, image or uri/file content types it + * supports. If targets is null (and all flags false) then the + * selection has explicitly been erased. + */ + private native void advertiseContent(String[] targets, + boolean text, + boolean images, + boolean files); + + /** + * Called by the gtk+ clipboard when an application has requested + * text. Return a string representing the current clipboard + * contents or null when no text can be provided. + */ + private String provideText() + { + Transferable contents = this.contents; + if (contents == null || contents instanceof GtkSelection) + return null; + + // Handle StringSelection special since that is just pure text. + if (contents instanceof StringSelection) + { + try + { + return (String) contents.getTransferData(DataFlavor.stringFlavor); + } + catch (UnsupportedFlavorException ufe) + { + } + catch (IOException ioe) + { + } + catch (ClassCastException cce) + { + } + } + + // Try to get a plain text reader for the current contents and + // turn the result into a string. + try + { + DataFlavor plainText = DataFlavor.getTextPlainUnicodeFlavor(); + Reader r = plainText.getReaderForText(contents); + if (r != null) + { + CPStringBuilder sb = new CPStringBuilder(); + char[] cs = new char[1024]; + int l = r.read(cs); + while (l != -1) + { + sb.append(cs, 0, l); + l = r.read(cs); + } + return sb.toString(); + } + } + catch (IllegalArgumentException iae) + { + } + catch (UnsupportedEncodingException iee) + { + } + catch (UnsupportedFlavorException ufe) + { + } + catch (IOException ioe) + { + } + + return null; + } + + /** + * Called by the gtk+ clipboard when an application has requested an + * image. Returns a GtkImage representing the current clipboard + * contents or null when no image can be provided. + */ + private GtkImage provideImage() + { + Transferable contents = this.contents; + if (contents == null || contents instanceof GtkSelection) + return null; + + try + { + Object o = contents.getTransferData(DataFlavor.imageFlavor); + if( o instanceof GtkImage ) + return (GtkImage) o; + else + return new GtkImage(((Image)o).getSource()); + } + catch (UnsupportedFlavorException ufe) + { + } + catch (IOException ioe) + { + } + catch (ClassCastException cce) + { + } + + return null; + } + + /** + * Called by the gtk+ clipboard when an application has requested a + * uri-list. Return a string array containing the URIs representing + * the current clipboard contents or null when no URIs can be + * provided. + */ + private String[] provideURIs() + { + Transferable contents = this.contents; + if (contents == null || contents instanceof GtkSelection) + return null; + + try + { + List list = (List) contents.getTransferData(DataFlavor.javaFileListFlavor); + String[] uris = new String[list.size()]; + int u = 0; + Iterator it = list.iterator(); + while (it.hasNext()) + uris[u++] = ((File) it.next()).toURI().toString(); + return uris; + } + catch (UnsupportedFlavorException ufe) + { + } + catch (IOException ioe) + { + } + catch (ClassCastException cce) + { + } + + return null; + } + + /** + * Called by gtk+ clipboard when an application requests the given + * target mime-type. Returns a byte array containing the requested + * data, or null when the contents cannot be provided in the + * requested target mime-type. Only called after any explicit text, + * image or file/uri requests have been handled earlier and failed. + */ + private byte[] provideContent(String target) + { + // Sanity check. The callback could be triggered just after we + // changed the clipboard. + Transferable contents = this.contents; + if (contents == null || contents instanceof GtkSelection) + return null; + + // XXX - We are being called from a gtk+ callback. Which means we + // should return as soon as possible and not call arbitrary code + // that could deadlock or go bonkers. But we don't really know + // what DataTransfer contents object we are dealing with. Same for + // the other provideXXX() methods. + try + { + DataFlavor flavor = new DataFlavor(target); + Object o = contents.getTransferData(flavor); + + if (o instanceof byte[]) + return (byte[]) o; + + if (o instanceof InputStream) + { + InputStream is = (InputStream) o; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] bs = new byte[1024]; + int l = is.read(bs); + while (l != -1) + { + baos.write(bs, 0, l); + l = is.read(bs); + } + return baos.toByteArray(); + } + + if (o instanceof Serializable) + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(o); + oos.close(); + return baos.toByteArray(); + } + } + catch (ClassNotFoundException cnfe) + { + } + catch (UnsupportedFlavorException ufe) + { + } + catch (IOException ioe) + { + } + catch (ClassCastException cce) + { + } + + return null; + } + + /** + * Initializes the gtk+ clipboards and caches any native side + * structures needed. Returns whether or not the contents of the + * Clipboard can be cached (gdk_display_supports_selection_notification). + */ + private static native boolean initNativeState(GtkClipboard clipboard, + GtkClipboard selection, + String stringTarget, + String imageTarget, + String filesTarget); +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkClipboardNotifier.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkClipboardNotifier.java new file mode 100644 index 000000000..8e5934557 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkClipboardNotifier.java @@ -0,0 +1,129 @@ +/* GtkClipboardNotifier.java -- Helper for announcing GtkSelection changes. + 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.java.awt.peer.gtk; + + +class GtkClipboardNotifier extends Thread +{ + /** Whether to announce a new GtkSelection has been set for CLIPBOARD. */ + static private boolean announceClipboardChange; + + /** Whether to announce a new GtkSelection has been set for PRIMARY. */ + static private boolean announcePrimaryChange; + + /** + * The one and only instance. All operations are synchronized on + * this. + */ + private static GtkClipboardNotifier notifier = new GtkClipboardNotifier(); + + /** + * Creates a deamon thread that monitors this for change + * announcements. + */ + private GtkClipboardNotifier() + { + super("GtkClipBoardNotifier"); + setDaemon(true); + start(); + } + + /** + * Notifies that a new GtkSelection has to be announced. + * + * @param clipboard either the GtkClipboard.clipboard or the + * GtkClipboard.selection. + */ + static void announce(GtkClipboard clipboard) + { + synchronized (notifier) + { + if (clipboard == GtkClipboard.clipboard) + announceClipboardChange = true; + else + announcePrimaryChange = true; + notifier.notifyAll(); + } + } + + public void run() + { + GtkClipboard clipboard; + while (true) + { + synchronized (this) + { + while (! announceClipboardChange && ! announcePrimaryChange) + { + try + { + this.wait(); + } + catch (InterruptedException ie) + { + // ignore + } + } + + if (announceClipboardChange) + { + clipboard = GtkClipboard.clipboard; + announceClipboardChange = false; + } + else + { + clipboard = GtkClipboard.selection; + announcePrimaryChange = false; + } + } + + // Do the actual announcement without the lock held. We will + // notice a new change after this notification has finished. + try + { + clipboard.setContents(new GtkSelection(clipboard), null); + } + catch (Throwable t) + { + // should never happen, but might if we have some faulty listener. + t.printStackTrace(); + } + } + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkComponentPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkComponentPeer.java new file mode 100644 index 000000000..6e5069bc1 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkComponentPeer.java @@ -0,0 +1,920 @@ +/* GtkComponentPeer.java -- Implements ComponentPeer with GTK + Copyright (C) 1998, 1999, 2002, 2004, 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.java.awt.peer.gtk; + +import java.awt.AWTEvent; +import java.awt.AWTException; +import java.awt.BufferCapabilities; +import java.awt.Color; +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.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.Insets; +import java.awt.ItemSelectable; +import java.awt.KeyboardFocusManager; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.Window; +import java.awt.event.FocusEvent; +import java.awt.event.ItemEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.event.MouseWheelEvent; +import java.awt.event.PaintEvent; +import java.awt.event.TextEvent; +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; +import java.awt.peer.LightweightPeer; +import java.util.Timer; +import java.util.TimerTask; + +public class GtkComponentPeer extends GtkGenericPeer + implements ComponentPeer +{ + VolatileImage backBuffer; + BufferCapabilities caps; + + Component awtComponent; + + Insets insets; + + /** + * The current repaint area. Use should be guarded by synchronizing on this. + */ + private Rectangle currentPaintArea; + + /* 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 */ + native boolean isEnabled (); + static native boolean modalHasGrab(); + + native int[] gtkWidgetGetForeground (); + native int[] gtkWidgetGetBackground (); + native void gtkWidgetGetDimensions (int[] dim); + native void gtkWidgetGetPreferredDimensions (int[] dim); + native void gtkWindowGetLocationOnScreen (int[] point); + native void gtkWindowGetLocationOnScreenUnlocked (int[] point); + native void gtkWidgetGetLocationOnScreen (int[] point); + native void gtkWidgetGetLocationOnScreenUnlocked (int[] point); + native void gtkWidgetSetCursor (int type, GtkImage image, int x, int y); + native void gtkWidgetSetCursorUnlocked (int type, GtkImage image, + int x, int y); + native void gtkWidgetSetBackground (int red, int green, int blue); + native void gtkWidgetSetForeground (int red, int green, int blue); + native void gtkWidgetSetSensitive (boolean sensitive); + native void gtkWidgetSetParent (ComponentPeer parent); + native void gtkWidgetRequestFocus (); + native void gtkWidgetDispatchKeyEvent (int id, long when, int mods, + int keyCode, int keyLocation); + native boolean gtkWidgetHasFocus(); + native boolean gtkWidgetCanFocus(); + + native void realize(); + native void setNativeEventMask (); + + void create () + { + throw new RuntimeException (); + } + + native void connectSignals (); + + protected GtkComponentPeer (Component awtComponent) + { + super (awtComponent); + this.awtComponent = awtComponent; + insets = new Insets (0, 0, 0, 0); + + create (); + + connectSignals (); + + if (awtComponent.getForeground () != null) + setForeground (awtComponent.getForeground ()); + if (awtComponent.getBackground () != null) + setBackground (awtComponent.getBackground ()); + if (awtComponent.getFont() != null) + setFont(awtComponent.getFont()); + + Component parent = awtComponent.getParent (); + + setParentAndBounds (); + + setNativeEventMask (); + + // This peer is guaranteed to have an X window upon construction. + // That is, native methods such as those in GdkGraphics can rely + // on this component's widget->window field being non-null. + realize (); + + if (awtComponent.isCursorSet()) + setCursor (); + } + + void setParentAndBounds () + { + setParent (); + + setComponentBounds (); + + setVisibleAndEnabled (); + } + + void setParent () + { + ComponentPeer p; + Component component = awtComponent; + do + { + component = component.getParent (); + p = component.getPeer (); + } + while (p instanceof java.awt.peer.LightweightPeer); + + if (p != null) + gtkWidgetSetParent (p); + } + + /* + * Set the bounds of this peer's AWT Component based on dimensions + * returned by the native windowing system. Most Components impose + * their dimensions on the peers which is what the default + * implementation does. However some peers, like GtkFileDialogPeer, + * need to pass their size back to the AWT Component. + */ + void setComponentBounds () + { + Rectangle bounds = awtComponent.getBounds (); + setBounds (bounds.x, bounds.y, bounds.width, bounds.height); + } + + void setVisibleAndEnabled () + { + setVisible (awtComponent.isVisible ()); + setEnabled (awtComponent.isEnabled ()); + } + + public int checkImage (Image image, int width, int height, + ImageObserver observer) + { + return getToolkit().checkImage(image, width, height, observer); + } + + public Image createImage (ImageProducer producer) + { + return new GtkImage (producer); + } + + public Image createImage (int width, int height) + { + return CairoSurface.getBufferedImage(width, height); + } + + public void disable () + { + setEnabled (false); + } + + public void enable () + { + setEnabled (true); + } + + public ColorModel getColorModel () + { + return ColorModel.getRGBdefault (); + } + + public FontMetrics getFontMetrics (Font font) + { + return getToolkit().getFontMetrics(font); + } + + // getGraphics may be overridden by derived classes but it should + // never return null. + public Graphics getGraphics () + { + return ComponentGraphics.getComponentGraphics(this); + } + + public Point getLocationOnScreen () + { + int point[] = new int[2]; + if (Thread.currentThread() == GtkMainThread.mainThread) + gtkWidgetGetLocationOnScreenUnlocked (point); + else + gtkWidgetGetLocationOnScreen (point); + return new Point (point[0], point[1]); + } + + public Dimension getMinimumSize () + { + return minimumSize (); + } + + public Dimension getPreferredSize () + { + return preferredSize (); + } + + public Toolkit getToolkit () + { + return Toolkit.getDefaultToolkit(); + } + + public void handleEvent (AWTEvent event) + { + int id = event.getID(); + KeyEvent ke = null; + + switch (id) + { + case PaintEvent.PAINT: + paintComponent((PaintEvent) event); + break; + case PaintEvent.UPDATE: + updateComponent((PaintEvent) event); + break; + case KeyEvent.KEY_PRESSED: + ke = (KeyEvent) event; + gtkWidgetDispatchKeyEvent (ke.getID (), ke.getWhen (), ke.getModifiersEx (), + ke.getKeyCode (), ke.getKeyLocation ()); + break; + case KeyEvent.KEY_RELEASED: + ke = (KeyEvent) event; + gtkWidgetDispatchKeyEvent (ke.getID (), ke.getWhen (), ke.getModifiersEx (), + ke.getKeyCode (), ke.getKeyLocation ()); + break; + } + } + + // This method and its overrides are the only methods in the peers + // that should call awtComponent.paint. + protected void paintComponent (PaintEvent event) + { + // Do not call Component.paint if the component is not showing or + // if its bounds form a degenerate rectangle. + if (!awtComponent.isShowing() + || (awtComponent.getWidth() < 1 || awtComponent.getHeight() < 1)) + return; + + // Creating and disposing a GdkGraphics every time paint is called + // seems expensive. However, the graphics state does not carry + // over between calls to paint, and resetting the graphics object + // may even be more costly than simply creating a new one. + + // Make sure that the paintArea includes the area from the event + // in the case when an application sends PaintEvents directly. + coalescePaintEvent(event); + Rectangle paintArea; + synchronized (this) + { + paintArea = currentPaintArea; + currentPaintArea = null; + } + + if (paintArea != null) + { + Graphics g = getGraphics(); + try + { + g.setClip(paintArea); + awtComponent.paint(g); + } + finally + { + g.dispose(); + } + } + } + + // This method and its overrides are the only methods in the peers + // that should call awtComponent.update. + protected void updateComponent (PaintEvent event) + { + // Do not call Component.update if the component is not showing or + // if its bounds form a degenerate rectangle. + if (!awtComponent.isShowing() + || (awtComponent.getWidth() < 1 || awtComponent.getHeight() < 1)) + return; + + // Make sure that the paintArea includes the area from the event + // in the case when an application sends PaintEvents directly. + coalescePaintEvent(event); + Rectangle paintArea; + synchronized (this) + { + paintArea = currentPaintArea; + currentPaintArea = null; + } + + if (paintArea != null) + { + Graphics g = getGraphics(); + try + { + g.setClip(paintArea); + awtComponent.update(g); + } + finally + { + g.dispose(); + } + } + } + + public boolean isFocusTraversable () + { + return true; + } + + public Dimension minimumSize () + { + int dim[] = new int[2]; + + gtkWidgetGetPreferredDimensions (dim); + + return new Dimension (dim[0], dim[1]); + } + + public void paint (Graphics g) + { + } + + public Dimension preferredSize () + { + int dim[] = new int[2]; + + gtkWidgetGetPreferredDimensions (dim); + + return new Dimension (dim[0], dim[1]); + } + + public boolean prepareImage (Image image, int width, int height, + ImageObserver observer) + { + return getToolkit().prepareImage(image, width, height, observer); + } + + public void print (Graphics g) + { + g.drawImage( ComponentGraphics.grab( this ), 0, 0, null ); + } + + public void repaint (long tm, int x, int y, int width, int height) + { + if (width < 1 || height < 1) + return; + + 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); + } + + /** + * 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(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() + { + 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 () + { + assert false: "Call new requestFocus() method instead"; + } + + public void reshape (int x, int y, int width, int height) + { + setBounds (x, y, width, height); + } + + public void setBackground (Color c) + { + gtkWidgetSetBackground (c.getRed(), c.getGreen(), c.getBlue()); + } + + native void setNativeBounds (int x, int y, int width, int height); + + public void setBounds (int x, int y, int width, int height) + { + int new_x = x; + int new_y = y; + + Component parent = awtComponent.getParent (); + + // 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 + // knowledge of the lightweight containers' positions. So we have + // to add the offsets manually when placing a heavyweight + // component within a lightweight container. The lightweight + // container may itself be in a lightweight container and so on, + // so we need to continue adding offsets until we reach a + // container whose position GTK knows -- that is, the first + // non-lightweight. + Insets i; + while (parent.isLightweight()) + { + 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) + { + GtkWindowPeer peer = (GtkWindowPeer) parent.getPeer (); + // important: we want the window peer's insets here, not the + // window's, since user sub-classes of Window can override + // getInset and we only want to correct for the frame borders, + // not for any user-defined inset values + Insets insets = peer.getInsets (); + + int menuBarHeight = 0; + if (peer instanceof GtkFramePeer) + menuBarHeight = ((GtkFramePeer) peer).getMenuBarHeight (); + + new_x -= insets.left; + new_y -= insets.top; + new_y += menuBarHeight; + } + + setNativeBounds (new_x, new_y, width, height); + + // If the height or width were (or are now) smaller than zero + // then we want to adjust the visibility. + setVisible(awtComponent.isVisible()); + } + + void setCursor () + { + setCursor (awtComponent.getCursor ()); + } + + public void setCursor (Cursor cursor) + { + int x, y; + GtkImage image; + int type = cursor.getType(); + if (cursor instanceof GtkCursor) + { + GtkCursor gtkCursor = (GtkCursor) cursor; + image = gtkCursor.getGtkImage(); + Point hotspot = gtkCursor.getHotspot(); + x = hotspot.x; + y = hotspot.y; + } + else + { + image = null; + x = 0; + y = 0; + } + + if (Thread.currentThread() == GtkMainThread.mainThread) + gtkWidgetSetCursorUnlocked(cursor.getType(), image, x, y); + else + gtkWidgetSetCursor(cursor.getType(), image, x, y); + } + + public void setEnabled (boolean b) + { + gtkWidgetSetSensitive (b); + } + + public void setFont (Font f) + { + // FIXME: This should really affect the widget tree below me. + // Currently this is only handled if the call is made directly on + // a text widget, which implements setFont() itself. + gtkWidgetModifyFont(f.getName(), f.getStyle(), f.getSize()); + } + + public void setForeground (Color c) + { + gtkWidgetSetForeground (c.getRed(), c.getGreen(), c.getBlue()); + } + + public Color getForeground () + { + int rgb[] = gtkWidgetGetForeground (); + return new Color (rgb[0], rgb[1], rgb[2]); + } + + public Color getBackground () + { + int rgb[] = gtkWidgetGetBackground (); + return new Color (rgb[0], rgb[1], rgb[2]); + } + + public native void setVisibleNative (boolean b); + public native void setVisibleNativeUnlocked (boolean b); + + public void setVisible (boolean b) + { + // Only really set visible when component is bigger than zero pixels. + if (b && ! (awtComponent instanceof Window)) + { + Rectangle bounds = awtComponent.getBounds(); + b = (bounds.width > 0) && (bounds.height > 0); + } + + if (Thread.currentThread() == GtkMainThread.mainThread) + setVisibleNativeUnlocked (b); + else + setVisibleNative (b); + } + + public void hide () + { + setVisible (false); + } + + public void show () + { + setVisible (true); + } + + protected void postMouseEvent(int id, long when, int mods, int x, int y, + int clickCount, boolean popupTrigger) + { + // It is important to do the getLocationOnScreen() here, instead + // of using the old MouseEvent constructors, because + // Component.getLocationOnScreen() locks on the AWT lock, which can + // trigger a deadlock. You don't want this. + Point locOnScreen = getLocationOnScreen(); + q().postEvent(new MouseEvent(awtComponent, id, when, mods, x, y, + locOnScreen.x + x, locOnScreen.y + y, + clickCount, popupTrigger, + MouseEvent.NOBUTTON)); + } + + /** + * Callback for component_scroll_cb. + */ + protected void postMouseWheelEvent(int id, long when, int mods, + int x, int y, int clickCount, + boolean popupTrigger, + int type, int amount, int rotation) + { + q().postEvent(new MouseWheelEvent(awtComponent, id, when, mods, + x, y, clickCount, popupTrigger, + type, amount, rotation)); + } + + protected void postExposeEvent (int x, int y, int width, int height) + { + q().postEvent (new PaintEvent (awtComponent, PaintEvent.PAINT, + new Rectangle (x, y, width, height))); + } + + protected void postKeyEvent (int id, long when, int mods, + int keyCode, char keyChar, int keyLocation) + { + 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 + && (!keyEvent.isActionKey () + && keyCode != KeyEvent.VK_SHIFT + && keyCode != KeyEvent.VK_CONTROL + && keyCode != KeyEvent.VK_ALT)) + { + 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); + } + + /** + * Referenced from native code. + * + * @param id + * @param temporary + */ + protected void postFocusEvent (int id, boolean temporary) + { + q().postEvent (new FocusEvent (awtComponent, id, temporary)); + } + + protected void postItemEvent (Object item, int stateChange) + { + q().postEvent (new ItemEvent ((ItemSelectable)awtComponent, + ItemEvent.ITEM_STATE_CHANGED, + item, stateChange)); + } + + protected void postTextEvent () + { + q().postEvent (new TextEvent (awtComponent, TextEvent.TEXT_VALUE_CHANGED)); + } + + public GraphicsConfiguration getGraphicsConfiguration () + { + // FIXME: The component might be showing on a non-default screen. + GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice dev = env.getDefaultScreenDevice(); + return dev.getDefaultConfiguration(); + } + + public void setEventMask (long mask) + { + // FIXME: just a stub for now. + } + + public boolean isFocusable () + { + return false; + } + + public boolean requestFocus (Component request, boolean temporary, + boolean allowWindowFocus, long time) + { + assert request == awtComponent || isLightweightDescendant(request); + boolean retval = false; + if (gtkWidgetHasFocus()) + { + KeyboardFocusManager kfm = + KeyboardFocusManager.getCurrentKeyboardFocusManager(); + Component currentFocus = kfm.getFocusOwner(); + if (currentFocus == request) + // Nothing to do in this trivial case. + retval = true; + else + { + // Requested component is a lightweight descendant of this one + // or the actual heavyweight. + // Since this (native) component is already focused, we simply + // change the actual focus and be done. + postFocusEvent(FocusEvent.FOCUS_GAINED, temporary); + retval = true; + } + } + else + { + if (gtkWidgetCanFocus()) + { + if (allowWindowFocus) + { + Window window = getWindowFor(request); + GtkWindowPeer wPeer = (GtkWindowPeer) window.getPeer(); + if (! wPeer.gtkWindowHasFocus()) + wPeer.requestWindowFocus(); + } + // Store requested focus component so that the corresponding + // event is dispatched correctly. + gtkWidgetRequestFocus(); + retval = true; + } + } + return retval; + } + + private Window getWindowFor(Component c) + { + Component comp = c; + while (! (comp instanceof Window)) + comp = comp.getParent(); + return (Window) comp; + } + + /** + * Returns true if the component is a direct (== no intermediate + * heavyweights) lightweight descendant of this peer's component. + * + * @param c the component to check + * + * @return true if the component is a direct (== no intermediate + * heavyweights) lightweight descendant of this peer's component + */ + protected boolean isLightweightDescendant(Component c) + { + Component comp = c; + while (comp.getPeer() instanceof LightweightPeer) + comp = comp.getParent(); + return comp == awtComponent; + } + + public boolean isObscured () + { + return false; + } + + public boolean canDetermineObscurity () + { + return false; + } + + public void coalescePaintEvent (PaintEvent e) + { + synchronized (this) + { + Rectangle newRect = e.getUpdateRect(); + if (currentPaintArea == null) + currentPaintArea = newRect; + else + Rectangle.union(currentPaintArea, newRect, currentPaintArea); + } + } + + public void updateCursorImmediately () + { + if (awtComponent.getCursor() != null) + setCursor(awtComponent.getCursor()); + } + + public boolean handlesWheelScrolling () + { + return false; + } + + // Convenience method to create a new volatile image on the screen + // on which this component is displayed. + public VolatileImage createVolatileImage (int width, int height) + { + return new GtkVolatileImage (this, width, height, null); + } + + // Creates buffers used in a buffering strategy. + public void createBuffers (int numBuffers, BufferCapabilities caps) + throws AWTException + { + // numBuffers == 2 implies double-buffering, meaning one back + // buffer and one front buffer. + if (numBuffers == 2) + backBuffer = new GtkVolatileImage(this, awtComponent.getWidth(), + awtComponent.getHeight(), + caps.getBackBufferCapabilities()); + else + throw new AWTException("GtkComponentPeer.createBuffers:" + + " multi-buffering not supported"); + this.caps = caps; + } + + // Return the back buffer. + public Image getBackBuffer () + { + return backBuffer; + } + + // FIXME: flip should be implemented as a fast native operation + public void flip (BufferCapabilities.FlipContents contents) + { + getGraphics().drawImage(backBuffer, + awtComponent.getWidth(), + awtComponent.getHeight(), + null); + + // create new back buffer and clear it to the background color. + if (contents == BufferCapabilities.FlipContents.BACKGROUND) + { + backBuffer = createVolatileImage(awtComponent.getWidth(), + awtComponent.getHeight()); + backBuffer.getGraphics().clearRect(0, 0, + awtComponent.getWidth(), + awtComponent.getHeight()); + } + // FIXME: support BufferCapabilities.FlipContents.PRIOR + } + + // Release the resources allocated to back buffers. + public void destroyBuffers () + { + backBuffer.flush(); + } + + public String toString () + { + return "peer of " + awtComponent.toString(); + } + public Rectangle getBounds() + { + // FIXME: implement + return null; + } + public void reparent(ContainerPeer parent) + { + // FIXME: implement + + } + public void setBounds(int x, int y, int width, int height, int z) + { + // FIXME: implement + setBounds (x, y, width, height); + + } + public boolean isReparentSupported() + { + // FIXME: implement + + return false; + } + public void layout() + { + // FIXME: implement + + } + + public boolean requestFocus(Component lightweightChild, boolean temporary, + boolean focusedWindowChangeAllowed, + long time, sun.awt.CausedFocusEvent.Cause cause) + { + // TODO: Implement this properly and remove the other requestFocus() + // methods. + return true; + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkContainerPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkContainerPeer.java new file mode 100644 index 000000000..b7eacb9f6 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkContainerPeer.java @@ -0,0 +1,138 @@ +/* GtkContainerPeer.java -- Implements ContainerPeer with GTK + Copyright (C) 1998, 1999, 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.gtk; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Font; +import java.awt.Insets; +import java.awt.peer.ContainerPeer; + +public class GtkContainerPeer extends GtkComponentPeer + implements ContainerPeer +{ + Container c; + + public GtkContainerPeer(Container c) + { + super (c); + this.c = c; + } + + public void beginValidate () + { + } + + public void endValidate () + { + } + + public Insets getInsets() + { + return insets; + } + + public Insets insets() + { + return getInsets (); + } + + public void setBounds (int x, int y, int width, int height) + { + super.setBounds (x, y, width, height); + } + + public void setFont(Font f) + { + super.setFont(f); + Component[] components = ((Container) awtComponent).getComponents(); + for (int i = 0; i < components.length; i++) + { + if (components[i].isLightweight ()) + components[i].setFont (f); + else + { + GtkComponentPeer peer = (GtkComponentPeer) components[i].getPeer(); + if (peer != null && ! peer.awtComponent.isFontSet()) + peer.setFont(f); + } + } + } + + public void beginLayout () { } + public void endLayout () { } + public boolean isPaintPending () { return false; } + + public void setBackground (Color c) + { + super.setBackground(c); + + Object components[] = ((Container) awtComponent).getComponents(); + for (int i = 0; i < components.length; i++) + { + Component comp = (Component) components[i]; + + // If the child's background has not been explicitly set yet, + // it should inherit this container's background. This makes the + // child component appear as if it has a transparent background. + // Note that we do not alter the background property of the child, + // but only repaint the child with the parent's background color. + if (!comp.isBackgroundSet() && comp.getPeer() != null) + comp.getPeer().setBackground(c); + } + } + + public boolean isRestackSupported() + { + // FIXME: implement + return false; + } + + public void cancelPendingPaint(int x, int y, int width, int height) + { + // FIXME: implement + } + + public void restack() + { + //FIXME: implement + + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkCursor.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkCursor.java new file mode 100644 index 000000000..e382d6331 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkCursor.java @@ -0,0 +1,72 @@ +/* GtkCursor.java -- Simple wrapper for custom cursor. + 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.gtk; + +import java.awt.Cursor; +import java.awt.Image; +import java.awt.Point; + +/** + * Simple wrapper for custom Cursor. + */ +public class GtkCursor extends Cursor +{ + private final GtkImage image; + private final Point hotspot; + + GtkCursor(Image image, Point hotspot, String name) + { + super(name); + if (image instanceof GtkImage) + this.image = (GtkImage) image; + else + this.image = new GtkImage(image.getSource()); + this.hotspot = hotspot; + } + + GtkImage getGtkImage() + { + return image; + } + + Point getHotspot() + { + return hotspot; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkDialogPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkDialogPeer.java new file mode 100644 index 000000000..3393eb9d0 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkDialogPeer.java @@ -0,0 +1,63 @@ +/* GtkDialogPeer.java -- Implements DialogPeer with GTK + Copyright (C) 1998, 1999, 2002, 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.gtk; + +import java.awt.Dialog; +import java.awt.peer.DialogPeer; + +public class GtkDialogPeer extends GtkWindowPeer + implements DialogPeer +{ + public GtkDialogPeer (Dialog dialog) + { + super (dialog); + } + + void create () + { + Dialog dialog = (Dialog) awtComponent; + + // Create a decorated dialog window. + create (GDK_WINDOW_TYPE_HINT_DIALOG, !((Dialog) awtComponent).isUndecorated ()); + + gtkWindowSetModal (dialog.isModal ()); + setTitle (dialog.getTitle ()); + setResizable (dialog.isResizable ()); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkEmbeddedWindowPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkEmbeddedWindowPeer.java new file mode 100644 index 000000000..0533d2759 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkEmbeddedWindowPeer.java @@ -0,0 +1,73 @@ +/* GtkEmbeddedWindowPeer.java -- Implements EmbeddedWindowPeer using a + GtkPlug + Copyright (C) 2003 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.gtk; + +import gnu.java.awt.EmbeddedWindow; +import gnu.java.awt.peer.EmbeddedWindowPeer; + +public class GtkEmbeddedWindowPeer extends GtkFramePeer + implements EmbeddedWindowPeer +{ + native void create (long socket_id); + + void create () + { + create (((EmbeddedWindow) awtComponent).getHandle ()); + } + + native void construct (long socket_id); + + // FIXME: embed doesn't work right now, though I believe it should. + // This means that you can't call setVisible (true) on an + // EmbeddedWindow before calling setHandle with a valid handle. The + // problem is that somewhere after the call to + // GtkEmbeddedWindow.create and before the call to + // GtkEmbeddedWindow.construct, the GtkPlug peer is being realized. + // GtkSocket silently fails to embed an already-realized GtkPlug. + public void embed (long handle) + { + construct (handle); + } + + public GtkEmbeddedWindowPeer (EmbeddedWindow w) + { + super (w); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkFileDialogPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkFileDialogPeer.java new file mode 100644 index 000000000..cddc530fd --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkFileDialogPeer.java @@ -0,0 +1,229 @@ +/* GtkFileDialogPeer.java -- Implements FileDialogPeer with GTK + Copyright (C) 1998, 1999, 2002, 2004, 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.java.awt.peer.gtk; + +import java.awt.Dialog; +import java.awt.FileDialog; +import java.awt.event.PaintEvent; +import java.awt.peer.FileDialogPeer; +import java.io.File; +import java.io.FilenameFilter; + +public class GtkFileDialogPeer extends GtkDialogPeer implements FileDialogPeer +{ + static final String FS = System.getProperty("file.separator"); + + private String currentFile = null; + private String currentDirectory = null; + private FilenameFilter filter; + + native void create (GtkContainerPeer parent, int mode); + native void connectSignals (); + native void nativeSetFile (String file); + public native String nativeGetDirectory(); + public native void nativeSetDirectory(String directory); + native void nativeSetFilenameFilter (FilenameFilter filter); + + public void create() + { + create((GtkContainerPeer) awtComponent.getParent().getPeer(), + ((FileDialog) awtComponent).getMode()); + + FileDialog fd = (FileDialog) awtComponent; + + nativeSetDirectory(System.getProperty("user.dir")); + setDirectory(fd.getDirectory()); + setFile(fd.getFile()); + + FilenameFilter filter = fd.getFilenameFilter(); + if (filter != null) + setFilenameFilter(filter); + } + + public GtkFileDialogPeer (FileDialog fd) + { + super (fd); + } + + void setComponentBounds () + { + if (awtComponent.getHeight () == 0 + && awtComponent.getWidth () == 0) + { + int[] dims = new int[2]; + gtkWidgetGetPreferredDimensions (dims); + + if (dims[0] != awtComponent.getWidth() + || dims[1] != awtComponent.getHeight()) + awtComponent.setSize(dims[0], dims[1]); + } + super.setComponentBounds (); + } + + public void setFile (String fileName) + { + /* If nothing changed do nothing. This usually happens because + the only way we have to set the file name in FileDialog is by + calling its SetFile which will call us back. */ + if ((fileName == null && currentFile == null) + || (fileName != null && fileName.equals (currentFile))) + return; + + if (fileName == null || fileName.equals ("")) + { + currentFile = ""; + nativeSetFile (""); + return; + } + + // GtkFileChooser requires absolute filenames. If the given filename + // is not absolute, let's construct it based on current directory. + currentFile = fileName; + if (fileName.indexOf(FS) == 0) + nativeSetFile(fileName); + else + nativeSetFile(nativeGetDirectory() + FS + fileName); + } + + public void setDirectory (String directory) + { + /* If nothing changed so nothing. This usually happens because + the only way we have to set the directory in FileDialog is by + calling its setDirectory which will call us back. */ + if ((directory == null && currentDirectory == null) + || (directory != null && directory.equals(currentDirectory))) + return; + + if (directory == null || directory.equals("")) + { + currentDirectory = FS; + nativeSetDirectory(FS); + return; + } + + // GtkFileChooser requires absolute directory names. If the given directory + // name is not absolute, construct it based on current directory if it is not + // null. Otherwise, use FS. + currentDirectory = directory; + if (directory.indexOf(FS) == 0) + nativeSetDirectory(directory); + else + nativeSetDirectory(nativeGetDirectory() + FS + directory); + } + + public void setFilenameFilter (FilenameFilter filter) + { + this.filter = filter; + nativeSetFilenameFilter(filter); + } + + /* This method interacts with the native callback function of the + same name. The native function will extract the filename from the + GtkFileFilterInfo object and send it to this method, which will + in turn call the filter's accept() method and give back the return + value. */ + // called back by native side: filename_filter_cb + boolean filenameFilterCallback (String fullname) + { + String filename = fullname.substring(fullname.lastIndexOf(FS) + 1); + String dirname = fullname.substring(0, fullname.lastIndexOf(FS)); + File dir = new File(dirname); + return filter.accept(dir, filename); + } + + // Sun does not call FileDialog.update. + protected void updateComponent (PaintEvent event) + { + // Override GtkComponetPeer.updateComponent to do nothing. + } + + // called back by native side: handle_response_cb + // only called from the GTK thread + void gtkHideFileDialog () + { + // hide calls back the peer's setVisible method, so locking is a + // problem. + ((Dialog) awtComponent).hide(); + } + + // called back by native side: handle_response_cb + void gtkDisposeFileDialog () + { + ((Dialog) awtComponent).dispose(); + } + + // Callback to set the file and directory values when the user is finished + // with the dialog. + // called back by native side: handle_response_cb + void gtkSetFilename (String fileName) + { + FileDialog fd = (FileDialog) awtWidget; + if (fileName == null) + { + currentFile = null; + fd.setFile(null); + return; + } + + int sepIndex = fileName.lastIndexOf (FS); + if (sepIndex < 0) + { + /* This should never happen on Unix (all paths start with '/') */ + currentFile = fileName; + } + else + { + if (fileName.length() > (sepIndex + 1)) + { + String fn = fileName.substring (sepIndex + 1); + currentFile = fn; + } + else + { + currentFile = null; + } + + String dn = fileName.substring (0, sepIndex + 1); + currentDirectory = dn; + fd.setDirectory(dn); + } + + fd.setFile (currentFile); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkFramePeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkFramePeer.java new file mode 100644 index 000000000..a36854ce0 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkFramePeer.java @@ -0,0 +1,254 @@ +/* GtkFramePeer.java -- Implements FramePeer with GTK + Copyright (C) 1999, 2002, 2004, 2006, 2007 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.gtk; + +import java.awt.Frame; +import java.awt.Image; +import java.awt.MenuBar; +import java.awt.Rectangle; +import java.awt.peer.FramePeer; +import java.awt.peer.MenuBarPeer; + +public class GtkFramePeer extends GtkWindowPeer + implements FramePeer +{ + private int menuBarHeight; + private MenuBarPeer menuBar; + native int getMenuBarHeight (MenuBarPeer bar); + native void setMenuBarWidthUnlocked (MenuBarPeer bar, int width); + native void setMenuBarWidth (MenuBarPeer bar, int width); + native void setMenuBarPeer (MenuBarPeer bar); + native void removeMenuBarPeer (); + native void gtkFixedSetVisible (boolean visible); + + private native void maximize(); + private native void unmaximize(); + private native void iconify(); + private native void deiconify(); + + int getMenuBarHeight () + { + return menuBar == null ? 0 : getMenuBarHeight (menuBar); + } + + public void setMenuBar (MenuBar bar) + { + if (bar == null && menuBar != null) + { + // We're removing the menubar. + gtkFixedSetVisible (false); + menuBar = null; + removeMenuBarPeer (); + insets.top -= menuBarHeight; + menuBarHeight = 0; + // 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) + { + // We're adding a menubar where there was no menubar before. + gtkFixedSetVisible (false); + menuBar = (MenuBarPeer) bar.getPeer(); + setMenuBarPeer (menuBar); + int menuBarWidth = + awtComponent.getWidth () - insets.left - insets.right; + if (menuBarWidth > 0) + setMenuBarWidth (menuBar, menuBarWidth); + menuBarHeight = getMenuBarHeight (); + insets.top += menuBarHeight; + // 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) + { + // We're swapping the menubar. + gtkFixedSetVisible (false); + removeMenuBarPeer(); + int oldHeight = menuBarHeight; + int menuBarWidth = + awtComponent.getWidth () - insets.left - insets.right; + menuBar = (MenuBarPeer) bar.getPeer (); + setMenuBarPeer (menuBar); + if (menuBarWidth > 0) + setMenuBarWidth (menuBar, menuBarWidth); + menuBarHeight = getMenuBarHeight (); + if (oldHeight != menuBarHeight) + { + insets.top += (menuBarHeight - oldHeight); + awtComponent.validate (); + } + gtkFixedSetVisible (true); + } + } + + public void setBounds (int x, int y, int width, int height) + { + int menuBarWidth = width - insets.left - insets.right; + if (menuBar != null && menuBarWidth > 0) + setMenuBarWidth (menuBar, menuBarWidth); + + super.setBounds(x, y, width, height + menuBarHeight); + } + + public void setResizable (boolean resizable) + { + // Call setSize; otherwise when resizable is changed from true to + // false the frame will shrink to the dimensions it had before it + // was resizable. + setSize (awtComponent.getWidth() - insets.left - insets.right, + awtComponent.getHeight() - insets.top - insets.bottom + + menuBarHeight); + gtkWindowSetResizable (resizable); + } + + protected void postInsetsChangedEvent (int top, int left, + int bottom, int right) + { + insets.top = top + menuBarHeight; + insets.left = left; + insets.bottom = bottom; + insets.right = right; + } + + public GtkFramePeer (Frame frame) + { + super (frame); + } + + void create () + { + // Create a normal decorated window. + create (GDK_WINDOW_TYPE_HINT_NORMAL, + !((Frame) awtComponent).isUndecorated ()); + + Frame frame = (Frame) awtComponent; + + setMenuBar (frame.getMenuBar ()); + + setTitle (frame.getTitle ()); + gtkWindowSetResizable (frame.isResizable ()); + setIconImage(frame.getIconImage()); + } + + native void nativeSetIconImage (GtkImage image); + + public void setIconImage (Image image) + { + if (image != null) + { + GtkImage gtkImage; + if (image instanceof GtkImage) + gtkImage = (GtkImage) image; + else + gtkImage = new GtkImage(image.getSource()); + + if (gtkImage.isLoaded && ! gtkImage.errorLoading) + nativeSetIconImage(gtkImage); + } + } + + protected void postConfigureEvent (int x, int y, int width, int height) + { + if (menuBar != null && width > 0) + setMenuBarWidthUnlocked (menuBar, width); + + // Since insets.top already includes the MenuBar's height, we need + // to subtract the MenuBar's height from the top inset. + int frame_height = height - menuBarHeight; + + // Likewise, since insets.top includes the MenuBar height, we need + // to add back the MenuBar height to the frame's y position. If + // no MenuBar exists in this frame, the MenuBar height will be 0. + int frame_y = y + menuBarHeight; + + super.postConfigureEvent(x, frame_y, width, frame_height); + } + + public int getState () + { + return windowState; + } + + public void setState (int state) + { + switch (state) + { + case Frame.NORMAL: + if ((windowState & Frame.ICONIFIED) != 0) + deiconify(); + if ((windowState & Frame.MAXIMIZED_BOTH) != 0) + unmaximize(); + break; + case Frame.ICONIFIED: + iconify(); + break; + case Frame.MAXIMIZED_BOTH: + maximize(); + } + } + + public void setMaximizedBounds (Rectangle r) + { + + } + public void setBoundsPrivate(int x, int y, int width, int height) + { + // TODO Auto-generated method stub + + } + + public boolean requestWindowFocus() + { + // TODO Auto-generated method stub + return false; + } + + public Rectangle getBoundsPrivate() + { + // TODO: Implement this properly. + throw new InternalError("Not yet implemented"); + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkGenericPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkGenericPeer.java new file mode 100644 index 000000000..1b2c07b5d --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkGenericPeer.java @@ -0,0 +1,145 @@ +/* GtkGenericPeer.java - Has a hashcode. Yuck. + Copyright (C) 1998, 1999, 2002, 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.gtk; + +import java.awt.EventQueue; +import java.awt.Font; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; + +import gnu.classpath.Pointer; + +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 final Object awtWidget; + + /** + * The pointer to the native GTK widget. + * + * This field is manipulated by native code. Don't change or remove + * without adjusting the native code. + */ + private Pointer widget; + + /** + * The pointer to the global reference to this object. The native + * code creates a JNI global reference of the peer object to be able + * to pass it to the event callbacks. It gets stored here, so that + * we can later delete it in the dispose() method. + * + * This field is manipulated by native code. Don't change or remove + * without adjusting the native code. + */ + private Pointer globalRef; + + /** + * We initialize the field IDs that are used by native code here because + * these remain valid until a class gets unloaded. + */ + static + { + GtkToolkit.initializeGlobalIDs(); + initIDs(); + } + + /** + * Initializes the field IDs that are used by the native code. + */ + private static native void initIDs(); + + /** + * 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 () + { + return Toolkit.getDefaultToolkit ().getSystemEventQueue (); + } + + protected GtkGenericPeer (Object awtWidget) + { + this.awtWidget = awtWidget; + } + + protected void postActionEvent (String command, int mods) + { + q().postEvent (new ActionEvent (awtWidget, ActionEvent.ACTION_PERFORMED, + command, mods)); + } + + // Return a unique integer for use in the native state mapping + // code. We can't use a hash code since that is not guaranteed to + // be unique. + static synchronized int getUniqueInteger () + { + // 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()); + } + + /** + * 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 () + { + System.out.println ("gtkgenericpeer, thread: " + Thread.currentThread ()); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkImage.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkImage.java new file mode 100644 index 000000000..b0a5aa0b1 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkImage.java @@ -0,0 +1,541 @@ +/* GtkImage.java + 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.java.awt.peer.gtk; + +import java.awt.Graphics; +import java.awt.Image; +import java.awt.image.ColorModel; +import java.awt.image.DirectColorModel; +import java.awt.image.MemoryImageSource; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.io.File; +import java.io.IOException; +import java.util.Hashtable; +import java.util.Vector; +import java.io.ByteArrayOutputStream; +import java.io.BufferedInputStream; +import java.net.URL; +import gnu.classpath.Pointer; + +/** + * GtkImage - wraps a GdkPixbuf. + * + * A GdkPixbuf is 'on-screen' and the gdk cannot draw to it, + * this is used for the other constructors (and other createImage methods), and + * corresponds to the Image implementations returned by the Toolkit.createImage + * methods, and is basically immutable. + * + * @author Sven de Marothy + */ +public class GtkImage extends Image +{ + int width = -1, height = -1; + + /** + * Properties. + */ + Hashtable props; + + /** + * Loaded or not flag, for asynchronous compatibility. + */ + boolean isLoaded; + + /** + * Pointer to the GdkPixbuf - + * don't change the name without changing the native code. + */ + Pointer pixbuf; + + /** + * Observer queue. + */ + Vector observers; + + /** + * Error flag for loading. + */ + boolean errorLoading; + + /** + * Original source, if created from an ImageProducer. + */ + ImageProducer source; + + /* + * The 32-bit AABBGGRR format the GDK uses. + */ + static ColorModel nativeModel = new DirectColorModel(32, + 0x000000FF, + 0x0000FF00, + 0x00FF0000, + 0xFF000000); + + /** + * The singleton GtkImage that is returned on errors by GtkToolkit. + */ + private static GtkImage errorImage; + + /** + * Lock that should be held for all gdkpixbuf operations. We don't use + * the global gdk_threads_enter/leave functions in most places since + * most gdkpixbuf operations can be done in parallel to drawing and + * manipulating gtk widgets. + */ + static Object pixbufLock = new Object(); + + /** + * Allocate a PixBuf from a given ARGB32 buffer pointer. + */ + private native void initFromBuffer( long bufferPointer ); + + /** + * Returns a copy of the pixel data as a java array. + * Should be called with the pixbufLock held. + */ + native int[] getPixels(); + + /** + * Sets the pixel data from a java array. + * Should be called with the pixbufLock held. + */ + private native void setPixels(int[] pixels); + + /** + * Loads an image using gdk-pixbuf from a file. + * Should be called with the pixbufLock held. + */ + private native boolean loadPixbuf(String name); + + /** + * Loads an image using gdk-pixbuf from data. + * Should be called with the pixbufLock held. + */ + private native boolean loadImageFromData(byte[] data); + + /** + * Allocates a Gtk Pixbuf + * Should be called with the pixbufLock held. + */ + private native void createPixbuf(); + + /** + * Frees the above. + * Should be called with the pixbufLock held. + */ + private native void freePixbuf(); + + /** + * Sets the pixbuf to scaled copy of src image. hints are rendering hints. + * Should be called with the pixbufLock held. + */ + private native void createScaledPixbuf(GtkImage src, int hints); + + /** + * Constructs a GtkImage from an ImageProducer. Asynchronity is handled in + * the following manner: + * A GtkImageConsumer gets the image data, and calls setImage() when + * completely finished. The GtkImage is not considered loaded until the + * GtkImageConsumer is completely finished. We go for all "all or nothing". + */ + public GtkImage (ImageProducer producer) + { + isLoaded = false; + observers = new Vector(); + source = producer; + errorLoading = false; + source.startProduction(new GtkImageConsumer(this, source)); + } + + /** + * Constructs a blank GtkImage. This is called when + * GtkToolkit.createImage (String) is called with an empty string + * argument (""). A blank image is loaded immediately upon + * construction and has width -1 and height -1. + */ + public GtkImage () + { + isLoaded = true; + observers = null; + props = new Hashtable(); + errorLoading = false; + } + + /** + * Constructs a GtkImage by loading a given file. + * + * @throws IllegalArgumentException if the image could not be loaded. + */ + public GtkImage (String filename) + { + File f = new File(filename); + try + { + String path = f.getCanonicalPath(); + synchronized(pixbufLock) + { + if (loadPixbuf(f.getCanonicalPath()) != true) + throw new IllegalArgumentException("Couldn't load image: " + + filename); + } + } + catch(IOException e) + { + IllegalArgumentException iae; + iae = new IllegalArgumentException("Couldn't load image: " + + filename); + iae.initCause(e); + throw iae; + } + + isLoaded = true; + observers = null; + props = new Hashtable(); + } + + /** + * Constructs a GtkImage from a byte array of an image file. + * + * @throws IllegalArgumentException if the image could not be + * loaded. + */ + public GtkImage (byte[] data) + { + synchronized(pixbufLock) + { + if (loadImageFromData (data) != true) + throw new IllegalArgumentException ("Couldn't load image."); + } + + isLoaded = true; + observers = null; + props = new Hashtable(); + errorLoading = false; + } + + /** + * Constructs a GtkImage from a URL. May result in an error image. + */ + public GtkImage (URL url) + { + isLoaded = false; + observers = new Vector(); + errorLoading = false; + if( url == null) + return; + ByteArrayOutputStream baos = new ByteArrayOutputStream (5000); + try + { + BufferedInputStream bis = new BufferedInputStream (url.openStream()); + + byte[] buf = new byte[5000]; + int n = 0; + + while ((n = bis.read(buf)) != -1) + baos.write(buf, 0, n); + bis.close(); + } + catch(IOException e) + { + throw new IllegalArgumentException ("Couldn't load image."); + } + byte[] array = baos.toByteArray(); + synchronized(pixbufLock) + { + if (loadImageFromData(array) != true) + throw new IllegalArgumentException ("Couldn't load image."); + } + + isLoaded = true; + observers = null; + props = new Hashtable(); + } + + /** + * Constructs a scaled version of the src bitmap, using the GDK. + */ + private GtkImage (GtkImage src, int width, int height, int hints) + { + this.width = width; + this.height = height; + props = new Hashtable(); + isLoaded = true; + observers = null; + + // Use the GDK scaling method. + synchronized(pixbufLock) + { + createScaledPixbuf(src, hints); + } + } + + /** + * Package private constructor to create a GtkImage from a given + * PixBuf pointer. + */ + GtkImage (Pointer pixbuf) + { + this.pixbuf = pixbuf; + synchronized(pixbufLock) + { + createFromPixbuf(); + } + isLoaded = true; + observers = null; + props = new Hashtable(); + } + + /** + * Wraps a buffer with a GtkImage. + * + * @param bufferPointer a pointer to an ARGB32 buffer + */ + GtkImage(int width, int height, long bufferPointer) + { + this.width = width; + this.height = height; + props = new Hashtable(); + isLoaded = true; + observers = null; + initFromBuffer( bufferPointer ); + } + + /** + * 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. + * Should be called with the pixbufLock held. + */ + private native void createFromPixbuf(); + + /** + * Callback from the image consumer. + */ + public void setImage(int width, int height, + int[] pixels, Hashtable properties) + { + this.width = width; + this.height = height; + props = (properties != null) ? properties : new Hashtable(); + + if (width <= 0 || height <= 0 || pixels == null) + { + errorLoading = true; + return; + } + + synchronized(pixbufLock) + { + createPixbuf(); + setPixels(pixels); + } + isLoaded = true; + deliver(); + } + + // java.awt.Image methods //////////////////////////////////////////////// + + public synchronized int getWidth (ImageObserver observer) + { + if (addObserver(observer)) + return -1; + + return width; + } + + public synchronized int getHeight (ImageObserver observer) + { + if (addObserver(observer)) + return -1; + + return height; + } + + public synchronized Object getProperty (String name, ImageObserver observer) + { + if (addObserver(observer)) + return UndefinedProperty; + + Object value = props.get (name); + return (value == null) ? UndefinedProperty : value; + } + + /** + * Returns the source of this image. + */ + public ImageProducer getSource () + { + if (!isLoaded) + return null; + + int[] pixels; + synchronized (pixbufLock) + { + if (!errorLoading) + pixels = getPixels(); + else + return null; + } + return new MemoryImageSource(width, height, nativeModel, pixels, + 0, width); + } + + /** + * Does nothing. Should not be called. + */ + public Graphics getGraphics () + { + throw new IllegalAccessError("This method only works for off-screen" + +" Images."); + } + + /** + * Returns a scaled instance of this pixbuf. + */ + public Image getScaledInstance(int width, + int height, + int hints) + { + if (width <= 0 || height <= 0) + throw new IllegalArgumentException("Width and height of scaled bitmap" + + "must be >= 0"); + + return new GtkImage(this, width, height, hints); + } + + /** + * If the image is loaded and comes from an ImageProducer, + * regenerate the image from there. + * + * I have no idea if this is ever actually used. Since GtkImage can't be + * instantiated directly, how is the user to know if it was created from + * an ImageProducer or not? + */ + public synchronized void flush () + { + if (isLoaded && source != null) + { + observers = new Vector(); + isLoaded = false; + synchronized(pixbufLock) + { + freePixbuf(); + } + source.startProduction(new GtkImageConsumer(this, source)); + } + } + + public void finalize() + { + if (isLoaded) + { + synchronized(pixbufLock) + { + freePixbuf(); + } + } + } + + /** + * Returns the image status, used by GtkToolkit + */ + public int checkImage (ImageObserver observer) + { + if (addObserver(observer)) + { + if (errorLoading == true) + return ImageObserver.ERROR; + else + return 0; + } + + return ImageObserver.ALLBITS | ImageObserver.WIDTH | ImageObserver.HEIGHT; + } + + + // Private methods //////////////////////////////////////////////// + + /** + * Delivers notifications to all queued observers. + */ + private void deliver() + { + int flags = ImageObserver.HEIGHT | + ImageObserver.WIDTH | + ImageObserver.PROPERTIES | + ImageObserver.ALLBITS; + + if (observers != null) + for(int i=0; i < observers.size(); i++) + ((ImageObserver)observers.elementAt(i)).imageUpdate(this, flags, 0, 0, + width, height); + + observers = null; + } + + /** + * Adds an observer, if we need to. + * @return true if an observer was added. + */ + private boolean addObserver(ImageObserver observer) + { + if (!isLoaded) + { + if(observer != null) + if (!observers.contains (observer)) + observers.addElement (observer); + return true; + } + return false; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkImageConsumer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkImageConsumer.java new file mode 100644 index 000000000..65cae7a89 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkImageConsumer.java @@ -0,0 +1,169 @@ +/* GtkImageConsumer.java + 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.java.awt.peer.gtk; + +import java.awt.image.ColorModel; +import java.awt.image.ImageConsumer; +import java.awt.image.ImageProducer; +import java.awt.image.MemoryImageSource; +import java.nio.ByteOrder; +import java.util.Hashtable; + +/** + * Helper class to GtkImage. Sits and gathers pixels for a GtkImage and then + * calls GtkImage.setImage(). + * + * @author Sven de Marothy + */ +public class GtkImageConsumer implements ImageConsumer +{ + private GtkImage target; + private int width, height; + private Hashtable properties; + private int[] pixelCache = null; + private ImageProducer source; + + public GtkImageConsumer(GtkImage target, ImageProducer source) + { + this.target = target; + this.source = source; + } + + public synchronized void imageComplete (int status) + { + // we need to reuse the pixel cache for memory image sources since + // a memory image's backing array can be updated "live". + if (!(source instanceof MemoryImageSource)) + source.removeConsumer(this); + target.setImage(width, height, pixelCache, properties); + } + + public synchronized void setColorModel (ColorModel model) + { + // This method is to inform on what the most used color model + // in the image is, for optimization reasons. We ignore this + // information. + } + + public synchronized void setDimensions (int width, int height) + { + pixelCache = new int[width*height]; + + this.width = width; + this.height = height; + } + + public synchronized void setHints (int flags) + { + // This method informs us in which order the pixels are + // delivered, for progressive-loading support, etc. + // Since we wait until it's all loaded, we can ignore the hints. + } + + public synchronized void setPixels (int x, int y, int width, int height, + ColorModel cm, byte[] pixels, + int offset, int scansize) + { + setPixels (x, y, width, height, cm, convertPixels (pixels), offset, + scansize); + } + + public synchronized void setPixels (int x, int y, int width, int height, + ColorModel cm, int[] pixels, + int offset, int scansize) + { + if (pixelCache == null) + return; // Not sure this should ever happen. + + if (cm.equals(GtkImage.nativeModel)) + for (int i = 0; i < height; i++) + System.arraycopy (pixels, offset + (i * scansize), + pixelCache, (y + i) * this.width + x, + width); + else + { + if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) + { + for (int i = 0; i < height; i++) + for (int j = 0; j < width; j++) + { + // get in RRGGBBAA and convert to AARRGGBB + int pix = cm.getRGB(pixels[offset + (i * scansize) + x + j]); + int a = ((pix & 0xFF000000) >> 24) & 0xFF; + int rgb = (pix & 0x00FFFFFF) << 8; + pix = rgb | a; + pixelCache[(y + i) * this.width + x + j] = pix; + } + } + else + { + for (int i = 0; i < height; i++) + for (int j = 0; j < width; j++) + { + // get in AARRGGBB and convert to AABBGGRR + int pix = cm.getRGB(pixels[offset + (i * scansize) + x + j]); + byte b = (byte)(pix & 0xFF); + byte r = (byte)(((pix & 0x00FF0000) >> 16) & 0xFF); + pix &= 0xFF00FF00; + pix |= ((b & 0xFF) << 16); + pix |= (r & 0xFF); + pixelCache[(y + i) * this.width + x + j] = pix; + } + } + } + } + + /** + * This is an old method, no idea if it's correct. + */ + private int[] convertPixels (byte[] pixels) + { + int ret[] = new int[pixels.length]; + + for (int i = 0; i < pixels.length; i++) + ret[i] = pixels[i] & 0xFF; + + return ret; + } + + public synchronized void setProperties (Hashtable props) + { + this.properties = props; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkLabelPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkLabelPeer.java new file mode 100644 index 000000000..0bdacbf33 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkLabelPeer.java @@ -0,0 +1,102 @@ +/* GtkLabelPeer.java -- Implements LabelPeer with GTK + Copyright (C) 1998, 1999, 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.java.awt.peer.gtk; + +import java.awt.Label; +import java.awt.peer.LabelPeer; + +// A composite widget. GtkLabels have transparent backgrounds. An +// AWT Label is opaque. To compensate, a GtkLabelPeer is a GtkLabel +// packed in a GtkEventBox. +public class GtkLabelPeer extends GtkComponentPeer + implements LabelPeer +{ + native void create (String text, float alignment); + + /** + * 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 setNativeText(String text); + native void setNativeBounds (int x, int y, int width, int height); + + // Because this is a composite widget, we need to retrieve the + // GtkLabel's preferred dimensions, not the enclosing GtkEventBox's. + native void gtkWidgetGetPreferredDimensions (int[] dim); + + void create () + { + Label label = (Label) awtComponent; + create (label.getText (), getGtkAlignment (label.getAlignment ())); + } + + public void setText(String text) + { + if (text != null) + setNativeText(text); + } + + public GtkLabelPeer (Label l) + { + super (l); + } + + public void setAlignment (int alignment) + { + nativeSetAlignment (getGtkAlignment (alignment)); + } + + float getGtkAlignment (int alignment) + { + switch (alignment) + { + case Label.LEFT: + return 0.0f; + case Label.CENTER: + return 0.5f; + case Label.RIGHT: + return 1.0f; + } + + return 0.0f; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkListPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkListPeer.java new file mode 100644 index 000000000..b1cc6e522 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkListPeer.java @@ -0,0 +1,187 @@ +/* GtkListPeer.java -- Implements ListPeer with GTK + Copyright (C) 1998, 1999, 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.gtk; + +import java.awt.AWTEvent; +import java.awt.Dimension; +import java.awt.FontMetrics; +import java.awt.List; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.peer.ListPeer; + +public class GtkListPeer extends GtkComponentPeer + implements ListPeer +{ + void create () + { + List list = (List) awtComponent; + + create (list.getRows ()); + + setMultipleMode (list.isMultipleMode ()); + } + + native void create (int rows); + native void connectSignals (); + + /** + * 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[]); + + public GtkListPeer (List list) + { + super (list); + + setMultipleMode (list.isMultipleMode ()); + + if (list.getItemCount () > 0) + append (list.getItems ()); + } + + native void append (String items[]); + + public native void add (String item, int index); + + public void addItem (String item, int index) + { + add (item, index); + } + + public void clear () + { + removeAll (); + } + + public native void delItems (int start, int end); + public native void deselect (int index); + + public Dimension getMinimumSize (int rows) + { + return minimumSize (rows); + } + + public Dimension getPreferredSize (int rows) + { + return preferredSize (rows); + } + + public native int[] getSelectedIndexes (); + public native void makeVisible (int index); + + public Dimension minimumSize (int rows) + { + int dims[] = new int[2]; + + int visibleRows = ((List) awtComponent).getRows(); + getSize (rows, visibleRows, dims); + return new Dimension (dims[0], dims[1]); + } + + public Dimension preferredSize (int rows) + { + // getSize returns the minimum size of the list. + // The width is too narrow for a typical list. + List l = (List) awtComponent; + Dimension d = getMinimumSize(); + FontMetrics fm = l.getFontMetrics(l.getFont()); + return new Dimension(d.width + fm.stringWidth("1234567890"), d.height); + } + + public void removeAll () + { + delItems (0, -1); + } + + public native void select (int index); + public native void setMultipleMode (boolean b); + + public void setMultipleSelections (boolean b) + { + setMultipleMode (b); + } + + public void handleEvent (AWTEvent e) + { + if (e.getID () == MouseEvent.MOUSE_CLICKED && isEnabled ()) + { + // Only generate the ActionEvent on the second click of a + // multiple click. + MouseEvent me = (MouseEvent) e; + if (!me.isConsumed () + && (me.getModifiersEx () & MouseEvent.BUTTON1_DOWN_MASK) != 0 + && me.getClickCount() == 2) + { + String selectedItem = ((List) awtComponent).getSelectedItem (); + + // Double-click only generates an Action event if + // something is selected. + if (selectedItem != null) + postActionEvent (((List) awtComponent).getSelectedItem (), + me.getModifiersEx ()); + } + } + + if (e.getID () == KeyEvent.KEY_PRESSED) + { + KeyEvent ke = (KeyEvent) e; + if (!ke.isConsumed () && ke.getKeyCode () == KeyEvent.VK_ENTER) + { + String selectedItem = ((List) awtComponent).getSelectedItem (); + + // Enter only generates an Action event if something is + // selected. + if (selectedItem != null) + postActionEvent (selectedItem, ke.getModifiersEx ()); + } + } + + super.handleEvent (e); + } + + protected void postItemEvent (int item, int stateChange) + { + postItemEvent (new Integer (item), stateChange); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkMainThread.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMainThread.java new file mode 100644 index 000000000..0ee61df84 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMainThread.java @@ -0,0 +1,188 @@ +/* GtkMainThread.java -- Wrapper for the GTK main thread, and some utilities. + 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.gtk; + +import gnu.java.awt.peer.NativeEventLoopRunningEvent; + +/** + * The Java thread representing the native GTK main loop, that is, + * GtkMainThread.mainThread, terminates when GtkToolkit.gtkMain() + * returns. That happens in response to the last window peer being + * disposed (see GtkWindowPeer.dispose). + * + * When GtkMainThread.destroyWindow is called for the last window, it + * in turn calls GtkMainThread.endMainThread, which calls gtk_quit. + * gtk_quit signals gtk_main to return, which causes GtkMainThread.run + * to return. + * + * There should only be one native GTK main loop running at any given + * time. In order to safely start and stop the GTK main loop, we use + * a running flag and corresponding runningLock. startMainThread will + * not return until the native GTK main loop has started, as confirmed + * by the native set_running_flag callback setting the running flag to + * true. Without this protection, gtk_quit could be called before the + * main loop has actually started, which causes GTK assertion + * failures. Likewise endMainThread will not return until the native + * GTK main loop has ended. + * + * post_running_flag_callback is called during gtk_main initialization + * and no window can be created before startMainThread returns. This + * ensures that calling post_running_flag_callback is the first action + * taken by the native GTK main loop. + * + * GtkMainThread.mainThread is started when the window count goes from + * zero to one. + * + * GtkMainThread keeps the AWT event queue informed of its status by + * posting NativeEventLoopRunningEvents. The AWT event queue uses + * this status to determine whether or not the AWT exit conditions + * have been met (see EventQueue.isShutdown). + */ +public class GtkMainThread extends Thread +{ + /** Count of the number of open windows */ + private static int numberOfWindows = 0; + + /** Lock for the above */ + private static Object nWindowsLock = new Object(); + + /** Indicates whether or not the GTK main loop is running. */ + private static boolean running = false; + + /** Lock for the above. */ + private static Object runningLock = new Object(); + + /** The main thread instance (singleton) */ + public static GtkMainThread mainThread; + + /** Constructs a main thread */ + private GtkMainThread() + { + super("GTK main thread"); + } + + public void run () + { + GtkToolkit.gtkMain (); + } + + private static void setRunning(boolean running) + { + synchronized (runningLock) + { + GtkMainThread.running = running; + runningLock.notifyAll(); + } + } + + private static void startMainThread() + { + synchronized (runningLock) + { + if (!running) + { + mainThread = new GtkMainThread(); + mainThread.start(); + + while (!running) + { + try + { + runningLock.wait(); + } + catch (InterruptedException e) + { + System.err.println ("GtkMainThread.startMainThread:" + + " interrupted while waiting " + + " for GTK main loop to start"); + } + } + GtkGenericPeer.q() + .postEvent(new NativeEventLoopRunningEvent(Boolean.TRUE)); + } + } + } + + private static void endMainThread() + { + synchronized (runningLock) + { + if (running) + { + GtkToolkit.gtkQuit(); + + while (running) + { + try + { + runningLock.wait(); + } + catch (InterruptedException e) + { + System.err.println ("GtkMainThread.endMainThread:" + + " interrupted while waiting " + + " for GTK main loop to stop"); + } + } + GtkGenericPeer.q() + .postEvent(new NativeEventLoopRunningEvent(Boolean.FALSE)); + } + } + } + + public static void createWindow() + { + synchronized (nWindowsLock) + { + if (numberOfWindows == 0) + startMainThread(); + numberOfWindows++; + } + } + + public static void destroyWindow() + { + synchronized (nWindowsLock) + { + numberOfWindows--; + if (numberOfWindows == 0) + endMainThread(); + } + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuBarPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuBarPeer.java new file mode 100644 index 000000000..c3427b18f --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuBarPeer.java @@ -0,0 +1,113 @@ +/* GtkMenuBarPeer.java -- Implements MenuBarPeer with GTK+ + Copyright (C) 1999, 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.java.awt.peer.gtk; + +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.peer.MenuBarPeer; + +public class GtkMenuBarPeer extends GtkMenuComponentPeer + implements MenuBarPeer +{ + /** 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(menubar); + } + + /** + * 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) + { + 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); + + /** + * 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) + { + // 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/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuComponentPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuComponentPeer.java new file mode 100644 index 000000000..78f640361 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuComponentPeer.java @@ -0,0 +1,104 @@ +/* GtkMenuComponentPeer.java -- Implements MenuComponentPeer with GTK+ + Copyright (C) 1999, 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.gtk; + +import java.awt.Font; +import java.awt.MenuComponent; +import java.awt.MenuContainer; +import java.awt.peer.MenuComponentPeer; + +public abstract class GtkMenuComponentPeer extends GtkGenericPeer + implements MenuComponentPeer +{ + /** + * Creates the associated gtk+ widget and stores it in the nsa table + * for this peer. Called by the constructor. + */ + protected abstract void create (); + + /** + * 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); + } + + /** + * Will call the abstract create() 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(component); + create(); + setFont(); + } + + /** + * Removes the awtWidget components from the native state tables. + * Subclasses should call super.dispose() 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) + { + if (font != null) + gtkWidgetModifyFont(font); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuItemPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuItemPeer.java new file mode 100644 index 000000000..ea523e953 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuItemPeer.java @@ -0,0 +1,116 @@ +/* GtkMenuItemPeer.java -- Implements MenuItemPeer with GTK+ + Copyright (C) 1999, 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.java.awt.peer.gtk; + +import java.awt.MenuItem; +import java.awt.peer.MenuItemPeer; + +public class GtkMenuItemPeer extends GtkMenuComponentPeer + implements MenuItemPeer +{ + /** + * 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()); + } + + /** + * Creates a new GtkMenuItemPeer associated with the given MenuItem. + * It will call create(), setFont(), setEnabled() and + * connectSignals() in that order. + */ + public GtkMenuItemPeer(MenuItem item) + { + super(item); + setEnabled (item.isEnabled()); + connectSignals(); + } + + /** + * Calls setEnabled(false). + */ + public void disable() + { + setEnabled(false); + } + + /** + * Calls setEnabled(true). + */ + public void enable() + { + 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/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuPeer.java new file mode 100644 index 000000000..c55347393 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuPeer.java @@ -0,0 +1,126 @@ +/* GtkMenuPeer.java -- Implements MenuPeer with GTK+ + Copyright (C) 1999, 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.java.awt.peer.gtk; + +import java.awt.Component; +import java.awt.Menu; +import java.awt.MenuContainer; +import java.awt.MenuItem; +import java.awt.MenuShortcut; +import java.awt.peer.MenuItemPeer; +import java.awt.peer.MenuPeer; + +public class GtkMenuPeer extends GtkMenuItemPeer + implements MenuPeer +{ + /** + * 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); + + private native void addTearOff (); + + /** + * Overridden to not connect any signals. + */ + protected void connectSignals() + { + // No signals to connect. + } + + public GtkMenuPeer (Menu menu) + { + super (menu); + + if (menu.isTearOff()) + addTearOff(); + + MenuContainer parent = menu.getParent (); + if (parent instanceof Menu) + setupAccelGroup ((GtkMenuPeer)((Menu)parent).getPeer ()); + else if (parent instanceof Component) + setupAccelGroup ((GtkComponentPeer)((Component)parent).getPeer ()); + else + setupAccelGroup (null); // XXX, should we warn about unknown parent? + } + + public void addItem (MenuItem item) + { + int key = 0; + boolean shiftModifier = false; + + MenuShortcut ms = item.getShortcut (); + if (ms != null) + { + key = ms.getKey (); + shiftModifier = ms.usesShiftModifier (); + } + + addItem ((MenuItemPeer) item.getPeer (), key, shiftModifier); + } + + public void addItem (MenuItemPeer item, MenuShortcut ms) + { + int key = 0; + boolean shiftModifier = false; + + if (ms != null) + { + key = ms.getKey (); + shiftModifier = ms.usesShiftModifier (); + } + + addItem (item, key, shiftModifier); + } + + public native void delItem(int index); + + public void addSeparator() + { + // FIXME: implement + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkMouseInfoPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMouseInfoPeer.java new file mode 100644 index 000000000..55c9146c4 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMouseInfoPeer.java @@ -0,0 +1,65 @@ +/* GtkToolkit.java -- Implements an AWT Toolkit using GTK 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.gtk; + +import java.awt.Point; +import java.awt.GraphicsDevice; +import java.awt.Window; +import java.awt.peer.MouseInfoPeer; + +/** + * The MouseInfoPeer is so small, I'm including it here. + */ +public class GtkMouseInfoPeer implements MouseInfoPeer +{ + private static GdkGraphicsEnvironment gde = new GdkGraphicsEnvironment(); + + public int fillPointWithCoords(Point p) + { + int[] coords = gde.getMouseCoordinates(); + p.x = coords[1]; + p.y = coords[2]; + return coords[0]; + } + + public boolean isWindowUnderMouse(Window w) + { + return gde.isWindowUnderMouse((GtkWindowPeer) w.getPeer()); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkPanelPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkPanelPeer.java new file mode 100644 index 000000000..00b506c10 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkPanelPeer.java @@ -0,0 +1,67 @@ +/* GtkPanelPeer.java -- Implements PanelPeer with GTK + Copyright (C) 1998, 1999, 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.gtk; + +import java.awt.AWTEvent; +import java.awt.Panel; +import java.awt.event.MouseEvent; +import java.awt.peer.PanelPeer; + +public class GtkPanelPeer extends GtkContainerPeer + implements PanelPeer +{ + native void create (); + + public GtkPanelPeer (Panel p) + { + super (p); + } + + public void handleEvent(AWTEvent event) + { + int id = event.getID(); + + if (id == MouseEvent.MOUSE_PRESSED) + awtComponent.requestFocusInWindow(); + + super.handleEvent(event); + } + + native void connectSignals (); +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkPopupMenuPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkPopupMenuPeer.java new file mode 100644 index 000000000..1b0ec8e63 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkPopupMenuPeer.java @@ -0,0 +1,68 @@ +/* GtkPopupMenuPeer.java -- Implements PopupMenuPeer with GTK+ + Copyright (C) 1999, 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.gtk; + +import java.awt.Component; +import java.awt.Event; +import java.awt.Point; +import java.awt.PopupMenu; +import java.awt.peer.PopupMenuPeer; + +public class GtkPopupMenuPeer extends GtkMenuPeer + implements PopupMenuPeer +{ + public GtkPopupMenuPeer (PopupMenu menu) + { + super (menu); + } + + native void setupAccelGroup (GtkGenericPeer container); + + native void show (int x, int y, long time); + public void show (Component origin, int x, int y) + { + Point abs = origin.getLocationOnScreen (); + show (abs.x + x, abs.y + y, 0); + } + + public void show (Event e) + { + + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkScrollPanePeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkScrollPanePeer.java new file mode 100644 index 000000000..657a27608 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkScrollPanePeer.java @@ -0,0 +1,111 @@ +/* GtkScrollPanePeer.java -- Implements ScrollPanePeer with GTK + Copyright (C) 1998, 1999, 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.java.awt.peer.gtk; + +import java.awt.Adjustable; +import java.awt.Dimension; +import java.awt.ScrollPane; +import java.awt.peer.ScrollPanePeer; + +public class GtkScrollPanePeer extends GtkContainerPeer + implements ScrollPanePeer +{ + native void create (int width, int height); + + void create () + { + create (awtComponent.getWidth (), awtComponent.getHeight ()); + } + + // native void gtkScrolledWindowSetScrollPosition(int x, int y); + native void gtkScrolledWindowSetHScrollIncrement (int u); + native void gtkScrolledWindowSetVScrollIncrement (int u); + + public GtkScrollPanePeer (ScrollPane sp) + { + super (sp); + + setPolicy (sp.getScrollbarDisplayPolicy ()); + } + + native void setPolicy (int policy); + public void childResized (int width, int height) + { + int dim[] = new int[2]; + + gtkWidgetGetDimensions (dim); + + // If the child is in this range, GTK adds both scrollbars, but + // the AWT doesn't. So set the peer's scroll policy to + // GTK_POLICY_NEVER. + if ((width > dim[0] - getVScrollbarWidth () && width <= dim[0]) + && (height > dim[1] - getHScrollbarHeight () && height <= dim[1])) + setPolicy (ScrollPane.SCROLLBARS_NEVER); + else + setPolicy (((ScrollPane) awtComponent).getScrollbarDisplayPolicy ()); + } + + public native int getHScrollbarHeight(); + public native int getVScrollbarWidth(); + public native void setScrollPosition(int x, int y); + + public Dimension getPreferredSize () + { + return awtComponent.getSize(); + } + + public void setUnitIncrement (Adjustable adj, int u) + { + if (adj.getOrientation()==Adjustable.HORIZONTAL) + gtkScrolledWindowSetHScrollIncrement (u); + else + gtkScrolledWindowSetVScrollIncrement (u); + } + + public void setValue (Adjustable adj, int v) + { +// System.out.println("SPP: setVal: "+adj+":"+v); +// Point p=myScrollPane.getScrollPosition (); +// if (adj.getOrientation()==Adjustable.HORIZONTAL) +// gtkScrolledWindowSetScrollPosition (v,p.y); +// else +// gtkScrolledWindowSetScrollPosition (p.x,v); +// adj.setValue(v); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkScrollbarPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkScrollbarPeer.java new file mode 100644 index 000000000..d3f160c83 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkScrollbarPeer.java @@ -0,0 +1,92 @@ +/* GtkScrollbarPeer.java -- Implements ScrollbarPeer with GTK+ + Copyright (C) 1998, 1999, 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.java.awt.peer.gtk; + +import java.awt.Scrollbar; +import java.awt.event.AdjustmentEvent; +import java.awt.peer.ScrollbarPeer; + +public class GtkScrollbarPeer extends GtkComponentPeer + implements ScrollbarPeer +{ + void create () + { + Scrollbar sb = (Scrollbar) awtComponent; + + create (sb.getOrientation (), sb.getValue (), + sb.getMinimum (), sb.getMaximum (), + sb.getUnitIncrement (), sb.getBlockIncrement (), + sb.getVisibleAmount ()); + } + + native void create (int orientation, int value, + int min, int max, int stepIncr, int pageIncr, + int visibleAmount); + + native void connectSignals (); + + public GtkScrollbarPeer (Scrollbar s) + { + super (s); + } + + public native void setLineIncrement(int amount); + public native void setPageIncrement(int amount); + + 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) + { + Scrollbar bar = (Scrollbar) awtComponent; + q().postEvent(new AdjustmentEvent(bar, + AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED, + type, value, true)); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkSelection.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkSelection.java new file mode 100644 index 000000000..78ed69676 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkSelection.java @@ -0,0 +1,675 @@ +/* GtkClipboard.java - Class representing gtk+ clipboard selection. + 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.java.awt.peer.gtk; + +import gnu.classpath.Pointer; + +import java.awt.datatransfer.*; + +import java.io.*; +import java.net.*; +import java.util.*; + +import java.awt.Image; + +/** + * Class representing the gtk+ clipboard selection. This is used when + * another program owns the clipboard. Whenever the system clipboard + * selection changes we create a new instance to notify the program + * that the available flavors might have changed. When requested it + * (lazily) caches the targets, and (text, image, or files/uris) + * clipboard contents. + */ +public class GtkSelection implements Transferable +{ + /** + * Static lock used for requests of mimetypes and contents retrieval. + */ + static private Object requestLock = new Object(); + + /** + * Whether we belong to the Clipboard (true) or to the Primary selection. + */ + private final boolean clipboard; + + /** + * Whether a request for mimetypes, text, images, uris or byte[] is + * currently in progress. Should only be tested or set with + * requestLock held. When true no other requests should be made till + * it is false again. + */ + private boolean requestInProgress; + + /** + * Indicates a requestMimeTypes() call was made and the + * corresponding mimeTypesAvailable() callback was triggered. + */ + private boolean mimeTypesDelivered; + + /** + * Set and returned by getTransferDataFlavors. Only valid when + * mimeTypesDelivered is true. + */ + private DataFlavor[] dataFlavors; + + /** + * Indicates a requestText() call was made and the corresponding + * textAvailable() callback was triggered. + */ + private boolean textDelivered; + + /** + * Set as response to a requestText() call and possibly returned by + * getTransferData() for text targets. Only valid when textDelivered + * is true. + */ + private String text; + + /** + * Indicates a requestImage() call was made and the corresponding + * imageAvailable() callback was triggered. + */ + private boolean imageDelivered; + + /** + * Set as response to a requestImage() call and possibly returned by + * getTransferData() for image targets. Only valid when + * imageDelivered is true and image is null. + */ + private Pointer imagePointer; + + /** + * Cached image value. Only valid when imageDelivered is + * true. Created from imagePointer. + */ + private Image image; + + /** + * Indicates a requestUris() call was made and the corresponding + * urisAvailable() callback was triggered. + */ + private boolean urisDelivered; + + /** + * Set as response to a requestURIs() call. Only valid when + * urisDelivered is true + */ + private List uris; + + /** + * Indicates a requestBytes(String) call was made and the + * corresponding bytesAvailable() callback was triggered. + */ + private boolean bytesDelivered; + + /** + * Set as response to a requestBytes(String) call. Only valid when + * bytesDelivered is true. + */ + private byte[] bytes; + + /** + * Should only be created by the GtkClipboard class. The clipboard + * should be either GtkClipboard.clipboard or + * GtkClipboard.selection. + */ + GtkSelection(GtkClipboard clipboard) + { + this.clipboard = (clipboard == GtkClipboard.clipboard); + } + + /** + * Gets an array of mime-type strings from the gtk+ clipboard and + * transforms them into an array of DataFlavors. + */ + public DataFlavor[] getTransferDataFlavors() + { + DataFlavor[] result; + synchronized (requestLock) + { + // Did we request already and cache the result? + if (mimeTypesDelivered) + result = (DataFlavor[]) dataFlavors.clone(); + else + { + // Wait till there are no pending requests. + while (requestInProgress) + { + try + { + requestLock.wait(); + } + catch (InterruptedException ie) + { + // ignored + } + } + + // If nobody else beat us and cached the result we try + // ourselves to get it. + if (! mimeTypesDelivered) + { + requestInProgress = true; + requestMimeTypes(clipboard); + while (! mimeTypesDelivered) + { + try + { + requestLock.wait(); + } + catch (InterruptedException ie) + { + // ignored + } + } + requestInProgress = false; + } + result = dataFlavors; + if (! GtkClipboard.canCache) + { + dataFlavors = null; + mimeTypesDelivered = false; + } + requestLock.notifyAll(); + } + } + return result; + } + + /** + * Callback that sets the available DataFlavors[]. Note that this + * should not call any code that could need the main gdk lock. + */ + private void mimeTypesAvailable(String[] mimeTypes) + { + synchronized (requestLock) + { + if (mimeTypes == null) + dataFlavors = new DataFlavor[0]; + else + { + // Most likely the mimeTypes include text in which case we add an + // extra element. + ArrayList flavorsList = + new ArrayList(mimeTypes.length + 1); + + for (int i = 0; i < mimeTypes.length; i++) + { + try + { + if (mimeTypes[i] == GtkClipboard.stringMimeType) + { + // XXX - Fix DataFlavor.getTextPlainUnicodeFlavor() + // and also add it to the list. + flavorsList.add(DataFlavor.stringFlavor); + flavorsList.add(DataFlavor.plainTextFlavor); + } + else if (mimeTypes[i] == GtkClipboard.imageMimeType) + flavorsList.add(DataFlavor.imageFlavor); + else if (mimeTypes[i] == GtkClipboard.filesMimeType) + flavorsList.add(DataFlavor.javaFileListFlavor); + else + { + // We check the target to prevent duplicates + // of the "magic" targets above. + DataFlavor target = new DataFlavor(mimeTypes[i]); + if (! flavorsList.contains(target)) + flavorsList.add(target); + } + } + catch (ClassNotFoundException cnfe) + { + cnfe.printStackTrace(); + } + catch (NullPointerException npe) + { + npe.printStackTrace(); + } + } + + dataFlavors = new DataFlavor[flavorsList.size()]; + flavorsList.toArray(dataFlavors); + } + + mimeTypesDelivered = true; + requestLock.notifyAll(); + } + } + + /** + * Gets the available data flavors for this selection and checks + * that at least one of them is equal to the given DataFlavor. + */ + public boolean isDataFlavorSupported(DataFlavor flavor) + { + DataFlavor[] dfs = getTransferDataFlavors(); + for (int i = 0; i < dfs.length; i++) + if (flavor.equals(dfs[i])) + return true; + + return false; + } + + /** + * Helper method that tests whether we already have the text for the + * current gtk+ selection on the clipboard and if not requests it + * and waits till it is available. + */ + private String getText() + { + String result; + synchronized (requestLock) + { + // Did we request already and cache the result? + if (textDelivered) + result = text; + else + { + // Wait till there are no pending requests. + while (requestInProgress) + { + try + { + requestLock.wait(); + } + catch (InterruptedException ie) + { + // ignored + } + } + + // If nobody else beat us we try ourselves to get and + // caching the result. + if (! textDelivered) + { + requestInProgress = true; + requestText(clipboard); + while (! textDelivered) + { + try + { + requestLock.wait(); + } + catch (InterruptedException ie) + { + // ignored + } + } + requestInProgress = false; + } + result = text; + if (! GtkClipboard.canCache) + { + text = null; + textDelivered = false; + } + requestLock.notifyAll(); + } + } + return result; + } + + /** + * Callback that sets the available text on the clipboard. Note that + * this should not call any code that could need the main gdk lock. + */ + private void textAvailable(String text) + { + synchronized (requestLock) + { + this.text = text; + textDelivered = true; + requestLock.notifyAll(); + } + } + + /** + * Helper method that tests whether we already have an image for the + * current gtk+ selection on the clipboard and if not requests it + * and waits till it is available. + */ + private Image getImage() + { + Image result; + synchronized (requestLock) + { + // Did we request already and cache the result? + if (imageDelivered) + result = image; + else + { + // Wait till there are no pending requests. + while (requestInProgress) + { + try + { + requestLock.wait(); + } + catch (InterruptedException ie) + { + // ignored + } + } + + // If nobody else beat us we try ourselves to get and + // caching the result. + if (! imageDelivered) + { + requestInProgress = true; + requestImage(clipboard); + while (! imageDelivered) + { + try + { + requestLock.wait(); + } + catch (InterruptedException ie) + { + // ignored + } + } + requestInProgress = false; + } + + if (imagePointer != null) + image = new GtkImage(imagePointer); + + imagePointer = null; + result = image; + if (! GtkClipboard.canCache) + { + image = null; + imageDelivered = false; + } + requestLock.notifyAll(); + } + } + return result; + } + + /** + * Callback that sets the available image on the clipboard. Note + * that this should not call any code that could need the main gdk + * lock. Note that we get a Pointer to a GdkPixbuf which we cannot + * turn into a real GtkImage at this point. That will be done on the + * "user thread" in getImage(). + */ + private void imageAvailable(Pointer pointer) + { + synchronized (requestLock) + { + this.imagePointer = pointer; + imageDelivered = true; + requestLock.notifyAll(); + } + } + + /** + * Helper method that test whether we already have a list of + * URIs/Files and if not requests them and waits till they are + * available. + */ + private List getURIs() + { + List result; + synchronized (requestLock) + { + // Did we request already and cache the result? + if (urisDelivered) + result = uris; + else + { + // Wait till there are no pending requests. + while (requestInProgress) + { + try + { + requestLock.wait(); + } + catch (InterruptedException ie) + { + // ignored + } + } + + // If nobody else beat us we try ourselves to get and + // caching the result. + if (! urisDelivered) + { + requestInProgress = true; + requestURIs(clipboard); + while (! urisDelivered) + { + try + { + requestLock.wait(); + } + catch (InterruptedException ie) + { + // ignored + } + } + requestInProgress = false; + } + result = uris; + if (! GtkClipboard.canCache) + { + uris = null; + urisDelivered = false; + } + requestLock.notifyAll(); + } + } + return result; + } + + /** + * Callback that sets the available File list. Note that this should + * not call any code that could need the main gdk lock. + */ + private void urisAvailable(String[] uris) + { + synchronized (requestLock) + { + if (uris != null && uris.length != 0) + { + ArrayList list = new ArrayList(uris.length); + for (int i = 0; i < uris.length; i++) + { + try + { + URI uri = new URI(uris[i]); + if (uri.getScheme().equals("file")) + list.add(new File(uri)); + } + catch (URISyntaxException use) + { + } + } + this.uris = list; + } + + urisDelivered = true; + requestLock.notifyAll(); + } + } + + /** + * Helper method that requests a byte[] for the given target + * mime-type flavor and waits till it is available. Note that unlike + * the other get methods this one doesn't cache the result since + * there are possibly many targets. + */ + private byte[] getBytes(String target) + { + byte[] result; + synchronized (requestLock) + { + // Wait till there are no pending requests. + while (requestInProgress) + { + try + { + requestLock.wait(); + } + catch (InterruptedException ie) + { + // ignored + } + } + + // Request bytes and wait till they are available. + requestInProgress = true; + requestBytes(clipboard, target); + while (! bytesDelivered) + { + try + { + requestLock.wait(); + } + catch (InterruptedException ie) + { + // ignored + } + } + result = bytes; + bytes = null; + bytesDelivered = false; + requestInProgress = false; + + requestLock.notifyAll(); + } + return result; + } + + /** + * Callback that sets the available byte array on the + * clipboard. Note that this should not call any code that could + * need the main gdk lock. + */ + private void bytesAvailable(byte[] bytes) + { + synchronized (requestLock) + { + this.bytes = bytes; + bytesDelivered = true; + requestLock.notifyAll(); + } + } + + public Object getTransferData(DataFlavor flavor) + throws UnsupportedFlavorException + { + // Note the fall throughs for the "magic targets" if they fail we + // try one more time through getBytes(). + if (flavor.equals(DataFlavor.stringFlavor)) + { + String text = getText(); + if (text != null) + return text; + } + + if (flavor.equals(DataFlavor.plainTextFlavor)) + { + String text = getText(); + if (text != null) + return new StringBufferInputStream(text); + } + + if (flavor.equals(DataFlavor.imageFlavor)) + { + Image image = getImage(); + if (image != null) + return image; + } + + if (flavor.equals(DataFlavor.javaFileListFlavor)) + { + List uris = getURIs(); + if (uris != null) + return uris; + } + + byte[] bytes = getBytes(flavor.getMimeType()); + if (bytes == null) + throw new UnsupportedFlavorException(flavor); + + if (flavor.isMimeTypeSerializedObject()) + { + try + { + ByteArrayInputStream bais = new ByteArrayInputStream(bytes); + ObjectInputStream ois = new ObjectInputStream(bais); + return ois.readObject(); + } + catch (IOException ioe) + { + ioe.printStackTrace(); + } + catch (ClassNotFoundException cnfe) + { + cnfe.printStackTrace(); + } + } + + if (flavor.isRepresentationClassInputStream()) + return new ByteArrayInputStream(bytes); + + // XXX, need some more conversions? + + throw new UnsupportedFlavorException(flavor); + } + + /* + * Requests text, Image or an byte[] for a particular target from the + * other application. These methods return immediately. When the + * content is available the contentLock will be notified through + * textAvailable, imageAvailable, urisAvailable or bytesAvailable and the + * appropriate field is set. + * The clipboard argument is true if we want the Clipboard, and false + * if we want the (primary) selection. + */ + private native void requestText(boolean clipboard); + private native void requestImage(boolean clipboard); + private native void requestURIs(boolean clipboard); + private native void requestBytes(boolean clipboard, String target); + + /* Similar to the above but for requesting the supported targets. */ + private native void requestMimeTypes(boolean clipboard); +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextAreaPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextAreaPeer.java new file mode 100644 index 000000000..0c7d3a860 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextAreaPeer.java @@ -0,0 +1,223 @@ +/* GtkTextAreaPeer.java -- Implements TextAreaPeer with GTK + Copyright (C) 1998, 1999, 2002 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.gtk; + +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Rectangle; +import java.awt.TextArea; +import java.awt.im.InputMethodRequests; +import java.awt.peer.TextAreaPeer; +import java.awt.peer.TextComponentPeer; + +public class GtkTextAreaPeer extends GtkComponentPeer + implements TextComponentPeer, TextAreaPeer +{ + private static transient int DEFAULT_ROWS = 10; + private static transient int DEFAULT_COLS = 80; + + native void create (int width, int height, int scrollbarVisibility); + + /** + * 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 (); + + public native int getCaretPosition (); + public native void setCaretPosition (int pos); + public native int getSelectionStart (); + public native int getSelectionEnd (); + public native String getText (); + public native void select (int start, int end); + public native void setEditable (boolean state); + public native void setText (String text); + + public int getIndexAtPoint(int x, int y) + { + // FIXME + return 0; + } + + public Rectangle getCharacterBounds (int pos) + { + // FIXME + return null; + } + + public long filterEvents (long filter) + { + // FIXME + return filter; + } + + void create () + { + Font f = awtComponent.getFont (); + + // By default, Sun sets a TextArea's font when its peer is + // created. If f != null then the peer's font is set by + // GtkComponent.create. + if (f == null) + { + f = new Font ("Dialog", Font.PLAIN, 12); + awtComponent.setFont (f); + } + + FontMetrics fm = getFontMetrics (f); + + TextArea ta = ((TextArea) awtComponent); + int sizeRows = ta.getRows (); + int sizeCols = ta.getColumns (); + + sizeRows = sizeRows == 0 ? DEFAULT_ROWS : sizeRows; + sizeCols = sizeCols == 0 ? DEFAULT_COLS : sizeCols; + + int width = sizeCols * fm.getMaxAdvance (); + int height = sizeRows * (fm.getMaxDescent () + fm.getMaxAscent ()); + + create (width, height, ta.getScrollbarVisibility ()); + setEditable (ta.isEditable ()); + } + + public GtkTextAreaPeer (TextArea ta) + { + super (ta); + + setText (ta.getText ()); + setCaretPosition (0); + } + + public native void insert (String str, int pos); + public native void replaceRange (String str, int start, int end); + + public Dimension getMinimumSize (int rows, int cols) + { + return minimumSize (rows == 0 ? DEFAULT_ROWS : rows, + cols == 0 ? DEFAULT_COLS : cols); + } + + public Dimension getPreferredSize (int rows, int cols) + { + return preferredSize (rows == 0 ? DEFAULT_ROWS : rows, + cols == 0 ? DEFAULT_COLS : cols); + } + + native int getHScrollbarHeight (); + native int getVScrollbarWidth (); + + // Deprecated + public Dimension minimumSize (int rows, int cols) + { + TextArea ta = ((TextArea) awtComponent); + int height = 0; + int width = 0; + + if (ta.getScrollbarVisibility () == TextArea.SCROLLBARS_BOTH + || ta.getScrollbarVisibility () == TextArea.SCROLLBARS_HORIZONTAL_ONLY) + height = getHScrollbarHeight (); + + if (ta.getScrollbarVisibility () == TextArea.SCROLLBARS_BOTH + || ta.getScrollbarVisibility () == TextArea.SCROLLBARS_VERTICAL_ONLY) + width = getVScrollbarWidth (); + + Font f = awtComponent.getFont (); + if (f == null) + return new Dimension (width, height); + + FontMetrics fm = getFontMetrics (f); + + int sizeRows = rows == 0 ? DEFAULT_ROWS : rows; + int sizeCols = cols == 0 ? DEFAULT_COLS : cols; + + width += sizeCols * fm.getMaxAdvance (); + height += sizeRows * (fm.getMaxDescent () + fm.getMaxAscent ()); + + return new Dimension (width, height); + } + + public Dimension preferredSize (int rows, int cols) + { + TextArea ta = ((TextArea) awtComponent); + int height = 0; + int width = 0; + + if (ta.getScrollbarVisibility () == TextArea.SCROLLBARS_BOTH + || ta.getScrollbarVisibility () == TextArea.SCROLLBARS_HORIZONTAL_ONLY) + height = getHScrollbarHeight (); + + if (ta.getScrollbarVisibility () == TextArea.SCROLLBARS_BOTH + || ta.getScrollbarVisibility () == TextArea.SCROLLBARS_VERTICAL_ONLY) + width = getVScrollbarWidth (); + + Font f = awtComponent.getFont (); + if (f == null) + return new Dimension (width, height); + + FontMetrics fm = getFontMetrics (f); + + int sizeRows = rows == 0 ? DEFAULT_ROWS : rows; + int sizeCols = cols == 0 ? DEFAULT_COLS : cols; + + width += sizeCols * fm.getMaxAdvance (); + height += sizeRows * (fm.getMaxDescent () + fm.getMaxAscent ()); + + return new Dimension (width, height); + } + + public void replaceText (String str, int start, int end) + { + replaceRange (str, start, end); + } + + public void insertText (String str, int pos) + { + insert (str, pos); + } + + public InputMethodRequests getInputMethodRequests() + { + // FIXME: implement + return null; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextFieldPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextFieldPeer.java new file mode 100644 index 000000000..9e62c8e79 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextFieldPeer.java @@ -0,0 +1,200 @@ +/* GtkTextFieldPeer.java -- Implements TextFieldPeer with GTK + Copyright (C) 1998, 1999, 2002 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.gtk; + +import java.awt.AWTEvent; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Rectangle; +import java.awt.TextField; +import java.awt.event.KeyEvent; +import java.awt.im.InputMethodRequests; +import java.awt.peer.TextFieldPeer; +import java.awt.peer.TextComponentPeer; + +public class GtkTextFieldPeer extends GtkComponentPeer + implements TextComponentPeer, TextFieldPeer +{ + native void create (int width); + native void gtkWidgetSetBackground (int red, int green, int blue); + native void gtkWidgetSetForeground (int red, int green, int blue); + + public native void connectSignals (); + + public native int getCaretPosition (); + public native void setCaretPosition (int pos); + public native int getSelectionStart (); + public native int getSelectionEnd (); + public native String getText (); + public native void select (int start, int end); + public native void setEditable (boolean state); + public native void setText (String text); + + public int getIndexAtPoint(int x, int y) + { + // FIXME + return 0; + } + + public Rectangle getCharacterBounds (int pos) + { + // FIXME + return null; + } + + public long filterEvents (long filter) + { + // FIXME + return filter; + } + + void create () + { + Font f = awtComponent.getFont (); + + // By default, Sun sets a TextField's font when its peer is + // created. If f != null then the peer's font is set by + // GtkComponent.create. + if (f == null) + { + f = new Font ("Dialog", Font.PLAIN, 12); + awtComponent.setFont (f); + } + + FontMetrics fm = getFontMetrics (f); + + TextField tf = ((TextField) awtComponent); + int cols = tf.getColumns (); + + int text_width = cols * fm.getMaxAdvance (); + + create (text_width); + + setEditable (tf.isEditable ()); + } + + native int gtkEntryGetBorderWidth (); + + public GtkTextFieldPeer (TextField tf) + { + super (tf); + + setText (tf.getText ()); + setCaretPosition (0); + + if (tf.echoCharIsSet ()) + setEchoChar (tf.getEchoChar ()); + } + + public Dimension getMinimumSize (int cols) + { + return minimumSize (cols); + } + + public Dimension getPreferredSize (int cols) + { + return preferredSize (cols); + } + + public native void setEchoChar (char c); + + // Deprecated + public Dimension minimumSize (int cols) + { + int dim[] = new int[2]; + + gtkWidgetGetPreferredDimensions (dim); + + Font f = awtComponent.getFont (); + if (f == null) + return new Dimension (2 * gtkEntryGetBorderWidth (), dim[1]); + + FontMetrics fm = getFontMetrics (f); + + int text_width = cols * fm.getMaxAdvance (); + + int width = text_width + 2 * gtkEntryGetBorderWidth (); + + return new Dimension (width, dim[1]); + } + + public Dimension preferredSize (int cols) + { + int dim[] = new int[2]; + + gtkWidgetGetPreferredDimensions (dim); + + Font f = awtComponent.getFont (); + if (f == null) + return new Dimension (2 * gtkEntryGetBorderWidth (), dim[1]); + + FontMetrics fm = getFontMetrics (f); + + int text_width = cols * fm.getMaxAdvance (); + + int width = text_width + 2 * gtkEntryGetBorderWidth (); + + return new Dimension (width, dim[1]); + } + + public void setEchoCharacter (char c) + { + setEchoChar (c); + } + + public void handleEvent (AWTEvent e) + { + if (e.getID () == KeyEvent.KEY_PRESSED) + { + KeyEvent ke = (KeyEvent) e; + + if (!ke.isConsumed () + && ke.getKeyCode () == KeyEvent.VK_ENTER) + postActionEvent (getText (), ke.getModifiersEx ()); + } + + super.handleEvent (e); + } + public InputMethodRequests getInputMethodRequests() + { + // FIXME: implement + return null; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkToolkit.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkToolkit.java new file mode 100644 index 000000000..150656511 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkToolkit.java @@ -0,0 +1,766 @@ +/* GtkToolkit.java -- Implements an AWT Toolkit using GTK for peers + Copyright (C) 1998, 1999, 2002, 2003, 2004, 2005, 2006, 2007 + 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.gtk; + +import gnu.classpath.Configuration; + +import gnu.java.awt.AWTUtilities; +import gnu.java.awt.EmbeddedWindow; +import gnu.java.awt.dnd.GtkMouseDragGestureRecognizer; +import gnu.java.awt.dnd.peer.gtk.GtkDragSourceContextPeer; +import gnu.java.awt.peer.ClasspathFontPeer; +import gnu.java.awt.peer.EmbeddedWindowPeer; + +import java.awt.AWTException; +import java.awt.Button; +import java.awt.Canvas; +import java.awt.Checkbox; +import java.awt.CheckboxMenuItem; +import java.awt.Choice; +import java.awt.Component; +import java.awt.Cursor; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FileDialog; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Frame; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.HeadlessException; +import java.awt.Image; +import java.awt.Label; +import java.awt.List; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.Point; +import java.awt.PopupMenu; +import java.awt.PrintJob; +import java.awt.Rectangle; +import java.awt.ScrollPane; +import java.awt.Scrollbar; +import java.awt.TextArea; +import java.awt.TextField; +import java.awt.Window; +import java.awt.datatransfer.Clipboard; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragGestureRecognizer; +import java.awt.dnd.DragSource; +import java.awt.dnd.InvalidDnDOperationException; +import java.awt.dnd.peer.DragSourceContextPeer; +import java.awt.font.TextAttribute; +import java.awt.im.InputMethodHighlight; +import java.awt.image.ColorModel; +import java.awt.image.DirectColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.peer.ButtonPeer; +import java.awt.peer.CanvasPeer; +import java.awt.peer.CheckboxMenuItemPeer; +import java.awt.peer.CheckboxPeer; +import java.awt.peer.ChoicePeer; +import java.awt.peer.DialogPeer; +import java.awt.peer.FileDialogPeer; +import java.awt.peer.FontPeer; +import java.awt.peer.FramePeer; +import java.awt.peer.LabelPeer; +import java.awt.peer.ListPeer; +import java.awt.peer.MenuBarPeer; +import java.awt.peer.MenuItemPeer; +import java.awt.peer.MenuPeer; +import java.awt.peer.MouseInfoPeer; +import java.awt.peer.PanelPeer; +import java.awt.peer.PopupMenuPeer; +import java.awt.peer.RobotPeer; +import java.awt.peer.ScrollPanePeer; +import java.awt.peer.ScrollbarPeer; +import java.awt.peer.TextAreaPeer; +import java.awt.peer.TextFieldPeer; +import java.awt.peer.WindowPeer; +import java.io.InputStream; +import java.net.URL; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Properties; + +import javax.imageio.spi.IIORegistry; + +/* This class uses a deprecated method java.awt.peer.ComponentPeer.getPeer(). + This merits comment. We are basically calling Sun's bluff on this one. + We think Sun has deprecated it simply to discourage its use as it is + bad programming style. However, we need to get at a component's peer in + this class. If getPeer() ever goes away, we can implement a hash table + that will keep up with every window's peer, but for now this is faster. */ + +public class GtkToolkit extends gnu.java.awt.ClasspathToolkit +{ + static final Object GTK_LOCK; + + private static EventQueue q; + + static native void gtkInit(int portableNativeSync, Object lock); + + static native void gtkMain(); + + static native void gtkQuit(); + + /** + * Initializes field IDs that are used by native code. + */ + private static native void initIDs(); + + /** + * True when the field IDs are already initialized, false otherwise. + */ + private static boolean initializedGlobalIDs = false; + + /** + * Initializes some global fieldIDs for use in the native code. This is + * called by a couple of classes in the GTK peers to ensure that + * some necessary stuff is loaded. + */ + static synchronized void initializeGlobalIDs() + { + if (! initializedGlobalIDs) + { + initIDs(); + initializedGlobalIDs = true; + } + } + + static + { + if (true) // GCJ LOCAL + { + System.loadLibrary("gtkpeer"); + } + + /** + * Gotta do that first. + */ + initializeGlobalIDs(); + + int portableNativeSync; + String portNatSyncProp = + System.getProperty("gnu.classpath.awt.gtk.portable.native.sync"); + + if (portNatSyncProp == null) + portableNativeSync = -1; // unset + else if (Boolean.valueOf(portNatSyncProp).booleanValue()) + portableNativeSync = 1; // true + else + portableNativeSync = 0; // false + + GTK_LOCK = new String("GTK LOCK"); + gtkInit(portableNativeSync, GTK_LOCK); + } + + public GtkToolkit () + { + } + + public native void beep(); + + private native void getScreenSizeDimensions(int[] xy); + + public int checkImage (Image image, int width, int height, + ImageObserver observer) + { + int status = ImageObserver.ALLBITS + | ImageObserver.WIDTH + | ImageObserver.HEIGHT; + + if (image instanceof GtkImage) + return ((GtkImage) image).checkImage (observer); + + if (image instanceof AsyncImage) + return ((AsyncImage) image).checkImage(observer); + + if (observer != null) + observer.imageUpdate (image, status, + -1, -1, + image.getWidth (observer), + image.getHeight (observer)); + + return status; + } + + /** + * Helper to return either a Image -- the argument -- or a + * GtkImage with the errorLoading flag set if the argument is null. + */ + static Image imageOrError(Image b) + { + if (b == null) + return GtkImage.getErrorImage(); + else + return b; + } + + public Image createImage (String filename) + { + if (filename.length() == 0) + return new GtkImage (); + + Image image; + try + { + image = CairoSurface.getBufferedImage( new GtkImage( filename ) ); + } + catch (IllegalArgumentException iae) + { + image = null; + } + return imageOrError(image); + } + + public Image createImage (URL url) + { + return new AsyncImage(url); + } + + public Image createImage (ImageProducer producer) + { + if (producer == null) + return null; + + Image image; + try + { + image = CairoSurface.getBufferedImage( new GtkImage( producer ) ); + } + catch (IllegalArgumentException iae) + { + image = null; + } + return imageOrError(image); + } + + public Image createImage (byte[] imagedata, int imageoffset, + int imagelength) + { + Image image; + try + { + byte[] data = new byte[ imagelength ]; + System.arraycopy(imagedata, imageoffset, data, 0, imagelength); + image = CairoSurface.getBufferedImage( new GtkImage( data ) ); + } + catch (IllegalArgumentException iae) + { + image = null; + } + return imageOrError(image); + } + + /** + * Creates an ImageProducer from the specified URL. The image is assumed + * to be in a recognised format. + * + * @param url URL to read image data from. + */ + public ImageProducer createImageProducer(URL url) + { + return createImage( url ).getSource(); + } + + /** + * Returns the native color model (which isn't the same as the default + * ARGB color model, but doesn't have to be). + */ + public ColorModel getColorModel () + { + /* Return the GDK-native ABGR format */ + return new DirectColorModel(32, + 0x000000FF, + 0x0000FF00, + 0x00FF0000, + 0xFF000000); + } + + public String[] getFontList () + { + return (new String[] { "Dialog", + "DialogInput", + "Monospaced", + "Serif", + "SansSerif" }); + } + + static class LRUCache extends LinkedHashMap + { + int max_entries; + public LRUCache(int max) + { + super(max, 0.75f, true); + max_entries = max; + } + protected boolean removeEldestEntry(Map.Entry eldest) + { + return size() > max_entries; + } + } + + private LRUCache fontCache = + new LRUCache(50); + private LRUCache imageCache = new LRUCache(50); + + public FontMetrics getFontMetrics (Font font) + { + return ((GdkFontPeer) font.getPeer()).getFontMetrics(font); + } + + public Image getImage (String filename) + { + if (imageCache.containsKey(filename)) + return imageCache.get(filename); + else + { + Image im = createImage(filename); + imageCache.put(filename, im); + return im; + } + } + + public Image getImage (URL url) + { + if (imageCache.containsKey(url)) + return imageCache.get(url); + else + { + Image im = createImage(url); + imageCache.put(url, im); + return im; + } + } + + public PrintJob getPrintJob (Frame frame, String jobtitle, Properties props) + { + SecurityManager sm; + sm = System.getSecurityManager(); + if (sm != null) + sm.checkPrintJobAccess(); + + return null; + } + + public native int getScreenResolution(); + + public Dimension getScreenSize () + { + int dim[] = new int[2]; + getScreenSizeDimensions(dim); + return new Dimension(dim[0], dim[1]); + } + + public Clipboard getSystemClipboard() + { + SecurityManager secman = System.getSecurityManager(); + if (secman != null) + secman.checkSystemClipboardAccess(); + + return GtkClipboard.getClipboardInstance(); + } + + public Clipboard getSystemSelection() + { + SecurityManager secman = System.getSecurityManager(); + if (secman != null) + secman.checkSystemClipboardAccess(); + + return GtkClipboard.getSelectionInstance(); + } + + /** + * Prepares a GtkImage. For every other kind of Image it just + * assumes the image is already prepared for rendering. + */ + public boolean prepareImage (Image image, int width, int height, + ImageObserver observer) + { + /* GtkImages are always prepared, as long as they're loaded. */ + if (image instanceof GtkImage) + return ((((GtkImage)image).checkImage (observer) + & ImageObserver.ALLBITS) != 0); + + if (image instanceof AsyncImage) + { + AsyncImage aImg = (AsyncImage) image; + aImg.addObserver(observer); + return aImg.realImage != null; + } + + /* Assume anything else is too */ + return true; + } + + public native void sync(); + + protected void setComponentState (Component c, GtkComponentPeer cp) + { + /* Make the Component reflect Peer defaults */ + if (c.getForeground () == null) + c.setForeground (cp.getForeground ()); + if (c.getBackground () == null) + c.setBackground (cp.getBackground ()); + // if (c.getFont () == null) + // c.setFont (cp.getFont ()); + + /* Make the Peer reflect the state of the Component */ + if (! (c instanceof Window)) + { + cp.setCursor (c.getCursor ()); + + Rectangle bounds = c.getBounds (); + cp.setBounds (bounds.x, bounds.y, bounds.width, bounds.height); + cp.setVisible (c.isVisible ()); + } + } + + protected ButtonPeer createButton (Button b) + { + checkHeadless(); + return new GtkButtonPeer (b); + } + + protected CanvasPeer createCanvas (Canvas c) + { + checkHeadless(); + return new GtkCanvasPeer (c); + } + + protected CheckboxPeer createCheckbox (Checkbox cb) + { + checkHeadless(); + return new GtkCheckboxPeer (cb); + } + + protected CheckboxMenuItemPeer createCheckboxMenuItem (CheckboxMenuItem cmi) + { + checkHeadless(); + return new GtkCheckboxMenuItemPeer (cmi); + } + + protected ChoicePeer createChoice (Choice c) + { + checkHeadless(); + return new GtkChoicePeer (c); + } + + protected DialogPeer createDialog (Dialog d) + { + checkHeadless(); + GtkMainThread.createWindow(); + return new GtkDialogPeer (d); + } + + protected FileDialogPeer createFileDialog (FileDialog fd) + { + checkHeadless(); + return new GtkFileDialogPeer (fd); + } + + protected FramePeer createFrame (Frame f) + { + checkHeadless(); + GtkMainThread.createWindow(); + return new GtkFramePeer (f); + } + + protected LabelPeer createLabel (Label label) + { + checkHeadless(); + return new GtkLabelPeer (label); + } + + protected ListPeer createList (List list) + { + checkHeadless(); + return new GtkListPeer (list); + } + + protected MenuPeer createMenu (Menu m) + { + checkHeadless(); + return new GtkMenuPeer (m); + } + + protected MenuBarPeer createMenuBar (MenuBar mb) + { + checkHeadless(); + return new GtkMenuBarPeer (mb); + } + + protected MenuItemPeer createMenuItem (MenuItem mi) + { + checkHeadless(); + return new GtkMenuItemPeer (mi); + } + + protected PanelPeer createPanel (Panel p) + { + checkHeadless(); + return new GtkPanelPeer (p); + } + + protected PopupMenuPeer createPopupMenu (PopupMenu target) + { + checkHeadless(); + return new GtkPopupMenuPeer (target); + } + + protected ScrollPanePeer createScrollPane (ScrollPane sp) + { + checkHeadless(); + return new GtkScrollPanePeer (sp); + } + + protected ScrollbarPeer createScrollbar (Scrollbar sb) + { + checkHeadless(); + return new GtkScrollbarPeer (sb); + } + + protected TextAreaPeer createTextArea (TextArea ta) + { + checkHeadless(); + return new GtkTextAreaPeer (ta); + } + + protected TextFieldPeer createTextField (TextField tf) + { + checkHeadless(); + return new GtkTextFieldPeer (tf); + } + + protected WindowPeer createWindow (Window w) + { + checkHeadless(); + GtkMainThread.createWindow(); + return new GtkWindowPeer (w); + } + + public EmbeddedWindowPeer createEmbeddedWindow (EmbeddedWindow w) + { + checkHeadless(); + GtkMainThread.createWindow(); + return new GtkEmbeddedWindowPeer (w); + } + + /** + * @deprecated part of the older "logical font" system in earlier AWT + * implementations. Our newer Font class uses getClasspathFontPeer. + */ + protected FontPeer getFontPeer (String name, int style) { + // All fonts get a default size of 12 if size is not specified. + return getFontPeer(name, style, 12); + } + + /** + * Private method that allows size to be set at initialization time. + */ + private FontPeer getFontPeer (String name, int style, int size) + { + Map attrs = new HashMap(); + ClasspathFontPeer.copyStyleToAttrs (style, attrs); + ClasspathFontPeer.copySizeToAttrs (size, attrs); + return getClasspathFontPeer (name, attrs); + } + + /** + * Newer method to produce a peer for a Font object, even though Sun's + * design claims Font should now be peerless, we do not agree with this + * model, hence "ClasspathFontPeer". + */ + + public ClasspathFontPeer getClasspathFontPeer (String name, + Map attrs) + { + Map keyMap = new HashMap(attrs); + // We don't know what kind of "name" the user requested (logical, face, + // family), and we don't actually *need* to know here. The worst case + // involves failure to consolidate fonts with the same backend in our + // cache. This is harmless. + keyMap.put ("GtkToolkit.RequestedFontName", name); + if (fontCache.containsKey (keyMap)) + return fontCache.get (keyMap); + else + { + ClasspathFontPeer newPeer = new GdkFontPeer (name, attrs); + fontCache.put (keyMap, newPeer); + return newPeer; + } + } + + protected EventQueue getSystemEventQueueImpl() + { + synchronized (GtkToolkit.class) + { + if (q == null) + { + q = new EventQueue(); + } + } + return q; + } + + public Cursor createCustomCursor(Image image, Point hotspot, String name) + { + return new GtkCursor(image, hotspot, name); + } + + protected native void loadSystemColors (int[] systemColors); + + public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent e) + { + if (GraphicsEnvironment.isHeadless()) + throw new InvalidDnDOperationException(); + return new GtkDragSourceContextPeer(e); + } + + public T + createDragGestureRecognizer(Class recognizer, DragSource ds, + Component comp, int actions, + DragGestureListener l) + { + if (recognizer.getName().equals("java.awt.dnd.MouseDragGestureRecognizer") + && ! GraphicsEnvironment.isHeadless()) + { + GtkMouseDragGestureRecognizer gestureRecognizer + = new GtkMouseDragGestureRecognizer(ds, comp, actions, l); + gestureRecognizer.registerListeners(); + return recognizer.cast(gestureRecognizer); + } + else + { + return null; + } + } + + public Map mapInputMethodHighlight(InputMethodHighlight highlight) + { + throw new Error("not implemented"); + } + + public Rectangle getBounds() + { + int[] dims = new int[2]; + getScreenSizeDimensions(dims); + return new Rectangle(0, 0, dims[0], dims[1]); + } + + // ClasspathToolkit methods + + public GraphicsEnvironment getLocalGraphicsEnvironment() + { + return new GdkGraphicsEnvironment(); + } + + public Font createFont(int format, InputStream stream) + { + throw new UnsupportedOperationException(); + } + + public RobotPeer createRobot (GraphicsDevice screen) throws AWTException + { + return new GdkRobotPeer (screen); + } + + public boolean getLockingKeyState(int keyCode) + { + int state = getLockState(keyCode); + + if (state != -1) + return state == 1; + + if (AWTUtilities.isValidKey(keyCode)) + throw new UnsupportedOperationException + ("cannot get locking state of key code " + keyCode); + + throw new IllegalArgumentException("invalid key code " + keyCode); + } + + protected native int getLockState(int keyCode); + + public void registerImageIOSpis(IIORegistry reg) + { + GdkPixbufDecoder.registerSpis(reg); + } + + protected MouseInfoPeer getMouseInfoPeer() + { + return new GtkMouseInfoPeer(); + } + + public boolean isFrameStateSupported(int state) + { + // GTK supports ICONFIED, NORMAL and MAXIMIZE_BOTH, but + // not (yet?) MAXIMIZE_VERT and MAXIMIZE_HORIZ. + return state == Frame.NORMAL || state == Frame.ICONIFIED + || state == Frame.MAXIMIZED_BOTH; + } + + private void checkHeadless() + { + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException(); + } + + public native int getMouseNumberOfButtons(); + + @Override + public boolean isModalExclusionTypeSupported + (Dialog.ModalExclusionType modalExclusionType) + { + return false; + } + + @Override + public boolean isModalityTypeSupported(Dialog.ModalityType modalityType) + { + return false; + } + +} // class GtkToolkit diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkVolatileImage.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkVolatileImage.java new file mode 100644 index 000000000..663839f23 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkVolatileImage.java @@ -0,0 +1,207 @@ +/* GtkVolatileImage.java -- wraps an X pixmap + 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.java.awt.peer.gtk; + +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.ImageCapabilities; +import java.awt.Point; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.DirectColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.Raster; +import java.awt.image.SampleModel; +import java.awt.image.SinglePixelPackedSampleModel; +import java.awt.image.VolatileImage; +import java.awt.image.WritableRaster; + +public class GtkVolatileImage extends VolatileImage +{ + int width, height; + private ImageCapabilities caps; + + final GtkComponentPeer component; + + static ColorModel gdkColorModel = new DirectColorModel(32, + 0x000000FF, + 0x0000FF00, + 0x00FF0000, + 0xFF000000); + + /** + * Don't touch, accessed from native code. + */ + long nativePointer; + + native long init(GtkComponentPeer component, int width, int height); + + native void destroy(long pointer); + + native int[] nativeGetPixels(long pointer); + + /** + * Gets the pixels in the current image from GDK. + * + * Note that pixels are in 32-bit RGBA, non-premultiplied, which is different + * from Cairo's premultiplied ARGB, which is different from Java's standard + * non-premultiplied ARGB. Caution is advised when using this method, to + * ensure that the data format remains consistent with what you expect. + * + * @return the current pixels, as reported by GDK. + */ + public int[] getPixels() + { + return nativeGetPixels(nativePointer); + } + + native void nativeCopyArea(long pointer, int x, int y, int w, int h, int dx, + int dy ); + public void copyArea(int x, int y, int w, int h, int dx, int dy) + { + nativeCopyArea(nativePointer, x, y, w, h, dx, dy); + } + + native void nativeDrawVolatile(long pointer, long srcPtr, int x, int y, + int w, int h ); + public void drawVolatile(long srcPtr, int x, int y, int w, int h ) + { + nativeDrawVolatile(nativePointer, srcPtr, x, y, w, h); + } + + public GtkVolatileImage(GtkComponentPeer component, + int width, int height, ImageCapabilities caps) + { + this.width = width; + this.height = height; + this.caps = caps; + this.component = component; + nativePointer = init( component, width, height ); + } + + public GtkVolatileImage(int width, int height, ImageCapabilities caps) + { + this(null, width, height, caps); + } + + public GtkVolatileImage(int width, int height) + { + this(null, width, height, null); + } + + public void finalize() + { + dispose(); + } + + public void dispose() + { + destroy(nativePointer); + } + + public BufferedImage getSnapshot() + { + WritableRaster raster = Raster.createWritableRaster(createGdkSampleModel(width, height), + new Point(0, 0)); + raster.setDataElements(0, 0, getPixels()); + return new BufferedImage(gdkColorModel, raster, + gdkColorModel.isAlphaPremultiplied(), null); + } + + public Graphics getGraphics() + { + return createGraphics(); + } + + public Graphics2D createGraphics() + { + return new VolatileImageGraphics( this ); + } + + public int validate(GraphicsConfiguration gc) + { + return VolatileImage.IMAGE_OK; + } + + public boolean contentsLost() + { + return false; + } + + public ImageCapabilities getCapabilities() + { + return caps; + } + + public int getWidth() + { + return width; + } + + public int getHeight() + { + return height; + } + + public int getWidth(java.awt.image.ImageObserver observer) + { + return width; + } + + public int getHeight(java.awt.image.ImageObserver observer) + { + return height; + } + + public Object getProperty(String name, ImageObserver observer) + { + return null; + } + + /** + * Creates a SampleModel that matches GDK's native format + */ + protected static SampleModel createGdkSampleModel(int w, int h) + { + return new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT, w, h, + new int[]{0x000000FF, 0x0000FF00, + 0x00FF0000, 0xFF000000}); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkWindowPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkWindowPeer.java new file mode 100644 index 000000000..c8e1bceb7 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkWindowPeer.java @@ -0,0 +1,437 @@ +/* GtkWindowPeer.java -- Implements WindowPeer with GTK + Copyright (C) 1998, 1999, 2002, 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.java.awt.peer.gtk; + +import gnu.java.awt.ComponentReshapeEvent; + +import java.awt.Component; +import java.awt.Font; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.KeyboardFocusManager; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Window; +import java.awt.event.ComponentEvent; +import java.awt.event.FocusEvent; +import java.awt.event.PaintEvent; +import java.awt.event.WindowEvent; +import java.awt.peer.WindowPeer; + +public class GtkWindowPeer extends GtkContainerPeer + implements WindowPeer +{ + protected static final int GDK_WINDOW_TYPE_HINT_NORMAL = 0; + protected static final int GDK_WINDOW_TYPE_HINT_DIALOG = 1; + protected static final int GDK_WINDOW_TYPE_HINT_MENU = 2; + protected static final int GDK_WINDOW_TYPE_HINT_TOOLBAR = 3; + protected static final int GDK_WINDOW_TYPE_HINT_SPLASHSCREEN = 4; + protected static final int GDK_WINDOW_TYPE_HINT_UTILITY = 5; + protected static final int GDK_WINDOW_TYPE_HINT_DOCK = 6; + protected static final int GDK_WINDOW_TYPE_HINT_DESKTOP = 7; + + protected int windowState = Frame.NORMAL; + + // Cached awt window component location, width and height. + private int x, y, width, height; + + native void gtkWindowSetTitle (String title); + native void gtkWindowSetResizable (boolean resizable); + native void gtkWindowSetModal (boolean modal); + native void gtkWindowSetAlwaysOnTop ( boolean alwaysOnTop ); + native boolean gtkWindowHasFocus(); + native void realize (); + + public void dispose() + { + super.dispose(); + GtkMainThread.destroyWindow(); + } + + /** Returns the cached width of the AWT window component. */ + int getX () + { + return x; + } + + /** Returns the cached width of the AWT window component. */ + int getY () + { + return y; + } + + /** Returns the cached width of the AWT window component. */ + int getWidth () + { + return width; + } + + /** Returns the cached height of the AWT window component. */ + int getHeight () + { + return height; + } + + native void create (int type, boolean decorated, GtkWindowPeer parent); + + void create (int type, boolean decorated) + { + Window window = (Window) awtComponent; + GtkWindowPeer parent_peer = null; + Component parent = awtComponent.getParent(); + x = awtComponent.getX(); + y = awtComponent.getY(); + height = awtComponent.getHeight(); + width = awtComponent.getWidth(); + + if (!window.isFocusableWindow()) + type = GDK_WINDOW_TYPE_HINT_MENU; + + if (parent != null) + parent_peer = (GtkWindowPeer) awtComponent.getParent().getPeer(); + + create (type, decorated, parent_peer); + } + + void create () + { + // Create a normal undecorated window. + create (GDK_WINDOW_TYPE_HINT_NORMAL, false); + } + + void setParent () + { + setVisible (awtComponent.isVisible ()); + setEnabled (awtComponent.isEnabled ()); + } + + void setVisibleAndEnabled () + { + } + + public native void setVisibleNative (boolean b); + public native void setVisibleNativeUnlocked (boolean b); + + native void connectSignals (); + + public GtkWindowPeer (Window window) + { + super (window); + // Set reasonable font for the window. + window.setFont(new Font("Dialog", Font.PLAIN, 12)); + } + + public native void toBack(); + public native void toFront(); + + 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); + + // Called from show. + protected void setLocation (int x, int y) + { + nativeSetLocation (x, y); + } + + public void setBounds (int x, int y, int width, int height) + { + if (x != getX() || y != getY() || width != getWidth() + || height != getHeight()) + { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + + nativeSetBounds (x, y, + width - insets.left - insets.right, + height - insets.top - insets.bottom); + } + } + + public void setTitle (String title) + { + gtkWindowSetTitle (title); + } + + // Called from setResizable + protected native void setSize (int width, int height); + + /** + * Needed by both GtkFramePeer and GtkDialogPeer subclasses, so + * implemented here. But never actually called on a GtkWindowPeer + * itself. + */ + public void setResizable (boolean resizable) + { + // Call setSize; otherwise when resizable is changed from true to + // false the window will shrink to the dimensions it had before it + // was resizable. + x = awtComponent.getX(); + y = awtComponent.getY(); + width = awtComponent.getWidth(); + height = awtComponent.getHeight(); + setSize (width - insets.left - insets.right, + height - insets.top - insets.bottom); + gtkWindowSetResizable (resizable); + } + + protected void postInsetsChangedEvent (int top, int left, + int bottom, int right) + { + insets.top = top; + insets.left = left; + insets.bottom = bottom; + insets.right = right; + } + + // called back by native side: window_configure_cb + // only called from GTK thread + protected void postConfigureEvent (int x, int y, int width, int height) + { + int frame_x = x - insets.left; + int frame_y = y - insets.top; + int frame_width = width + insets.left + insets.right; + int frame_height = height + insets.top + insets.bottom; + + // Update the component's knowledge about the size. + // Important: Please look at the big comment in ComponentReshapeEvent + // to learn why we did it this way. If you change this code, make + // sure that the peer->AWT bounds update still works. + // (for instance: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=29448 ) + + // We do this befor we post the ComponentEvent, because (in Window) + // we invalidate() / revalidate() when a ComponentEvent is seen, + // and the AWT must already know about the new size then. + if (frame_x != this.x || frame_y != this.y || frame_width != this.width + || frame_height != this.height) + { + ComponentReshapeEvent ev = new ComponentReshapeEvent(awtComponent, + frame_x, + frame_y, + frame_width, + frame_height); + awtComponent.dispatchEvent(ev); + } + + if (frame_width != getWidth() || frame_height != getHeight()) + { + this.width = frame_width; + this.height = frame_height; + q().postEvent(new ComponentEvent(awtComponent, + ComponentEvent.COMPONENT_RESIZED)); + } + + if (frame_x != getX() || frame_y != getY()) + { + this.x = frame_x; + this.y = frame_y; + q().postEvent(new ComponentEvent(awtComponent, + ComponentEvent.COMPONENT_MOVED)); + } + + } + + public void show () + { + x = awtComponent.getX(); + y = awtComponent.getY(); + width = awtComponent.getWidth(); + height = awtComponent.getHeight(); + setLocation(x, y); + setVisible (true); + } + + void postWindowEvent (int id, Window opposite, int newState) + { + if (id == WindowEvent.WINDOW_STATE_CHANGED) + { + if (windowState != newState) + { + // Post old styleWindowEvent with WINDOW_ICONIFIED or + // WINDOW_DEICONIFIED if appropriate. + if ((windowState & Frame.ICONIFIED) != 0 + && (newState & Frame.ICONIFIED) == 0) + q().postEvent(new WindowEvent((Window) awtComponent, + WindowEvent.WINDOW_DEICONIFIED, + opposite, 0, 0)); + else if ((windowState & Frame.ICONIFIED) == 0 + && (newState & Frame.ICONIFIED) != 0) + q().postEvent(new WindowEvent((Window) awtComponent, + WindowEvent.WINDOW_ICONIFIED, + opposite, 0, 0)); + // Post new-style WindowStateEvent. + q().postEvent (new WindowEvent ((Window) awtComponent, id, + opposite, windowState, newState)); + windowState = newState; + } + } + else + q().postEvent (new WindowEvent ((Window) awtComponent, id, opposite)); + } + + /** + * Update the always-on-top status of the native window. + */ + public void updateAlwaysOnTop() + { + gtkWindowSetAlwaysOnTop( ((Window)awtComponent).isAlwaysOnTop() ); + } + + protected void postExposeEvent (int x, int y, int width, int height) + { + // Translate GTK co-ordinates, which do not include a window + // frame's insets, to AWT co-ordinates, which do include a window + // frame's insets. GtkWindowPeer should always have all-zero + // insets but GtkFramePeer and GtkDialogPeer insets will be + // non-zero. + q().postEvent (new PaintEvent (awtComponent, PaintEvent.PAINT, + new Rectangle (x + insets.left, + y + insets.top, + width, height))); + } + + public boolean requestWindowFocus() + { + // TODO Auto-generated method stub + return false; + } + + public boolean requestFocus (Component request, boolean temporary, + boolean allowWindowFocus, long time) + { + assert request == awtComponent || isLightweightDescendant(request); + boolean retval = false; + if (gtkWindowHasFocus()) + { + KeyboardFocusManager kfm = + KeyboardFocusManager.getCurrentKeyboardFocusManager(); + Component currentFocus = kfm.getFocusOwner(); + if (currentFocus == request) + // Nothing to do in this trivial case. + retval = true; + else + { + // Requested component is a lightweight descendant of this one + // or the actual heavyweight. + // Since this (native) component is already focused, we simply + // change the actual focus and be done. + postFocusEvent(FocusEvent.FOCUS_GAINED, temporary); + retval = true; + } + } + else + { + if (allowWindowFocus) + { + retval = requestWindowFocus(); + } + } + return retval; + } + + public Graphics getGraphics () + { + Graphics g = super.getGraphics (); + // Translate AWT co-ordinates, which include a window frame's + // insets, to GTK co-ordinates, which do not include a window + // frame's insets. GtkWindowPeer should always have all-zero + // insets but GtkFramePeer and GtkDialogPeer insets will be + // non-zero. + g.translate (-insets.left, -insets.top); + return g; + } + + protected void postMouseEvent(int id, long when, int mods, int x, int y, + int clickCount, boolean popupTrigger) + { + // Translate AWT co-ordinates, which include a window frame's + // insets, to GTK co-ordinates, which do not include a window + // frame's insets. GtkWindowPeer should always have all-zero + // insets but GtkFramePeer and GtkDialogPeer insets will be + // non-zero. + super.postMouseEvent (id, when, mods, + x + insets.left, y + insets.top, + clickCount, popupTrigger); + } + + public Point getLocationOnScreen() + { + int point[] = new int[2]; + if (Thread.currentThread() == GtkMainThread.mainThread) + gtkWindowGetLocationOnScreenUnlocked(point); + else + gtkWindowGetLocationOnScreen(point); + return new Point(point[0], point[1]); + } + + // We override this to keep it in sync with our internal + // representation. + public Rectangle getBounds() + { + return new Rectangle(x, y, width, height); + } + + public void updateIconImages() + { + // TODO: Implement properly. + } + + public void updateMinimumSize() + { + // TODO: Implement properly. + } + + public void setModalBlocked(java.awt.Dialog d, boolean b) + { + // TODO: Implement properly. + } + + public void updateFocusableWindowState() + { + // TODO: Implement properly. + } + + public void setAlwaysOnTop(boolean b) + { + // TODO: Implement properly. + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/VolatileImageGraphics.java b/libjava/classpath/gnu/java/awt/peer/gtk/VolatileImageGraphics.java new file mode 100644 index 000000000..2dfcdbdec --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/VolatileImageGraphics.java @@ -0,0 +1,325 @@ +/* VolatileImageGraphics.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.java.awt.peer.gtk; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.Image; +import java.awt.Point; +import java.awt.Shape; +import java.awt.Toolkit; +import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; +import java.util.Hashtable; + +public class VolatileImageGraphics extends ComponentGraphics +{ + private GtkVolatileImage owner; + private BufferedImage buffer; + + public VolatileImageGraphics(GtkVolatileImage img) + { + this.owner = img; + cairo_t = initFromVolatile( owner.nativePointer ); + setup( cairo_t ); + } + + private VolatileImageGraphics(VolatileImageGraphics copy) + { + this.owner = copy.owner; + cairo_t = initFromVolatile(owner.nativePointer); + copy( copy, cairo_t ); + } + + public void copyAreaImpl(int x, int y, int width, int height, int dx, int dy) + { + owner.copyArea(x, y, width, height, dx, dy); + } + + public GraphicsConfiguration getDeviceConfiguration() + { + GraphicsConfiguration conf; + if (owner.component != null) + { + conf = owner.component.getGraphicsConfiguration(); + } + else + { + return java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration(); + } + return conf; + } + + public Graphics create() + { + return new VolatileImageGraphics( this ); + } + + public void draw(Shape s) + { + if (comp == null || comp instanceof AlphaComposite) + super.draw(s); + + // Custom composite + else + { + // Draw operation to temporary buffer + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setColor(this.getColor()); + g2d.setStroke(this.getStroke()); + g2d.draw(s); + + drawComposite(s.getBounds2D(), null); + } + } + + public void fill(Shape s) + { + if (comp == null || comp instanceof AlphaComposite) + super.fill(s); + + // Custom composite + else + { + // Draw operation to temporary buffer + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setPaint(this.getPaint()); + g2d.setColor(this.getColor()); + g2d.fill(s); + + drawComposite(s.getBounds2D(), null); + } + } + + public void drawGlyphVector(GlyphVector gv, float x, float y) + { + if (comp == null || comp instanceof AlphaComposite) + super.drawGlyphVector(gv, x, y); + + // Custom composite + else + { + // Draw operation to temporary buffer + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + + g2d.setPaint(this.getPaint()); + g2d.setColor(this.getColor()); + g2d.drawGlyphVector(gv, x, y); + + Rectangle2D bounds = gv.getLogicalBounds(); + bounds = new Rectangle2D.Double(x + bounds.getX(), y + bounds.getY(), + bounds.getWidth(), bounds.getHeight()); + drawComposite(bounds, null); + } + } + + protected boolean drawImage(Image img, AffineTransform xform, + Color bgcolor, ImageObserver obs) + { + if (comp == null || comp instanceof AlphaComposite) + return super.drawImage(img, xform, bgcolor, obs); + + // Custom composite + else + { + // Get buffered image of source + if( !(img instanceof BufferedImage) ) + { + ImageProducer source = img.getSource(); + if (source == null) + return false; + img = Toolkit.getDefaultToolkit().createImage(source); + } + BufferedImage bImg = (BufferedImage) img; + + // Find dimensions of translation + Point2D origin = new Point2D.Double(bImg.getMinX(), bImg.getMinY()); + Point2D pt = new Point2D.Double(bImg.getWidth(), bImg.getHeight()); + if (xform != null) + { + origin = xform.transform(origin, origin); + pt = xform.transform(pt, pt); + } + + // Create buffer and draw image + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setRenderingHints(this.getRenderingHints()); + g2d.drawImage(img, xform, obs); + + // Perform compositing from buffer to screen + return drawComposite(new Rectangle2D.Double((int)origin.getX(), + (int)origin.getY(), + (int)pt.getX(), + (int)pt.getY()), + obs); + } + } + + public boolean drawImage(Image img, int x, int y, ImageObserver observer) + { + if (img instanceof GtkVolatileImage + && (comp == null || comp instanceof AlphaComposite)) + { + owner.drawVolatile( ((GtkVolatileImage)img).nativePointer, + x, y, + ((GtkVolatileImage)img).width, + ((GtkVolatileImage)img).height ); + return true; + } + return super.drawImage( img, x, y, observer ); + } + + public boolean drawImage(Image img, int x, int y, int width, int height, + ImageObserver observer) + { + if ((img instanceof GtkVolatileImage) + && (comp == null || comp instanceof AlphaComposite)) + { + owner.drawVolatile( ((GtkVolatileImage)img).nativePointer, + x, y, width, height ); + return true; + } + return super.drawImage( img, x, y, width, height, observer ); + } + + protected Rectangle2D getRealBounds() + { + return new Rectangle2D.Double(0, 0, owner.width, owner.height); + } + + private boolean drawComposite(Rectangle2D bounds, ImageObserver observer) + { + // Clip source to visible areas that need updating + Rectangle2D clip = this.getClipBounds(); + Rectangle2D.intersect(bounds, clip, bounds); + + BufferedImage buffer2 = buffer; + if (!bounds.equals(buffer2.getRaster().getBounds())) + buffer2 = buffer2.getSubimage((int)bounds.getX(), (int)bounds.getY(), + (int)bounds.getWidth(), + (int)bounds.getHeight()); + + // Get current on-screen pixels (destination) and clip to bounds + BufferedImage current = owner.getSnapshot(); + + double[] points = new double[] {bounds.getX(), bounds.getY(), + bounds.getMaxX(), bounds.getMaxY()}; + transform.transform(points, 0, points, 0, 2); + + Rectangle2D deviceBounds = new Rectangle2D.Double(points[0], points[1], + points[2] - points[0], + points[3] - points[1]); + Rectangle2D.intersect(deviceBounds, this.getClipInDevSpace(), deviceBounds); + + current = current.getSubimage((int)deviceBounds.getX(), + (int)deviceBounds.getY(), + (int)deviceBounds.getWidth(), + (int)deviceBounds.getHeight()); + + // Perform actual composite operation + compCtx.compose(buffer2.getRaster(), current.getRaster(), + buffer2.getRaster()); + + // This MUST call directly into the "action" method in CairoGraphics2D, + // not one of the wrappers, to ensure that the composite isn't processed + // more than once! + Composite oldComp = comp; // so that ComponentGraphics doesn't + comp = null; // process the composite again + boolean rv = super.drawImage(buffer2, + AffineTransform.getTranslateInstance(bounds.getX(), + bounds.getY()), + null, null); + comp = oldComp; + + return rv; + } + + private void createBuffer() + { + if (buffer == null) + { + WritableRaster rst; + rst = Raster.createWritableRaster(GtkVolatileImage.createGdkSampleModel(owner.width, + owner.height), + new Point(0,0)); + + buffer = new BufferedImage(GtkVolatileImage.gdkColorModel, rst, + GtkVolatileImage.gdkColorModel.isAlphaPremultiplied(), + new Hashtable()); + } + else + { + Graphics2D g2d = ((Graphics2D)buffer.getGraphics()); + + g2d.setBackground(new Color(0,0,0,0)); + g2d.clearRect(0, 0, buffer.getWidth(), buffer.getHeight()); + } + } + + protected ColorModel getNativeCM() + { + // We should really return GtkVolatileImage.gdkColorModel , + // but CairoGraphics2D doesn't handle alpha premultiplication properly (see + // the fixme in drawImage) so we use the naive Cairo model instead to trick + // the compositing context. + // Because getNativeCM() == getBufferCM() for this peer, it doesn't break. + return CairoSurface.cairoCM_pre; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/package.html b/libjava/classpath/gnu/java/awt/peer/gtk/package.html new file mode 100644 index 000000000..8dd4dd892 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.awt.peer.gtk + + +

This package implements the GTK peer for java.awt.

+ + + diff --git a/libjava/classpath/gnu/java/awt/peer/headless/HeadlessGraphicsEnvironment.java b/libjava/classpath/gnu/java/awt/peer/headless/HeadlessGraphicsEnvironment.java new file mode 100644 index 000000000..401b895b8 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/headless/HeadlessGraphicsEnvironment.java @@ -0,0 +1,118 @@ +/* HeadlessGraphicsEnvironment.java -- A graphics environment for headless mode + 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.headless; + +import gnu.java.awt.java2d.RasterGraphics; + +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.HeadlessException; +import java.awt.image.BufferedImage; +import java.awt.image.Raster; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.Locale; + +public class HeadlessGraphicsEnvironment + extends GraphicsEnvironment +{ + + public Graphics2D createGraphics(BufferedImage image) + { + Graphics2D g2d; + try + { + // Try to get a CairoGraphics (accellerated) when available. Do this + // via reflection to avoid having a hard compile time dependency. + Class cairoSurfaceCl = + Class.forName("gnu.java.awt.peer.gtk.CairoSurface"); + Raster raster = image.getRaster(); + if (cairoSurfaceCl.isInstance(raster)) + { + Method getGraphicsM = cairoSurfaceCl.getMethod("getGraphics", + new Class[0]); + g2d = (Graphics2D) getGraphicsM.invoke(raster, new Object[0]); + } + else + { + Class bigCl = + Class.forName("gnu.java.awt.peer.gtk.BufferedImageGraphics"); + Constructor bigC = + bigCl.getConstructor(new Class[]{BufferedImage.class }); + g2d = (Graphics2D) bigC.newInstance(new Object[]{ image}); + } + } + catch (Exception ex) + { + g2d = new RasterGraphics(image.getRaster(), image.getColorModel()); + } + return g2d; + } + + public Font[] getAllFonts() + { + // FIXME: Implement. + return null; + } + + public String[] getAvailableFontFamilyNames() + { + // FIXME: Implement. + return null; + } + + public String[] getAvailableFontFamilyNames(Locale l) + { + // FIXME: Implement. + return null; + } + + public GraphicsDevice getDefaultScreenDevice() + { + throw new HeadlessException(); + } + + public GraphicsDevice[] getScreenDevices() + { + throw new HeadlessException(); + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/headless/HeadlessToolkit.java b/libjava/classpath/gnu/java/awt/peer/headless/HeadlessToolkit.java new file mode 100644 index 000000000..58b5f3334 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/headless/HeadlessToolkit.java @@ -0,0 +1,385 @@ +/* HeadlessToolkit.java -- A toolkit for headless mode + 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.headless; + +import gnu.java.awt.ClasspathToolkit; +import gnu.java.awt.EmbeddedWindow; +import gnu.java.awt.peer.ClasspathFontPeer; +import gnu.java.awt.peer.EmbeddedWindowPeer; + +import java.awt.AWTException; +import java.awt.Button; +import java.awt.Canvas; +import java.awt.Checkbox; +import java.awt.CheckboxMenuItem; +import java.awt.Choice; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FileDialog; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Frame; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.HeadlessException; +import java.awt.Image; +import java.awt.Label; +import java.awt.List; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.PopupMenu; +import java.awt.PrintJob; +import java.awt.ScrollPane; +import java.awt.Scrollbar; +import java.awt.TextArea; +import java.awt.TextField; +import java.awt.Window; +import java.awt.datatransfer.Clipboard; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.peer.DragSourceContextPeer; +import java.awt.im.InputMethodHighlight; +import java.awt.image.ColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.peer.ButtonPeer; +import java.awt.peer.CanvasPeer; +import java.awt.peer.CheckboxMenuItemPeer; +import java.awt.peer.CheckboxPeer; +import java.awt.peer.ChoicePeer; +import java.awt.peer.DialogPeer; +import java.awt.peer.FileDialogPeer; +import java.awt.peer.FontPeer; +import java.awt.peer.FramePeer; +import java.awt.peer.LabelPeer; +import java.awt.peer.ListPeer; +import java.awt.peer.MenuBarPeer; +import java.awt.peer.MenuItemPeer; +import java.awt.peer.MenuPeer; +import java.awt.peer.PanelPeer; +import java.awt.peer.PopupMenuPeer; +import java.awt.peer.RobotPeer; +import java.awt.peer.ScrollPanePeer; +import java.awt.peer.ScrollbarPeer; +import java.awt.peer.TextAreaPeer; +import java.awt.peer.TextFieldPeer; +import java.awt.peer.WindowPeer; +import java.io.InputStream; +import java.net.URL; +import java.util.Map; +import java.util.Properties; + +public class HeadlessToolkit + extends ClasspathToolkit +{ + + /** + * The graphics environment for headless graphics. + */ + private HeadlessGraphicsEnvironment graphicsEnv; + + public void beep() + { + // TODO Auto-generated method stub + + } + + public int checkImage(Image image, int width, int height, + ImageObserver observer) + { + // TODO Auto-generated method stub + return 0; + } + + protected ButtonPeer createButton(Button target) + { + throw new HeadlessException(); + } + + protected CanvasPeer createCanvas(Canvas target) + { + throw new HeadlessException(); + } + + protected CheckboxPeer createCheckbox(Checkbox target) + { + throw new HeadlessException(); + } + + protected CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem target) + { + throw new HeadlessException(); + } + + protected ChoicePeer createChoice(Choice target) + { + throw new HeadlessException(); + } + + protected DialogPeer createDialog(Dialog target) + { + throw new HeadlessException(); + } + + public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent e) + { + throw new HeadlessException(); + } + + protected FileDialogPeer createFileDialog(FileDialog target) + { + throw new HeadlessException(); + } + + protected FramePeer createFrame(Frame target) + { + throw new HeadlessException(); + } + + public Image createImage(String filename) + { + // FIXME: Implement. + return null; + } + + public Image createImage(URL url) + { + // FIXME: Implement. + return null; + } + + public Image createImage(ImageProducer producer) + { + // FIXME: Implement. + return null; + } + + public Image createImage(byte[] data, int offset, int len) + { + // TODO Auto-generated method stub + return null; + } + + protected LabelPeer createLabel(Label target) + { + throw new HeadlessException(); + } + + protected ListPeer createList(List target) + { + throw new HeadlessException(); + } + + protected MenuPeer createMenu(Menu target) + { + throw new HeadlessException(); + } + + protected MenuBarPeer createMenuBar(MenuBar target) + { + throw new HeadlessException(); + } + + protected MenuItemPeer createMenuItem(MenuItem target) + { + throw new HeadlessException(); + } + + protected PanelPeer createPanel(Panel target) + { + throw new HeadlessException(); + } + + protected PopupMenuPeer createPopupMenu(PopupMenu target) + { + throw new HeadlessException(); + } + + protected ScrollPanePeer createScrollPane(ScrollPane target) + { + throw new HeadlessException(); + } + + protected ScrollbarPeer createScrollbar(Scrollbar target) + { + throw new HeadlessException(); + } + + protected TextAreaPeer createTextArea(TextArea target) + { + throw new HeadlessException(); + } + + protected TextFieldPeer createTextField(TextField target) + { + throw new HeadlessException(); + } + + protected WindowPeer createWindow(Window target) + { + throw new HeadlessException(); + } + + public ColorModel getColorModel() + { + // TODO Auto-generated method stub + return null; + } + + public String[] getFontList() + { + // TODO Auto-generated method stub + return null; + } + + public FontMetrics getFontMetrics(Font name) + { + // TODO Auto-generated method stub + return null; + } + + protected FontPeer getFontPeer(String name, int style) + { + // TODO Auto-generated method stub + return null; + } + + public Image getImage(String name) + { + // TODO Auto-generated method stub + return null; + } + + public Image getImage(URL url) + { + // TODO Auto-generated method stub + return null; + } + + public PrintJob getPrintJob(Frame frame, String title, Properties props) + { + // TODO Auto-generated method stub + return null; + } + + public int getScreenResolution() + { + throw new HeadlessException(); + } + + public Dimension getScreenSize() + { + throw new HeadlessException(); + } + + public Clipboard getSystemClipboard() + { + throw new HeadlessException(); + } + + protected EventQueue getSystemEventQueueImpl() + { + throw new HeadlessException(); + } + + public Map mapInputMethodHighlight(InputMethodHighlight highlight) + { + // TODO Auto-generated method stub + return null; + } + + public boolean prepareImage(Image image, int width, int height, + ImageObserver observer) + { + // TODO Auto-generated method stub + return false; + } + + public void sync() + { + // TODO Auto-generated method stub + + } + + public EmbeddedWindowPeer createEmbeddedWindow(EmbeddedWindow w) + { + throw new HeadlessException(); + } + + public Font createFont(int format, InputStream stream) + { + // TODO Auto-generated method stub + return null; + } + + public RobotPeer createRobot(GraphicsDevice screen) throws AWTException + { + throw new HeadlessException(); + } + + public ClasspathFontPeer getClasspathFontPeer(String name, Map attrs) + { + // TODO Auto-generated method stub + return null; + } + + public GraphicsEnvironment getLocalGraphicsEnvironment() + { + if (graphicsEnv == null) + graphicsEnv = new HeadlessGraphicsEnvironment(); + return graphicsEnv; + } + + @Override + public boolean isModalExclusionTypeSupported + (Dialog.ModalExclusionType modalExclusionType) + { + return false; + } + + @Override + public boolean isModalityTypeSupported(Dialog.ModalityType modalityType) + { + return false; + } + + +} diff --git a/libjava/classpath/gnu/java/awt/peer/package.html b/libjava/classpath/gnu/java/awt/peer/package.html new file mode 100644 index 000000000..846759a28 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.awt.peer + + +

+ + + diff --git a/libjava/classpath/gnu/java/awt/peer/qt/MainQtThread.java b/libjava/classpath/gnu/java/awt/peer/qt/MainQtThread.java new file mode 100644 index 000000000..bee979ac7 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/MainQtThread.java @@ -0,0 +1,84 @@ +/* MainQtThread.java -- + 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.java.awt.peer.qt; + +/** + * This Thread is the main Qt thread. + * + * It doesn't appear to do much here, since all custom code executed by + * this thread is injected into Qt's main event loop through the (native) + * MainThreadInterface class. + */ +public class MainQtThread extends Thread +{ + long QApplicationPointer; + long mainThreadInterface; + String theme; + private boolean running; + private boolean doublebuffer; + + public MainQtThread( String theme, boolean doublebuffer ) + { + this.theme = theme; + this.doublebuffer = doublebuffer; + running = false; + } + + public boolean isRunning() + { + return running; + } + + /** + * Creates the QApplication + */ + public native long init(String theme, boolean doublebuffer); + + /** + * Runs the QApplication (doesn't return.) + */ + public native void exec(long ptr); + + public void run() + { + QApplicationPointer = init(theme, doublebuffer); + running = true; + exec(QApplicationPointer); + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/NativeWrapper.java b/libjava/classpath/gnu/java/awt/peer/qt/NativeWrapper.java new file mode 100644 index 000000000..706e0df6c --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/NativeWrapper.java @@ -0,0 +1,43 @@ +/* NativeWrapper.java -- + 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.java.awt.peer.qt; + +public class NativeWrapper +{ + protected long nativeObject; +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QMatrix.java b/libjava/classpath/gnu/java/awt/peer/qt/QMatrix.java new file mode 100644 index 000000000..ca4d55b59 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QMatrix.java @@ -0,0 +1,72 @@ +/* QMatrix.java -- + 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.java.awt.peer.qt; + +import java.awt.geom.AffineTransform; + +/** + * A simple wrapper class for a QMatrix, + * interfacing it to an AffineTransform. + */ +public class QMatrix extends NativeWrapper +{ + + public QMatrix( AffineTransform t ) + { + double[] matrix = new double[6]; + t.getMatrix( matrix ); + init( matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5] ); + } + + private native void init(double m00, double m10, double m01, double m11, + double m02, double m12 ); + + private native double[] getMatrix(); + + public AffineTransform getTransform() + { + return new AffineTransform( getMatrix() ); + } + + public native void dispose(); + + public void finalize() + { + dispose(); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QPainterPath.java b/libjava/classpath/gnu/java/awt/peer/qt/QPainterPath.java new file mode 100644 index 000000000..848b10497 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QPainterPath.java @@ -0,0 +1,140 @@ +/* QPainterPath.java -- + 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.java.awt.peer.qt; + +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.PathIterator; +import java.awt.geom.GeneralPath; + +/** + * A simple wrapper class for a QPainterPath, + * createable from an AWT Shape + */ +public class QPainterPath extends NativeWrapper +{ + QPainterPath() + { + } + + public QPainterPath( Shape s ) + { + PathIterator pi = s.getPathIterator( new AffineTransform() ); + double[] coords = new double[6]; + + init( pi.getWindingRule() ); + + while( !pi.isDone() ) + { + switch( pi.currentSegment(coords) ) + { + case PathIterator.SEG_MOVETO: + moveTo( coords[0], coords[1] ); + break; + + case PathIterator.SEG_CLOSE: + close(); + break; + + case PathIterator.SEG_LINETO: + lineTo( coords[0], coords[1] ); + break; + + case PathIterator.SEG_QUADTO: + quadTo( coords[0], coords[1], coords[2], coords[3] ); + break; + + case PathIterator.SEG_CUBICTO: + cubicTo( coords[0], coords[1], + coords[2], coords[3], + coords[4], coords[5] ); + break; + } + pi.next(); + } + } + + /** + * Constructor for rectangles. + */ + public QPainterPath( double x, double y, double w, double h ) + { + init(PathIterator.WIND_EVEN_ODD); + moveTo( x, y ); + lineTo( x + w, y ); + lineTo( x + w, y + h ); + lineTo( x , y + h ); + lineTo( x, y ); + close(); + } + + /** + * Constructor for lines. + */ + public QPainterPath( double x1, double y1, double x2, double y2, boolean s ) + { + init(PathIterator.WIND_EVEN_ODD); + moveTo( x1, y1 ); + lineTo( x2, y2 ); + } + + /** + * Returns the QPainterPath as a GeneralPath + */ + public native GeneralPath getPath(); + + private native void init(int windingRule); + + private native void moveTo(double x, double y); + + private native void close(); + + private native void lineTo(double x, double y); + + private native void quadTo(double x1, double y1, double x2, double y2); + + private native void cubicTo(double x1, double y1, double x2, double y2, + double x3, double y3); + + public native void dispose(); + + public void finalize() + { + dispose(); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QPen.java b/libjava/classpath/gnu/java/awt/peer/qt/QPen.java new file mode 100644 index 000000000..aee308c26 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QPen.java @@ -0,0 +1,70 @@ +/* QPen.java -- + 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.java.awt.peer.qt; + +import java.awt.Stroke; +import java.awt.BasicStroke; + +/** + * A simple wrapper class for a QPen, + * interfacing it to an BasicStroke. + */ +public class QPen extends NativeWrapper +{ + + public QPen( Stroke stroke ) + { + if( !( stroke instanceof BasicStroke ) ) + throw new IllegalArgumentException("Not a basic stroke."); + + BasicStroke s = (BasicStroke)stroke; + if(s.getDashArray() != null) + throw new IllegalArgumentException("Can't handle dashed strokes."); + + init(s.getLineWidth(), s.getEndCap(), s.getLineJoin(), s.getMiterLimit()); + } + + private native void init(double width, int cap, int join, double miterlimit); + + public native void dispose(); + + public void finalize() + { + dispose(); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtAudioClip.java b/libjava/classpath/gnu/java/awt/peer/qt/QtAudioClip.java new file mode 100644 index 000000000..ae2e350eb --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtAudioClip.java @@ -0,0 +1,110 @@ +/* QtAudioClip.java -- Qt implementation of the applet AudioClip interface + 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.java.awt.peer.qt; + +import java.applet.AudioClip; +import java.awt.Toolkit; +import java.io.File; +import java.io.IOException; +import java.net.URL; + +/** + * Implementation of the applet AudioClip interface on a Qt + * QSound object. + */ +public class QtAudioClip extends NativeWrapper implements AudioClip +{ + private static Toolkit t = null; + + public QtAudioClip(String filename) + { + checkForQt(); + File f = new File(filename); + try + { + String fn = f.getCanonicalPath(); + loadClip( fn ); + } + catch(IOException e) + { + } + } + + public QtAudioClip(URL url) + { + + } + + private native void loadClip(String filename); + + private native void play(boolean looped); + + private native boolean isAvailable(); + + /** + * Checks that Qt and sound is available. + */ + private void checkForQt() + { + if( t == null ) + t = Toolkit.getDefaultToolkit(); + if( !( t instanceof QtToolkit) ) + throw new IllegalStateException("This requires Qt peers."); + } + + // *************** Public methods ******************* + + public void loop() + { + play( true ); + } + + public void play() + { + play( false ); + } + + public native void stop(); + + public native void dispose(); + + public void finalize() + { + dispose(); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtButtonPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtButtonPeer.java new file mode 100644 index 000000000..6722eb285 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtButtonPeer.java @@ -0,0 +1,75 @@ +/* QtButtonPeer.java -- + 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.java.awt.peer.qt; + +import java.awt.Button; +import java.awt.event.ActionEvent; +import java.awt.peer.ButtonPeer; + +public class QtButtonPeer extends QtComponentPeer implements ButtonPeer +{ + public QtButtonPeer( QtToolkit kit, Button owner ) + { + super( kit, owner ); + } + + public native void init(); + + protected void setup() + { + super.setup(); + setLabel( ((Button)owner).getLabel() ); + } + + /** + * Callback for button click events + */ + void fireClick(int modifiers) + { + ActionEvent e = new ActionEvent(owner, + ActionEvent.ACTION_PERFORMED, + ((Button)owner).getActionCommand(), + System.currentTimeMillis(), + modifiers); + QtToolkit.eventQueue.postEvent(e); + } + + // ************ Public methods ********************* + + public native void setLabel( String label ); +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtCanvasPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtCanvasPeer.java new file mode 100644 index 000000000..2367cd066 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtCanvasPeer.java @@ -0,0 +1,65 @@ +/* QtCanvasPeer.java -- + 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.java.awt.peer.qt; + +import java.awt.Canvas; +import java.awt.Dimension; +import java.awt.peer.CanvasPeer; + +public class QtCanvasPeer extends QtComponentPeer implements CanvasPeer +{ + public QtCanvasPeer( QtToolkit kit, Canvas owner ) + { + super( kit, owner ); + } + + public native void init(); + + protected void setup() + { + super.setup(); + } + + /** + * Overloaded, because a Canvas doesn't have a preferred size. + */ + public Dimension getPreferredSize() + { + return owner.getSize(); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtCheckboxPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtCheckboxPeer.java new file mode 100644 index 000000000..37fb51c48 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtCheckboxPeer.java @@ -0,0 +1,111 @@ +/* QtCheckboxPeer.java -- + 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.java.awt.peer.qt; + +import java.awt.Checkbox; +import java.awt.CheckboxGroup; +import java.awt.event.ItemEvent; +import java.awt.peer.CheckboxPeer; +import java.util.WeakHashMap; + +public class QtCheckboxPeer extends QtComponentPeer implements CheckboxPeer +{ + private CheckboxGroup group; + + // Map QButtonGroup<->CheckboxGroup + private static WeakHashMap groupMap; + + static + { + groupMap = new WeakHashMap(); + } + + public QtCheckboxPeer( QtToolkit kit, Checkbox owner ) + { + super( kit, owner ); + } + + protected native void init(); + + protected void setup() + { + super.setup(); + setCheckboxGroup( ((Checkbox)owner).getCheckboxGroup() ); + setLabel( ((Checkbox)owner).getLabel() ); + setState( ((Checkbox)owner).getState() ); + } + + private void fireToggle(boolean checked) + { + if (group == null) + ((Checkbox)owner).setState( checked ); + else + if ( checked ) + group.setSelectedCheckbox((Checkbox)owner); + + int sel = checked ? ItemEvent.SELECTED : ItemEvent.DESELECTED; + ItemEvent e = new ItemEvent((Checkbox)owner, + ItemEvent.ITEM_STATE_CHANGED, + ((Checkbox)owner).getLabel(), + sel); + QtToolkit.eventQueue.postEvent(e); + } + + // ************ Public methods ********************* + + public void setCheckboxGroup( CheckboxGroup group ) + { + if(this.group == group) + return; + + // if we change from a checkbox to a radio button or vice versa + if((this.group == null) != (group == null)) + { + this.group = group; + callInit(); + setup(); + } + + this.group = group; + } + + public native void setLabel( String label ); + + public native void setState( boolean state ); + +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtChoicePeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtChoicePeer.java new file mode 100644 index 000000000..d279468cd --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtChoicePeer.java @@ -0,0 +1,93 @@ +/* QtChoicePeer.java -- + 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.java.awt.peer.qt; + +import java.awt.Choice; +import java.awt.event.ItemEvent; +import java.awt.peer.ChoicePeer; + +public class QtChoicePeer extends QtComponentPeer implements ChoicePeer +{ + public QtChoicePeer( QtToolkit kit, Choice owner ) + { + super( kit, owner ); + } + + protected native void init(); + + protected void setup() + { + super.setup(); + + Choice c = (Choice) owner; + int n = c.getItemCount(); + for ( int i = 0; i < n ; i++ ) + add( c.getItem( i ), i ); + select( c.getSelectedIndex() ); + } + + private void fireChoice( int index ) + { + ((Choice)owner).select( index ); + ItemEvent e = new ItemEvent((Choice)owner, + ItemEvent.ITEM_STATE_CHANGED, + ((Choice)owner).getItem(index), + ItemEvent.SELECTED); + QtToolkit.eventQueue.postEvent(e); + } + + // ************ Public methods ********************* + + public native void add( String item, int index ); + + public void addItem( String item, int index ) + { + add(item, index); + } + + public native void remove( int index ); + + public void removeAll() + { + int n = ((Choice)owner).getItemCount(); + for (int i = 0; i < n; i++) + remove( i ); + } + + public native void select( int index ); +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtComponentGraphics.java b/libjava/classpath/gnu/java/awt/peer/qt/QtComponentGraphics.java new file mode 100644 index 000000000..27e12e659 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtComponentGraphics.java @@ -0,0 +1,120 @@ +/* QtComponentGraphics.java -- + 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.java.awt.peer.qt; + +import java.awt.Color; +import java.awt.GraphicsConfiguration; +import java.awt.Graphics; +import java.awt.Rectangle; + +/** + * QtComponentPainter is a Graphics2D context for painting directly to AWT + * components. They require an existing QPainter object (the one passed into + * the native paint method), and are created there (ONLY). + * + * Since this context does direct on-screen drawing it is NOT thread-safe, + * and should NOT be used outside the thread in which it was created. + * + * In other words, + * this is intended for use by QtComponentPeer.paintEvent() only. + * + */ +public class QtComponentGraphics extends QtGraphics +{ + private QtComponentPeer peer; + + /** + * Creates a new ComponentGraphics from an *existing* QPainter object. + * + * @param ptr the pointer to the QPainter object. + */ + public QtComponentGraphics(long ptr, QtComponentPeer component, + int x, int y, int w, int h) + { + nativeObject = ptr; + peer = component; + + Rectangle r = new Rectangle(x, y, w, h); + initialClip = r; + + setAlpha( 1.0 ); + Color c = component.owner.getBackground(); + if(c == null) + setBackground(Color.white); + else + setBackground( c ); + + c = component.owner.getForeground(); + if(c == null) + setColor( Color.black ); + else + setColor( c ); + setup(); + setClip( initialClip ); + } + + /** + * Copying constructor + */ + QtComponentGraphics( QtComponentGraphics g ) + { + super( g ); // Slalom is fun + } + + public Graphics create() + { + return new QtComponentGraphics( this ); + } + + /** + * This is a tricky one + */ + public void copyArea(int x, int y, int width, int height, + int dx, int dy) + { + // FIXME + } + + /** + * Returns the GraphicsConfiguration of the context component. + */ + public GraphicsConfiguration getDeviceConfiguration() + { + return peer.getGraphicsConfiguration(); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtComponentPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtComponentPeer.java new file mode 100644 index 000000000..16149b2e6 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtComponentPeer.java @@ -0,0 +1,834 @@ +/* QtComponentPeer.java -- + 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.java.awt.peer.qt; + +import java.awt.AWTEvent; +import java.awt.AWTException; +import java.awt.BufferCapabilities; +import java.awt.Component; +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Image; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.KeyboardFocusManager; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.Window; +import java.awt.peer.ComponentPeer; +import java.awt.peer.ContainerPeer; +import java.awt.image.ColorModel; +import java.awt.image.VolatileImage; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.event.ComponentEvent; // 100% +import java.awt.event.FocusEvent; // 100% +import java.awt.event.InputEvent; // (abstract) +import java.awt.event.KeyEvent; // 2/3 +import java.awt.event.MouseEvent; // 70%? +import java.awt.event.PaintEvent; // Yup. +import java.awt.event.WindowEvent; // 2/ 12 +import java.util.Timer; +import java.util.TimerTask; + +public class QtComponentPeer extends NativeWrapper implements ComponentPeer +{ + + /** + * Popup trigger button, may differ between platforms + */ + protected static final int POPUP_TRIGGER = 3; + + /** + * The toolkit which manufactured this peer. + */ + protected QtToolkit toolkit; + + /** + * The component which owns this peer. + */ + Component owner; + + /** + * Classpath updates our eventMask. + */ + private long eventMask; + + /** + * if the thing has mouse motion listeners or not. + */ + private boolean hasMotionListeners; + + /** + * The component's double buffer for off-screen drawing. + */ + protected QtImage backBuffer; + + protected long qtApp; + + private boolean settingUp; + + private boolean ignoreResize = false; + + QtComponentPeer( QtToolkit kit, Component owner ) + { + this.owner = owner; + this.toolkit = kit; + qtApp = QtToolkit.guiThread.QApplicationPointer; + nativeObject = 0; + synchronized(this) + { + callInit(); // Calls the init method FROM THE MAIN THREAD. + try + { + wait(); // Wait for the thing to be created. + } + catch(InterruptedException e) + { + } + } + setup(); + hasMotionListeners = false; + } + + protected native void callInit(); + + /** + * Init does the creation of native widgets, it is therefore + * called from the main thread. (the constructor waits for this to happen.) + */ + protected void init() + { + } + + protected void setup() + { + settingUp = true; + if (owner != null) + { + if (owner instanceof javax.swing.JComponent) + setBackground(owner.getBackground()); + else + owner.setBackground(getNativeBackground()); + + if (owner.getForeground() != null) + setForeground(owner.getForeground()); + else + setForeground( Color.black ); + + if (owner.getCursor() != null) + if (owner.getCursor().getType() != Cursor.DEFAULT_CURSOR) + setCursor(owner.getCursor()); + + if (owner.getFont() != null) + setFont(owner.getFont()); + + setEnabled( owner.isEnabled() ); + + backBuffer = null; + updateBounds(); + + setVisible( owner.isVisible() ); + QtToolkit.repaintThread.queueComponent(this); + } + settingUp = false; + } + + native void QtUpdate(); + native void QtUpdateArea( int x, int y, int w, int h ); + private synchronized native void disposeNative(); + private native void setGround( int r, int g, int b, boolean isForeground ); + private native void setBoundsNative( int x, int y, int width, int height ); + private native void setCursor( int ctype ); + private native Color getNativeBackground(); + private native void setFontNative( QtFontPeer fp ); + private native int whichScreen(); + private native void reparentNative( QtContainerPeer parent ); + private native void getLocationOnScreenNative( Point p ); + + private boolean drawableComponent() + { + return ((this instanceof QtContainerPeer && + !(this instanceof QtScrollPanePeer)) || + (this instanceof QtCanvasPeer)); + } + + void updateBounds() + { + Rectangle r = owner.getBounds(); + setBounds( r.x, r.y, r.width, r.height ); + } + + synchronized void updateBackBuffer(int width, int height) + { + if(width <= 0 || height <= 0) + return; + + if( !drawableComponent() && backBuffer == null) + return; + + if( backBuffer != null ) + { + if( width < backBuffer.width && height < backBuffer.height ) + return; + backBuffer.dispose(); + } + backBuffer = new QtImage(width, height); + } + + + // ************ Event methods ********************* + + /** + * Window closing event + */ + protected void closeEvent() + { + if (owner instanceof Window) + { + WindowEvent e = new WindowEvent((Window)owner, + WindowEvent.WINDOW_CLOSING); + QtToolkit.eventQueue.postEvent(e); + } + } + + protected void enterEvent(int modifiers, int x, int y, int dummy) + { + MouseEvent e = new MouseEvent(owner, + MouseEvent.MOUSE_ENTERED, + System.currentTimeMillis(), + (modifiers & 0x2FF), x, y, 0, false); + QtToolkit.eventQueue.postEvent(e); + } + + protected void focusInEvent() + { + FocusEvent e = new FocusEvent(owner, FocusEvent.FOCUS_GAINED); + QtToolkit.eventQueue.postEvent(e); + } + + protected void focusOutEvent() + { + FocusEvent e = new FocusEvent(owner, FocusEvent.FOCUS_LOST); + QtToolkit.eventQueue.postEvent(e); + } + + protected void keyPressEvent(int modifiers, int code, int unicode, int dummy) + { + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + KeyEvent e = new KeyEvent(owner, + KeyEvent.KEY_PRESSED, + System.currentTimeMillis(), + modifiers, code, (char)(unicode & 0xFFFF), + KeyEvent.KEY_LOCATION_UNKNOWN); + if (!manager.dispatchEvent (e)) + QtToolkit.eventQueue.postEvent(e); + } + + protected void keyReleaseEvent(int modifiers, int code, int unicode, int dummy) + { + KeyEvent e = new KeyEvent(owner, + KeyEvent.KEY_RELEASED, + System.currentTimeMillis(), + modifiers, code, (char)(unicode & 0xFFFF), + KeyEvent.KEY_LOCATION_UNKNOWN); + QtToolkit.eventQueue.postEvent(e); + } + + protected void leaveEvent(int modifiers, int x, int y, int dummy) + { + MouseEvent e = new MouseEvent(owner, + MouseEvent.MOUSE_EXITED, + System.currentTimeMillis(), + (modifiers & 0x2FF), x, y, 0, false); + QtToolkit.eventQueue.postEvent(e); + } + + // FIXME: Coalesce press-release events into clicks. + protected void mouseDoubleClickEvent( int modifiers, int x, int y, int clickCount) + { + if( (eventMask & AWTEvent.MOUSE_EVENT_MASK) == 0 ) + return; + int button = 0; + if((modifiers & InputEvent.BUTTON1_DOWN_MASK) == + InputEvent.BUTTON1_DOWN_MASK) button = 1; + if((modifiers & InputEvent.BUTTON2_DOWN_MASK) == + InputEvent.BUTTON2_DOWN_MASK) button = 2; + if((modifiers & InputEvent.BUTTON3_DOWN_MASK) == + InputEvent.BUTTON3_DOWN_MASK) button = 3; + MouseEvent e = new MouseEvent(owner, + MouseEvent.MOUSE_CLICKED, + System.currentTimeMillis(), + (modifiers & 0x2FF), x, y, clickCount, + false, button); + QtToolkit.eventQueue.postEvent(e); + } + + protected void mouseMoveEvent( int modifiers, int x, int y, int clickCount) + { + if( (eventMask & AWTEvent.MOUSE_EVENT_MASK) == 0 ) + return; + + int button = 0; + if((modifiers & InputEvent.BUTTON1_DOWN_MASK) == + InputEvent.BUTTON1_DOWN_MASK) button = 1; + if((modifiers & InputEvent.BUTTON2_DOWN_MASK) == + InputEvent.BUTTON2_DOWN_MASK) button = 2; + if((modifiers & InputEvent.BUTTON3_DOWN_MASK) == + InputEvent.BUTTON3_DOWN_MASK) button = 3; + + int type = (button != 0) ? + MouseEvent.MOUSE_DRAGGED :MouseEvent.MOUSE_MOVED; + + MouseEvent e = new MouseEvent(owner, + type, + System.currentTimeMillis(), + (modifiers & 0x2FF), x, y, clickCount, + false, button); + QtToolkit.eventQueue.postEvent(e); + } + + protected void mousePressEvent( int modifiers, int x, int y, int clickCount) + { + if( (eventMask & AWTEvent.MOUSE_EVENT_MASK) == 0 ) + return; + int button = 0; + if((modifiers & InputEvent.BUTTON1_DOWN_MASK) == + InputEvent.BUTTON1_DOWN_MASK) button = 1; + if((modifiers & InputEvent.BUTTON2_DOWN_MASK) == + InputEvent.BUTTON2_DOWN_MASK) button = 2; + if((modifiers & InputEvent.BUTTON3_DOWN_MASK) == + InputEvent.BUTTON3_DOWN_MASK) button = 3; + MouseEvent e = new MouseEvent(owner, + MouseEvent.MOUSE_PRESSED, + System.currentTimeMillis(), + (modifiers & 0x2FF), x, y, clickCount, + ( button == POPUP_TRIGGER ), + button); + QtToolkit.eventQueue.postEvent(e); + } + + protected void mouseReleaseEvent( int modifiers, int x, int y, int clickCount) + { + if( (eventMask & AWTEvent.MOUSE_EVENT_MASK) == 0 ) + return; + int button = 0; + if((modifiers & InputEvent.BUTTON1_DOWN_MASK) == + InputEvent.BUTTON1_DOWN_MASK) button = 1; + if((modifiers & InputEvent.BUTTON2_DOWN_MASK) == + InputEvent.BUTTON2_DOWN_MASK) button = 2; + if((modifiers & InputEvent.BUTTON3_DOWN_MASK) == + InputEvent.BUTTON3_DOWN_MASK) button = 3; + + MouseEvent e = new MouseEvent(owner, + MouseEvent.MOUSE_RELEASED, + System.currentTimeMillis(), + (modifiers & 0x2FF), x, y, clickCount, + false, button); + QtToolkit.eventQueue.postEvent(e); + } + + protected void moveEvent(int x, int y, int oldx, int oldy) + { + if( !ignoreResize ) + { + // Since Component.setLocation calls back to setBounds, + // we need to ignore that. + ignoreResize = true; + owner.setLocation( x, y ); + ignoreResize = false; + } + } + + protected void resizeEvent(int oldWidth, int oldHeight, + int width, int height) + { + if(!(owner instanceof Window)) + return; + updateBackBuffer(width, height); + ignoreResize = true; + owner.setSize(width, height); + ignoreResize = false; + ComponentEvent e = new ComponentEvent(owner, + ComponentEvent.COMPONENT_RESIZED); + QtToolkit.eventQueue.postEvent(e); + QtToolkit.repaintThread.queueComponent(this); + } + + protected void showEvent() + { + if (owner instanceof Window) + { + WindowEvent e = new WindowEvent((Window)owner, + WindowEvent.WINDOW_OPENED); + QtToolkit.eventQueue.postEvent(e); + } + else + { + ComponentEvent e = new ComponentEvent(owner, + ComponentEvent.COMPONENT_SHOWN); + QtToolkit.eventQueue.postEvent(e); + } + } + + protected void hideEvent() + { + ComponentEvent e = new ComponentEvent(owner, + ComponentEvent.COMPONENT_HIDDEN); + QtToolkit.eventQueue.postEvent(e); + } + + // ************ Public methods ********************* + + /** Classpath-specific method */ + public void setEventMask(long x) + { + eventMask = x; + } + + + public boolean canDetermineObscurity() + { + return true; + } + + public int checkImage(Image img, + int w, + int h, + ImageObserver o) + { + return toolkit.checkImage(img, w, h, o); + } + + public void createBuffers(int numBuffers, BufferCapabilities caps) + throws AWTException + { + // FIXME + } + + public Image createImage(ImageProducer producer) + { + return toolkit.createImage(producer); + } + + public Image createImage(int width, int height) + { + return new QtImage(width, height); + } + + public void coalescePaintEvent(PaintEvent e) + { + // FIXME + } + + public VolatileImage createVolatileImage(int w, int h) + { + return new QtVolatileImage( w, h ); + } + + public void destroyBuffers() + { + // FIXME + } + + public void disable() + { + setEnabled(false); + } + + public void dispose() + { + disposeNative(); + if( backBuffer != null ) + backBuffer.dispose(); + } + + public void enable() + { + setEnabled(true); + } + + public void finalize() + { + dispose(); + } + + public void flip(BufferCapabilities.FlipContents contents) + { + } + + public Image getBackBuffer() + { + return backBuffer; + } + + public ColorModel getColorModel() + { + return toolkit.getColorModel(); + } + + public FontMetrics getFontMetrics(Font font) + { + return new QtFontMetrics( font, getGraphics() ); + } + + public Graphics getGraphics() + { + if( backBuffer == null ) + { + Rectangle r = owner.getBounds(); + backBuffer = new QtImage( r.width, r.height ); + } + return backBuffer.getDirectGraphics( this ); + } + + public GraphicsConfiguration getGraphicsConfiguration() + { + int id = whichScreen(); // get the ID of the screen the widget is on. + GraphicsDevice[] devs = QtToolkit.graphicsEnv.getScreenDevices(); + return devs[id].getDefaultConfiguration(); + } + + public Point getLocationOnScreen() + { + Point p = new Point(); + synchronized( p ) + { + getLocationOnScreenNative( p ); + try + { + p.wait(); // Wait for the thing to be created. + } + catch(InterruptedException e) + { + } + } + return p; + } + + private native void getSizeNative(Dimension d, boolean preferred); + + private Dimension getSize(boolean preferred) + { + Dimension d = new Dimension(); + synchronized( d ) + { + getSizeNative(d, preferred); + try + { + d.wait(); // Wait for the thing to be created. + } + catch(InterruptedException e) + { + } + } + return d; + } + + public Dimension getMinimumSize() + { + return getSize( false ); + } + + public Dimension getPreferredSize() + { + return getSize( true ); + } + + public Toolkit getToolkit() + { + return toolkit; + } + + public native boolean handlesWheelScrolling(); + + public void hide() + { + setVisible(false); + } + + public native boolean isFocusable(); + + public boolean isFocusTraversable() + { + // FIXME + return false; + } + + public native boolean isObscured(); + + public Dimension minimumSize() + { + return getMinimumSize(); + } + + public Dimension preferredSize() + { + return getPreferredSize(); + } + + public native void requestFocus(); + + public boolean requestFocus (Component source, boolean bool1, + boolean bool2, long x) + { + // FIXME + return true; + } + + public void reshape(int x, + int y, + int width, + int height) + { + setBounds( x, y, width, height ); + } + + public void setBackground(Color c) + { + if(c == null && !settingUp) + return; + setGround(c.getRed(), c.getGreen(), c.getBlue(), false); + } + + public void setBounds(int x, int y, int width, int height) + { + if( ignoreResize ) + return; + updateBackBuffer(width, height); + QtToolkit.repaintThread.queueComponent(this); + setBoundsNative(x, y, width, height); + } + + public void setCursor(Cursor cursor) + { + if (cursor != null) + setCursor(cursor.getType()); + } + + public native void setEnabled(boolean b); + + public void setFont(Font f) + { + if( f == null || f.getPeer() == null) + throw new IllegalArgumentException("Null font."); + setFontNative( (QtFontPeer)f.getPeer() ); + } + + public void setForeground(Color c) + { + if(c == null && !settingUp) + return; + setGround(c.getRed(), c.getGreen(), c.getBlue(), true); + } + + public native void setVisible(boolean b); + + public void show() + { + setVisible(true); + } + + public void handleEvent (AWTEvent e) + { + int eventID = e.getID(); + Rectangle r; + + switch (eventID) + { + case ComponentEvent.COMPONENT_SHOWN: + QtToolkit.repaintThread.queueComponent(this); + break; + case PaintEvent.PAINT: + case PaintEvent.UPDATE: + r = ((PaintEvent)e).getUpdateRect(); + QtToolkit.repaintThread.queueComponent(this, r.x, r.y, + r.width, r.height); + break; + case KeyEvent.KEY_PRESSED: + break; + case KeyEvent.KEY_RELEASED: + break; + } + } + + /** + * paint() is called back from the native side in response to a native + * repaint event. + */ + public void paint(Graphics g) + { + Rectangle r = g.getClipBounds(); + + if (backBuffer != null) + backBuffer.drawPixelsScaledFlipped ((QtGraphics) g, + 0, 0, 0, /* bg colors */ + false, false, /* no flipping */ + r.x, r.y, r.width, r.height, + r.x, r.y, r.width, r.height, + false ); /* no compositing */ + } + + public void paintBackBuffer() throws InterruptedException + { + if( backBuffer != null ) + { + backBuffer.clear(); + Graphics2D bbg = (Graphics2D)backBuffer.getGraphics(); + owner.paint(bbg); + bbg.dispose(); + } + } + + public void paintBackBuffer(int x, int y, int w, int h) + throws InterruptedException + { + if( backBuffer != null ) + { + Graphics2D bbg = (Graphics2D)backBuffer.getGraphics(); + bbg.setBackground( getNativeBackground() ); + bbg.clearRect(x, y, w, h); + bbg.setClip(x, y, w, h); + owner.paint(bbg); + bbg.dispose(); + } + } + + public boolean prepareImage(Image img, + int w, + int h, + ImageObserver o) + { + return toolkit.prepareImage(img, w, h, o); + } + + public void print(Graphics g) + { + // FIXME + } + + /** + * Schedules a timed repaint. + */ + public void repaint(long tm, + int x, + int y, + int w, + int h) + { + if( tm <= 0 ) + { + QtToolkit.repaintThread.queueComponent(this, x, y, w, h); + return; + } + Timer t = new Timer(); + t.schedule(new RepaintTimerTask(this, x, y, w, h), tm); + } + + /** + * Update the cursor (note that setCursor is usually not called) + */ + public void updateCursorImmediately() + { + if (owner.getCursor() != null) + setCursor(owner.getCursor().getType()); + } + + /** + * Timed repainter + */ + private class RepaintTimerTask extends TimerTask + { + private int x, y, w, h; + private QtComponentPeer peer; + RepaintTimerTask(QtComponentPeer peer, int x, int y, int w, int h) + { + this.x=x; + this.y=y; + this.w=w; + this.h=h; + this.peer=peer; + } + public void run() + { + QtToolkit.repaintThread.queueComponent(peer, x, y, w, h); + } + } + + public native Rectangle getBounds(); + + public void reparent(ContainerPeer parent) + { + if(!(parent instanceof QtContainerPeer)) + throw new IllegalArgumentException("Illegal peer."); + reparentNative((QtContainerPeer)parent); + } + + public void setBounds(int x, int y, int width, int height, int z) + { + // TODO Auto-generated method stub + + } + + public boolean isReparentSupported() + { + return true; + } + + // What does this do, anyway? + public void layout() + { + // TODO Auto-generated method stub + } + + public boolean requestFocus(Component lightweightChild, boolean temporary, + boolean focusedWindowChangeAllowed, + long time, sun.awt.CausedFocusEvent.Cause cause) + { + // TODO: Implement this properly and remove the other requestFocus() + // methods. + return true; + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtContainerPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtContainerPeer.java new file mode 100644 index 000000000..ee2873730 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtContainerPeer.java @@ -0,0 +1,112 @@ +/* QtContainerPeer.java -- + 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.java.awt.peer.qt; + +import java.awt.Component; +import java.awt.Insets; +import java.awt.peer.ContainerPeer; + +public class QtContainerPeer extends QtComponentPeer implements ContainerPeer +{ + public QtContainerPeer( QtToolkit kit, Component owner ) + { + super( kit, owner ); + } + + protected void init() + { + } + + protected void setup() + { + super.setup(); + } + + // ************ Public methods ********************* + public void beginLayout() + { + // FIXME + } + + public void beginValidate() + { + } + + public void endLayout() + { + QtUpdate(); + } + + public void endValidate() + { + } + + public Insets getInsets() + { + return new Insets(0, 0, 0, 0); + } + + public Insets insets() + { + return getInsets(); + } + + public boolean isPaintPending() + { + // FIXME etc. + return false; + } + + public boolean isRestackSupported() + { + // TODO Auto-generated method stub + return false; + } + + public void cancelPendingPaint(int x, int y, int width, int height) + { + // TODO Auto-generated method stub + + } + + public void restack() + { + // TODO Auto-generated method stub + + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtDialogPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtDialogPeer.java new file mode 100644 index 000000000..2f2c25550 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtDialogPeer.java @@ -0,0 +1,73 @@ +/* QtDialogPeer.java -- + 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.java.awt.peer.qt; + +import java.awt.Dialog; +import java.awt.peer.DialogPeer; + +public class QtDialogPeer extends QtWindowPeer implements DialogPeer +{ + public QtDialogPeer( QtToolkit kit, Dialog owner ) + { + super( kit, owner ); + } + + protected native void init(); + + protected void setup() + { + super.setup(); + setTitle( ((Dialog)owner).getTitle() ); + setResizable( ((Dialog)owner).isResizable() ); + setModal( ((Dialog)owner).isModal() ); + } + + native void setModal(boolean modal); + + private native void setBoundsNative(int x, int y, int width, int height, boolean fixed); + + // ************ Public methods ********************* + + public native void setResizable (boolean resizeable); + + public void setBounds(int x, int y, int width, int height) + { + setBoundsNative(x, y, width, height, + !((Dialog)owner).isResizable()); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtEmbeddedWindowPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtEmbeddedWindowPeer.java new file mode 100644 index 000000000..de76cd17f --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtEmbeddedWindowPeer.java @@ -0,0 +1,64 @@ +/* QtEmbeddedWindowPeer.java -- embedded window peer + 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.java.awt.peer.qt; + +import java.awt.Component; +import gnu.java.awt.peer.EmbeddedWindowPeer; + +/** + * Embedded window peer for applets. + * FIXME: EmbeddedWindowPeer and this class should extend Window, NOT Frame. + */ +public class QtEmbeddedWindowPeer extends QtFramePeer implements EmbeddedWindowPeer +{ + public QtEmbeddedWindowPeer( QtToolkit kit, Component owner ) + { + super( kit, owner ); + } + + protected native void init(); + + protected void setup() + { + super.setup(); + } + + // ************ Public methods ********************* + + public native void embed( long handle ); +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtFileDialogPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtFileDialogPeer.java new file mode 100644 index 000000000..06943d955 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtFileDialogPeer.java @@ -0,0 +1,83 @@ +/* QtFileDialogPeer.java -- + 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.java.awt.peer.qt; + +import java.awt.FileDialog; +import java.io.FilenameFilter; +import java.awt.peer.FileDialogPeer; + +public class QtFileDialogPeer extends QtDialogPeer implements FileDialogPeer +{ + public QtFileDialogPeer( QtToolkit kit, FileDialog owner ) + { + super( kit, owner ); + } + + protected native void init(); + + protected void setup() + { + super.setup(); + setMode( ((FileDialog)owner).getMode() ); + } + + /** + * Sets load or save mode + */ + private native void setMode(int mode); + + private void fileDialogDone(String path, String filename) + { + } + + // ************ Public methods ********************* + public void setFile (String file) + { + // FIXME + } + + public void setDirectory (String dir) + { + // FIXME + } + + public void setFilenameFilter (FilenameFilter ff) + { + // FIXME + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtFontMetrics.java b/libjava/classpath/gnu/java/awt/peer/qt/QtFontMetrics.java new file mode 100644 index 000000000..1998339dc --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtFontMetrics.java @@ -0,0 +1,125 @@ +/* QtFontMetrics.java -- + 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.java.awt.peer.qt; + +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.geom.Rectangle2D; + +public class QtFontMetrics extends FontMetrics +{ + + private long nativeObject; + private QtFontPeer peer; + + public QtFontMetrics( Font f ) + { + super( f ); + if(f.getPeer() == null || !(f.getPeer() instanceof QtFontPeer)) + throw new IllegalArgumentException("Invalid Font object."); + peer = (QtFontPeer) f.getPeer(); + init( peer ); + } + + public QtFontMetrics( Font f, Graphics g ) + { + super( f ); + if(f.getPeer() == null || !(f.getPeer() instanceof QtFontPeer)) + throw new IllegalArgumentException("Invalid Font object."); + if( !(g instanceof QtGraphics) ) + throw new IllegalArgumentException("Invalid graphics object."); + peer = (QtFontPeer) f.getPeer(); + initGraphics(peer, (QtGraphics)g ); + } + + QtFontMetrics( QtFontPeer f, Graphics g ) + { + super( null ); + if( !(g instanceof QtGraphics) ) + throw new IllegalArgumentException("Invalid graphics object."); + peer = f; + initGraphics(peer, (QtGraphics)g ); + } + + public QtFontMetrics( QtFontPeer fp ) + { + super( (Font)null ); + peer = fp; + init( peer ); + } + + private native void init(QtFontPeer fp); + + private native void initGraphics(QtFontPeer fp, QtGraphics g); + + private native void dispose(); + + native Rectangle2D getStringBounds(String s); + + // ****************** Package private *************************** + + native boolean canDisplay( int c ); + + // ****************** Public methods **************************** + + public native int getAscent(); + + public native int getDescent(); + + public native int getHeight(); + + public native int getLeading(); + + public native int getMaxAdvance(); + + public native int charWidth(char c); + + public int charsWidth(char[] chars, int off, int len) + { + return stringWidth( new String(chars, off, len) ); + } + + public native int stringWidth(String str); + + public Rectangle2D getStringBounds(String str, Graphics context) + { + QtFontMetrics fm = new QtFontMetrics(peer, context); + return fm.getStringBounds( str ); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtFontPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtFontPeer.java new file mode 100644 index 000000000..03ed1d2df --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtFontPeer.java @@ -0,0 +1,197 @@ +/* QtFontPeer.java -- + 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.java.awt.peer.qt; + +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.geom.Rectangle2D; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.font.LineMetrics; +import java.text.CharacterIterator; +import java.util.Locale; +import java.util.Map; + +import gnu.java.awt.peer.ClasspathFontPeer; + +public class QtFontPeer extends ClasspathFontPeer +{ + // Pointer to native QFont structure. + private long nativeObject; + private QtFontMetrics metrics; + + + public QtFontPeer (String name, int style) + { + this(name, style, 12); + } + + public QtFontPeer (String name, int style, int size) + { + super(name, style, size); + init(); + } + + public QtFontPeer (String name, Map attributes) + { + super(name, attributes); + init(); + } + + public void init() + { + if(this.familyName == null) + throw new IllegalArgumentException("null family name"); + if(this.familyName.equals("Helvetica")) + this.familyName = "sans serif"; + if(this.familyName.equals("Dialog")) + this.familyName = "sans serif"; + create(this.familyName, this.style, (int)this.size); + metrics = new QtFontMetrics(this); + } + + /** + * Creates the QFont object. + */ + private native void create(String name, int style, int size); + + /** + * Destroys the QFont. + */ + public native void dispose(); + + + // ****************** ClasspathFontPeer Methods. + + public boolean canDisplay (Font font, int c) + { + return metrics.canDisplay( c ); + } + + public int canDisplayUpTo (Font font, CharacterIterator i, + int start, int limit) + { + int index = start; + char c = i.setIndex( index ); + while( index <= limit ) + { + if(!canDisplay(font, c)) + return index; + index++; + c = i.next(); + } + return -1; + } + + public String getSubFamilyName (Font font, Locale locale) + { + throw new UnsupportedOperationException(); + } + + public String getPostScriptName (Font font) + { + throw new UnsupportedOperationException(); + } + + public int getNumGlyphs (Font font) + { + throw new UnsupportedOperationException(); + } + + public int getMissingGlyphCode (Font font) + { + throw new UnsupportedOperationException(); + } + + public byte getBaselineFor (Font font, char c) + { + throw new UnsupportedOperationException(); + } + + public String getGlyphName (Font font, int glyphIndex) + { + throw new UnsupportedOperationException(); + } + + public GlyphVector createGlyphVector (Font font, + FontRenderContext frc, + CharacterIterator ci) + { + throw new UnsupportedOperationException(); + } + + public GlyphVector createGlyphVector (Font font, + FontRenderContext ctx, + int[] glyphCodes) + { + throw new UnsupportedOperationException(); + } + + public GlyphVector layoutGlyphVector (Font font, + FontRenderContext frc, + char[] chars, int start, + int limit, int flags) + { + throw new UnsupportedOperationException(); + } + + public FontMetrics getFontMetrics (Font font) + { + return new QtFontMetrics( this ); + } + + public boolean hasUniformLineMetrics (Font font) + { + throw new UnsupportedOperationException(); + } + + public LineMetrics getLineMetrics (Font font, + CharacterIterator ci, + int begin, int limit, + FontRenderContext rc) + { + throw new UnsupportedOperationException(); + } + + public Rectangle2D getMaxCharBounds (Font font, + FontRenderContext rc) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtFramePeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtFramePeer.java new file mode 100644 index 000000000..d5162106f --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtFramePeer.java @@ -0,0 +1,164 @@ +/* QtFramePeer.java -- + 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.java.awt.peer.qt; + +import java.awt.Component; +import java.awt.Frame; +import java.awt.Image; +import java.awt.Insets; +import java.awt.MenuBar; +import java.awt.Rectangle; +import java.awt.peer.FramePeer; + +public class QtFramePeer extends QtWindowPeer implements FramePeer +{ + private int theState; // FIXME + + long frameObject; + + public QtFramePeer( QtToolkit kit, Component owner ) + { + super( kit, owner ); + } + + protected native void init(); + + protected void setup() + { + super.setup(); + setTitle( ((Frame)owner).getTitle() ); + if( ((Frame)owner).getMenuBar() != null ) + setMenuBar( ((Frame)owner).getMenuBar() ); + } + + private native void setIcon(QtImage image); + + private native void setMaximizedBounds(int w, int h); + + private native void setMenu(QtMenuBarPeer mb); + + private native int menuBarHeight(); + + // ************ Public methods ********************* + + public void destroy() + { + dispose(); + } + + public int getState() + { + // FIXME + return theState; + } + + public Insets getInsets() + { + int mbHeight = ( ((Frame)owner).getMenuBar() != null ) ? + menuBarHeight() : 0; + return new Insets(mbHeight, 0, 0, 0); + } + + public void setIconImage(Image im) + { + if (im instanceof QtImage) + setIcon( (QtImage)im ); + else + setIcon( new QtImage( im.getSource() ) ); + } + + public void setMaximizedBounds(Rectangle rect) + { + // FIXME + } + + public void setMenuBar(MenuBar mb) + { + if( mb != null ) + { + QtMenuBarPeer mbpeer = (QtMenuBarPeer)mb.getPeer(); + if( mbpeer == null ) + { + mb.addNotify(); + mbpeer = (QtMenuBarPeer)mb.getPeer(); + if( mbpeer == null ) + throw new IllegalStateException("No menu bar peer."); + } + mbpeer.addMenus(); + setMenu( mbpeer ); + } + else + setMenu( null ); + } + + public void setResizable(boolean resizeable) + { + // FIXME + } + + public void setState(int s) + { + theState = s; + // FIXME + } + + public void setBoundsPrivate(int x, int y, int width, int height) + { + // TODO Auto-generated method stub + + } + + public void updateAlwaysOnTop() + { + // TODO Auto-generated method stub + + } + + public boolean requestWindowFocus() + { + // TODO Auto-generated method stub + return false; + } + + public Rectangle getBoundsPrivate() + { + // TODO: Implement this properly. + throw new InternalError("Not yet implemented"); + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtGraphics.java b/libjava/classpath/gnu/java/awt/peer/qt/QtGraphics.java new file mode 100644 index 000000000..f68cc0dbd --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtGraphics.java @@ -0,0 +1,714 @@ +/* QtGraphics.java -- + 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.java.awt.peer.qt; + +import java.awt.AlphaComposite; +import java.awt.AWTPermission; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Composite; +import java.awt.GradientPaint; +import java.awt.GraphicsConfiguration; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.RenderingHints; +import java.awt.Rectangle; +import java.awt.Paint; +import java.awt.Polygon; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.awt.geom.Arc2D; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Line2D; +import java.awt.geom.Rectangle2D; +import java.awt.geom.RoundRectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.BufferedImageOp; +import java.awt.image.ImageObserver; +import java.awt.image.RenderedImage; +import java.awt.image.renderable.RenderableImage; + +import java.text.AttributedCharacterIterator; +import java.text.CharacterIterator; +import java.util.Map; + +/** + * QtGraphics is an abstract implementation of Graphics2D over a QPainter + * object. This is to be subclassed for different drawing contexts, + * which may have different requirements. + */ +public abstract class QtGraphics extends Graphics2D +{ + /** + * Native QPainter pointer. + */ + protected long nativeObject; + + private static final AffineTransform identity = new AffineTransform(); + + // Graphics state + protected Font font; // Current font. + protected Color color, bgcolor; // Current color and background color. + protected Shape clip; // Current clipping area. + protected Shape initialClip; // Initial clip bounds + protected AffineTransform xform; // Current transform + protected Stroke currentStroke; // the current stroke + protected boolean nativeStroking; // whether we're using Qt's stroking or not + protected Composite composite; // current composite operator + protected double currentAlpha; // current alpha + protected Paint currentPaint; // current paint + protected RenderingHints renderingHints; // the rendering hints. + + /** + * Owner Graphics, used by subcontext created by create() + * to avoid GC of the original context. + */ + Graphics parent; + + /** + * Do-nothing constructor. + */ + QtGraphics() + { + } + + /** + * Copying constructor - used by copy() and subclasses. + */ + QtGraphics(QtGraphics parent) + { + cloneNativeContext( parent ); + setFont( parent.getFont() ); + setAlpha( parent.currentAlpha ); + setBackground( parent.getBackground() ); + setColor( parent.getColor() ); + setClip( (initialClip = parent.getClip()) ); + setTransform( parent.getTransform() ); + setStroke( parent.getStroke() ); + setComposite( parent.getComposite() ); + setPaint( parent.getPaint() ); + setRenderingHints( parent.getRenderingHints() ); + } + + /** + * Set up some generic defaults. + */ + protected void setup() + { + font = new Font ("Dialog", Font.PLAIN, 12); + setTransform( identity ); + setStroke( new BasicStroke() ); + renderingHints = new RenderingHints( null ); + } + + public synchronized native void delete(); + + public void dispose() + { + } + + // ********************** etc ******************************* + + private void resetClip() + { + AffineTransform current = getTransform(); + setTransform( identity ); + setClip( initialClip ); + setTransform( current ); + } + + protected native void initImage(QtImage image); + protected native void initVolatileImage(QtVolatileImage image); + + // Creates a new native QPainter object on the same context. + private native void cloneNativeContext( QtGraphics parent ); + private native void setColor(int r, int g, int b, int a); + private native void drawNative( QPainterPath p ); + private native void fillNative( QPainterPath p ); + private native void setClipNative( QPainterPath p ); + private native void setClipRectNative( int x, int y, int w, int h ); + private native void intersectClipNative( QPainterPath p ); + private native void intersectClipRectNative( int x, int y, int w, int h ); + private native void setQtTransform(QMatrix m); + private native void setNativeStroke(QPen p); + private native void setNativeComposite(int alphaMode); + private native void drawStringNative(String string, double x, double y); + private native void setLinearGradient(int r1, int g1, int b1, + int r2, int g2, int b2, + double x1, double y1, + double x2, double y2, boolean cyclic); + private native void setAlphaNative(double alpha); + private native void setFontNative(QtFontPeer font); + private native QPainterPath getClipNative(); + + void setAlpha(double alpha) + { + currentAlpha = alpha; + setAlphaNative(currentAlpha); + } + + // ************ Public methods ********************* + + /** + * Context-sensitive methods are declared abstract. + */ + public abstract Graphics create(); + + public abstract void copyArea(int x, int y, int width, int height, + int dx, int dy); + + public abstract GraphicsConfiguration getDeviceConfiguration(); + + + public Color getColor() + { + return new Color(color.getRed(), color.getGreen(), color.getBlue()); + } + + public void setColor(Color c) + { + if( c == null ) + c = Color.white; + this.color = c; + int alpha = (int)(c.getAlpha() * currentAlpha); + setColor(c.getRed(), c.getGreen(), c.getBlue(), alpha); + } + + public void setBackground(Color color) + { + bgcolor = new Color(color.getRed(), color.getGreen(), color.getBlue()); + } + + public Color getBackground() + { + return new Color(bgcolor.getRed(), bgcolor.getGreen(), bgcolor.getBlue()); + } + + public void setPaintMode() + { + } + + public void setXORMode(Color color) + { + // FIXME + } + + public boolean hit(Rectangle rect, Shape s, boolean onStroke) + { + if( onStroke ) + { + Shape stroked = currentStroke.createStrokedShape( s ); + return stroked.intersects( (double)rect.x, (double)rect.y, + (double)rect.width, (double)rect.height ); + } + return s.intersects( (double)rect.x, (double)rect.y, + (double)rect.width, (double)rect.height ); + } + + // ******************* Font *********************** + public Font getFont() + { + return font; + } + + public void setFont(Font font) + { + if( font == null ) + return; + this.font = font; + if(font.getPeer() != null && font.getPeer() instanceof QtFontPeer) + setFontNative( (QtFontPeer)font.getPeer() ); + } + + public FontMetrics getFontMetrics(Font font) + { + return new QtFontMetrics(font, this); + } + + // ***************** Clipping ********************* + + /** + * Intersects the current clip with the shape + */ + public void clip(Shape s) + { + intersectClipNative( new QPainterPath( s ) ); + } + + public void clipRect(int x, int y, int width, int height) + { + intersectClipRectNative( x, y, width, height ); + } + + public void setClip(int x, int y, int width, int height) + { + setClipRectNative( x, y, width, height ); + } + + public Shape getClip() + { + return getClipNative().getPath(); + } + + public native Rectangle getClipBounds(); + + /** + * Sets the clip + */ + public void setClip(Shape clip) + { + if (clip == null) + resetClip(); + else + setClipNative(new QPainterPath( clip )); + } + + // ***************** Drawing primitives ********************* + + public void draw(Shape s) + { + if( nativeStroking ) + drawNative( new QPainterPath(s) ); + else + fillNative( new QPainterPath( currentStroke.createStrokedShape( s ) ) ); + } + + public void fill(Shape s) + { + fillNative( new QPainterPath(s) ); + } + + public void drawLine(int x1, int y1, int x2, int y2) + { + if( nativeStroking ) + drawNative( new QPainterPath((double)x1, (double)y1, (double)x2, (double)y2, true) ); + else + draw( new Line2D.Double((double)x1, (double)y1, (double)x2, (double)y2) ); + } + + public void drawRect(int x, int y, int width, int height) + { + if( nativeStroking ) + drawNative( new QPainterPath((double)x, (double)y, + (double)width, (double)height) ); + else + fillNative( new QPainterPath + ( currentStroke.createStrokedShape + (new Rectangle2D.Double + ((double)x, (double)y, + (double)width, (double)height) ) ) ); + } + + public void fillRect(int x, int y, int width, int height) + { + fillNative( new QPainterPath( x, y, width, height ) ); + } + + public void clearRect(int x, int y, int width, int height) + { + Color c = color; + setColor( bgcolor ); // FIXME + fillRect( x, y, width, height ); + setColor( c ); + } + + public void drawRoundRect(int x, int y, int width, int height, + int arcWidth, int arcHeight) + { + draw( new RoundRectangle2D.Double(x, y, width, height, + arcWidth, arcHeight) ); + } + + public void fillRoundRect(int x, int y, int width, int height, + int arcWidth, int arcHeight) + { + fill( new RoundRectangle2D.Double(x, y, width, height, + arcWidth, arcHeight) ); + } + + public void drawOval(int x, int y, int width, int height) + { + draw( new Ellipse2D.Double((double)x, (double)y, + (double)width, (double)height) ); + } + + public void fillOval(int x, int y, int width, int height) + { + fill( new Ellipse2D.Double(x, y, width, height) ); + } + + public void drawArc(int x, int y, int width, int height, + int arcStart, int arcAngle) + { + draw( new Arc2D.Double(x, y, width, height, arcStart, arcAngle, + Arc2D.OPEN) ); + } + + public void fillArc(int x, int y, int width, int height, + int arcStart, int arcAngle) + { + fill( new Arc2D.Double(x, y, width, height, arcStart, arcAngle, + Arc2D.CHORD) ); + } + + public void drawPolyline(int xPoints[], int yPoints[], int npoints) + { + for( int i = 0; i < npoints - 1; i++) + drawLine(xPoints[i], yPoints[i], xPoints[i + 1], yPoints[i + 1]); + } + + public void drawPolygon(int xPoints[], int yPoints[], int npoints) + { + draw( new Polygon(xPoints, yPoints, npoints) ); + } + + public void fillPolygon(int xPoints[], int yPoints[], int npoints) + { + fill( new Polygon(xPoints, yPoints, npoints) ); + } + + public native void fill3DRect(int x, int y, int width, int height, boolean raised); + + public native void draw3DRect(int x, int y, int width, int height, boolean raised); + + // *********************** Text rendering ************************* + + public void drawString(String string, int x, int y) + { + drawStringNative(string, (double)x, (double)y); + } + + public void drawString(String string, float x, float y) + { + drawStringNative(string, (double)x, (double)y); + } + + public void drawString (AttributedCharacterIterator ci, int x, int y) + { + // FIXME - to something more correct ? + String s = ""; + for(char c = ci.first(); c != CharacterIterator.DONE; c = ci.next()) + s += c; + drawString(s, x, y); + } + + public void drawString(AttributedCharacterIterator ci, + float x, float y) + { + // FIXME - to something more correct ? + String s = ""; + for(char c = ci.first(); c != CharacterIterator.DONE; c = ci.next()) + s += c; + drawString(s, x, y); + } + + public void drawGlyphVector(GlyphVector v, float x, float y) + { + throw new RuntimeException("Not implemented"); + } + + // ******************* Image drawing ****************************** + public boolean drawImage(Image image, + AffineTransform Tx, + ImageObserver obs) + { + if (image instanceof QtImage) + return ((QtImage)image).drawImage(this, new QMatrix( Tx ), obs); + + return (new QtImage(image.getSource())).drawImage(this, + new QMatrix( Tx ), + obs); + } + + public boolean drawImage(Image image, int x, int y, Color bgcolor, + ImageObserver observer) + { + if (image instanceof QtImage) + return ((QtImage)image).drawImage (this, x, y, bgcolor, observer); + return (new QtImage(image.getSource())).drawImage (this, x, y, + bgcolor, observer); + } + + public boolean drawImage(Image image, + int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, + Color bgcolor, ImageObserver observer) + { + if (image instanceof QtImage) + return ((QtImage)image).drawImage(this, dx1, dy1, dx2, dy2, + sx1, sy1, sx2, sy2, bgcolor, observer); + + return (new QtImage(image.getSource())).drawImage(this, dx1, dy1, + dx2, dy2, + sx1, sy1, sx2, sy2, + bgcolor, observer); + } + + public boolean drawImage(Image image, int x, int y, + int width, int height, Color bgcolor, + ImageObserver observer) + { + if (image instanceof QtImage) + return ((QtImage)image).drawImage (this, x, y, width, height, + bgcolor, observer); + return (new QtImage(image.getSource())).drawImage (this, x, y, + width, height, + bgcolor, observer); + } + + public boolean drawImage(Image image, int x, int y, int width, int height, + ImageObserver observer) + { + return drawImage(image, x, y, width, height, null, observer); + } + + public boolean drawImage(Image image, int x, int y, ImageObserver observer) + { + return drawImage(image, x, y, null, observer); + } + + public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer) + { + return drawImage(image, dx1, dy1, dx2, dy2, + sx1, sy1, sx2, sy2, null, observer); + } + + // *********************** Transform methods ************************* + public AffineTransform getTransform() + { + return new AffineTransform( xform ); + } + + public void setTransform(AffineTransform Tx) + { + xform = new AffineTransform( Tx ); + setQtTransform( new QMatrix( xform ) ); + } + + public void rotate(double theta) + { + xform.rotate( theta ); + setQtTransform( new QMatrix( xform ) ); + } + + public void rotate(double theta, double x, double y) + { + xform.rotate(theta, x, y); + setQtTransform( new QMatrix( xform ) ); + } + + public void scale(double sx, double sy) + { + xform.scale(sx, sy); + setQtTransform( new QMatrix( xform ) ); + } + + public void shear(double shx, double shy) + { + xform.shear(shx, shy); + setQtTransform( new QMatrix( xform ) ); + } + + public void transform(AffineTransform Tx) + { + xform.concatenate( Tx ); + setQtTransform( new QMatrix( xform ) ); + } + + public void translate(double tx, double ty) + { + xform.translate( tx, ty ); + setQtTransform( new QMatrix( xform ) ); + } + + public void translate(int x, int y) + { + translate((double)x, (double)y); + } + + // *************** Stroking, Filling, Compositing ***************** + public void setStroke(Stroke s) + { + try // ..to convert the stroke into a native one. + { + QPen pen = new QPen( s ); + nativeStroking = true; + setNativeStroke( pen ); + setColor( color ); + } + catch (IllegalArgumentException e) + { + nativeStroking = false; + } + currentStroke = s; + } + + public Stroke getStroke() + { // FIXME: return copy? + return currentStroke; + } + + public void setComposite(Composite comp) + { + if( comp == null) + { + setNativeComposite( AlphaComposite.SRC_OVER ); + return; + } + + if( comp instanceof AlphaComposite ) + { + if( ((AlphaComposite)comp).getRule() != AlphaComposite.XOR ) + setAlpha( ((AlphaComposite)comp).getAlpha() ); + setNativeComposite( ((AlphaComposite)comp).getRule() ); + composite = comp; + } + else + { + // FIXME: this check is only required "if this Graphics2D + // context is drawing to a Component on the display screen". + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new AWTPermission("readDisplayPixels")); + + throw new UnsupportedOperationException("We don't support custom"+ + " composites yet."); + } + } + + public Composite getComposite() + { + return composite; + } + + public void setPaint(Paint p) + { + if( p == null ) + return; + + // FIXME + currentPaint = p; + if( p instanceof GradientPaint ) + { + GradientPaint lg = (GradientPaint)p; + setLinearGradient(lg.getColor1().getRed(), lg.getColor1().getGreen(), + lg.getColor1().getBlue(), lg.getColor2().getRed(), + lg.getColor2().getGreen(), lg.getColor2().getBlue(), + lg.getPoint1().getX(), lg.getPoint1().getY(), + lg.getPoint2().getX(), lg.getPoint2().getY(), + lg.isCyclic() ); + return; + } + if( p instanceof Color ) + { + setColor((Color) p); + return; + } + throw new UnsupportedOperationException("We don't support custom"+ + " paints yet."); + } + + public Paint getPaint() + { + // FIXME + return currentPaint; + } + + // ********************** Rendering Hints ************************* + + public void addRenderingHints(Map hints) + { + renderingHints.putAll( hints ); + } + + public Object getRenderingHint(RenderingHints.Key hintKey) + { + return renderingHints.get( hintKey ); + } + + public RenderingHints getRenderingHints() + { + return (RenderingHints) renderingHints.clone(); + } + + public void setRenderingHints(Map hints) + { + renderingHints = new RenderingHints( null ); + renderingHints.putAll(hints); + updateRenderingHints(); + } + + public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue) + { + renderingHints.put( hintKey, hintValue ); + updateRenderingHints(); + } + + private void updateRenderingHints() + { + // FIXME - update native settings. + } + + ////////////////////////////// unimplemented ///////////////////// + + public FontRenderContext getFontRenderContext() + { + throw new UnsupportedOperationException("Not implemented yet"); + } + + public void drawRenderableImage(RenderableImage image, AffineTransform xform) + { + throw new UnsupportedOperationException("Not implemented yet"); + } + + public void drawRenderedImage(RenderedImage image, AffineTransform xform) + { + throw new UnsupportedOperationException("Not implemented yet"); + } + + public void drawImage(BufferedImage image, BufferedImageOp op, int x, int y) + { + throw new UnsupportedOperationException("Not implemented yet"); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtGraphicsEnvironment.java b/libjava/classpath/gnu/java/awt/peer/qt/QtGraphicsEnvironment.java new file mode 100644 index 000000000..dec4db2c8 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtGraphicsEnvironment.java @@ -0,0 +1,105 @@ +/* QtGraphicsEnvironment.java -- + 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.java.awt.peer.qt; + +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.image.BufferedImage; +import java.util.Locale; + +public class QtGraphicsEnvironment extends GraphicsEnvironment +{ + QtToolkit toolkit; + GraphicsDevice[] screens; + + public QtGraphicsEnvironment (QtToolkit tk) + { + super(); + toolkit = tk; + // Get the number of screens from Qt. + int n = toolkit.numScreens(); + + /** + * Create the screen device objects + */ + screens = new GraphicsDevice[ n ]; + for(int i = 0; i < n; i++) + screens[ i ] = new QtScreenDevice( i ); + } + + public Font[] getAllFonts () + { + String[] fonts = getAvailableFontFamilyNames(); + Font[] fontObjs = new Font[fonts.length]; + for( int i = 0; i < fonts.length; i++) + fontObjs[i] = new Font(fonts[i], Font.PLAIN, 12); + return fontObjs; + } + + public String[] getAvailableFontFamilyNames() + { + return toolkit.getFontList(); + } + + public String[] getAvailableFontFamilyNames(Locale l) + { + return getAvailableFontFamilyNames(); + } + + public GraphicsDevice getDefaultScreenDevice () + { + return screens[ toolkit.defaultScreen() ]; + } + + public Graphics2D createGraphics (BufferedImage image) + { + return (Graphics2D)image.getGraphics(); + } + + public GraphicsDevice[] getScreenDevices() + { + return screens; + } + + public QtToolkit getToolkit() + { + return toolkit; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtImage.java b/libjava/classpath/gnu/java/awt/peer/qt/QtImage.java new file mode 100644 index 000000000..b7e50ea25 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtImage.java @@ -0,0 +1,641 @@ +/* QtImage.java -- + 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.java.awt.peer.qt; + +import java.awt.Graphics; +import java.awt.Color; +import java.awt.Image; +import java.awt.image.ColorModel; +import java.awt.image.DirectColorModel; +import java.awt.image.MemoryImageSource; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.io.File; +import java.io.IOException; +import java.io.ByteArrayOutputStream; +import java.io.BufferedInputStream; +import java.net.URL; +import java.util.Hashtable; +import java.util.WeakHashMap; +import java.util.Vector; + +/** + * QtImage - wraps a QImage + * + */ +public class QtImage extends Image +{ + int width = -1, height = -1; + + /** + * Properties. + */ + Hashtable props; + + /** + * Loaded or not flag, for asynchronous compatibility. + */ + boolean isLoaded; + + /** + * Pointer to the QImage + */ + long nativeObject; + + /** + * Observer queue. + */ + Vector observers; + + /** + * Error flag for loading. + */ + boolean errorLoading; + + /** + * Original source, if created from an ImageProducer. + */ + ImageProducer source; + + /* + * The 32-bit AARRGGBB format the uses. + */ + static ColorModel nativeModel = new DirectColorModel(32, + 0x00FF0000, + 0x0000FF00, + 0x000000FF, + 0xFF000000); + /** + * HashMap of Graphics objects painting on this Image. + */ + WeakHashMap painters; + + /** + * Flags if this image is to be destroyed. + */ + boolean killFlag; + + /** + * Clears the image to RGBA 0 + */ + public native void clear(); + + /** + * Returns a copy of the pixel data as a java array. + */ + private native int[] getPixels(); + + /** + * Sets the pixel data from a java array. + */ + private native void setPixels(int[] pixels); + + /** + * Loads an image + */ + private native boolean loadImage(String name); + + /** + * Loads an image from data. + */ + private native boolean loadImageFromData(byte[] data); + + /** + * Allocates a QImage + */ + private native void createImage(); + + /** + * Frees the above. + */ + private synchronized native void freeImage(); + + /** + * Sets the image to scaled copy of src image. hints are rendering hints. + */ + private native void createScaledImage(QtImage src, int hints); + + /** + * Draws the image optionally composited. + */ + native void drawPixels (QtGraphics gc, + int bg_red, int bg_green, int bg_blue, + int x, int y, + boolean composite); + /** + * Draws the image, optionally scaled and composited. + */ + private native void drawPixelsScaled (QtGraphics gc, + int bg_red, int bg_green, int bg_blue, + int x, int y, int width, int height, + boolean composite); + + /** + * Draws the image transformed. + */ + private native void drawPixelsTransformed (QtGraphics gc, QMatrix transform); + + /** + * Draws the image scaled flipped and optionally composited. + */ + native void drawPixelsScaledFlipped (QtGraphics gc, + int bg_red, int bg_green, + int bg_blue, + boolean flipX, boolean flipY, + int srcX, int srcY, + int srcWidth, int srcHeight, + int dstX, int dstY, + int dstWidth, int dstHeight, + boolean composite); + + /** + * Creates the image from an ImageProducer. May result in an error image. + */ + public QtImage (ImageProducer producer) + { + killFlag = false; + isLoaded = false; + observers = new Vector(); + source = producer; + errorLoading = false; + if( producer != null ) + source.startProduction(new QtImageConsumer(this, source)); + } + + /** + * Creates the image from a URL. May result in an error image. + */ + public QtImage (URL url) + { + killFlag = false; + isLoaded = false; + observers = new Vector(); + errorLoading = false; + if( url == null) + return; + ByteArrayOutputStream baos = new ByteArrayOutputStream( 5000 ); + try + { + BufferedInputStream bis = new BufferedInputStream(url.openStream()); + + byte[] buf = new byte[5000]; + int n = 0; + + while ( (n = bis.read( buf )) != -1 ) + baos.write(buf, 0, n); + bis.close(); + } + catch(IOException e) + { + throw new IllegalArgumentException("Couldn't load image."); + } + if ( loadImageFromData( baos.toByteArray() ) != true ) + throw new IllegalArgumentException("Couldn't load image."); + + isLoaded = true; + observers = null; + props = new Hashtable(); + } + + /** + * Constructs a QtImage by loading a given file. + * + * @throws IllegalArgumentException if the image could not be loaded. + */ + public QtImage (String filename) + { + killFlag = false; + File f = new File(filename); + observers = null; + props = new Hashtable(); + try + { + String fn = f.getCanonicalPath(); + if (loadImage( fn ) != true) + { + errorLoading = true; + isLoaded = false; + return; + } + } + catch(IOException e) + { + errorLoading = true; + isLoaded = false; + return; + } + errorLoading = false; + isLoaded = true; + } + + /** + * Constructs a QtImage from a byte array of an image file. + * + * @throws IllegalArgumentException if the image could not be loaded. + */ + public QtImage (byte[] data) + { + if (loadImageFromData(data) != true) + throw new IllegalArgumentException("Couldn't load image."); + + killFlag = false; + isLoaded = true; + observers = null; + errorLoading = false; + props = new Hashtable(); + } + + /** + * Constructs an empty QtImage. + */ + public QtImage (int width, int height) + { + this.width = width; + this.height = height; + props = new Hashtable(); + isLoaded = true; + killFlag = false; + observers = null; + errorLoading = false; + createImage(); + clear(); + } + + /** + * Constructs a scaled version of the src bitmap, using Qt + */ + private QtImage (QtImage src, int width, int height, int hints) + { + this.width = width; + this.height = height; + props = new Hashtable(); + isLoaded = true; + killFlag = false; + observers = null; + errorLoading = false; + + createScaledImage(src, hints); + } + + /** + * Callback from the image consumer. + */ + public void setImage(int width, int height, + int[] pixels, Hashtable properties) + { + this.width = width; + this.height = height; + props = (properties != null) ? properties : new Hashtable(); + + if (width <= 0 || height <= 0 || pixels == null) + { + errorLoading = true; + return; + } + + isLoaded = true; + deliver(); + createImage(); + setPixels(pixels); + } + + // java.awt.Image methods //////////////////////////////////////////////// + + public int getWidth (ImageObserver observer) + { + if (addObserver(observer)) + return -1; + + return width; + } + + public int getHeight (ImageObserver observer) + { + if (addObserver(observer)) + return -1; + + return height; + } + + public Object getProperty (String name, ImageObserver observer) + { + if (addObserver(observer)) + return UndefinedProperty; + + Object value = props.get (name); + return (value == null) ? UndefinedProperty : value; + } + + /** + * Returns the source of this image. + */ + public ImageProducer getSource () + { + if (!isLoaded) + return null; + return new MemoryImageSource(width, height, nativeModel, getPixels(), + 0, width); + } + + void putPainter(QtImageGraphics g) + { + if( painters == null ) + painters = new WeakHashMap(); + painters.put( g, "dummy" ); + } + + void removePainter(QtImageGraphics g) + { + painters.remove( g ); + if( killFlag && painters.isEmpty() ) + freeImage(); + } + + /** + * Creates a Graphics context for this image. + */ + public Graphics getGraphics () + { + if (!isLoaded || killFlag) + return null; + + return new QtImageGraphics(this); + } + + /** + * Creates a Graphics context for this image. + */ + Graphics getDirectGraphics(QtComponentPeer peer) + { + if (!isLoaded) + return null; + + return new QtImageDirectGraphics(this, peer); + } + + /** + * Returns a scaled instance of this image. + */ + public Image getScaledInstance(int width, + int height, + int hints) + { + if (width <= 0 || height <= 0) + throw new IllegalArgumentException("Width and height of scaled bitmap"+ + "must be >= 0"); + + return new QtImage(this, width, height, hints); + } + + /** + * If the image is loaded and comes from an ImageProducer, + * regenerate the image from there. + * + * I have no idea if this is ever actually used. Since QtImage can't be + * instantiated directly, how is the user to know if it was created from + * an ImageProducer or not? + */ + public synchronized void flush () + { + if (isLoaded && source != null) + { + observers = new Vector(); + isLoaded = false; + freeImage(); + source.startProduction(new QtImageConsumer(this, source)); + } + } + + public void finalize() + { + dispose(); + } + + public void dispose() + { + if (isLoaded) + { + if( painters == null || painters.isEmpty() ) + freeImage(); + else + killFlag = true; // can't destroy image yet. + // Do so when all painters are gone. + } + } + + /** + * Returns the image status, used by QtToolkit + */ + public int checkImage (ImageObserver observer) + { + if (addObserver(observer)) + { + if (errorLoading == true) + return ImageObserver.ERROR; + else + return 0; + } + + return ImageObserver.ALLBITS | ImageObserver.WIDTH | ImageObserver.HEIGHT; + } + + // Drawing methods //////////////////////////////////////////////// + + /** + * Draws an image with eventual scaling/transforming. + */ + public boolean drawImage (QtGraphics g, QMatrix matrix, + ImageObserver observer) + { + if (addObserver(observer)) + return false; + + drawPixelsTransformed (g, matrix); + + return true; + } + + /** + * Draws an image to the QtGraphics context, at (x,y) with optional + * compositing with a background color. + */ + public boolean drawImage (QtGraphics g, int x, int y, + Color bgcolor, ImageObserver observer) + { + if (addObserver(observer)) + return false; + + if(bgcolor != null) + drawPixels(g, bgcolor.getRed (), bgcolor.getGreen (), + bgcolor.getBlue (), x, y, true); + else + drawPixels(g, 0, 0, 0, x, y, false); + + return true; + } + + /** + * Draws an image to the QtGraphics context, at (x,y) scaled to + * width and height, with optional compositing with a background color. + */ + public boolean drawImage (QtGraphics g, int x, int y, int width, int height, + Color bgcolor, ImageObserver observer) + { + if (addObserver(observer)) + return false; + + if(bgcolor != null) + drawPixelsScaled(g, bgcolor.getRed (), bgcolor.getGreen (), + bgcolor.getBlue (), x, y, width, height, true); + else + drawPixelsScaled(g, 0, 0, 0, x, y, width, height, false); + + return true; + } + + /** + * Draws an image with eventual scaling/transforming. + */ + public boolean drawImage (QtGraphics g, int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, + Color bgcolor, ImageObserver observer) + { + if (addObserver(observer)) + return false; + + boolean flipX = (dx1 > dx2)^(sx1 > sx2); + boolean flipY = (dy1 > dy2)^(sy1 > sy2); + int dstWidth = Math.abs (dx2 - dx1); + int dstHeight = Math.abs (dy2 - dy1); + int srcWidth = Math.abs (sx2 - sx1); + int srcHeight = Math.abs (sy2 - sy1); + int srcX = (sx1 < sx2) ? sx1 : sx2; + int srcY = (sy1 < sy2) ? sy1 : sy2; + int dstX = (dx1 < dx2) ? dx1 : dx2; + int dstY = (dy1 < dy2) ? dy1 : dy2; + + // Clipping. This requires the dst to be scaled as well, + if (srcWidth > width) + { + dstWidth = (int)((double)dstWidth*((double)width/(double)srcWidth)); + srcWidth = width - srcX; + } + + if (srcHeight > height) + { + dstHeight = (int)((double)dstHeight*((double)height/(double)srcHeight)); + srcHeight = height - srcY; + } + + if (srcWidth + srcX > width) + { + dstWidth = (int)((double)dstWidth * (double)(width - srcX)/(double)srcWidth); + srcWidth = width - srcX; + } + + if (srcHeight + srcY > height) + { + dstHeight = (int)((double)dstHeight * (double)(width - srcY)/(double)srcHeight); + srcHeight = height - srcY; + } + + if ( srcWidth <= 0 || srcHeight <= 0 || dstWidth <= 0 || dstHeight <= 0) + return true; + + if(bgcolor != null) + drawPixelsScaledFlipped (g, bgcolor.getRed (), bgcolor.getGreen (), + bgcolor.getBlue (), + flipX, flipY, + srcX, srcY, + srcWidth, srcHeight, + dstX, dstY, + dstWidth, dstHeight, + true); + else + drawPixelsScaledFlipped (g, 0, 0, 0, flipX, flipY, + srcX, srcY, srcWidth, srcHeight, + dstX, dstY, dstWidth, dstHeight, + false); + return true; + } + + public native void copyArea(int x, int y, int width, int height, + int dx, int dy); + + // Private methods //////////////////////////////////////////////// + + /** + * Delivers notifications to all queued observers. + */ + private void deliver() + { + int flags = ImageObserver.HEIGHT | + ImageObserver.WIDTH | + ImageObserver.PROPERTIES | + ImageObserver.ALLBITS; + + if (observers != null) + for(int i=0; i < observers.size(); i++) + ((ImageObserver)observers.elementAt(i)). + imageUpdate(this, flags, 0, 0, width, height); + + observers = null; + } + + /** + * Adds an observer, if we need to. + * @return true if an observer was added. + */ + private boolean addObserver(ImageObserver observer) + { + if (!isLoaded) + { + if(observer != null) + if (!observers.contains (observer)) + observers.addElement (observer); + return true; + } + return false; + } + + public String toString() + { + return "QtImage [isLoaded="+isLoaded+", width="+width+", height="+height + +"]"; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtImageConsumer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtImageConsumer.java new file mode 100644 index 000000000..9883475f9 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtImageConsumer.java @@ -0,0 +1,147 @@ +/* QtImageConsumer.java -- + 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.java.awt.peer.qt; + +import java.awt.image.ColorModel; +import java.awt.image.ImageConsumer; +import java.awt.image.ImageProducer; +import java.util.Hashtable; + +/** + * Helper class to QtImage. Sits and gathers pixels for a QtImage and then + * calls QtImage.setImage(). + * + * @author Sven de Marothy + */ +public class QtImageConsumer implements ImageConsumer +{ + private QtImage target; + private int width, height; + private Hashtable properties; + private int[] pixelCache = null; + private ImageProducer source; + + public QtImageConsumer(QtImage target, ImageProducer source) + { + this.target = target; + this.source = source; + } + + public synchronized void imageComplete (int status) + { + source.removeConsumer(this); + target.setImage(width, height, pixelCache, properties); + } + + public synchronized void setColorModel (ColorModel model) + { + // This method is to inform on what the most used color model + // in the image is, for optimization reasons. We ignore this + // information. + } + + public synchronized void setDimensions (int width, int height) + { + pixelCache = new int[width*height]; + + this.width = width; + this.height = height; + } + + public synchronized void setHints (int flags) + { + // This method informs us in which order the pixels are + // delivered, for progressive-loading support, etc. + // Since we wait until it's all loaded, we can ignore the hints. + } + + public synchronized void setPixels (int x, int y, int width, int height, + ColorModel cm, byte[] pixels, + int offset, int scansize) + { + setPixels (x, y, width, height, cm, convertPixels (pixels), offset, + scansize); + } + + public synchronized void setPixels (int x, int y, int width, int height, + ColorModel cm, int[] pixels, + int offset, int scansize) + { + if (pixelCache == null) + return; // Not sure this should ever happen. + + if (cm.equals(QtImage.nativeModel)) + for (int i = 0; i < height; i++) + System.arraycopy (pixels, offset + (i * scansize), + pixelCache, (y + i) * this.width + x, + width); + else + { + for (int i = 0; i < height; i++) + for (int j = 0; j < width; j++) + { + // get in AARRGGBB and convert to AABBGGRR + int pix = cm.getRGB(pixels[offset + (i * scansize) + x + j]); + byte b = (byte)(pix & 0xFF); + byte r = (byte)(((pix & 0x00FF0000) >> 16) & 0xFF); + pix &= 0xFF00FF00; + pix |= ((b & 0xFF) << 16); + pix |= (r & 0xFF); + pixelCache[(y + i) * this.width + x + j] = pix; + } + } + } + + /** + * This is an old method, no idea if it's correct. + */ + private int[] convertPixels (byte[] pixels) + { + int ret[] = new int[pixels.length]; + + for (int i = 0; i < pixels.length; i++) + ret[i] = pixels[i] & 0xFF; + + return ret; + } + + public synchronized void setProperties (Hashtable props) + { + this.properties = props; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtImageDirectGraphics.java b/libjava/classpath/gnu/java/awt/peer/qt/QtImageDirectGraphics.java new file mode 100644 index 000000000..daa174ad4 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtImageDirectGraphics.java @@ -0,0 +1,145 @@ +/* QtImageDirectGraphics.java -- + 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.java.awt.peer.qt; + +import java.awt.Color; +import java.awt.Image; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.image.ImageObserver; + +/** + * A QtImagePainter that does an update after every drawing op. + */ +public class QtImageDirectGraphics extends QtImageGraphics +{ + private QtComponentPeer peer; + private boolean modified; + + public QtImageDirectGraphics(QtImage image, QtComponentPeer peer) + { + super( image ); + this.peer = peer; + modified = false; + } + + public QtImageDirectGraphics(QtImageGraphics g) + { + super( g ); + } + + private void scheduleUpdate() + { + } + + public void dispose() + { + super.dispose(); + peer.toolkit.sync(); + peer.QtUpdate(); + } + + public void draw(Shape s) + { + super.draw(s); + scheduleUpdate(); + } + + public void fill(Shape s) + { + super.fill(s); + scheduleUpdate(); + } + + public void drawString(String string, int x, int y) + { + super.drawString( string, x, y ); + scheduleUpdate(); + } + + public void drawString(String string, float x, float y) + { + super.drawString( string, x, y ); + scheduleUpdate(); + } + + public void drawLine(int x1, int y1, int x2, int y2) + { + super.drawLine(x1, y1, x2, y2); + scheduleUpdate(); + } + + public boolean drawImage(Image image, + AffineTransform Tx, + ImageObserver obs) + { + boolean r = super.drawImage(image, Tx, obs); + scheduleUpdate(); + return r; + } + + public boolean drawImage(Image image, int x, int y, Color bgcolor, + ImageObserver observer) + { + boolean r = super.drawImage(image, x, y, bgcolor, observer); + scheduleUpdate(); + return r; + } + + public boolean drawImage(Image image, + int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, + Color bgcolor, ImageObserver observer) + { + boolean r = super.drawImage( image, dx1, dy1, dx2, dy2, + sx1, sy1, sx2, sy2, + bgcolor, observer); + scheduleUpdate(); + return r; + } + + public boolean drawImage(Image image, int x, int y, + int width, int height, Color bgcolor, + ImageObserver observer) + { + boolean r = super.drawImage(image, x, y, width, height, bgcolor, + observer); + scheduleUpdate(); + return r; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtImageGraphics.java b/libjava/classpath/gnu/java/awt/peer/qt/QtImageGraphics.java new file mode 100644 index 000000000..bba25e068 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtImageGraphics.java @@ -0,0 +1,139 @@ +/* QtImageGraphics.java -- + 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.java.awt.peer.qt; + +import java.awt.Color; +import java.awt.GraphicsConfiguration; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Rectangle; +import java.util.Stack; + +/** + * QtComponentPainter is a Graphics2D context for painting to QtImage and + * QtVolatileImages. + */ +public class QtImageGraphics extends QtGraphics +{ + Image parentImage; + Stack owners; + QtImageGraphics topParent; + + public QtImageGraphics(Image image) + { + if(!( image instanceof QtVolatileImage || image instanceof QtImage)) + throw new IllegalArgumentException("Cannot create QtImageGraphics for a non-QImage context."); + + owners = new Stack(); + owners.push(this); + topParent = null; + int w, h; + if(image instanceof QtImage) + { + w = ((QtImage)image).width; + h = ((QtImage)image).height; + initImage((QtImage) image ); + ((QtImage)image).putPainter( this ); + } + else + { + w = ((QtVolatileImage)image).width; + h = ((QtVolatileImage)image).height; + initVolatileImage((QtVolatileImage) image ); + ((QtVolatileImage)image).putPainter( this ); + } + + parentImage = image; + initialClip = new Rectangle( 0, 0, w, h ); + setClip( initialClip ); + setBackground(Color.white); // fixme + currentAlpha = 1.0; + setColor(Color.black); + setup(); + } + + /** + * Copying constructor + */ + QtImageGraphics( QtImageGraphics g ) + { + super( g ); + parentImage = g.parentImage; + if(parentImage instanceof QtImage) + ((QtImage)parentImage).putPainter( this ); + else + ((QtVolatileImage)parentImage).putPainter( this ); + } + + public void dispose() + { + delete(); + if( parentImage instanceof QtImage ) + ((QtImage)parentImage).removePainter( this ); + else + ((QtVolatileImage)parentImage).removePainter( this ); + } + + /** + * Create a copy of this context. + */ + public Graphics create() + { + return new QtImageGraphics( this ); + } + + /** + * Copy an area. + */ + public void copyArea(int x, int y, int width, int height, + int dx, int dy) + { + if(parentImage instanceof QtImage) + ((QtImage)parentImage).copyArea(x, y, width, height, dx, dy); + else + ((QtVolatileImage)parentImage).copyArea(x, y, width, height, dx, dy); + } + + /** + * Returns the GraphicsConfiguration of the context component. + */ + public GraphicsConfiguration getDeviceConfiguration() + { + throw new UnsupportedOperationException("Not implemented yet"); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtLabelPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtLabelPeer.java new file mode 100644 index 000000000..80acd491d --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtLabelPeer.java @@ -0,0 +1,62 @@ +/* QtLabelPeer.java -- + 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.java.awt.peer.qt; + +import java.awt.Label; +import java.awt.peer.LabelPeer; + +public class QtLabelPeer extends QtComponentPeer implements LabelPeer +{ + public QtLabelPeer( QtToolkit kit, Label owner ) + { + super( kit, owner ); + } + + protected native void init(); + + protected void setup() + { + super.setup(); + setText( ((Label)owner).getText() ); + setAlignment( ((Label)owner).getAlignment() ); + } + + public native void setAlignment( int alignment ); + + public native void setText( String label ); +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtListPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtListPeer.java new file mode 100644 index 000000000..14ae2a0cd --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtListPeer.java @@ -0,0 +1,188 @@ +/* QtListPeer.java -- + 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.java.awt.peer.qt; + +import java.awt.Dimension; +import java.awt.List; +import java.awt.event.ActionEvent; +import java.awt.event.ItemEvent; +import java.awt.peer.ListPeer; + +public class QtListPeer extends QtComponentPeer implements ListPeer +{ + public QtListPeer( QtToolkit kit, List owner ) + { + super( kit, owner ); + } + + public native void init(); + + protected void setup() + { + super.setup(); + List o = (List)owner; + // Multiple selection + setMultipleMode(o.isMultipleMode()); + // Add initial list items. + String[] items = o.getItems(); + for (int i = 0; i < items.length; i++) + add(items[i], i); + + // Initial selections. + int[] selected = o.getSelectedIndexes(); + for (int i = 0; i < selected.length; i++) + select(selected[i]); + + // If no initial selection, use 0. + if(selected.length == 0 && items.length > 0) + select( 0 ); + } + + private boolean ignoreNextSelect = false; + + /** + * Called back when a row is selected. -1 if no row is selected. + */ + private void fireChoice( int index ) + { + ignoreNextSelect = true; + if( index == -1) + ((List)owner).deselect( ((List)owner).getSelectedIndex() ); + else + { + ((List)owner).select( index ); + ItemEvent e = new ItemEvent((List)owner, + ItemEvent.ITEM_STATE_CHANGED, + ""+index, + ItemEvent.SELECTED); + QtToolkit.eventQueue.postEvent(e); + } + } + + /** + * Called back when an item is double-clicked. + */ + private void itemDoubleClicked( int index, int modifiers ) + { + ActionEvent e = new ActionEvent(owner, + ActionEvent.ACTION_PERFORMED, + ((List)owner).getItem( index ), + System.currentTimeMillis(), + modifiers); + QtToolkit.eventQueue.postEvent(e); + } + + private native void select(int index, boolean selected); + + // ************ Public methods ********************* + + public native void add(String item, int index); + + public void addItem(String item, int index) + { + add(item, index); + } + + public void clear() + { + removeAll(); + } + + /** + * Deletes items from the starting index to the ending index (inclusive). + */ + public native void delItems(int start_index, int end_index); + + public void deselect(int index) + { + if( ignoreNextSelect == true ) + ignoreNextSelect = false; + else + select(index, false); + } + + public native int[] getSelectedIndexes(); + + public native void makeVisible(int index); + + public Dimension minimumSize(int s) + { + return getMinimumSize(s); + } + + public Dimension preferredSize(int s) + { + return getPreferredSize(s); + } + + public void removeAll() + { + delItems(0, ((List)owner).getItemCount() - 1); + } + + public void select(int index) + { + if( ignoreNextSelect == true ) + ignoreNextSelect = false; + else + select(index, true); + } + + /** + * Sets multiple-selection mode. + * Note there's a bug in multiple selection in Qt 4.0.0, use 4.0.1. + */ + public native void setMultipleMode(boolean multi); + + public void setMultipleSelections(boolean multi) + { + setMultipleMode(multi); + } + + public Dimension getPreferredSize(int s) + { + // FIXME + return getPreferredSize(); + } + + public Dimension getMinimumSize(int s) + { + // FIXME + return getMinimumSize(); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtMenuBarPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtMenuBarPeer.java new file mode 100644 index 000000000..962d76d41 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtMenuBarPeer.java @@ -0,0 +1,101 @@ +/* QtMenuBarPeer.java -- Qt peer for a menu bar. + 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.java.awt.peer.qt; + +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.peer.MenuBarPeer; + +public class QtMenuBarPeer extends QtMenuComponentPeer implements MenuBarPeer +{ + public QtMenuBarPeer( QtToolkit kit, MenuBar owner ) + { + super( kit, owner ); + } + + protected native void init(); + + protected void setup() + { + } + + /** + * Recurses the menubar adding menus (and menu items), + * called from the Frame peer. + */ + void addMenus() + { + MenuBar o = (MenuBar)owner; + int help = (o.getHelpMenu() != null) ? 1 : 0; + for (int i = 0; i < o.getMenuCount() - help; i++) + addMenu( o.getMenu(i) ); + if(o.getHelpMenu() != null) + addHelpMenu( o.getHelpMenu() ); + } + + private native void addMenu( QtMenuPeer mp ); + + private native void addHelpMenu( QtMenuPeer mp ); + + private native void delMenu( QtMenuPeer mp ); + + // ************ Public methods ********************* + + public void addMenu( Menu m ) + { + if (m.getPeer() == null) + m.addNotify(); + ((QtMenuPeer)m.getPeer()).addItems(); + addMenu( (QtMenuPeer)m.getPeer() ); + } + + public void addHelpMenu( Menu m ) + { + if (m.getPeer() == null) + m.addNotify(); + ((QtMenuPeer)m.getPeer()).addItems(); + addHelpMenu( (QtMenuPeer)m.getPeer() ); + } + + public void delMenu( int index ) + { + Menu m = ((MenuBar)owner).getMenu( index ); + if(m != null) + delMenu( (QtMenuPeer)m.getPeer() ); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtMenuComponentPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtMenuComponentPeer.java new file mode 100644 index 000000000..2050bef06 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtMenuComponentPeer.java @@ -0,0 +1,94 @@ +/* QtMenuComponentPeer.java -- + 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.java.awt.peer.qt; + +import java.awt.Font; +import java.awt.MenuComponent; +import java.awt.peer.MenuComponentPeer; + +public class QtMenuComponentPeer extends NativeWrapper + implements MenuComponentPeer +{ + protected QtToolkit toolkit; + protected MenuComponent owner; + + public QtMenuComponentPeer( QtToolkit kit, MenuComponent owner ) + { + this.toolkit = kit; + this.owner = owner; + nativeObject = 0; + synchronized(this) + { + callInit(); // Calls the init method FROM THE MAIN THREAD. + try + { + wait(); // Wait for the thing to be created. + } + catch(InterruptedException e) + { + } + } + setup(); + } + + protected native void callInit(); + + protected void init() + { + } + + protected void setup() + { + } + + public void finalize() + { + dispose(); + } + + // ************ Public methods ********************* + + public native void dispose(); + + public void setFont(Font font) + { + // TODO Auto-generated method stub + + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtMenuItemPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtMenuItemPeer.java new file mode 100644 index 000000000..2b77540a5 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtMenuItemPeer.java @@ -0,0 +1,100 @@ +/* QtMenuItemPeer.java -- + 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.java.awt.peer.qt; + +import java.awt.MenuItem; +import java.awt.CheckboxMenuItem; +import java.awt.event.ActionEvent; +import java.awt.peer.MenuItemPeer; +import java.awt.peer.CheckboxMenuItemPeer; + +public class QtMenuItemPeer extends QtMenuComponentPeer + implements MenuItemPeer, CheckboxMenuItemPeer +{ + public QtMenuItemPeer( QtToolkit toolkit, MenuItem owner ) + { + super(toolkit, owner); + } + + protected void init() + { + String label = ((MenuItem)owner).getLabel(); + create(label, label.equals("-"), (owner instanceof CheckboxMenuItem)); + } + + protected void setup() + { + } + + private native void create(String label, boolean isSeperator, boolean isCheckable); + + public void finalize() + { + dispose(); + } + + public native void dispose(); + + private void fireClick(int modifiers) + { + ActionEvent e = new ActionEvent(owner, + ActionEvent.ACTION_PERFORMED, + ((MenuItem)owner).getActionCommand(), + System.currentTimeMillis(), + (modifiers & 0x2FF)); + QtToolkit.eventQueue.postEvent(e); + } + + // ************ Public methods ********************* + + public void disable() + { + setEnabled(false); + } + + public void enable() + { + setEnabled(true); + } + + public native void setEnabled(boolean b); + + public native void setLabel(String label); + + public native void setState(boolean state); +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtMenuPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtMenuPeer.java new file mode 100644 index 000000000..0f65fecbd --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtMenuPeer.java @@ -0,0 +1,149 @@ +/* QtMenuPeer.java -- + 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.java.awt.peer.qt; + +import java.awt.Menu; +import java.awt.MenuItem; +import java.awt.PopupMenu; +import java.awt.event.ActionEvent; +import java.awt.peer.MenuPeer; +import java.util.Vector; + +public class QtMenuPeer extends QtMenuComponentPeer implements MenuPeer +{ + Vector items; + boolean itemsAdded; + + public QtMenuPeer( QtToolkit kit, Menu owner ) + { + super( kit, owner ); + itemsAdded = false; + } + + protected native void init(); + + protected void setup() + { + items = new Vector(); + setLabel( ((Menu)owner).getLabel() ); + if( ((Menu)owner).isTearOff() ) + allowTearOff(); + } + + // Recurse the menu tree adding items, + // called from the MenuBar addMenus() method, called from the Frame peer. + void addItems() + { + if(!itemsAdded) + { + Menu o = (Menu)owner; + for( int i=0; i < o.getItemCount(); i++ ) + { + MenuItem ci = o.getItem(i); + if (ci instanceof Menu && ci.getPeer() != null) + ((QtMenuPeer)ci.getPeer()).addItems(); + addItem( ci ); + } + itemsAdded = true; + } + } + + private void fireClick() + { + ActionEvent e = new ActionEvent(owner, + ActionEvent.ACTION_PERFORMED, + ((Menu)owner).getActionCommand()); + QtToolkit.eventQueue.postEvent(e); + } + + private native void allowTearOff(); + + private native void insertSeperator(); + + private native void insertItem(QtMenuItemPeer p); + + private native void insertMenu(QtMenuPeer menu); + + private native void delItem(long ptr); + + private void add(long ptr) + { + items.add(new Long(ptr)); + } + + // ************ Public methods ********************* + + public void addItem( MenuItem item ) + { + if( item instanceof Menu || item instanceof PopupMenu) + insertMenu((QtMenuPeer)item.getPeer()); + else + { + QtMenuItemPeer p = (QtMenuItemPeer)item.getPeer(); + insertItem(p); + } + } + + public void addSeparator() + { + insertSeperator(); + } + + public void delItem( int index ) + { + long ptr = ((Long)items.elementAt(index)).longValue(); + delItem(ptr); + items.removeElementAt(index); + } + + // Inherited methods.. + + public void disable() + { + setEnabled(false); + } + + public void enable() + { + setEnabled(true); + } + + public native void setEnabled(boolean enabled); + + public native void setLabel(String text); +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtPanelPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtPanelPeer.java new file mode 100644 index 000000000..1ac0ca9a6 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtPanelPeer.java @@ -0,0 +1,56 @@ +/* QtPanelPeer.java -- + 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.java.awt.peer.qt; + +import java.awt.Component; +import java.awt.peer.PanelPeer; + +public class QtPanelPeer extends QtContainerPeer implements PanelPeer +{ + public QtPanelPeer( QtToolkit kit, Component owner ) + { + super( kit, owner ); + } + + protected native void init(); + + protected void setup() + { + super.setup(); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtPopupMenuPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtPopupMenuPeer.java new file mode 100644 index 000000000..eb4dae404 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtPopupMenuPeer.java @@ -0,0 +1,76 @@ +/* QtPopupMenuPeer.java -- + 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.java.awt.peer.qt; + +import java.awt.Component; +import java.awt.Point; +import java.awt.PopupMenu; +import java.awt.Event; +import java.awt.peer.PopupMenuPeer; + +public class QtPopupMenuPeer extends QtMenuPeer implements PopupMenuPeer +{ + public QtPopupMenuPeer( QtToolkit kit, PopupMenu owner ) + { + super( kit, owner ); + } + + private native void showNative(int x, int y); + + // ************ Public methods ********************* + + /** + * Part of the older API, replaced by event version instead. + */ + public void show (Component origin, int x, int y) + { + if( origin == null ) + throw new NullPointerException("Null parent component."); + addItems(); + + Point p = origin.getLocationOnScreen(); + showNative( (int)p.getX() + x, (int)p.getY() + y ); + } + + public void show (Event e) + { + if (!(e.target instanceof Component)) + throw new IllegalArgumentException("Expecting a component Event target!"); + show((Component)e.target, e.x, e.y); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtRepaintThread.java b/libjava/classpath/gnu/java/awt/peer/qt/QtRepaintThread.java new file mode 100644 index 000000000..6861be8fc --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtRepaintThread.java @@ -0,0 +1,156 @@ +/* QtRepaintThread.java -- Repaint thread implementation + 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.java.awt.peer.qt; + +/** + * This class does repainting of Component back-buffers. It is undesirable to + * do this directly from the paint callback in QtComponentPeer, because that + * is executed from the main thread. Thus, if a call is made at the same time + * which requires execution by the main thread, and this is sharing a lock with + * paint(), then a deadlock will occur, which must be avoided. In general, + * the main Qt thread should avoid calling into java code as far as possible. + * + */ +public class QtRepaintThread extends Thread +{ + static class RepaintComponent + { + public QtComponentPeer curr; + public RepaintComponent next; + public boolean paintAll; + public int x, y, w, h; + + public RepaintComponent(QtComponentPeer p) + { + curr = p; + next = null; + paintAll = true; + } + + public RepaintComponent(QtComponentPeer p, int x, int y, int w, int h) + { + this(p); + paintAll = false; + this.x = x; + this.y = y; + this.w = w; + this.h = h; + } + } + + RepaintComponent component; + boolean busy; + + public QtRepaintThread() + { + component = null; + } + + public void run() + { + while( true ) + { + try + { + busy = false; + // Wait for a repaint + sleep(100); + busy = true; + } + catch (InterruptedException ie) + { + while( component != null ) + { + try + { + if( component.paintAll ) + { + // update the back-buffer. + component.curr.paintBackBuffer(); + component.curr.QtUpdate(); // trigger a native repaint event + } + else + { + component.curr.paintBackBuffer(component.x, component.y, + component.w, component.h); + component.curr.QtUpdateArea(component.x, component.y, + component.w, component.h); + } + } + catch (InterruptedException e) + { + } + component = component.next; + } + } + } + } + + /** + * Enqueue a component for repainting. + */ + public synchronized void queueComponent(QtComponentPeer p) + { + if( component == null ) + component = new RepaintComponent(p); + else + { + RepaintComponent r = component; + while( r.next != null ) r = r.next; + r.next = new RepaintComponent(p); + } + interrupt(); + } + + /** + * Enqueue a component for repainting. + */ + public synchronized void queueComponent(QtComponentPeer p, int x, int y, + int w, int h) + { + if( component == null ) + component = new RepaintComponent(p, x, y, w, h); + else + { + RepaintComponent r = component; + while( r.next != null ) r = r.next; + r.next = new RepaintComponent(p, x, y, w, h); + } + interrupt(); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtScreenDevice.java b/libjava/classpath/gnu/java/awt/peer/qt/QtScreenDevice.java new file mode 100644 index 000000000..c7d8a4784 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtScreenDevice.java @@ -0,0 +1,115 @@ +/* QtScreenDevice.java -- Wrapper on a Qt screen Widget + 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.java.awt.peer.qt; + +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.DisplayMode; +import java.awt.GraphicsConfigTemplate; +import java.awt.Rectangle; +import java.awt.Window; + +public class QtScreenDevice extends GraphicsDevice +{ + private long nativeObject; + private int id; + private String IDstring; + QtScreenDeviceConfiguration config; + + public QtScreenDevice(int id) + { + this.id = id; + IDstring = "QtScreen" + id; + init( id ); + config = new QtScreenDeviceConfiguration(this); + } + + public native void init( int id ); + public native void dispose(); + + // Package-private methods used by QtScreenDeviceConfiguration + native Rectangle getBounds(); + native int getDpiX(); + native int getDpiY(); + native int depth(); + + // ****************** Public methods *********************** + + public GraphicsConfiguration getBestConfiguration(GraphicsConfigTemplate gct) + { + return config; + } + + public GraphicsConfiguration[] getConfigurations() + { + return new GraphicsConfiguration[]{ config }; + } + + public GraphicsConfiguration getDefaultConfiguration() + { + return config; + } + + public String getIDstring() + { + return IDstring; + } + + public int getType() + { + return TYPE_RASTER_SCREEN; + } + + public boolean isDisplayChangeSupported() + { + return false; + } + + public boolean isFullScreenSupported() + { + return false; + } + + public void setDisplayMode(DisplayMode dm) + { + } + + public void setFullScreenWindow(Window w) + { + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtScreenDeviceConfiguration.java b/libjava/classpath/gnu/java/awt/peer/qt/QtScreenDeviceConfiguration.java new file mode 100644 index 000000000..34de36c09 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtScreenDeviceConfiguration.java @@ -0,0 +1,145 @@ +/* QtScreenDeviceConfiguration.java -- + 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.java.awt.peer.qt; + +import java.awt.ImageCapabilities; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.Rectangle; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.VolatileImage; +import java.awt.geom.AffineTransform; + +public class QtScreenDeviceConfiguration extends GraphicsConfiguration { + + private QtScreenDevice owner; + private Rectangle bounds; + private double dpiX, dpiY; + private int depth; + + public QtScreenDeviceConfiguration(QtScreenDevice owner) + { + this.owner = owner; + bounds = owner.getBounds(); + dpiX = owner.getDpiX(); + dpiY = owner.getDpiY(); + depth = owner.depth(); + } + + public BufferedImage createCompatibleImage(int width, int height) + { + switch( depth ) + { + case 24: + return new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR); + case 16: + return new BufferedImage(width, height, + BufferedImage.TYPE_USHORT_565_RGB); + case 8: + return new BufferedImage(width, height, BufferedImage.TYPE_BYTE_INDEXED); + default: + case 32: + return new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + } + } + + public BufferedImage createCompatibleImage(int width, int height, int transparency) + { + // FIXME: Take the transpareny flag into account? + // For now, ignore it and just use an alpha channel. + if(depth == 32) + return new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + return createCompatibleImage(width, height); + } + + public VolatileImage createCompatibleVolatileImage(int width, int height) + { + return new QtVolatileImage( width, height ); + } + + public VolatileImage createCompatibleVolatileImage(int width, int height, + ImageCapabilities caps) + { + return createCompatibleVolatileImage( width, height ); + } + + public Rectangle getBounds() + { + return bounds; + } + + public ColorModel getColorModel() + { + // FIXME? + return QtToolkit.getDefaultToolkit().getColorModel(); + } + + public ColorModel getColorModel(int transparency) + { + // FIXME? + return QtToolkit.getDefaultToolkit().getColorModel(); + } + + public AffineTransform getDefaultTransform() + { + return new AffineTransform(); + } + + public GraphicsDevice getDevice() + { + return owner; + } + + /** + * Returns the transform which transforms from this display's resolution + * to a 72 DPI resolution. + */ + public AffineTransform getNormalizingTransform() + { + AffineTransform nTrans = new AffineTransform(); + nTrans.scale( 72.0 / dpiX, 72.0 / dpiY ); + return nTrans; + } + + public VolatileImage createCompatibleVolatileImage(int width, int height, + int transparency) + { + return createCompatibleVolatileImage(width, height); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtScrollPanePeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtScrollPanePeer.java new file mode 100644 index 000000000..079d06de7 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtScrollPanePeer.java @@ -0,0 +1,90 @@ +/* QtScrollPanePeer.java -- + 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.java.awt.peer.qt; + +import java.awt.Adjustable; +import java.awt.Insets; +import java.awt.ScrollPane; +import java.awt.peer.ScrollPanePeer; + +public class QtScrollPanePeer extends QtContainerPeer implements ScrollPanePeer +{ + public QtScrollPanePeer( QtToolkit kit, ScrollPane owner ) + { + super( kit, owner ); + } + + protected native void init(); + + protected void setup() + { + super.setup(); + setPolicy( ((ScrollPane)owner).getScrollbarDisplayPolicy() ); + } + + private native void setPolicy(int policy); + + // ************ Public methods ********************* + + public native void childResized(int width, int height); + + public native int getHScrollbarHeight(); + + public native int getVScrollbarWidth(); + + public native void setScrollPosition(int x, int y); + + public Insets getInsets() + { + // FIXME : more accurate? + return new Insets(5 + getHScrollbarHeight(), // Top + 5 + getVScrollbarWidth(), // Left + 5, // Bottom + 5); // Right + } + + public void setUnitIncrement(Adjustable item, int inc) + { + // FIXME + } + + public void setValue(Adjustable item, int value) + { + // FIXME + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtScrollbarPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtScrollbarPeer.java new file mode 100644 index 000000000..694287131 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtScrollbarPeer.java @@ -0,0 +1,80 @@ +/* QtScrollbarPeer.java -- + 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.java.awt.peer.qt; + +import java.awt.Scrollbar; +import java.awt.event.AdjustmentEvent; +import java.awt.peer.ScrollbarPeer; + +public class QtScrollbarPeer extends QtComponentPeer implements ScrollbarPeer +{ + public QtScrollbarPeer( QtToolkit kit, Scrollbar owner ) + { + super( kit, owner ); + } + + public native void init(); + + protected void setup() + { + super.setup(); + Scrollbar o = (Scrollbar)owner; + setValues(o.getValue(), o.getVisible(), o.getMinimum(), o.getMaximum()); + setOrientation(o.getOrientation()); + setLineIncrement(o.getLineIncrement()); + setPageIncrement(o.getPageIncrement()); + } + + private native void setOrientation(int orientation); + + private void fireMoved(int type, int value) + { + AdjustmentEvent e = new AdjustmentEvent((Scrollbar)owner, + AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED, + type, value); + QtToolkit.eventQueue.postEvent(e); + } + + // ************ Public methods ********************* + + public native void setLineIncrement(int inc); + + public native void setPageIncrement(int inc); + + public native void setValues(int value, int visible, int min, int max); +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtTextAreaPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtTextAreaPeer.java new file mode 100644 index 000000000..a5aff58ef --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtTextAreaPeer.java @@ -0,0 +1,179 @@ +/* QtTextAreaPeer.java -- + 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.java.awt.peer.qt; + +import java.awt.Dimension; +import java.awt.Rectangle; +import java.awt.TextArea; +import java.awt.event.TextEvent; +import java.awt.im.InputMethodRequests; +import java.awt.peer.TextAreaPeer; + +public class QtTextAreaPeer extends QtComponentPeer implements TextAreaPeer +{ + public QtTextAreaPeer( QtToolkit kit, TextArea owner ) + { + super( kit, owner ); + } + + protected native void init(); + + protected void setup() + { + super.setup(); + setText(((TextArea)owner).getText()); + setEditable(((TextArea)owner).isEditable()); + } + + /** + * Returns the start (start = true) or end (start = false) of the selection. + */ + private native int getSelection(boolean start); + + /** + * Called back on a text edit. + */ + private void textChanged() + { + TextEvent e = new TextEvent(owner, TextEvent.TEXT_VALUE_CHANGED); + QtToolkit.eventQueue.postEvent(e); + } + + // ************ Public methods ********************* + + public long filterEvents(long filter) + { + return filter; + } + + public native int getCaretPosition(); + + public Rectangle getCharacterBounds(int pos) + { + // FIXME + return new Rectangle(0,0,0,0); + } + + /** + * Implemented, but who uses it? + */ + public native int getIndexAtPoint(int x, int y); + +// public void reshape(int x, int y, +// int width, int height) +// { +// if(width != 0 || height != 0) +// super.reshape(x, y, width, height); +// else +// super.reshape(x, y, 10, 10); +// } + + public Dimension getMinimumSize(int rows, int cols) + { + // FIXME + return getMinimumSize(); + } + + public Dimension getPreferredSize(int rows, int cols) + { + // FIXME + return getPreferredSize(); + } + + public int getSelectionEnd() + { + return getSelection(false); + } + + public int getSelectionStart() + { + return getSelection(true); + } + + public native String getText(); + + public void insert(String text, int pos) + { + // Not very efficient, no. + String s = getText(); + setText(s.substring(0, pos) + text + s.substring(pos)); + } + + public void insertText(String text, int pos) + { + insert(text, pos); + } + + public Dimension minimumSize(int rows, int cols) + { + return getMinimumSize(rows, cols); + } + + public Dimension preferredSize(int rows, int cols) + { + return getPreferredSize(rows, cols); + } + + public void replaceRange(String insert, int start_pos, int end_pos) + { + // Not very efficient, no. + String text = getText(); + String right = text.substring(0, start_pos); + String left = text.substring(end_pos); + setText(right + insert + left); + } + + public void replaceText(String text, int start_pos, int end_pos) + { + replaceRange(text, start_pos, end_pos); + } + + public native void setText(String text); + + public native void select(int start_pos, int end_pos); + + public native void setEditable(boolean editable); + + public native void setCaretPosition(int pos); + + public InputMethodRequests getInputMethodRequests() + { + // TODO Auto-generated method stub + return null; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtTextFieldPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtTextFieldPeer.java new file mode 100644 index 000000000..f92943202 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtTextFieldPeer.java @@ -0,0 +1,159 @@ +/* QtTextFieldPeer.java -- + 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.java.awt.peer.qt; + +import java.awt.Dimension; +import java.awt.Rectangle; +import java.awt.TextField; +import java.awt.event.TextEvent; +import java.awt.im.InputMethodRequests; +import java.awt.peer.TextFieldPeer; + +public class QtTextFieldPeer extends QtComponentPeer implements TextFieldPeer +{ + public QtTextFieldPeer( QtToolkit kit, TextField owner ) + { + super( kit, owner ); + } + + protected native void init(); + + protected void setup() + { + super.setup(); + setText(((TextField)owner).getText()); + setEditable(((TextField)owner).isEditable()); + } + + /** + * Called back on a text edit. + */ + private void textChanged() + { + TextEvent e = new TextEvent(owner, TextEvent.TEXT_VALUE_CHANGED); + QtToolkit.eventQueue.postEvent(e); + } + + /** + * Returns the start (start = true) or end (start = false) of the selection. + */ + private native int getSelection(boolean start); + + private native Dimension getMinimumSizeNative(int columns); + + private native Dimension getPreferredSizeNative(int columns); + + // ************ Public methods ********************* + + public long filterEvents(long e) + { + return e; + } + + public native int getCaretPosition(); + + public Rectangle getCharacterBounds(int i) + { + return new Rectangle(0,0,0,0); + } + + public int getIndexAtPoint(int x, int y) + { + // FIXME + return 0; + } + + public Dimension getMinimumSize(int columns) + { + Dimension d = getMinimumSizeNative( columns ); + if ( d == null ) + return new Dimension(10, 10); + return d; + } + + public Dimension getPreferredSize(int columns) + { + Dimension d = getPreferredSizeNative( columns ); + if ( d == null ) + return owner.getSize(); + return d; + } + + public int getSelectionEnd() + { + return getSelection(false); + } + + public int getSelectionStart() + { + return getSelection(true); + } + + public native String getText(); + + public Dimension minimumSize(int cols) + { + return getMinimumSize(cols); + } + + public Dimension preferredSize(int cols) + { + return getPreferredSize(cols); + } + + public native void select(int selStart, int selEnd); + + public native void setCaretPosition(int pos); + + public void setEchoCharacter(char c) + { + setEchoChar(c); + } + + public native void setEchoChar(char echoChar); + + public native void setEditable(boolean editable); + + public native void setText(String l); + + public InputMethodRequests getInputMethodRequests() + { + // TODO Auto-generated method stub + return null; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtToolkit.java b/libjava/classpath/gnu/java/awt/peer/qt/QtToolkit.java new file mode 100644 index 000000000..9f8a691c6 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtToolkit.java @@ -0,0 +1,470 @@ +/* QtToolkit.java -- + Copyright (C) 2005, 2006, 2007 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.qt; + +import gnu.java.awt.ClasspathToolkit; +import gnu.java.awt.EmbeddedWindow; +import gnu.java.awt.peer.ClasspathFontPeer; +import gnu.java.awt.peer.EmbeddedWindowPeer; + +import java.awt.AWTException; +import java.awt.Button; +import java.awt.Canvas; +import java.awt.Checkbox; +import java.awt.CheckboxMenuItem; +import java.awt.Choice; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FileDialog; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Frame; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.Label; +import java.awt.List; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.PopupMenu; +import java.awt.PrintJob; +import java.awt.ScrollPane; +import java.awt.Scrollbar; +import java.awt.TextArea; +import java.awt.TextField; +import java.awt.Window; +import java.awt.datatransfer.Clipboard; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.peer.DragSourceContextPeer; +import java.awt.event.AWTEventListener; +import java.awt.im.InputMethodHighlight; +import java.awt.image.ColorModel; +import java.awt.image.DirectColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.peer.ButtonPeer; +import java.awt.peer.CanvasPeer; +import java.awt.peer.CheckboxMenuItemPeer; +import java.awt.peer.CheckboxPeer; +import java.awt.peer.ChoicePeer; +import java.awt.peer.DialogPeer; +import java.awt.peer.FileDialogPeer; +import java.awt.peer.FontPeer; +import java.awt.peer.FramePeer; +import java.awt.peer.LabelPeer; +import java.awt.peer.ListPeer; +import java.awt.peer.MenuBarPeer; +import java.awt.peer.MenuItemPeer; +import java.awt.peer.MenuPeer; +import java.awt.peer.PanelPeer; +import java.awt.peer.PopupMenuPeer; +import java.awt.peer.RobotPeer; +import java.awt.peer.ScrollPanePeer; +import java.awt.peer.ScrollbarPeer; +import java.awt.peer.TextAreaPeer; +import java.awt.peer.TextFieldPeer; +import java.awt.peer.WindowPeer; +import java.io.InputStream; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +public class QtToolkit extends ClasspathToolkit +{ + public static EventQueue eventQueue = null; // the native event queue + public static QtRepaintThread repaintThread = null; + public static MainQtThread guiThread = null; + public static QtGraphicsEnvironment graphicsEnv = null; + + private static void initToolkit() + { + eventQueue = new EventQueue(); + repaintThread = new QtRepaintThread(); + System.loadLibrary("qtpeer"); + + String theme = null; + try + { + String style = System.getProperty("qtoptions.style"); + if(style != null) + theme = style; + } + catch(SecurityException e) + { + } + catch(IllegalArgumentException e) + { + } + + boolean doublebuffer = true; + try + { + String style = System.getProperty("qtoptions.nodoublebuffer"); + if(style != null) + doublebuffer = false; + } + catch(SecurityException e) + { + } + catch(IllegalArgumentException e) + { + } + + guiThread = new MainQtThread( theme, doublebuffer ); + guiThread.start(); + repaintThread.start(); + } + + /** + * Construct the toolkit! + */ + public QtToolkit() + { + if( guiThread == null ) + initToolkit(); + + // make sure the GUI thread has started. + while (!guiThread.isRunning()) + ; + + if( graphicsEnv == null ) + graphicsEnv = new QtGraphicsEnvironment( this ); + } + + native String[] nativeFontFamilies(); + + native int numScreens(); + + native int defaultScreen(); + + // ************ Public methods ********************* + + public synchronized native void beep(); + + public int checkImage(Image image, int w, int h, ImageObserver observer) + { + if(image instanceof QtImage) + return ((QtImage)image).checkImage(observer); + + return ImageObserver.ERROR; // FIXME + } + + protected ButtonPeer createButton( Button target ) + { + return new QtButtonPeer( this, target ); + } + + protected CanvasPeer createCanvas(Canvas target) + { + return new QtCanvasPeer( this, target ); + } + + protected CheckboxPeer createCheckbox(Checkbox target) + { + return new QtCheckboxPeer( this, target ); + } + + protected ChoicePeer createChoice(Choice target) + { + return new QtChoicePeer( this, target ); + } + + protected CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem target) + { + return new QtMenuItemPeer( this, target ); + } + + public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge) + { + throw new RuntimeException("Not implemented"); + } + + protected FramePeer createFrame(Frame target) + { + return new QtFramePeer( this, target ); + } + + protected FileDialogPeer createFileDialog(FileDialog target) + { + return new QtFileDialogPeer( this, target ); + } + + public Image createImage(ImageProducer producer) + { + return new QtImage( producer ); + } + + public Image createImage(byte[] imageData, + int imageOffset, + int imageLength) + { + byte[] dataCopy = new byte[imageLength]; + System.arraycopy(imageData, imageOffset, dataCopy, 0, imageLength); + return new QtImage( dataCopy ); + } + + public Image createImage(String filename) + { + return new QtImage( filename ); + } + + public Image createImage(URL url) + { + return new QtImage( url ); + } + + protected TextFieldPeer createTextField(TextField target) + { + return new QtTextFieldPeer(this,target); + } + + protected LabelPeer createLabel(Label target) + { + return new QtLabelPeer( this, target ); + } + + protected ListPeer createList(List target) + { + return new QtListPeer( this, target ); + } + + protected ScrollbarPeer createScrollbar(Scrollbar target) + { + return new QtScrollbarPeer( this, target ); + } + + protected ScrollPanePeer createScrollPane(ScrollPane target) + { + return new QtScrollPanePeer( this, target ); + } + + protected TextAreaPeer createTextArea(TextArea target) + { + return new QtTextAreaPeer( this, target ); + } + + protected PanelPeer createPanel(Panel target) + { + return new QtPanelPeer( this, target); + } + + protected WindowPeer createWindow(Window target) + { + return new QtWindowPeer( this, target ); + } + + protected DialogPeer createDialog(Dialog target) + { + return new QtDialogPeer( this, target ); + } + + protected MenuBarPeer createMenuBar(MenuBar target) + { + return new QtMenuBarPeer( this, target ); + } + + protected MenuPeer createMenu(Menu target) + { + return new QtMenuPeer( this, target ); + } + + protected PopupMenuPeer createPopupMenu(PopupMenu target) + { + return new QtPopupMenuPeer( this, target ); + } + + protected MenuItemPeer createMenuItem(MenuItem target) + { + return new QtMenuItemPeer( this, target ); + } + + /** + * @since 1.4 + */ + public AWTEventListener[] getAWTEventListeners() + { + return null; // FIXME + } + + /** + * @since 1.4 + */ + public AWTEventListener[] getAWTEventListeners(long mask) + { + return null; // FIXME + } + + public ColorModel getColorModel() + { + return new DirectColorModel(32, + 0x00FF0000, + 0x0000FF00, + 0x000000FF, + 0xFF000000); + } + + /** + * Just return the defaults. + */ + public String[] getFontList() + { + String[] builtIn = new String[] { "Dialog", + "DialogInput", + "Monospaced", + "Serif", + "SansSerif" }; + String[] nat = nativeFontFamilies(); + String[] allFonts = new String[ nat.length + 5 ]; + System.arraycopy(builtIn, 0, allFonts, 0, 5); + System.arraycopy(nat, 0, allFonts, 5, nat.length); + return allFonts; + } + + public FontMetrics getFontMetrics(Font font) + { + return new QtFontMetrics(font); + } + + protected FontPeer getFontPeer(String name, + int style) + { + Map attrs = new HashMap (); + ClasspathFontPeer.copyStyleToAttrs(style, attrs); + ClasspathFontPeer.copySizeToAttrs(12, attrs); // Default size is 12. + return getClasspathFontPeer (name, attrs); + } + + public Image getImage(String filename) + { + return new QtImage(filename); + } + + public Image getImage(URL url) + { + return createImage( url ); + } + + public PrintJob getPrintJob(Frame frame, + String jobtitle, + Properties props) + { + SecurityManager sm; + sm = System.getSecurityManager(); + if (sm != null) + sm.checkPrintJobAccess(); + + throw new RuntimeException("Not implemented"); + } + + public Clipboard getSystemClipboard() + { + throw new RuntimeException("Not implemented"); + } + + protected EventQueue getSystemEventQueueImpl() + { + return eventQueue; + } + + public native Dimension getScreenSize(); + + public native int getScreenResolution(); + + public Map mapInputMethodHighlight(InputMethodHighlight highlight) + { + return null; // FIXME + } + + public boolean prepareImage(Image image, int w, int h, ImageObserver observer) + { + if(image instanceof QtImage) + return true; + return false; // FIXME? + } + + public native void sync(); + + // ********************** ClasspathToolkit methods + + public GraphicsEnvironment getLocalGraphicsEnvironment() + { + return graphicsEnv; + } + + public ClasspathFontPeer getClasspathFontPeer (String name, Map attrs) + { + return new QtFontPeer (name, attrs); + } + + // FIXME + public Font createFont(int format, InputStream stream) + { + throw new UnsupportedOperationException(); + } + + // FIXME + public RobotPeer createRobot (GraphicsDevice screen) throws AWTException + { + throw new UnsupportedOperationException(); + } + + public EmbeddedWindowPeer createEmbeddedWindow(EmbeddedWindow w) + { + // return new QtEmbeddedWindowPeer( this, w ); + return null; + } + + @Override + public boolean isModalExclusionTypeSupported + (Dialog.ModalExclusionType modalExclusionType) + { + return false; + } + + @Override + public boolean isModalityTypeSupported(Dialog.ModalityType modalityType) + { + return false; + } + + +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtVolatileImage.java b/libjava/classpath/gnu/java/awt/peer/qt/QtVolatileImage.java new file mode 100644 index 000000000..a203de0d0 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtVolatileImage.java @@ -0,0 +1,434 @@ +/* QtVolatileImage.java -- + 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.java.awt.peer.qt; + +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Color; +import java.awt.Image; +import java.awt.ImageCapabilities; +import java.awt.GraphicsConfiguration; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.DirectColorModel; +import java.awt.image.MemoryImageSource; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.image.VolatileImage; +import java.util.Hashtable; +import java.util.WeakHashMap; + +/** + * QtVolatileImage - wraps a QImage + * + */ +public class QtVolatileImage extends VolatileImage +{ + int width = -1, height = -1; + + /** + * Properties. + */ + Hashtable props; + + /** + * Pointer to the QImage + */ + long nativeObject; + + /* + * The 32-bit AARRGGBB format the uses. + */ + static ColorModel nativeModel = new DirectColorModel(32, + 0x00FF0000, + 0x0000FF00, + 0x000000FF, + 0xFF000000); + + /** + * Clears the image to RGBA 0 + */ + public native void clear(); + + /** + * Returns a copy of the pixel data as a java array. + */ + private native int[] getPixels(); + + /** + * Allocates a QImage + */ + private native void createImage(); + + /** + * HashMap of Graphics objects painting on this Image. + */ + WeakHashMap painters; + + /** + * Flags if this image is to be destroyed. + */ + boolean killFlag; + + /** + * Frees the above. + */ + private native void freeImage(); + + /** + * Blit a QImage + */ + public native void blit(QtImage i); + public native void blit(QtImage i, int x, int y, int w, int h); + + /** + * Sets the image to scaled copy of src image. hints are rendering hints. + */ + private native void createScaledImage(QtVolatileImage src, int hints); + + /** + * Draws the image optionally composited. + */ + private native void drawPixels (QtGraphics gc, + int bg_red, int bg_green, int bg_blue, + int x, int y, + boolean composite); + /** + * Draws the image, optionally scaled and composited. + */ + private native void drawPixelsScaled (QtGraphics gc, + int bg_red, int bg_green, int bg_blue, + int x, int y, int width, int height, + boolean composite); + + /** + * Draws the image transformed. + */ + private native void drawPixelsTransformed (QtGraphics gc, QMatrix transform); + + /** + * Draws the image scaled flipped and optionally composited. + */ + native void drawPixelsScaledFlipped (QtGraphics gc, + int bg_red, int bg_green, + int bg_blue, + boolean flipX, boolean flipY, + int srcX, int srcY, + int srcWidth, int srcHeight, + int dstX, int dstY, + int dstWidth, int dstHeight, + boolean composite); + + /** + * Constructs an empty QtVolatileImage. + */ + public QtVolatileImage (int width, int height) + { + this.width = width; + this.height = height; + props = new Hashtable(); + createImage(); + clear(); + } + + /** + * Constructs a scaled version of the src bitmap, using Qt + */ + private QtVolatileImage (QtVolatileImage src, int width, int height, + int hints) + { + this.width = width; + this.height = height; + props = new Hashtable(); + + createScaledImage(src, hints); + } + + + public void finalize() + { + dispose(); + } + + public void dispose() + { + if( painters == null || painters.isEmpty() ) + freeImage(); + else + killFlag = true; // can't destroy image yet. + // Do so when all painters are gone. + } + + // java.awt.Image methods //////////////////////////////////////////////// + + public int getWidth (ImageObserver observer) + { + return getWidth(); + } + + public int getHeight (ImageObserver observer) + { + return getHeight(); + } + + public Object getProperty (String name, ImageObserver observer) + { + Object value = props.get (name); + return (value == null) ? UndefinedProperty : value; + } + + /** + * Returns the source of this image. + */ + public ImageProducer getSource () + { + return new MemoryImageSource(width, height, nativeModel, getPixels(), + 0, width); + } + + void putPainter(QtImageGraphics g) + { + if( painters == null ) + painters = new WeakHashMap(); + painters.put( g, "dummy" ); + } + + void removePainter(QtImageGraphics g) + { + painters.remove( g ); + if( killFlag && painters.isEmpty() ) + freeImage(); + } + + /** + * Creates a Graphics context for this image. + */ + public Graphics getGraphics () + { + QtImageGraphics g = new QtImageGraphics( this ); + putPainter( g ); + return g; + } + + /** + * Returns a scaled instance of this image. + */ + public Image getScaledInstance(int width, + int height, + int hints) + { + if (width <= 0 || height <= 0) + throw new IllegalArgumentException("Width and height of scaled bitmap"+ + "must be >= 0"); + + return new QtVolatileImage(this, width, height, hints); + } + + /** + */ + public void flush () + { + // FIXME ? + } + + /** + * Returns the image status, used by QtToolkit + */ + public int checkImage (ImageObserver observer) + { + return ImageObserver.ALLBITS | ImageObserver.WIDTH | ImageObserver.HEIGHT; + } + + // Drawing methods //////////////////////////////////////////////// + + /** + * Draws an image with eventual scaling/transforming. + */ + public boolean drawImage (QtGraphics g, QMatrix matrix, + ImageObserver observer) + { + drawPixelsTransformed (g, matrix); + return true; + } + + /** + * Draws an image to the QtGraphics context, at (x,y) with optional + * compositing with a background color. + */ + public boolean drawImage (QtGraphics g, int x, int y, + Color bgcolor, ImageObserver observer) + { + if(bgcolor != null) + drawPixels(g, bgcolor.getRed (), bgcolor.getGreen (), + bgcolor.getBlue (), x, y, true); + else + drawPixels(g, 0, 0, 0, x, y, false); + + return true; + } + + /** + * Draws an image to the QtGraphics context, at (x,y) scaled to + * width and height, with optional compositing with a background color. + */ + public boolean drawImage (QtGraphics g, int x, int y, int width, int height, + Color bgcolor, ImageObserver observer) + { + if(bgcolor != null) + drawPixelsScaled(g, bgcolor.getRed (), bgcolor.getGreen (), + bgcolor.getBlue (), x, y, width, height, true); + else + drawPixelsScaled(g, 0, 0, 0, x, y, width, height, false); + + return true; + } + + /** + * Draws an image with eventual scaling/transforming. + */ + public boolean drawImage (QtGraphics g, int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, + Color bgcolor, ImageObserver observer) + { + boolean flipX = (dx1 > dx2)^(sx1 > sx2); + boolean flipY = (dy1 > dy2)^(sy1 > sy2); + int dstWidth = Math.abs (dx2 - dx1); + int dstHeight = Math.abs (dy2 - dy1); + int srcWidth = Math.abs (sx2 - sx1); + int srcHeight = Math.abs (sy2 - sy1); + int srcX = (sx1 < sx2) ? sx1 : sx2; + int srcY = (sy1 < sy2) ? sy1 : sy2; + int dstX = (dx1 < dx2) ? dx1 : dx2; + int dstY = (dy1 < dy2) ? dy1 : dy2; + + // Clipping. This requires the dst to be scaled as well, + if (srcWidth > width) + { + dstWidth = (int)((double)dstWidth*((double)width/(double)srcWidth)); + srcWidth = width - srcX; + } + + if (srcHeight > height) + { + dstHeight = (int)((double)dstHeight*((double)height/(double)srcHeight)); + srcHeight = height - srcY; + } + + if (srcWidth + srcX > width) + { + dstWidth = (int)((double)dstWidth * (double)(width - srcX)/(double)srcWidth); + srcWidth = width - srcX; + } + + if (srcHeight + srcY > height) + { + dstHeight = (int)((double)dstHeight * (double)(width - srcY)/(double)srcHeight); + srcHeight = height - srcY; + } + + if ( srcWidth <= 0 || srcHeight <= 0 || dstWidth <= 0 || dstHeight <= 0) + return true; + + if(bgcolor != null) + drawPixelsScaledFlipped (g, bgcolor.getRed (), bgcolor.getGreen (), + bgcolor.getBlue (), + flipX, flipY, + srcX, srcY, + srcWidth, srcHeight, + dstX, dstY, + dstWidth, dstHeight, + true); + else + drawPixelsScaledFlipped (g, 0, 0, 0, flipX, flipY, + srcX, srcY, srcWidth, srcHeight, + dstX, dstY, dstWidth, dstHeight, + false); + return true; + } + + public native void copyArea(int x, int y, int width, int height, + int dx, int dy); + + //******************** VolatileImage stuff ******************** + + public boolean contentsLost() + { + return false; + } + + public Graphics2D createGraphics() + { + QtImageGraphics g = new QtImageGraphics(this); + putPainter( g ); + return g; + } + + public ImageCapabilities getCapabilities() + { + return new ImageCapabilities(false) + { + public boolean isTrueVolatile() + { + return false; + } + }; + } + + public int getHeight() + { + return height; + } + + public BufferedImage getSnapshot() + { + BufferedImage bi = new BufferedImage(width, height, + BufferedImage.TYPE_INT_ARGB_PRE); + bi.setRGB( 0, 0, width, height, getPixels(), 0, width); + return bi; + } + + public int getWidth() + { + return width; + } + + public int validate(GraphicsConfiguration gc) + { + return IMAGE_OK; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtWindowPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtWindowPeer.java new file mode 100644 index 000000000..2dfe2ec5a --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtWindowPeer.java @@ -0,0 +1,105 @@ +/* QtWindowPeer.java -- + 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.java.awt.peer.qt; + +import java.awt.Component; +import java.awt.peer.WindowPeer; + +public class QtWindowPeer extends QtContainerPeer implements WindowPeer +{ + public QtWindowPeer( QtToolkit kit, Component owner ) + { + super( kit, owner ); + } + + protected native void init(); + + protected void setup() + { + super.setup(); + } + + // ************ Public methods ********************* + + public native void toBack(); + + public native void toFront(); + + /* + * Belongs to Frame and Dialog, but no sense in duplicating code. + */ + public native void setTitle(String title); + + public void updateAlwaysOnTop() + { + // TODO Auto-generated method stub + + } + + public boolean requestWindowFocus() + { + // TODO Auto-generated method stub + return false; + } + + public void updateIconImages() + { + // TODO: Implement properly. + } + + public void updateMinimumSize() + { + // TODO: Implement properly. + } + + public void setModalBlocked(java.awt.Dialog d, boolean b) + { + // TODO: Implement properly. + } + + public void updateFocusableWindowState() + { + // TODO: Implement properly. + } + + public void setAlwaysOnTop(boolean b) + { + // TODO: Implement properly. + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingButtonPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingButtonPeer.java new file mode 100644 index 000000000..1a42fc953 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingButtonPeer.java @@ -0,0 +1,261 @@ +/* SwingButtonPeer.java -- A Swing based peer for AWT buttons + Copyright (C) 2006, 2007 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.Container; +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.FocusEvent; +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 + { + Button button; + + SwingButton(Button button) + { + this.button = button; + } + + /** + * 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 true if the button is currently showing, + * false otherwise + */ + public boolean isShowing() + { + boolean retVal = false; + if (button != null) + retVal = button.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 + * processMouseEvent() 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 + * processMouseMotionEvent() 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 + * processKeyEvent() after having retargetted it to this + * button. + * + * @param ev the mouse event + */ + public void handleKeyEvent(KeyEvent ev) + { + ev.setSource(this); + processKeyEvent(ev); + } + + public Container getParent() + { + Container par = null; + if (button != null) + par = button.getParent(); + return par; + } + + /** + * Handles focus events by forwarding it to + * processFocusEvent(). + * + * @param ev the Focus event + */ + public void handleFocusEvent(FocusEvent ev) + { + processFocusEvent(ev); + } + + public void requestFocus() { + SwingButtonPeer.this.requestFocus(awtComponent, false, true, 0); + } + + public boolean requestFocus(boolean temporary) { + return SwingButtonPeer.this.requestFocus(awtComponent, temporary, + true, 0); + } + } + + /** + * 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(theButton); + 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/libjava/classpath/gnu/java/awt/peer/swing/SwingCanvasPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingCanvasPeer.java new file mode 100644 index 000000000..abef9ef12 --- /dev/null +++ b/libjava/classpath/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 SwingCanvasPeer for the specified Canvas. + * + * @param canvas the canvas. + */ + public SwingCanvasPeer(Canvas canvas) + { + init(canvas, null); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingCheckboxPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingCheckboxPeer.java new file mode 100755 index 000000000..7080831a2 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingCheckboxPeer.java @@ -0,0 +1,256 @@ +/* SwingCheckboxPeer.java -- A Swing based peer for AWT checkboxes + Copyright (C) 2007 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.Checkbox; +import java.awt.CheckboxGroup; +import java.awt.Container; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Point; +import java.awt.event.FocusEvent; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.peer.CheckboxPeer; + +import javax.swing.JCheckBox; +import javax.swing.JComponent; +import javax.swing.JToggleButton; + +/** + * A CheckboxPeer implementation that is backed by the Swing JCheckBox. + */ +public class SwingCheckboxPeer extends SwingComponentPeer implements + CheckboxPeer { + + /** + * A spezialized Swing checkbox used to paint the checkbox for the + * AWT checkbox. + */ + private class SwingCheckbox + extends JCheckBox + implements SwingComponent + { + Checkbox checkbox; + + SwingCheckbox(Checkbox checkbox) + { + this.checkbox = checkbox; + } + + /** + * Returns this checkbox. + * + * @return this + */ + public JComponent getJComponent() + { + return this; + } + + /** + * Handles mouse events by forwarding it to + * processMouseEvent(). + * + * @param ev the mouse event + */ + public void handleMouseEvent(MouseEvent ev) + { + ev.setSource(this); + processMouseEvent(ev); + } + + /** + * Handles mouse motion events by forwarding it to + * processMouseMotionEvent(). + * + * @param ev the mouse motion event + */ + public void handleMouseMotionEvent(MouseEvent ev) + { + ev.setSource(this); + processMouseMotionEvent(ev); + } + + /** + * Handles key events by forwarding it to processKeyEvent(). + * + * @param ev the mouse event + */ + public void handleKeyEvent(KeyEvent ev) + { + ev.setSource(this); + processKeyEvent(ev); + } + + /** + * Handles focus events by forwarding it to + * processFocusEvent(). + * + * @param ev the Focus event + */ + public void handleFocusEvent(FocusEvent ev) + { + processFocusEvent(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 SwingCheckboxPeer.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 true if the button is currently showing, + * false otherwise + */ + public boolean isShowing() + { + boolean retVal = false; + if (checkbox != null) + retVal = checkbox.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 SwingCheckboxPeer.this.createImage(w, h); + } + + public Graphics getGraphics() + { + return SwingCheckboxPeer.this.getGraphics(); + } + + public Container getParent() + { + Container par = null; + if (checkbox != null) + par = checkbox.getParent(); + return par; + } + + public void requestFocus() { + SwingCheckboxPeer.this.requestFocus(awtComponent, false, true, 0); + } + + public boolean requestFocus(boolean temporary) { + return SwingCheckboxPeer.this.requestFocus(awtComponent, temporary, + true, 0); + } + } + + /** + * Listens for ActionEvents on the Swing button and triggers corresponding + * ActionEvents on the AWT button. + */ + class SwingCheckboxListener implements ItemListener + { + Checkbox awtCheckbox; + + SwingCheckboxListener(Checkbox checkbox) + { + awtCheckbox = checkbox; + } + + /** + * Receives notification when an action was performend on the button. + * + * @param event the action event + */ + public void itemStateChanged(ItemEvent event) + { + awtCheckbox.setState(event.getStateChange()==ItemEvent.SELECTED); + ItemListener[] l = awtCheckbox.getItemListeners(); + if (l.length == 0) + return; + ItemEvent ev = new ItemEvent(awtCheckbox, ItemEvent.ITEM_STATE_CHANGED, + awtCheckbox, event.getStateChange()); + for (int i = 0; i < l.length; ++i) + l[i].itemStateChanged(ev); + } + } + + /** + * Creates a new SwingCheckboxPeer instance. + */ + public SwingCheckboxPeer(Checkbox checkbox) + { + SwingCheckbox swingCheckbox = new SwingCheckbox(checkbox); + swingCheckbox.addItemListener(new SwingCheckboxListener(checkbox)); + + init(checkbox, swingCheckbox); + setLabel(checkbox.getLabel()); + setState(checkbox.getState()); + } + + public void setCheckboxGroup(CheckboxGroup group) + { + // TODO: Implement this. + } + + public void setLabel(String label) + { + ((JToggleButton) swingComponent).setText(label); + } + + public void setState(boolean state) + { + ((JToggleButton) swingComponent).setSelected(state); + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingComponent.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingComponent.java new file mode 100644 index 000000000..ca42fb748 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingComponent.java @@ -0,0 +1,99 @@ +/* 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.FocusEvent; +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); + + /** + * Handles a focus event. This is usually forwarded to + * {@link Component#processFocusEvent(FocusEvent)} of the swing + * component. + * + * @param ev the focus event + */ + void handleFocusEvent(FocusEvent ev); +} diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingComponentPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingComponentPeer.java new file mode 100644 index 000000000..8be95dcb7 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingComponentPeer.java @@ -0,0 +1,1136 @@ +/* SwingComponentPeer.java -- An abstract base class for Swing based peers + Copyright (C) 2006, 2007 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.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.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.FocusEvent; +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; +import java.awt.peer.LightweightPeer; + +import javax.swing.JComponent; +import javax.swing.RepaintManager; + +/** + * 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; + + /** + * The font that is set for this peer. + */ + protected Font peerFont; + + /** + * The current repaint area. + */ + protected Rectangle paintArea; + + /** + * 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; + if (swingComponent != null) + { + JComponent c = swingComponent.getJComponent(); + if (c != null) + { + c.addNotify(); + RepaintManager.currentManager(c).setDoubleBufferingEnabled(false); + System.setProperty("gnu.awt.swing.doublebuffering", "true"); + } + } + + // Register this heavyweight component with the nearest heavyweight + // container, so we get peerPaint() triggered by that container. + if (! (this instanceof LightweightPeer)) + { + Component comp = awtComponent; + Container parent = comp.getParent(); + while (parent != null && + ! (parent.getPeer() instanceof SwingContainerPeer)) + { + comp = parent; + parent = comp.getParent(); + } + + // At this point we have the ancestor with a SwingContainerPeer + // (or null peer). + if (parent != null && parent.getPeer() instanceof SwingContainerPeer) + { + SwingContainerPeer p = (SwingContainerPeer) parent.getPeer(); + p.addHeavyweightDescendent(awtComponent); + } + } + } + + /** + * 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 width and + * height. + * + * 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() + { + // Unregister this heavyweight component from the nearest heavyweight + // container. + if (! (this instanceof LightweightPeer)) + { + Component comp = awtComponent; + Container parent = comp.getParent(); + while (parent != null && + ! (parent.getPeer() instanceof SwingContainerPeer)) + { + comp = parent; + parent = comp.getParent(); + } + + // At this point we have the ancestor with a SwingContainerPeer + // (or null peer). + if (parent != null && parent.getPeer() instanceof SwingContainerPeer) + { + SwingContainerPeer p = (SwingContainerPeer) parent.getPeer(); + p.removeHeavyweightDescendent(awtComponent); + } + } + + 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(); + Graphics g = parent.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() + { + return minimumSize(); + } + + /** + * 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() + { + return preferredSize(); + } + + /** + * 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: + if (awtComponent.isShowing()) + { + Rectangle clip ; + synchronized (this) + { + coalescePaintEvent((PaintEvent) e); + assert paintArea != null; + clip = paintArea; + paintArea = null; + } + Graphics g = awtComponent.getGraphics(); + try + { + g.clipRect(clip.x, clip.y, clip.width, clip.height); + peerPaint(g, e.getID() == PaintEvent.UPDATE); + } + finally + { + 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; + case FocusEvent.FOCUS_GAINED: + case FocusEvent.FOCUS_LOST: + handleFocusEvent((FocusEvent)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); + + Component parent = awtComponent.getParent(); + if (parent != null) + parent.repaint(awtComponent.getX(), awtComponent.getY(), + awtComponent.getWidth(), awtComponent.getHeight()); + } + + /** + * Returns true 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 true 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; + } + + /** + * Paints the component. This is triggered by + * {@link Component#paintAll(Graphics)}. + * + * @param graphics the graphics to paint with + */ + public void paint(Graphics graphics) + { + peerPaint(graphics, false); + } + + /** + * 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) + */ + public boolean prepareImage(Image img, int width, int height, ImageObserver ob) + { + Component parent = awtComponent.getParent(); + if(parent != null) + { + ComponentPeer parentPeer = parent.getPeer(); + return parentPeer.prepareImage(img, width, height, ob); + } + else + { + return Toolkit.getDefaultToolkit().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) + { + // NOTE: This is never called by AWT but is mandated by the peer interface. + 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() + { + // NOTE: This is never called by AWT but is mandated by the peer interface. + Toolkit tk = Toolkit.getDefaultToolkit(); + EventQueue q = tk.getSystemEventQueue(); + q.postEvent(new FocusEvent(awtComponent, FocusEvent.FOCUS_GAINED, false)); + } + + /** + * Requests that this component receives the focus. This is called from + * {@link Component#requestFocus()}. + * + * This calls requestFocus() on the Swing component. + * + * @param source the actual component that requests focus (may be a + * lightweight descendant of the heavyweight container) + * @param tmp true when the change is temporary + * @param allowWindowFocus + * @param tm the timestamp of the focus change + * + * @return true when the focus change is guaranteed to be granted, false + * otherwise + */ + public boolean requestFocus(Component source, boolean tmp, + boolean allowWindowFocus, long tm) + { + Toolkit tk = Toolkit.getDefaultToolkit(); + EventQueue q = tk.getSystemEventQueue(); + q.postEvent(new FocusEvent(source, FocusEvent.FOCUS_GAINED, tmp)); + return true; + } + + /** + * 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) + { + reshape(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 true to enable the component, + * false 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) + { + peerFont = 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 true to make the component visible, + * false to make it invisible + */ + public void setVisible(boolean visible) + { + if (visible) + show(); + else + hide(); + } + + /** + * 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 true if this component has been obscured, + * false otherwise. This will only work if + * {@link #canDetermineObscurity()} also returns true. + * + * This is not yet implemented. + * + * @return true if this component has been obscured, + * false otherwise. + */ + public boolean isObscured() + { + return false; + } + + /** + * Returns true if this component peer can determine if the + * component has been obscured, false otherwise. + * + * This is not yet implemented. + * + * @return true if this component peer can determine if the + * component has been obscured, false otherwise + */ + public boolean canDetermineObscurity() + { + return false; + } + + /** + * Coalesces the specified paint event. + * + * @param e the paint event + */ + public void coalescePaintEvent(PaintEvent e) + { + synchronized (this) + { + Rectangle newRect = e.getUpdateRect(); + if (paintArea == null) + paintArea = newRect; + else + Rectangle.union(paintArea, newRect, paintArea); + } + } + + /** + * 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, + * false otherwise. + * + * This is not yet implemented and returns false. + * + * @return true, if this component can handle wheel scrolling, + * false 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(); + VolatileImage im = null; + if (parent != null) + { + ComponentPeer parentPeer = parent.getPeer(); + im = parentPeer.createVolatileImage(width, height); + } + return im; + } + + /** + * 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 + * @param update wether we need to call update or paint on the AWT component + */ + protected void peerPaint(Graphics g, boolean update) + { + peerPaintComponent(g); + + Graphics userGraphics = g.create(); + try{ + if (update) + awtComponent.update(userGraphics); + else + awtComponent.paint(userGraphics); + } finally { + userGraphics.dispose(); + } + + } + + /** + * Paints the actual 'heavyweight' swing component, if there is one + * associated to this peer. + * + * @param g the graphics to paint the component with + */ + protected void peerPaintComponent(Graphics g) + { + // Paint the actual Swing component if this peer has one. + 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); + } + + /** + * Handles focus events on the component. This is usually forwarded to the + * SwingComponent's processFocusEvent() method. + * + * @param e the key event + */ + protected void handleFocusEvent(FocusEvent e) + { + if (swingComponent != null) + swingComponent.handleFocusEvent(e); + } + + + /** + * Returns the AWT component for this peer. + * + * @return the AWT component for this peer + */ + public Component getComponent() + { + return awtComponent; + } + + public boolean requestFocus(Component lightweightChild, boolean temporary, + boolean focusedWindowChangeAllowed, + long time, sun.awt.CausedFocusEvent.Cause cause) + { + return true; + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingContainerPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingContainerPeer.java new file mode 100644 index 000000000..ca3adc4c7 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingContainerPeer.java @@ -0,0 +1,378 @@ +/* SwingContainerPeer.java -- A Swing based peer for AWT containers + Copyright (C) 2006, 2007 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 gnu.classpath.SystemProperties; + +import java.awt.Component; +import java.awt.Container; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Insets; +import java.awt.Rectangle; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.peer.ComponentPeer; +import java.awt.peer.ContainerPeer; +import java.util.Iterator; +import java.util.LinkedList; + +/** + * 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 +{ + + /** + * Stores all heavyweight descendents of the container. This is used + * in {@link #peerPaintChildren(Graphics)}. + */ + private LinkedList heavyweightDescendents; + + /** + * The backbuffer used for painting UPDATE events. + */ + private Image backbuffer; + + /** + * Creates a new SwingContainerPeer. + * + * @param awtCont + */ + public SwingContainerPeer(Container awtCont) + { + heavyweightDescendents = new LinkedList(); + } + + /** + * Registers a heavyweight descendent. This is then painted by + * {@link #peerPaintChildren(Graphics)}. + * + * @param comp the descendent to register + * + * @see #peerPaintChildren(Graphics) + * @see #removeHeavyweightDescendent(Component) + */ + protected synchronized void addHeavyweightDescendent(Component comp) + { + heavyweightDescendents.add(comp); + focusOwner = null; + } + + /** + * Unregisters a heavyweight descendent. + * + * @param comp the descendent to unregister + * + * @see #peerPaintChildren(Graphics) + * @see #addHeavyweightDescendent(Component) + */ + protected synchronized void removeHeavyweightDescendent(Component comp) + { + heavyweightDescendents.remove(comp); + focusOwner = null; + } + + /** + * Returns an array of all registered heavyweight descendents. + * + * @return all registered heavyweight descendents + */ + protected Component[] getHeavyweightDescendents() + { + Component[] heavyweights = new Component[heavyweightDescendents.size()]; + heavyweights = (Component[]) heavyweightDescendents.toArray(heavyweights); + return heavyweights; + } + + /** + * 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() + { + return insets(); + } + + /** + * 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 false unconditionally. This method is not used at + * the moment. + * + * @return false + */ + public boolean isPaintPending() + { + return false; + } + + /** + * Returns false unconditionally. This method is not used at + * the moment. + * + * @return false + */ + 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. + } + + /** + * Performs the super behaviour (call peerPaintComponent() and + * awtComponent.paint()), and forwards the paint request to the heavyweight + * descendents of the container. + */ + protected void peerPaint(Graphics g, boolean update) + { + if (isDoubleBuffering()) + { + int width = awtComponent.getWidth(); + int height = awtComponent.getHeight(); + if (backbuffer == null + || backbuffer.getWidth(awtComponent) < width + || backbuffer.getHeight(awtComponent) < height) + backbuffer = awtComponent.createImage(width, height); + Graphics g2 = backbuffer.getGraphics(); + Rectangle clip = g.getClipRect(); + try + { + g2.setClip(clip); + super.peerPaint(g2, update); + peerPaintChildren(g2); + } + finally + { + g2.dispose(); + } + g.drawImage(backbuffer, 0, 0, awtComponent); + } + else + { + super.peerPaint(g, update); + peerPaintChildren(g); + } + } + + /** + * Determines if we should do double buffering or not. + * + * @return if we should do double buffering or not + */ + private boolean isDoubleBuffering() + { + Object prop = + SystemProperties.getProperty("gnu.awt.swing.doublebuffering", "false"); + return prop.equals("true"); + } + + /** + * Paints any heavyweight child components. + * + * @param g the graphics to use for painting + */ + protected synchronized void peerPaintChildren(Graphics g) + { + // TODO: Is this the right painting order? + for (Iterator i = heavyweightDescendents.iterator(); i.hasNext();) + { + Component child = (Component) i.next(); + ComponentPeer peer = child.getPeer(); + + if (peer instanceof SwingComponentPeer && child.isVisible()) + { + // TODO: The translation here doesn't work for deeper + // nested children. Fix this! + Graphics g2 = g.create(child.getX(), child.getY(), + child.getWidth(), child.getHeight()); + try + { + // update() is only called for the topmost component if + // necessary, all other components only get paint() called. + ((SwingComponentPeer) peer).peerPaint(g2, false); + } + finally + { + g2.dispose(); + } + } + } + } + + /** + * 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()); + if(comp == null) comp = awtComponent; + 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()); + if (comp != null) + { + ComponentPeer peer = comp.getPeer(); + if (awtComponent != comp && !comp.isLightweight() && peer instanceof SwingComponentPeer) + { + ev.translatePoint(comp.getX(), comp.getY()); + ((SwingComponentPeer) peer).handleMouseMotionEvent(ev); + } + } + } + + /** + * 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) + { + Component owner = getFocusOwner(); + if(owner != null) + owner.getPeer().handleEvent(e); + else + super.handleKeyEvent(e); + } + + private Component focusOwner = null; + + private Component getFocusOwner() + { + if(focusOwner == null) + { + for(Iterator iter=heavyweightDescendents.iterator(); iter.hasNext();) + { + Component child = (Component) iter.next(); + if(child.isFocusable()) + { + focusOwner = child; + break; + } + } + } + return focusOwner; + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingFramePeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingFramePeer.java new file mode 100644 index 000000000..56c7417cd --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingFramePeer.java @@ -0,0 +1,197 @@ +/* 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.ComponentPeer; +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: + *
    + *
  • {@link ComponentPeer#getLocationOnScreen()}
  • + *
  • {@link ComponentPeer#getGraphics()}
  • + *
  • {@link ComponentPeer#createImage(int, int)}
  • + *
+ * + * @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 peerPaintComponent(Graphics g) + { + super.peerPaintComponent(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/libjava/classpath/gnu/java/awt/peer/swing/SwingLabelPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingLabelPeer.java new file mode 100644 index 000000000..5c979d613 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingLabelPeer.java @@ -0,0 +1,242 @@ +/* SwingLabelPeer.java -- A Swing based peer for AWT labels + Copyright (C) 2006, 2007 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.Graphics; +import java.awt.Image; +import java.awt.Label; +import java.awt.Point; +import java.awt.event.FocusEvent; +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 + { + Label label; + + + SwingLabel(Label label) + { + this.label = label; + } + + /** + * Returns this label. + * + * @return this + */ + public JComponent getJComponent() + { + return this; + } + + /** + * Handles mouse events by forwarding it to + * processMouseEvent(). + * + * @param ev the mouse event + */ + public void handleMouseEvent(MouseEvent ev) + { + processMouseEvent(ev); + } + + /** + * Handles mouse motion events by forwarding it to + * processMouseMotionEvent(). + * + * @param ev the mouse motion event + */ + public void handleMouseMotionEvent(MouseEvent ev) + { + processMouseMotionEvent(ev); + } + + /** + * Handles key events by forwarding it to processKeyEvent(). + * + * @param ev the mouse event + */ + public void handleKeyEvent(KeyEvent ev) + { + processKeyEvent(ev); + } + + /** + * Handles focus events by forwarding it to + * processFocusEvent(). + * + * @param ev the Focus event + */ + public void handleFocusEvent(FocusEvent ev) + { + processFocusEvent(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 true if the button is currently showing, + * false otherwise + */ + public boolean isShowing() + { + boolean retVal = false; + if (label != null) + retVal = label.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); + } + + public Graphics getGraphics() + { + return SwingLabelPeer.this.getGraphics(); + } + + public Container getParent() + { + Container par = null; + if (label != null) + par = label.getParent(); + return par; + } + } + + /** + * Creates a new SwingLabelPeer for the specified AWT label. + * + * @param label the AWT label + */ + public SwingLabelPeer(Label label) + { + super(); + SwingLabel swingLabel = new SwingLabel(label); + swingLabel.setText(label.getText()); + swingLabel.setOpaque(true); + init(label, swingLabel); + setAlignment(label.getAlignment()); + } + + /** + * 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 swingLabel = (JLabel) swingComponent.getJComponent(); + switch (alignment) + { + case Label.RIGHT: + swingLabel.setHorizontalAlignment(JLabel.RIGHT); + break; + case Label.CENTER: + swingLabel.setHorizontalAlignment(JLabel.CENTER); + break; + case Label.LEFT: + default: + swingLabel.setHorizontalAlignment(JLabel.LEFT); + break; + } + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingListPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingListPeer.java new file mode 100644 index 000000000..cf766fd4f --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingListPeer.java @@ -0,0 +1,364 @@ +/* SwingListPeer.java -- A Swing based peer for AWT lists + Copyright (C) 2006, 2007 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.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.List; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.FocusEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.peer.ListPeer; + +import javax.swing.DefaultListModel; +import javax.swing.JComponent; +import javax.swing.JList; +import javax.swing.JScrollPane; +import javax.swing.ListSelectionModel; + +public class SwingListPeer + extends SwingComponentPeer + implements ListPeer +{ + + /** + * A spezialized Swing scroller used to hold the list. + * + * @author Roman Kennke (kennke@aicas.com) + */ + private class SwingList + extends JScrollPane + implements SwingComponent + { + + SwingList(Component comp) + { + super(comp, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, + JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); + } + + /** + * Returns this label. + * + * @return this + */ + public JComponent getJComponent() + { + return this; + } + + /** + * Handles mouse events by forwarding it to + * processMouseEvent(). + * + * @param ev the mouse event + */ + public void handleMouseEvent(MouseEvent ev) + { + ev.setSource(this); + dispatchEvent(ev); + } + + /** + * Force lightweight mouse dispatching. + */ + public boolean isLightweight() + { + return false; + } + + /** + * Handles mouse motion events by forwarding it to + * processMouseMotionEvent(). + * + * @param ev the mouse motion event + */ + public void handleMouseMotionEvent(MouseEvent ev) + { + processMouseMotionEvent(ev); + } + + /** + * Handles key events by forwarding it to processKeyEvent(). + * + * @param ev the mouse event + */ + public void handleKeyEvent(KeyEvent ev) + { + processKeyEvent(ev); + } + + /** + * Handles focus events by forwarding it to processFocusEvent(). + * + * @param ev the Focus event + */ + public void handleFocusEvent(FocusEvent ev) + { + processFocusEvent(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 SwingListPeer.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 true if the button is currently showing, + * false otherwise + */ + public boolean isShowing() + { + boolean retVal = false; + if (SwingListPeer.this.awtComponent != null) + retVal = SwingListPeer.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 SwingListPeer.this.createImage(w, h); + } + + public Graphics getGraphics() + { + return SwingListPeer.this.getGraphics(); + } + + public Container getParent() + { + Container par = null; + if (SwingListPeer.this.awtComponent != null) + par = SwingListPeer.this.awtComponent.getParent(); + return par; + } + } + + /** + * The actual Swing JList. + */ + private JList jList; + + private DefaultListModel listModel; + + public SwingListPeer(List list) + { + super(); + listModel = new DefaultListModel(); + jList = new JList(listModel); + SwingList swingList = new SwingList(jList); + init(list, swingList); + + // Pull over the items from the list. + String[] items = list.getItems(); + for (int i = 0 ; i < items.length; i++) + addItem(items[i], i); + } + + public void add(String item, int index) + { + if (listModel != null) + listModel.add(index, item); + } + + public void addItem(String item, int index) + { + if (listModel != null) + listModel.add(index, item); + } + + public void clear() + { + if (listModel != null) + listModel.clear(); + } + + public void delItems(int startIndex, int endIndex) + { + if (listModel != null) + listModel.removeRange(startIndex, endIndex); + } + + public void deselect(int index) + { + if (jList != null) + { + jList.getSelectionModel().removeSelectionInterval(index, index); + } + } + + public Dimension getMinimumSize(int s) + { + Dimension d = null; + if (jList != null) + { + d = jList.getComponent(s).getMinimumSize(); + } + return d; + } + + public Dimension getPreferredSize(int s) + { + Dimension d = null; + if (jList != null) + { + d = jList.getComponent(s).getPreferredSize(); + } + return d; + } + + public int[] getSelectedIndexes() + { + int[] sel = null; + if (jList != null) + { + sel = jList.getSelectedIndices(); + } + return sel; + } + + public void makeVisible(int index) + { + if (jList != null) + { + Component comp = jList.getComponent(index); + jList.scrollRectToVisible(comp.getBounds()); + } + } + + public Dimension minimumSize(int s) + { + Dimension d = null; + if (jList != null) + { + d = jList.getComponent(s).getMinimumSize(); + } + return d; + } + + public Dimension preferredSize(int s) + { + Dimension d = null; + if (jList != null) + { + d = jList.getComponent(s).getPreferredSize(); + } + return d; + } + + public void removeAll() + { + if (jList != null) + { + jList.removeAll(); + } + } + + public void select(int index) + { + if (jList != null) + { + jList.setSelectedIndex(index); + } + } + + public void setMultipleMode(boolean multi) + { + if (jList != null) + { + jList.setSelectionMode(multi + ? ListSelectionModel.MULTIPLE_INTERVAL_SELECTION + : ListSelectionModel.SINGLE_SELECTION); + } + } + + public void setMultipleSelections(boolean multi) + { + if (jList != null) + { + jList.setSelectionMode(multi + ? ListSelectionModel.MULTIPLE_INTERVAL_SELECTION + : ListSelectionModel.SINGLE_SELECTION); + } + } + + public void reshape(int x, int y, int width, int height) + { + if (swingComponent != null) + { + swingComponent.getJComponent().setBounds(x, y, width, height); + swingComponent.getJComponent().validate(); + } + } + + protected void peerPaint(Graphics g, boolean update) + { + super.peerPaint(g, update); + jList.doLayout(); + jList.list(); + + Rectangle r = getBounds(); + g.setColor(Color.RED); + g.drawRect(r.x, r.y, r.width, r.height); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingMenuBarPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingMenuBarPeer.java new file mode 100644 index 000000000..0033efb02 --- /dev/null +++ b/libjava/classpath/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 true, since we assume that when the + * menubar has a peer, it must be showing. + * + * @return true + */ + 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 + * processMouseEvent(). + * + * @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 SwingMenuBarPeer 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 SwingFramePeer of the frame that holds this menu. + * + * @param peer the SwingFramePeer 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 menu 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/libjava/classpath/gnu/java/awt/peer/swing/SwingMenuItemPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingMenuItemPeer.java new file mode 100644 index 000000000..721b3349f --- /dev/null +++ b/libjava/classpath/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 SwingMenuItemPeer. + * + * @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 enabled. + * + * @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/libjava/classpath/gnu/java/awt/peer/swing/SwingMenuPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingMenuPeer.java new file mode 100644 index 000000000..afe20616d --- /dev/null +++ b/libjava/classpath/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 true, since we assume that when the + * menu has a peer, it must be showing. + * + * @return true + */ + 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 + * processMouseEvent(). + * + * @param ev the mouse event + */ + public void handleMouseEvent(MouseEvent ev) + { + ev.setSource(this); + processMouseEvent(ev); + } + + /** + * Handles mouse events by forwarding them to + * processMouseMotionEvent(). + * + * @param ev the mouse event + */ + public void handleMouseMotionEvent(MouseEvent ev) + { + ev.setSource(this); + processMouseMotionEvent(ev); + } + } + + /** + * Creates a new SwingMenuPeer 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 enabled. + * + * @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/libjava/classpath/gnu/java/awt/peer/swing/SwingPanelPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingPanelPeer.java new file mode 100644 index 000000000..37c6dbc7a --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingPanelPeer.java @@ -0,0 +1,67 @@ +/* SwingPanelPeer.java -- A PanelPeer based on Swing + Copyright (C) 2006, 2007 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.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 consistent Look. +public class SwingPanelPeer + extends SwingContainerPeer + implements PanelPeer +{ + + /** + * Creates a new instance of SwingPanelPeer for the specified + * AWT panel. + * + * @param panel the AWT panel + */ + public SwingPanelPeer(Panel panel) + { + super(panel); + init(panel, null); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingTextAreaPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingTextAreaPeer.java new file mode 100644 index 000000000..d56e950ec --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingTextAreaPeer.java @@ -0,0 +1,487 @@ +/* SwingTextAreaPeer.java -- A Swing based peer for AWT textareas + Copyright (C) 2006, 2007 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.Dimension; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.TextArea; +import java.awt.event.ComponentEvent; +import java.awt.event.FocusEvent; +import java.awt.event.HierarchyEvent; +import java.awt.event.InputMethodEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.event.MouseWheelEvent; +import java.awt.im.InputMethodRequests; +import java.awt.peer.TextAreaPeer; + +import javax.swing.JComponent; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.JViewport; +import javax.swing.text.BadLocationException; + +public class SwingTextAreaPeer + extends SwingComponentPeer + implements TextAreaPeer +{ + + /** + * A spezialized Swing scroller used to hold the textarea. + * + * @author Roman Kennke (kennke@aicas.com) + */ + private class SwingScrollPane + extends JScrollPane + implements SwingComponent + { + + SwingTextArea textArea; + + SwingScrollPane(SwingTextArea textArea) + { + super(textArea, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, + JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); + + this.textArea = textArea; + } + + /** + * Returns this label. + * + * @return this + */ + public JComponent getJComponent() + { + return this; + } + + /** + * Handles mouse events by forwarding it to + * processMouseEvent(). + * + * @param ev the mouse event + */ + public void handleMouseEvent(MouseEvent ev) + { + JViewport viewPort = getViewport(); + if(viewPort.contains(ev.getPoint())) + { + ev.setSource(textArea); + textArea.dispatchEvent(ev); + } + else + { + ev.setSource(this); + this.dispatchEvent(ev); + } + } + + /** + * Force lightweight mouse dispatching. + */ + public boolean isLightweight() + { + return false; + } + + /** + * Handles mouse motion events by forwarding it to + * processMouseMotionEvent(). + * + * @param ev the mouse motion event + */ + public void handleMouseMotionEvent(MouseEvent ev) + { + textArea.processMouseMotionEvent(ev); + } + + /** + * Handles key events by forwarding it to processKeyEvent(). + * + * @param ev the mouse event + */ + public void handleKeyEvent(KeyEvent ev) + { + textArea.processKeyEvent(ev); + } + + /** + * Handles focus events by forwarding it to + * processFocusEvent(). + * + * @param ev the Focus event + */ + public void handleFocusEvent(FocusEvent ev) + { + textArea.processFocusEvent(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 SwingTextAreaPeer.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 true if the button is currently showing, + * false otherwise + */ + public boolean isShowing() + { + boolean retVal = false; + if (SwingTextAreaPeer.this.awtComponent != null) + retVal = SwingTextAreaPeer.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 SwingTextAreaPeer.this.createImage(w, h); + } + + public Graphics getGraphics() + { + return SwingTextAreaPeer.this.getGraphics(); + } + + public Container getParent() + { + Container par = null; + if (SwingTextAreaPeer.this.awtComponent != null) + par = SwingTextAreaPeer.this.awtComponent.getParent(); + return par; + } + + public void requestFocus() { + SwingTextAreaPeer.this.requestFocus(awtComponent, false, true, 0); + } + + public boolean requestFocus(boolean temporary) { + return SwingTextAreaPeer.this.requestFocus(awtComponent, temporary, + true, 0); + } + + } + + private class SwingTextArea extends JTextArea + { + /** + * Make this method accessible in this Package. + */ + protected final void processComponentKeyEvent(KeyEvent e) + { + super.processComponentKeyEvent(e); + } + + /** + * Make this method accessible in this Package. + */ + protected final void processMouseMotionEvent(MouseEvent ev) + { + super.processMouseMotionEvent(ev); + } + + /** + * Make this method accessible in this Package. + */ + protected final void processComponentEvent(ComponentEvent e) + { + super.processComponentEvent(e); + } + + /** + * Make this method accessible in this Package. + */ + protected final void processFocusEvent(FocusEvent e) + { + super.processFocusEvent(e); + } + + /** + * Make this method accessible in this Package. + */ + protected final void processHierarchyBoundsEvent(HierarchyEvent e) + { + super.processHierarchyBoundsEvent(e); + } + + /** + * Make this method accessible in this Package. + */ + protected final void processHierarchyEvent(HierarchyEvent e) + { + super.processHierarchyEvent(e); + } + + /** + * Make this method accessible in this Package. + */ + protected final void processInputMethodEvent(InputMethodEvent e) + { + super.processInputMethodEvent(e); + } + + /** + * Make this method accessible in this Package. + */ + protected final void processMouseEvent(MouseEvent e) + { + super.processMouseEvent(e); + } + + /** + * Make this method accessible in this Package. + */ + protected final void processMouseWheelEvent(MouseWheelEvent e) + { + super.processMouseWheelEvent(e); + } + + /** + * Make this method accessible in this Package. + */ + protected final void processKeyEvent(KeyEvent e) + { + super.processKeyEvent(e); + } + + public void requestFocus() { + SwingTextAreaPeer.this.requestFocus(awtComponent, false, true, 0); + } + + public boolean requestFocus(boolean temporary) { + return SwingTextAreaPeer.this.requestFocus(awtComponent, temporary, + true, 0); + } + } + + /** + * The actual JTextArea. + */ + private SwingTextArea jTextArea; + + public SwingTextAreaPeer(TextArea textArea) + { + super(); + jTextArea = new SwingTextArea(); + SwingScrollPane swingArea = new SwingScrollPane(jTextArea); + init(textArea, swingArea); + + JViewport viewport = new JViewport() + { + public Image createImage(int width, int height) + { + return awtComponent.createImage(width, height); + } + }; + + viewport.setView(jTextArea); + swingArea.setViewport(viewport); + // Pull over the text from the text area. + setText(textArea.getText()); + + // Pull over the number of rows and columns + // if non were set use default values + int columns = textArea.getColumns(); + int rows = textArea.getRows(); + + if(columns == 0 && rows == 0) + { + columns = 25; + textArea.setColumns(columns); + rows = 5; + textArea.setRows(rows); + } + + jTextArea.setColumns(columns); + jTextArea.setRows(rows); + } + + public Dimension getMinimumSize(int rows, int cols) + { + return jTextArea.getMinimumSize(); + } + + public Dimension getPreferredSize(int rows, int cols) + { + return jTextArea.getPreferredSize(); + } + + public void insert(String text, int pos) + { + jTextArea.insert(text, pos); + } + + public void insertText(String text, int pos) + { + jTextArea.insert(text, pos); + } + + public Dimension minimumSize() + { + return jTextArea.getMinimumSize(); + } + + public Dimension preferredSize() + { + return jTextArea.getPreferredSize(); + } + + public Dimension minimumSize(int rows, int cols) + { + return jTextArea.getMinimumSize(); + } + + public Dimension preferredSize(int rows, int cols) + { + return jTextArea.getPreferredSize(); + } + + public void replaceRange(String text, int start, int end) + { + jTextArea.replaceRange(text, start, end); + } + + public void replaceText(String text, int start, int end) + { + jTextArea.replaceRange(text, start, end); + } + + public long filterEvents(long filter) + { + // TODO Auto-generated method stub + return 0; + } + + public int getCaretPosition() + { + return jTextArea.getCaretPosition(); + } + + public Rectangle getCharacterBounds(int pos) + { + Rectangle r; + try + { + return jTextArea.modelToView(pos); + } + catch (BadLocationException ex) + { + r = null; + } + return r; + } + + public int getIndexAtPoint(int x, int y) + { + return jTextArea.viewToModel(new Point(x, y)); + } + + public InputMethodRequests getInputMethodRequests() + { + // TODO Auto-generated method stub + return null; + } + + public int getSelectionEnd() + { + return jTextArea.getSelectionEnd(); + } + + public int getSelectionStart() + { + return jTextArea.getSelectionStart(); + } + + public String getText() + { + return jTextArea.getText(); + } + + public void select(int start, int end) + { + jTextArea.select(start, end); + } + + public void setCaretPosition(int pos) + { + jTextArea.setCaretPosition(pos); + } + + public void setEditable(boolean editable) + { + jTextArea.setEditable(editable); + } + + public void setText(String text) + { + jTextArea.setText(text); + } + + public void reshape(int x, int y, int width, int height) + { + if (swingComponent != null) + { + swingComponent.getJComponent().setBounds(x, y, width, height); + swingComponent.getJComponent().validate(); + } + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingTextFieldPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingTextFieldPeer.java new file mode 100644 index 000000000..9750c9bf7 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingTextFieldPeer.java @@ -0,0 +1,411 @@ +/* SwingTextFieldPeer.java -- A Swing based peer for AWT textfields + Copyright (C) 2006, 2007 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.Dimension; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.TextField; +import java.awt.event.FocusEvent; +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 + { + + TextField textField; + + SwingTextField(TextField textField) + { + this.textField = textField; + } + + /** + * 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 true if the button is currently showing, + * false otherwise + */ + public boolean isShowing() + { + boolean retVal = false; + if (textField != null) + retVal = textField.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 this + */ + 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); + } + + /** + * Handles focus events by forwarding it to + * processFocusEvent(). + * + * @param ev the Focus event + */ + public void handleFocusEvent(FocusEvent ev) + { + processFocusEvent(ev); + } + + + public Container getParent() + { + Container par = null; + if (textField != null) + par = textField.getParent(); + return par; + } + + public Graphics getGraphics() + { + return SwingTextFieldPeer.this.getGraphics(); + } + + public void requestFocus() { + SwingTextFieldPeer.this.requestFocus(awtComponent, false, true, 0); + } + + public boolean requestFocus(boolean temporary) { + return SwingTextFieldPeer.this.requestFocus(awtComponent, temporary, + true, 0); + } + + } + + /** + * Creates a new SwingTextFieldPeer instance for the specified + * AWT textfield. + * + * @param textField the AWT textfield + */ + public SwingTextFieldPeer(TextField textField) + { + SwingTextField swingTextField = new SwingTextField(textField); + 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 startPos, int endPos) + { + // TODO: Must be implemented. + } + + /** + * Sets the editable flag of the text field. + * + * @param editable true to make the textfield editable, + * false 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/libjava/classpath/gnu/java/awt/peer/swing/SwingToolkit.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingToolkit.java new file mode 100644 index 000000000..63414050b --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingToolkit.java @@ -0,0 +1,181 @@ +/* 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.Dialog; +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); + } + + @Override + public boolean isModalExclusionTypeSupported + (Dialog.ModalExclusionType modalExclusionType) + { + return false; + } + + @Override + public boolean isModalityTypeSupported(Dialog.ModalityType modalityType) + { + return false; + } + + +} diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingWindowPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingWindowPeer.java new file mode 100644 index 000000000..bdc494e95 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingWindowPeer.java @@ -0,0 +1,99 @@ +/* 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.ComponentPeer; +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: + *
    + *
  • {@link ComponentPeer#getLocationOnScreen()}
  • + *
  • {@link ComponentPeer#getGraphics()}
  • + *
  • {@link ComponentPeer#createImage(int, int)}
  • + *
+ * + * @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); + init(window, null); + } + + public void updateIconImages() + { + // TODO: Implement properly. + } + + public void updateMinimumSize() + { + // TODO: Implement properly. + } + + public void setModalBlocked(java.awt.Dialog d, boolean b) + { + // TODO: Implement properly. + } + + public void updateFocusableWindowState() + { + // TODO: Implement properly. + } + + public void setAlwaysOnTop(boolean b) + { + // TODO: Implement properly. + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/swing/package.html b/libjava/classpath/gnu/java/awt/peer/swing/package.html new file mode 100644 index 000000000..506eda883 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/swing/package.html @@ -0,0 +1,71 @@ + + + + + + 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/libjava/classpath/gnu/java/awt/peer/x/GLGraphics.java b/libjava/classpath/gnu/java/awt/peer/x/GLGraphics.java new file mode 100644 index 000000000..3cf3797ab --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/x/GLGraphics.java @@ -0,0 +1,134 @@ +/* GLGraphics.java -- Graphics2D impl on top of GLX + 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.x; + +import java.awt.Color; +import java.awt.GraphicsConfiguration; +import java.awt.Rectangle; +import java.awt.image.ColorModel; +import java.util.Map; + +import gnu.java.awt.java2d.AbstractGraphics2D; +import gnu.x11.extension.glx.GL; + +/** + * An implementation of Graphics2D on top of the GLX extension of X. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class GLGraphics extends AbstractGraphics2D +{ + + /** + * The rendering context. + */ + private GL gl; + + /** + * Creates a new GLGraphics that paints on the specified GL context. + * + * @param g the GL context to paint to + */ + GLGraphics(GL g) + { + gl = g; + } + + public void setBackground(Color b) + { + super.setBackground(b); + + gl.clearColor(b.getRed() / 255.F, b.getGreen() / 255.F, + b.getBlue() / 255.F, b.getAlpha() / 255.F); + } + + public void clearRect(int x, int y, int w, int h) + { + // TODO: Maybe use fillRect(). + gl.clear(GL.COLOR_BUFFER_BIT); + } + + public void drawLine(int x1, int y1, int x2, int y2) + { + gl.begin(GL.LINES); + gl.vertex2i(x1, y1); + gl.vertex2i(x2, y2); + gl.end(); + // TODO: Maybe do: + // gl.flush(); + } + + public void drawRect(int x, int y, int w, int h) + { + gl.polygon_mode(GL.FRONT_AND_BACK, GL.LINE); + gl.begin(GL.POLYGON); + gl.recti(x, y, x + w, y + h); + gl.end(); + // TODO: Maybe do: + // gl.flush(); + } + + public void fillRect(int x, int y, int w, int h) + { + gl.polygon_mode(GL.FRONT_AND_BACK, GL.FILL); + gl.recti(x, y, x + w, y + h); + // TODO: Maybe do: + // gl.flush(); + } + + protected ColorModel getColorModel() + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public GraphicsConfiguration getDeviceConfiguration() + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + @Override + protected Rectangle getDeviceBounds() + { + // FIXME: not sure it's correct + return new Rectangle(0, 0, + gl.display.default_screen.width, + gl.display.default_screen.height); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/x/KeyboardMapping.java b/libjava/classpath/gnu/java/awt/peer/x/KeyboardMapping.java new file mode 100644 index 000000000..c982a30d5 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/x/KeyboardMapping.java @@ -0,0 +1,419 @@ +/* KeyboardMapping.java -- Maps X keysyms to Java keyCode and keyChar + 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.x; + +import gnu.x11.Input; +import gnu.x11.keysym.Latin1; +import gnu.x11.keysym.Misc; + +import java.awt.event.KeyEvent; + +/** + * Defines the keyboard mapping from X keysyms to Java + * keycodes and keychars. + * + * @author Roman Kennke (kennke@aicas.com) + */ +final class KeyboardMapping +{ + + /** + * Maps X keycodes to AWT keycodes. + * + * @param xInput the X input event + * @param xKeyCode the X keycode to map + * @param xMods the X modifiers + * + * @return the AWT keycode and keychar + */ + static int mapToKeyCode(gnu.x11.Input xInput, int xKeyCode, int xMods) + { + int mapped = KeyEvent.VK_UNDEFINED; + int keysym = xInput.keycode_to_keysym(xKeyCode, xMods, true); + + // Special keys. + if (keysym >= 255 << 8) + { + // FIXME: Add missing mappings. + switch (keysym) + { + case Misc.BACKSPACE: + mapped = KeyEvent.VK_BACK_SPACE; + break; + case Misc.TAB: + mapped = KeyEvent.VK_TAB; + break; + case Misc.CLEAR: + mapped = KeyEvent.VK_CLEAR; + break; + case Misc.RETURN: + mapped = KeyEvent.VK_ENTER; + break; + case Misc.PAUSE: + mapped = KeyEvent.VK_PAUSE; + break; + case Misc.SCROLL_LOCK: + mapped = KeyEvent.VK_SCROLL_LOCK; + break; + case Misc.ESCAPE: + mapped = KeyEvent.VK_ESCAPE; + break; + case Misc.HOME: + mapped = KeyEvent.VK_HOME; + break; + case Misc.LEFT: + mapped = KeyEvent.VK_LEFT; + break; + case Misc.UP: + mapped = KeyEvent.VK_UP; + break; + case Misc.RIGHT: + mapped = KeyEvent.VK_RIGHT; + break; + case Misc.DOWN: + mapped = KeyEvent.VK_DOWN; + break; + case Misc.PAGE_UP: + mapped = KeyEvent.VK_PAGE_UP; + break; + case Misc.PAGE_DOWN: + mapped = KeyEvent.VK_PAGE_DOWN; + break; + case Misc.END: + mapped = KeyEvent.VK_END; + break; + case Misc.BEGIN: + mapped = KeyEvent.VK_BEGIN; + break; + case Misc.INSERT: + mapped = KeyEvent.VK_INSERT; + break; + case Misc.UNDO: + mapped = KeyEvent.VK_UNDO; + break; + case Misc.FIND: + mapped = KeyEvent.VK_FIND; + break; + case Misc.CANCEL: + mapped = KeyEvent.VK_CANCEL; + break; + case Misc.HELP: + mapped = KeyEvent.VK_HELP; + break; + case Misc.MODE_SWITCH: + mapped = KeyEvent.VK_MODECHANGE; + break; + case Misc.NUM_LOCK: + mapped = KeyEvent.VK_NUM_LOCK; + break; + case Misc.KP_LEFT: + mapped = KeyEvent.VK_KP_LEFT; + break; + case Misc.KP_UP: + mapped = KeyEvent.VK_KP_UP; + break; + case Misc.KP_RIGHT: + mapped = KeyEvent.VK_KP_RIGHT; + break; + case Misc.KP_DOWN: + mapped = KeyEvent.VK_KP_DOWN; + break; + case Misc.F1: + mapped = KeyEvent.VK_F1; + break; + case Misc.F2: + mapped = KeyEvent.VK_F2; + break; + case Misc.F3: + mapped = KeyEvent.VK_F3; + break; + case Misc.F4: + mapped = KeyEvent.VK_F4; + break; + case Misc.F5: + mapped = KeyEvent.VK_F5; + break; + case Misc.F6: + mapped = KeyEvent.VK_F6; + break; + case Misc.F7: + mapped = KeyEvent.VK_F7; + break; + case Misc.F8: + mapped = KeyEvent.VK_F8; + break; + case Misc.F9: + mapped = KeyEvent.VK_F9; + break; + case Misc.F10: + mapped = KeyEvent.VK_F10; + break; + case Misc.F11: + mapped = KeyEvent.VK_F11; + break; + case Misc.F12: + mapped = KeyEvent.VK_F12; + break; + case Misc.F13: + mapped = KeyEvent.VK_F13; + break; + case Misc.F14: + mapped = KeyEvent.VK_F14; + break; + case Misc.F15: + mapped = KeyEvent.VK_F15; + break; + case Misc.F16: + mapped = KeyEvent.VK_F16; + break; + case Misc.F17: + mapped = KeyEvent.VK_F17; + break; + case Misc.F18: + mapped = KeyEvent.VK_F18; + break; + case Misc.F19: + mapped = KeyEvent.VK_F19; + break; + case Misc.F20: + mapped = KeyEvent.VK_F20; + break; + case Misc.F21: + mapped = KeyEvent.VK_F21; + break; + case Misc.F22: + mapped = KeyEvent.VK_F22; + break; + case Misc.F23: + mapped = KeyEvent.VK_F23; + break; + case Misc.F24: + mapped = KeyEvent.VK_F24; + break; + case Misc.SHIFT_L: + case Misc.SHIFT_R: + mapped = KeyEvent.VK_SHIFT; + break; + case Misc.CONTROL_L: + case Misc.CONTROL_R: + mapped = KeyEvent.VK_CONTROL; + break; + case Misc.CAPS_LOCK: + case Misc.SHIFT_LOCK: + mapped = KeyEvent.VK_CAPS_LOCK; + break; + case Misc.META_L: + case Misc.META_R: + mapped = KeyEvent.VK_META; + break; + case Misc.ALT_L: + case Misc.ALT_R: + mapped = KeyEvent.VK_ALT; + break; + case Misc.DELETE: + mapped = KeyEvent.VK_DELETE; + break; + default: + mapped = KeyEvent.VK_UNDEFINED; + } + } + // Map Latin1 characters. + else if (keysym < 256) + { + // TODO: Add missing mappings, if any. + // Lowercase characters are mapped to + // their corresponding upper case pendants. + if (keysym >= Latin1.A_SMALL && keysym <= Latin1.Z_SMALL) + mapped = keysym - 0x20; + // Uppercase characters are mapped 1:1. + else if (keysym >= Latin1.A && keysym <= Latin1.Z) + mapped = keysym; + // Digits are mapped 1:1. + else if (keysym >= Latin1.NUM_0 && keysym <= Latin1.NUM_9) + mapped = keysym; + else + { + switch (keysym) + { + case Latin1.SPACE: + mapped = KeyEvent.VK_SPACE; + break; + case Latin1.EXCLAM: + mapped = KeyEvent.VK_EXCLAMATION_MARK; + break; + case Latin1.QUOTE_DBL: + mapped = KeyEvent.VK_QUOTEDBL; + break; + case Latin1.NUMBER_SIGN: + mapped = KeyEvent.VK_NUMBER_SIGN; + break; + case Latin1.DOLLAR: + mapped = KeyEvent.VK_DOLLAR; + break; + case Latin1.AMPERSAND: + mapped = KeyEvent.VK_AMPERSAND; + break; + case Latin1.APOSTROPHE: + mapped = KeyEvent.VK_QUOTE; + break; + case Latin1.PAREN_LEFT: + mapped = KeyEvent.VK_LEFT_PARENTHESIS; + break; + case Latin1.PAREN_RIGHT: + mapped = KeyEvent.VK_RIGHT_PARENTHESIS; + break; + case Latin1.ASTERISK: + mapped = KeyEvent.VK_ASTERISK; + break; + case Latin1.PLUS: + mapped = KeyEvent.VK_PLUS; + break; + case Latin1.COMMA: + mapped = KeyEvent.VK_COMMA; + break; + case Latin1.MINUS: + mapped = KeyEvent.VK_MINUS; + break; + case Latin1.PERIOD: + mapped = KeyEvent.VK_PERIOD; + break; + case Latin1.SLASH: + mapped = KeyEvent.VK_SLASH; + break; + case Latin1.COLON: + mapped = KeyEvent.VK_COLON; + break; + case Latin1.SEMICOLON: + mapped = KeyEvent.VK_SEMICOLON; + break; + case Latin1.LESS: + mapped = KeyEvent.VK_LESS; + break; + case Latin1.EQUAL: + mapped = KeyEvent.VK_EQUALS; + break; + case Latin1.GREATER: + mapped = KeyEvent.VK_GREATER; + break; + case Latin1.AT: + mapped = KeyEvent.VK_AT; + break; + case Latin1.BRACKET_LEFT: + mapped = KeyEvent.VK_OPEN_BRACKET; + break; + case Latin1.BACKSLASH: + mapped = KeyEvent.VK_BACK_SLASH; + break; + case Latin1.BRACKET_RIGHT: + mapped = KeyEvent.VK_CLOSE_BRACKET; + break; + case Latin1.ASCII_CIRCUM: + mapped = KeyEvent.VK_CIRCUMFLEX; + break; + case Latin1.UNDERSCORE: + mapped = KeyEvent.VK_UNDERSCORE; + break; + case Latin1.GRAVE: + mapped = KeyEvent.VK_DEAD_GRAVE; + break; + case Latin1.BRACE_LEFT: + mapped = KeyEvent.VK_BRACELEFT; + break; + case Latin1.BRACE_RIGHT: + mapped = KeyEvent.VK_BRACERIGHT; + break; + case Latin1.ASCII_TILDE: + mapped = KeyEvent.VK_DEAD_TILDE; + break; + case Latin1.EXCLAM_DOWN: + mapped = KeyEvent.VK_INVERTED_EXCLAMATION_MARK; + break; + default: + mapped = KeyEvent.VK_UNDEFINED; + } + } + } + return mapped; + } + + /** + * Maps X keycodes+modifiers to Java keychars. + * + * @param xInput The X Input to use for mapping + * @param xKeyCode the X keycode + * @param xMods the X key modifiers + * + * @return the Java keychar + */ + static char mapToKeyChar(gnu.x11.Input xInput, int xKeyCode, int xMods) + { + char mapped = KeyEvent.CHAR_UNDEFINED; + char keysym = (char) xInput.keycode_to_keysym(xKeyCode, xMods, false); + // FIXME: Map other encodings properly. + if (keysym < 256) // Latin1. + { + mapped = keysym; + } + return mapped; + } + + /** + * Maps X modifier masks to AWT modifier masks. + * + * @param xMods the X modifiers + * + * @return the AWT modifiers + */ + static int mapModifiers(int xMods) + { + int mods = 0; + + if ((xMods & Input.SHIFT_MASK) != 0) + mods |= KeyEvent.SHIFT_MASK | KeyEvent.SHIFT_DOWN_MASK; + if ((xMods & Input.META_MASK) != 0) + mods |= KeyEvent.META_MASK | KeyEvent.META_DOWN_MASK; + if ((xMods & Input.ALT_MASK) != 0) + mods |= KeyEvent.ALT_MASK | KeyEvent.ALT_DOWN_MASK; + if ((xMods & Input.MOD5_MASK) != 0) + mods |= KeyEvent.ALT_GRAPH_MASK | KeyEvent.ALT_GRAPH_DOWN_MASK; + if ((xMods & Input.CONTROL_MASK) != 0) + mods |= KeyEvent.CTRL_MASK | KeyEvent.CTRL_DOWN_MASK; + + return mods; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/x/PixmapVolatileImage.java b/libjava/classpath/gnu/java/awt/peer/x/PixmapVolatileImage.java new file mode 100644 index 000000000..131647fab --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/x/PixmapVolatileImage.java @@ -0,0 +1,185 @@ +/* PixmapVolatileImage.java -- VolatileImage implementation around a Pixmap + Copyright (C) 2007 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.x; + +import gnu.x11.GC; +import gnu.x11.Pixmap; +import gnu.x11.image.Image; +import gnu.x11.image.ZPixmap; + +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsEnvironment; +import java.awt.ImageCapabilities; +import java.awt.Point; +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ComponentColorModel; +import java.awt.image.ComponentSampleModel; +import java.awt.image.DataBuffer; +import java.awt.image.ImageObserver; +import java.awt.image.Raster; +import java.awt.image.SampleModel; +import java.awt.image.VolatileImage; +import java.awt.image.WritableRaster; + +/** + * A {@link VolatileImage} implementation that wraps an X Pixmap. + */ +class PixmapVolatileImage + extends VolatileImage +{ + + /** + * The shared capabilities instance. + */ + private static final ImageCapabilities caps = new ImageCapabilities(true); + + /** + * The underlying pixmap. + */ + private Pixmap pixmap; + + /** + * Creates a new PixmapVolatileImage. + * + * @param w the width of the image + * @param h the height of the image + */ + public PixmapVolatileImage(int w, int h) + { + GraphicsEnvironment env = + GraphicsEnvironment.getLocalGraphicsEnvironment(); + XGraphicsDevice dev = (XGraphicsDevice) env.getDefaultScreenDevice(); + pixmap = new Pixmap(dev.getDisplay(), w, h); + + // Clear pixmap. + GC gc = new GC(pixmap); + gc.set_foreground(0xffffffff); + pixmap.fill_rectangle(gc, 0, 0, w, h); + + } + + @Override + public boolean contentsLost() + { + return false; + } + + @Override + public Graphics2D createGraphics() + { + return new XGraphics2D(pixmap); + } + + @Override + public ImageCapabilities getCapabilities() + { + return caps; + } + + @Override + public int getHeight() + { + return pixmap.height; + } + + @Override + public BufferedImage getSnapshot() + { + // TODO: Support non-24-bit resolutions. + int w = pixmap.width; + int h = pixmap.height; + ZPixmap zpixmap = (ZPixmap) pixmap.image(0, 0, w, h, 0xffffffff, + Image.Format.ZPIXMAP); + DataBuffer buffer = new ZPixmapDataBuffer(zpixmap); + SampleModel sm = new ComponentSampleModel(DataBuffer.TYPE_BYTE, w, h, 4, + w * 4, + new int[]{0, 1, 2, 3 }); + ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB); + ColorModel cm = new ComponentColorModel(cs, true, false, + Transparency.OPAQUE, + DataBuffer.TYPE_BYTE); + WritableRaster raster = Raster.createWritableRaster(sm, buffer, + new Point(0, 0)); + return new BufferedImage(cm, raster, false, null); + } + + @Override + public int getWidth() + { + return pixmap.width; + } + + @Override + public int validate(GraphicsConfiguration gc) + { + // TODO: Check compatibility with gc. + return IMAGE_OK; + } + + @Override + public int getHeight(ImageObserver observer) + { + return getHeight(); + } + + @Override + public Object getProperty(String name, ImageObserver observer) + { + return null; + } + + @Override + public int getWidth(ImageObserver observer) + { + return getWidth(); + } + + /** + * Returns the underlying X pixmap. This is used for the graphics code. + * + * @return the underlying X pixmap + */ + Pixmap getPixmap() + { + return pixmap; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/x/XDialogPeer.java b/libjava/classpath/gnu/java/awt/peer/x/XDialogPeer.java new file mode 100644 index 000000000..45ad24d67 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/x/XDialogPeer.java @@ -0,0 +1,61 @@ +/* XDialogPeer.java -- The peer for AWT dialogs + 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.x; + +import java.awt.Dialog; +import java.awt.peer.DialogPeer; + +public class XDialogPeer + extends XWindowPeer + implements DialogPeer +{ + + XDialogPeer(Dialog target) + { + super(target); + } + + public void setResizable(boolean resizeable) + { + } + + public void setTitle(String title) + { + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/x/XEventPump.java b/libjava/classpath/gnu/java/awt/peer/x/XEventPump.java new file mode 100644 index 000000000..8e80b97a3 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/x/XEventPump.java @@ -0,0 +1,486 @@ +/* XEventPump.java -- Pumps events from X to AWT + 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.x; + +import java.awt.AWTEvent; +import java.awt.Component; +import java.awt.Container; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.Window; +import java.awt.event.ComponentEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.event.PaintEvent; +import java.awt.event.WindowEvent; +import java.util.HashMap; + +import gnu.java.awt.ComponentReshapeEvent; +import gnu.x11.Atom; +import gnu.x11.Display; +import gnu.x11.event.ButtonPress; +import gnu.x11.event.ButtonRelease; +import gnu.x11.event.ClientMessage; +import gnu.x11.event.ConfigureNotify; +import gnu.x11.event.DestroyNotify; +import gnu.x11.event.Event; +import gnu.x11.event.Expose; +import gnu.x11.event.Input; +import gnu.x11.event.KeyPress; +import gnu.x11.event.KeyRelease; +import gnu.x11.event.MotionNotify; +import gnu.x11.event.PropertyNotify; +import gnu.x11.event.ResizeRequest; +import gnu.x11.event.UnmapNotify; + +/** + * Fetches events from X, translates them to AWT events and pumps them up + * into the AWT event queue. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class XEventPump + implements Runnable +{ + + /** + * The X Display from which we fetch and pump up events. + */ + private Display display; + + /** + * Maps X Windows to AWT Windows to be able to correctly determine the + * event targets. + */ + private HashMap windows; + + /** + * Indicates if we are currently inside a drag operation. This is + * set to the button ID when a button is pressed and to -1 (indicating + * that no drag is active) when the mouse is released. + */ + private int drag; + + /** + * Creates a new XEventPump for the specified X Display. + * + * @param d the X Display + */ + XEventPump(Display d) + { + display = d; + windows = new HashMap(); + drag = -1; + Thread thread = new Thread(this, "X Event Pump"); + thread.setDaemon(true); + thread.start(); + } + + /** + * The main event pump loop. This basically fetches events from the + * X Display and pumps them into the system event queue. + */ + public void run() + { + while (display.connected) + { + try + { + Event xEvent = display.next_event(); + handleEvent(xEvent); + } + catch (ThreadDeath death) + { + // If someone wants to kill us, let them. + return; + } + catch (Throwable x) + { + System.err.println("Exception during event dispatch:"); + x.printStackTrace(System.err); + } + } + } + + /** + * Adds an X Window to AWT Window mapping. This is required so that the + * event pump can correctly determine the event targets. + * + * @param xWindow the X Window + * @param awtWindow the AWT Window + */ + void registerWindow(gnu.x11.Window xWindow, Window awtWindow) + { + if (XToolkit.DEBUG) + System.err.println("registering window id: " + xWindow.id); + windows.put(new Integer(xWindow.id), awtWindow); + } + + void unregisterWindow(gnu.x11.Window xWindow) + { + windows.remove(new Integer(xWindow.id)); + } + + private void handleButtonPress(ButtonPress event) + { + Integer key = new Integer(event.getEventWindowID()); + Window awtWindow = (Window) windows.get(key); + + // Create and post the mouse event. + int button = event.detail(); + + // AWT cannot handle more than 3 buttons and expects 0 instead. + if (button >= gnu.x11.Input.BUTTON3) + button = 0; + drag = button; + + Component target = + findMouseEventTarget(awtWindow, event.getEventX(), event.getEventY()); + if(target == null) + { + target = awtWindow; + } + + MouseEvent mp = new MouseEvent(target, MouseEvent.MOUSE_PRESSED, + System.currentTimeMillis(), + KeyboardMapping.mapModifiers(event.getState()) + | buttonToModifier(button), + event.getEventX(), event.getEventY(), + 1, false, button); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(mp); + } + + private void handleButtonRelease(ButtonRelease event) + { + Integer key = new Integer(event.getEventWindowID()); + Window awtWindow = (Window) windows.get(key); + + int button = event.detail(); + + // AWT cannot handle more than 3 buttons and expects 0 instead. + if (button >= gnu.x11.Input.BUTTON3) + button = 0; + drag = -1; + + Component target = + findMouseEventTarget(awtWindow, event.getEventX(), event.getEventY()); + if(target == null) + { + target = awtWindow; + } + + MouseEvent mr = new MouseEvent(target, MouseEvent.MOUSE_RELEASED, + System.currentTimeMillis(), + KeyboardMapping.mapModifiers(event.getState()) + | buttonToModifier(button), + event.getEventX(), event.getEventY(), + 1, false, button); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(mr); + } + + + private void handleMotionNotify(MotionNotify event) + { + Integer key = new Integer(event.getEventWindowID()); + Window awtWindow = (Window) windows.get(key); + + int button = event.detail(); + + // AWT cannot handle more than 3 buttons and expects 0 instead. + if (button >= gnu.x11.Input.BUTTON3) + button = 0; + + MouseEvent mm = null; + if (drag == -1) + { + mm = new MouseEvent(awtWindow, MouseEvent.MOUSE_MOVED, + System.currentTimeMillis(), + KeyboardMapping.mapModifiers(event.getState()) + | buttonToModifier(button), + event.getEventX(), event.getEventY(), + 1, false); + + } + else + { + mm = new MouseEvent(awtWindow, MouseEvent.MOUSE_DRAGGED, + System.currentTimeMillis(), + KeyboardMapping.mapModifiers(event.getState()) + | buttonToModifier(drag), + event.getEventX(), event.getEventY(), + 1, false); + } + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(mm); + } + + // FIME: refactor and make faster, maybe caching the event and handle + // and/or check timing (timing is generated for PropertyChange)? + private void handleExpose(Expose event) + { + Integer key = new Integer(event.window_id); + Window awtWindow = (Window) windows.get(key); + + if (XToolkit.DEBUG) + System.err.println("expose request for window id: " + key); + + Rectangle r = new Rectangle(event.x(), event.y(), event.width(), + event.height()); + // We need to clear the background of the exposed rectangle. + assert awtWindow != null : "awtWindow == null for window ID: " + key; + + Graphics g = awtWindow.getGraphics(); + g.clearRect(r.x, r.y, r.width, r.height); + g.dispose(); + + XWindowPeer xwindow = (XWindowPeer) awtWindow.getPeer(); + Insets i = xwindow.insets(); + if (event.width() != awtWindow.getWidth() - i.left - i.right + || event.height() != awtWindow.getHeight() - i.top - i.bottom) + { + int w = event.width(); + int h = event.height(); + int x = xwindow.xwindow.x; + int y = xwindow.xwindow.y; + + if (XToolkit.DEBUG) + System.err.println("Setting size on AWT window: " + w + + ", " + h + ", " + awtWindow.getWidth() + + ", " + awtWindow.getHeight()); + + // new width and height + xwindow.xwindow.width = w; + xwindow.xwindow.height = h; + + // reshape the window + ComponentReshapeEvent cre = + new ComponentReshapeEvent(awtWindow, x, y, w, h); + awtWindow.dispatchEvent(cre); + } + + ComponentEvent ce = + new ComponentEvent(awtWindow, ComponentEvent.COMPONENT_RESIZED); + awtWindow.dispatchEvent(ce); + + PaintEvent pev = new PaintEvent(awtWindow, PaintEvent.UPDATE, r); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(pev); + } + + private void handleDestroyNotify(DestroyNotify destroyNotify) + { + if (XToolkit.DEBUG) + System.err.println("DestroyNotify event: " + destroyNotify); + + Integer key = new Integer(destroyNotify.event_window_id); + Window awtWindow = (Window) windows.get(key); + + AWTEvent event = new WindowEvent(awtWindow, WindowEvent.WINDOW_CLOSED); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(event); + } + + private void handleClientMessage(ClientMessage clientMessage) + { + if (XToolkit.DEBUG) + System.err.println("ClientMessage event: " + clientMessage); + + if (clientMessage.delete_window()) + { + if (XToolkit.DEBUG) + System.err.println("ClientMessage is a delete_window event"); + + Integer key = new Integer(clientMessage.window_id); + Window awtWindow = (Window) windows.get(key); + + AWTEvent event = new WindowEvent(awtWindow, WindowEvent.WINDOW_CLOSING); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(event); + } + } + + private void handleEvent(Event xEvent) + { + if (XToolkit.DEBUG) + System.err.println("fetched event: " + xEvent); + + switch (xEvent.code() & 0x7f) + { + case ButtonPress.CODE: + this.handleButtonPress((ButtonPress) xEvent); + break; + case ButtonRelease.CODE: + this.handleButtonRelease((ButtonRelease) xEvent); + break; + case MotionNotify.CODE: + this.handleMotionNotify((MotionNotify) xEvent); + break; + case Expose.CODE: + this.handleExpose((Expose) xEvent); + break; + case KeyPress.CODE: + case KeyRelease.CODE: + Integer key = new Integer(((Input) xEvent).getEventWindowID()); + Window awtWindow = (Window) windows.get(key); + handleKeyEvent(xEvent, awtWindow); + break; + case DestroyNotify.CODE: + this.handleDestroyNotify((DestroyNotify) xEvent); + break; + case ClientMessage.CODE: + this.handleClientMessage((ClientMessage) xEvent); + break; + case PropertyNotify.CODE: + key = new Integer (((PropertyNotify) xEvent).getWindowID()); + awtWindow = (Window) windows.get(key); + AWTEvent event = new WindowEvent(awtWindow, WindowEvent.WINDOW_STATE_CHANGED); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(event); + break; + default: + if (XToolkit.DEBUG) + System.err.println("Unhandled X event: " + xEvent); + } + } + + /** + * Handles key events from X. + * + * @param xEvent the X event + * @param awtWindow the AWT window to which the event gets posted + */ + private void handleKeyEvent(Event xEvent, Window awtWindow) + { + Input keyEvent = (Input) xEvent; + int xKeyCode = keyEvent.detail(); + int xMods = keyEvent.getState(); + int keyCode = KeyboardMapping.mapToKeyCode(xEvent.display.input, xKeyCode, + xMods); + char keyChar = KeyboardMapping.mapToKeyChar(xEvent.display.input, xKeyCode, + xMods); + if (XToolkit.DEBUG) + System.err.println("XEventPump.handleKeyEvent: " + xKeyCode + ", " + + xMods + ": " + ((int) keyChar) + ", " + keyCode); + int awtMods = KeyboardMapping.mapModifiers(xMods); + long when = System.currentTimeMillis(); + KeyEvent ke; + if (keyEvent.code() == KeyPress.CODE) + { + ke = new KeyEvent(awtWindow, KeyEvent.KEY_PRESSED, when, + awtMods, keyCode, + KeyEvent.CHAR_UNDEFINED); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(ke); + if (keyChar != KeyEvent.CHAR_UNDEFINED) + { + ke = new KeyEvent(awtWindow, KeyEvent.KEY_TYPED, when, + awtMods, KeyEvent.VK_UNDEFINED, + keyChar); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(ke); + } + + } + else + { + ke = new KeyEvent(awtWindow, KeyEvent.KEY_RELEASED, when, + awtMods, keyCode, + KeyEvent.CHAR_UNDEFINED); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(ke); + } + + } + + /** Translates an X button identifier to the AWT's MouseEvent modifier + * mask. As the AWT cannot handle more than 3 buttons those return + * 0. + */ + static int buttonToModifier(int button) + { + switch (button) + { + case gnu.x11.Input.BUTTON1: + return MouseEvent.BUTTON1_DOWN_MASK | MouseEvent.BUTTON1_MASK; + case gnu.x11.Input.BUTTON2: + return MouseEvent.BUTTON2_DOWN_MASK | MouseEvent.BUTTON2_MASK; + case gnu.x11.Input.BUTTON3: + return MouseEvent.BUTTON3_DOWN_MASK | MouseEvent.BUTTON3_MASK; + } + + return 0; + } + + /** + * Finds the heavyweight mouse event target. + * + * @param src the original source of the event + * + * @param pt the event coordinates + * + * @return the real mouse event target + */ + private Component findMouseEventTarget(Component src, int x, int y) + { + Component found = null; + if (src instanceof Container) + { + Container cont = (Container) src; + int numChildren = cont.getComponentCount(); + for (int i = 0; i < numChildren && found == null; i++) + { + Component child = cont.getComponent(i); + if (child != null && child.isVisible() + && child.contains(x - child.getX(), y - child.getY())) + { + if (child instanceof Container) + { + Component deeper = findMouseEventTarget(child, + x - child.getX(), + y - child.getY()); + if (deeper != null) + found = deeper; + } + else if (! child.isLightweight()) + found = child; + } + } + } + + // Consider the source itself. + if (found == null && src.contains(x, y) && ! src.isLightweight()) + found = src; + + return found; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/x/XFontPeer.java b/libjava/classpath/gnu/java/awt/peer/x/XFontPeer.java new file mode 100644 index 000000000..190209014 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/x/XFontPeer.java @@ -0,0 +1,770 @@ +/* XFontPeer.java -- The font peer for X + 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.x; + +import gnu.java.lang.CPStringBuilder; + +import java.awt.AWTError; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.font.LineMetrics; +import java.awt.font.TextAttribute; +import java.awt.geom.Rectangle2D; +import java.io.IOException; +import java.io.InputStream; +import java.text.CharacterIterator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Locale; +import java.util.Map; +import java.util.Properties; + +import gnu.java.awt.peer.ClasspathFontPeer; +import gnu.x11.Display; +import gnu.x11.Fontable; + +/** + * The bridge from AWT to X fonts. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class XFontPeer + extends ClasspathFontPeer +{ + + /** + * The font mapping as specified in the file fonts.properties. + */ + private static Properties fontProperties; + static + { + fontProperties = new Properties(); + InputStream in = XFontPeer.class.getResourceAsStream("xfonts.properties"); + try + { + fontProperties.load(in); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + + /** + * The FontMetrics implementation for XFontPeer. + */ + private class XFontMetrics + extends FontMetrics + { + /** + * The ascent of the font. + */ + int ascent; + + /** + * The descent of the font. + */ + int descent; + + /** + * The maximum of the character advances. + */ + private int maxAdvance; + + /** + * The internal leading. + */ + int leading; + + /** + * Cached string metrics. This caches string metrics locally so that the + * server doesn't have to be asked each time. + */ + private HashMap metricsCache; + + /** + * The widths of the characters indexed by the characters themselves. + */ + private int[] charWidths; + + /** + * Creates a new XFontMetrics for the specified font. + * + * @param font the font + */ + protected XFontMetrics(Font font) + { + super(font); + metricsCache = new HashMap(); + Fontable.FontInfo info = getXFont().info(); + ascent = info.font_ascent(); + descent = info.font_descent(); + maxAdvance = info.max_bounds().character_width(); + leading = 0; // TODO: Not provided by X. Possible not needed. + + if (info.min_byte1() == 0 && info.max_byte1() == 0) + readCharWidthsLinear(info); + else + readCharWidthsNonLinear(info); + } + + /** + * Reads the character widths when specified in a linear fashion. That is + * when the min-byte1 and max-byte2 fields are both zero in the X protocol. + * + * @param info the font info reply + */ + private void readCharWidthsLinear(Fontable.FontInfo info) + { + int startIndex = info.min_char_or_byte2(); + int endIndex = info.max_char_or_byte2(); + charWidths = new int[endIndex + 1]; + // All the characters before startIndex are zero width. + for (int i = 0; i < startIndex; i++) + { + charWidths[i] = 0; + } + // All the other character info is fetched from the font info. + int index = startIndex; + Fontable.FontInfo.CharInfo[] charInfos = info.char_infos(); + for (Fontable.FontInfo.CharInfo charInfo : charInfos) + { + charWidths[index] = charInfo.character_width(); + index++; + } + } + + private void readCharWidthsNonLinear(Fontable.FontInfo info) + { + // TODO: Implement. + throw new UnsupportedOperationException("Not yet implemented"); + } + + /** + * Returns the ascent of the font. + * + * @return the ascent of the font + */ + public int getAscent() + { + return ascent; + } + + /** + * Returns the descent of the font. + * + * @return the descent of the font + */ + public int getDescent() + { + return descent; + } + + /** + * Returns the overall height of the font. This is the distance from + * baseline to baseline (usually ascent + descent + leading). + * + * @return the overall height of the font + */ + public int getHeight() + { + return ascent + descent; + } + + /** + * Returns the leading of the font. + * + * @return the leading of the font + */ + public int getLeading() + { + return leading; + } + + /** + * Returns the maximum advance for this font. + * + * @return the maximum advance for this font + */ + public int getMaxAdvance() + { + return maxAdvance; + } + + /** + * Determines the width of the specified character c. + * + * @param c the character + * + * @return the width of the character + */ + public int charWidth(char c) + { + int width; + if (c > charWidths.length) + width = charWidths['?']; + else + width = charWidths[c]; + return width; + } + + /** + * Determines the overall width of the specified string. + * + * @param c the char buffer holding the string + * @param offset the starting offset of the string in the buffer + * @param length the number of characters in the string buffer + * + * @return the overall width of the specified string + */ + public int charsWidth(char[] c, int offset, int length) + { + int width = 0; + if (c.length > 0 && length > 0) + { + String s = new String(c, offset, length); + width = stringWidth(s); + } + return width; + } + + /** + * Determines the overall width of the specified string. + * + * @param s the string + * + * @return the overall width of the specified string + */ + public int stringWidth(String s) + { + int width = 0; + if (s.length() > 0) + { + if (metricsCache.containsKey(s)) + { + width = ((Integer) metricsCache.get(s)).intValue(); + } + else + { + Fontable.TextExtentInfo extents = getXFont().text_extent(s); + /* + System.err.println("string: '" + s + "' : "); + System.err.println("ascent: " + extents.getAscent()); + System.err.println("descent: " + extents.getDescent()); + System.err.println("overall ascent: " + extents.getOverallAscent()); + System.err.println("overall descent: " + extents.getOverallDescent()); + System.err.println("overall width: " + extents.getOverallWidth()); + System.err.println("overall left: " + extents.getOverallLeft()); + System.err.println("overall right: " + extents.getOverallRight()); + */ + width = extents.overall_width(); // + extents.overall_left(); + //System.err.println("String: " + s + ", width: " + width); + metricsCache.put(s, new Integer(width)); + } + } + //System.err.print("stringWidth: '" + s + "': "); + //System.err.println(width); + return width; + } + } + + /** + * The LineMetrics implementation for the XFontPeer. + */ + private class XLineMetrics + extends LineMetrics + { + + /** + * Returns the ascent of the font. + * + * @return the ascent of the font + */ + public float getAscent() + { + return fontMetrics.ascent; + } + + public int getBaselineIndex() + { + // FIXME: Implement this. + throw new UnsupportedOperationException(); + } + + public float[] getBaselineOffsets() + { + // FIXME: Implement this. + throw new UnsupportedOperationException(); + } + + /** + * Returns the descent of the font. + * + * @return the descent of the font + */ + public float getDescent() + { + return fontMetrics.descent; + } + + /** + * Returns the overall height of the font. This is the distance from + * baseline to baseline (usually ascent + descent + leading). + * + * @return the overall height of the font + */ + public float getHeight() + { + return fontMetrics.ascent + fontMetrics.descent; + } + + /** + * Returns the leading of the font. + * + * @return the leading of the font + */ + public float getLeading() + { + return fontMetrics.leading; + } + + public int getNumChars() + { + // FIXME: Implement this. + throw new UnsupportedOperationException(); + } + + public float getStrikethroughOffset() + { + return 0.F; // TODO: Provided by X?? + } + + public float getStrikethroughThickness() + { + return 1.F; // TODO: Provided by X?? + } + + public float getUnderlineOffset() + { + return 0.F; // TODO: Provided by X?? + } + + public float getUnderlineThickness() + { + return 1.F; // TODO: Provided by X?? + } + + } + + /** + * The X font. + */ + private gnu.x11.Font xfont; + + private String name; + + private int style; + + private int size; + + /** + * The font metrics for this font. + */ + XFontMetrics fontMetrics; + + /** + * Creates a new XFontPeer for the specified font name, style and size. + * + * @param name the font name + * @param style the font style (bold / italic / normal) + * @param size the size of the font + */ + public XFontPeer(String name, int style, int size) + { + super(name, style, size); + this.name = name; + this.style = style; + this.size = size; + } + + /** + * Creates a new XFontPeer for the specified font name and style + * attributes. + * + * @param name the font name + * @param atts the font attributes + */ + public XFontPeer(String name, Map atts) + { + super(name, atts); + String family = name; + if (family == null || family.equals("")) + family = (String) atts.get(TextAttribute.FAMILY); + if (family == null) + family = "SansSerif"; + + int size = 12; + Float sizeFl = (Float) atts.get(TextAttribute.SIZE); + if (sizeFl != null) + size = sizeFl.intValue(); + + int style = 0; + // Detect italic attribute. + Float posture = (Float) atts.get(TextAttribute.POSTURE); + if (posture != null && !posture.equals(TextAttribute.POSTURE_REGULAR)) + style |= Font.ITALIC; + + // Detect bold attribute. + Float weight = (Float) atts.get(TextAttribute.WEIGHT); + if (weight != null && weight.compareTo(TextAttribute.WEIGHT_REGULAR) > 0) + style |= Font.BOLD; + + this.name = name; + this.style = style; + this.size = size; + } + + /** + * Initializes the font peer with the specified attributes. This method is + * called from both constructors. + * + * @param name the font name + * @param style the font style + * @param size the font size + */ + private void init(String name, int style, int size) + { + if (name == null) + { + name = "SansSerif"; + } + GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice dev = env.getDefaultScreenDevice(); + if (dev instanceof XGraphicsDevice) + { + Display display = ((XGraphicsDevice) dev).getDisplay(); + String fontDescr = encodeFont(name, style, size); + if (XToolkit.DEBUG) + System.err.println("XLFD font description: " + fontDescr); + xfont = new gnu.x11.Font(display, fontDescr); + } + else + { + throw new AWTError("Local GraphicsEnvironment is not XWindowGraphicsEnvironment"); + } + } + + public boolean canDisplay(Font font, int c) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public int canDisplayUpTo(Font font, CharacterIterator i, int start, int limit) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public String getSubFamilyName(Font font, Locale locale) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public String getPostScriptName(Font font) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public int getNumGlyphs(Font font) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public int getMissingGlyphCode(Font font) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public byte getBaselineFor(Font font, char c) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public String getGlyphName(Font font, int glyphIndex) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public GlyphVector createGlyphVector(Font font, FontRenderContext frc, + CharacterIterator ci) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public GlyphVector createGlyphVector(Font font, FontRenderContext ctx, + int[] glyphCodes) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public GlyphVector layoutGlyphVector(Font font, FontRenderContext frc, + char[] chars, int start, int limit, + int flags) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + /** + * Returns the font metrics for the specified font. + * + * @param font the font for which to fetch the font metrics + * + * @return the font metrics for the specified font + */ + public FontMetrics getFontMetrics(Font font) + { + if (font.getPeer() != this) + throw new AWTError("The specified font has a different peer than this"); + + if (fontMetrics == null) + fontMetrics = new XFontMetrics(font); + return fontMetrics; + } + + /** + * Frees the font in the X server. + */ + protected void finalize() + { + if (xfont != null) + xfont.close(); + } + + public boolean hasUniformLineMetrics(Font font) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + /** + * Returns the line metrics for this font and the specified string and + * font render context. + */ + public LineMetrics getLineMetrics(Font font, CharacterIterator ci, int begin, + int limit, FontRenderContext rc) + { + return new XLineMetrics(); + } + + public Rectangle2D getMaxCharBounds(Font font, FontRenderContext rc) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public Rectangle2D getStringBounds(Font font, CharacterIterator ci, + int begin, int limit, FontRenderContext frc) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + /** + * Encodes a font name + style + size specification into a X logical font + * description (XLFD) as described here: + * + * http://www.meretrx.com/e93/docs/xlfd.html + * + * This is implemented to look up the font description in the + * fonts.properties of this package. + * + * @param name the font name + * @param atts the text attributes + * + * @return the encoded font description + */ + static String encodeFont(String name, Map atts) + { + String family = name; + if (family == null || family.equals("")) + family = (String) atts.get(TextAttribute.FAMILY); + if (family == null) + family = "SansSerif"; + + int size = 12; + Float sizeFl = (Float) atts.get(TextAttribute.SIZE); + if (sizeFl != null) + size = sizeFl.intValue(); + + int style = 0; + // Detect italic attribute. + Float posture = (Float) atts.get(TextAttribute.POSTURE); + if (posture != null && !posture.equals(TextAttribute.POSTURE_REGULAR)) + style |= Font.ITALIC; + + // Detect bold attribute. + Float weight = (Float) atts.get(TextAttribute.WEIGHT); + if (weight != null && weight.compareTo(TextAttribute.WEIGHT_REGULAR) > 0) + style |= Font.BOLD; + + return encodeFont(family, style, size); + } + + /** + * Encodes a font name + style + size specification into a X logical font + * description (XLFD) as described here: + * + * http://www.meretrx.com/e93/docs/xlfd.html + * + * This is implemented to look up the font description in the + * fonts.properties of this package. + * + * @param name the font name + * @param style the font style + * @param size the font size + * + * @return the encoded font description + */ + static String encodeFont(String name, int style, int size) + { + CPStringBuilder key = new CPStringBuilder(); + key.append(validName(name)); + key.append('.'); + switch (style) + { + case Font.BOLD: + key.append("bold"); + break; + case Font.ITALIC: + key.append("italic"); + break; + case (Font.BOLD | Font.ITALIC): + key.append("bolditalic"); + break; + case Font.PLAIN: + default: + key.append("plain"); + + } + + String protoType = fontProperties.getProperty(key.toString()); + int s = validSize(size); + return protoType.replaceFirst("%d", String.valueOf(s)); + } + + /** + * Checks the specified font name for a valid font name. If the font name + * is not known, then this returns 'sansserif' as fallback. + * + * @param name the font name to check + * + * @return a valid font name + */ + static String validName(String name) + { + String retVal; + if (name.equalsIgnoreCase("sansserif") + || name.equalsIgnoreCase("serif") + || name.equalsIgnoreCase("monospaced") + || name.equalsIgnoreCase("dialog") + || name.equalsIgnoreCase("dialoginput")) + { + retVal = name.toLowerCase(); + } + else + { + retVal = "sansserif"; + } + return retVal; + } + + /** + * Translates an arbitrary point size to a size that is typically available + * on an X server. These are the sizes 8, 10, 12, 14, 18 and 24. + * + * @param size the queried size + * @return the real available size + */ + private static final int validSize(int size) + { + int val; + if (size <= 9) + val = 8; + else if (size <= 11) + val = 10; + else if (size <= 13) + val = 12; + else if (size <= 17) + val = 14; + else if (size <= 23) + val = 18; + else + val = 24; + return val; + } + + /** + * Returns the X Font reference. This lazily loads the font when first + * requested. + * + * @return the X Font reference + */ + gnu.x11.Font getXFont() + { + if (xfont == null) + { + init(name, style, size); + } + return xfont; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/x/XFramePeer.java b/libjava/classpath/gnu/java/awt/peer/x/XFramePeer.java new file mode 100644 index 000000000..cde67778d --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/x/XFramePeer.java @@ -0,0 +1,145 @@ +/* XFramePeer.java -- The X FramePeer implementation + 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.x; + +import java.awt.Component; +import java.awt.EventQueue; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Insets; +import java.awt.MenuBar; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.PaintEvent; +import java.awt.event.WindowEvent; +import java.awt.peer.FramePeer; + +import gnu.java.awt.peer.swing.SwingFramePeer; +import gnu.x11.Window; +import gnu.x11.event.Event; + +public class XFramePeer + extends XWindowPeer + implements FramePeer +{ + + XFramePeer(Frame f) + { + super(f); + setTitle(f.getTitle()); + } + + public void setIconImage(Image image) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public void setMenuBar(MenuBar mb) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public void setResizable(boolean resizable) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public void setTitle(String title) + { + xwindow.set_wm_name (title); + } + + public int getState() + { + return 0; + } + + public void setState(int state) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public void setMaximizedBounds(Rectangle r) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + /** + * Check if this frame peer supports being restacked. + * + * @return true if this frame peer can be restacked, + * false otherwise + * @since 1.5 + */ + public boolean isRestackSupported() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + /** + * Sets the bounds of this frame peer. + * + * @param x the new x co-ordinate + * @param y the new y co-ordinate + * @param width the new width + * @param height the new height + * @since 1.5 + */ + public void setBoundsPrivate(int x, int y, int width, int height) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public Rectangle getBoundsPrivate() + { + // TODO: Implement this properly. + throw new InternalError("Not yet implemented"); + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/x/XGraphics2D.java b/libjava/classpath/gnu/java/awt/peer/x/XGraphics2D.java new file mode 100644 index 000000000..1fce2dcf7 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/x/XGraphics2D.java @@ -0,0 +1,508 @@ +/* XGraphics2D.java -- A Java based Graphics2D impl for X + 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.x; + +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.Image; +import java.awt.Paint; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.Toolkit; +import java.awt.Transparency; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.ImageObserver; +import java.awt.image.Raster; +import java.awt.peer.FontPeer; +import java.util.HashMap; +import java.util.WeakHashMap; + +import gnu.java.awt.image.AsyncImage; +import gnu.java.awt.java2d.AbstractGraphics2D; +import gnu.java.awt.java2d.ScanlineCoverage; +import gnu.x11.Colormap; +import gnu.x11.Drawable; +import gnu.x11.GC; +import gnu.x11.image.ZPixmap; + +public class XGraphics2D + extends AbstractGraphics2D +{ + + /** + * When this property is set to true, then images are always rendered as + * opaque images, ignoring their translucence. This is intended for + * debugging and demonstration purposes. + */ + private static final boolean RENDER_OPAQUE = + Boolean.getBoolean("escherpeer.renderopaque"); + + /** + * The X Drawable to draw on. + */ + private Drawable xdrawable; + + /** + * The X graphics context (GC). + */ + private GC xgc; + + /** + * Indicates if this graphics has already been disposed. + */ + private boolean disposed; + + /** + * The current foreground color, possibly null. + */ + private Color foreground; + + XGraphics2D(Drawable d) + { + super(); + xdrawable = d; + xgc = new GC(d); + init(); + disposed = false; + //setClip(new Rectangle(0, 0, xdrawable.width, xdrawable.height)); + } + + @Override + protected void rawDrawLine(int x0, int y0, int x1, int y1) + { + xdrawable.segment(xgc, x0, y0, x1, y1); + } + + @Override + protected void rawDrawRect(int x, int y, int w, int h) + { + xdrawable.rectangle(xgc, x, y, w, h, false); + } + + @Override + protected void rawFillRect(int x, int y, int w, int h) + { + xdrawable.rectangle(xgc, x, y, w, h, true); + } + + /** + * Returns the color model of this Graphics object. + * + * @return the color model of this Graphics object + */ + protected ColorModel getColorModel() + { + return Toolkit.getDefaultToolkit().getColorModel(); + } + + /** + * Returns the color model of the target device. + * + * @return the color model of the target device + */ + protected ColorModel getDestinationColorModel() + { + return Toolkit.getDefaultToolkit().getColorModel(); + } + + /** + * Returns the bounds of the target. + * + * @return the bounds of the target + */ + protected Rectangle getDeviceBounds() + { + return new Rectangle(0, 0, xdrawable.width, xdrawable.height); + } + + public GraphicsConfiguration getDeviceConfiguration() + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public void dispose() + { + if (!disposed) + { + xgc.free(); + xdrawable.display.flush(); + disposed = true; + } + } + + public Graphics create() + { + // super.create() returns a copy created by clone(), so it should + // be a XGraphics2D. + XGraphics2D copy = (XGraphics2D) super.create(); + copy.xgc = xgc.copy(); + return copy; + } + + public void setClip(Shape c) + { + super.setClip(c); + if (c instanceof Rectangle) + { + Rectangle r = (Rectangle) c; + AffineTransform t = getTransform(); + int translateX = (int) t.getTranslateX(); + //System.err.println("translateX: " + translateX); + int translateY = (int) t.getTranslateY(); + //System.err.println("translateY: " + translateY); + //System.err.println("clip: " + c); + gnu.x11.Rectangle clip = new gnu.x11.Rectangle(r.x, r.y, r.width, + r.height); + xgc.set_clip_rectangles(translateX, translateY, + new gnu.x11.Rectangle[]{clip}, GC.UN_SORTED); + } + } + + /** + * Notifies the backend that the raster has changed in the specified + * rectangular area. The raster that is provided in this method is always + * the same as the one returned in {@link #getDestinationRaster}. + * Backends that reflect changes to this raster directly don't need to do + * anything here. + * + * @param raster the updated raster, identical to the raster returned + * by {@link #getDestinationRaster()} + * @param x the upper left corner of the updated region, X coordinate + * @param y the upper lef corner of the updated region, Y coordinate + * @param w the width of the updated region + * @param h the height of the updated region + */ + protected void updateRaster(Raster raster, int x, int y, int w, int h) + { + if (w > 0 && h > 0) + { + ZPixmap zPixmap = new ZPixmap(xdrawable.display, w, h, + xdrawable.display.default_pixmap_format); + int[] pixel = null; + int x1 = x + w; + int y1 = y + h; + for (int tx = x; tx < x1; tx++) + { + for (int ty = y; ty < y1; ty++) + { + pixel = raster.getPixel(tx, ty, pixel); + //System.err.println("tx: " + tx + ", ty: " + ty + ", pixel: " + pixel[0] + ", " + pixel[1] + ", " + pixel[2]); +// System.err.print("r: " + pixel[0]); +// System.err.print(", g: " + pixel[1]); +// System.err.println(", b: " + pixel[2]); + zPixmap.set_red(tx - x, ty - y, pixel[0]); + zPixmap.set_green(tx - x, ty - y, pixel[1]); + zPixmap.set_blue(tx - x, ty - y, pixel[2]); + } + } + xdrawable.put_image(xgc, zPixmap, x, y); + } + } + + @Override + public void renderScanline(int y, ScanlineCoverage c) + { + if (y >= xdrawable.height) + return; + + // TODO: Handle Composite and Paint. + ScanlineCoverage.Iterator iter = c.iterate(); + int coverageAlpha = 0; + int maxCoverage = c.getMaxCoverage(); + while (iter.hasNext()) + { + ScanlineCoverage.Range range = iter.next(); + + coverageAlpha = range.getCoverage(); + int x0 = range.getXPos(); + int l = range.getLength(); + if (coverageAlpha == c.getMaxCoverage()) + { + // Simply paint the current color over the existing pixels. + xdrawable.fill_rectangle(xgc, x0, y, l, 1); + } + else if (coverageAlpha > 0) + { + // Composite the current color with the existing pixels. + int x1 = x0 + l; + x0 = Math.min(Math.max(0, x0), xdrawable.width - 1); + x1 = Math.min(Math.max(0, x1), xdrawable.width - 1); + if ((x1 - x0) < 1) + continue; + l = x1 - x0; + gnu.x11.image.ZPixmap existing = (ZPixmap) + xdrawable.image(x0, y, l, 1, 0xFFFFFFFF, + gnu.x11.image.Image.Format.ZPIXMAP); + for (int x = 0; x < l; x++) + { + Color col = getColor(); + if (col == null) + { + col = Color.BLACK; + } + int red = col.getRed(); + int green = col.getGreen(); + int blue = col.getBlue(); + int redOut = existing.get_red(x, 0); + int greenOut = existing.get_green(x, 0); + int blueOut = existing.get_blue(x, 0); + int outAlpha = maxCoverage - coverageAlpha; + redOut = redOut * outAlpha + red * coverageAlpha; + redOut = redOut / maxCoverage; + greenOut = greenOut * outAlpha + green * coverageAlpha; + greenOut = greenOut / maxCoverage; + blueOut = blueOut * outAlpha + blue * coverageAlpha; + blueOut = blueOut / maxCoverage; + existing.set(x, 0, redOut, greenOut, blueOut); + } + xdrawable.put_image(xgc, existing, x0, y); + } + } + } + + protected void init() + { + super.init(); + } + + public void setPaint(Paint p) + { + super.setPaint(p); + if (p instanceof Color) + { + // TODO: Optimize for different standard bit-depths. + Color c = (Color) p; + /* XToolkit tk = (XToolkit) Toolkit.getDefaultToolkit(); + HashMap colorMap = tk.colorMap; + gnu.x11.Color col = (gnu.x11.Color) colorMap.get(c); + if (col == null) + { + Colormap map = xdrawable.display.default_colormap; + col = map.alloc_color (c.getRed() * 256, + c.getGreen() * 256, + c.getBlue() * 256); + colorMap.put(c, col); + }*/ + //xgc.set_foreground(col); + + xgc.set_foreground(c.getRGB()); + foreground = c; + } + } + + protected void fillShape(Shape s, boolean isFont) + { + synchronized (xdrawable.display) { + super.fillShape(s, isFont); + } + } + + private static WeakHashMap imageCache = new WeakHashMap(); + + protected boolean rawDrawImage(Image image, int x, int y, ImageObserver obs) + { + image = unwrap(image); + boolean ret; + if (image instanceof XImage) + { + XImage xImage = (XImage) image; + xdrawable.copy_area(xImage.pixmap, xgc, 0, 0, xImage.getWidth(obs), + xImage.getHeight(obs), x, y); + ret = true; + } + else if (image instanceof PixmapVolatileImage) + { + PixmapVolatileImage pvi = (PixmapVolatileImage) image; + xdrawable.copy_area(pvi.getPixmap(), xgc, 0, 0, pvi.getWidth(obs), + pvi.getHeight(obs), x, y); + ret = true; + } + else if (image instanceof BufferedImage) + { + BufferedImage bi = (BufferedImage) image; + DataBuffer db = bi.getRaster().getDataBuffer(); + if (db instanceof ZPixmapDataBuffer) + { + ZPixmapDataBuffer zpmdb = (ZPixmapDataBuffer) db; + ZPixmap zpixmap = zpmdb.getZPixmap(); + xdrawable.put_image(xgc, zpixmap, x, y); + ret = true; + } + else + { + int transparency = bi.getTransparency(); + int w = bi.getWidth(); + int h = bi.getHeight(); + if (imageCache.containsKey(image)) + { + ZPixmap zpixmap = imageCache.get(image); + xdrawable.put_image(xgc, zpixmap, x, y); + } + else if (transparency == Transparency.OPAQUE || RENDER_OPAQUE) + { + XGraphicsDevice gd = XToolkit.getDefaultDevice(); + ZPixmap zpixmap = new ZPixmap(gd.getDisplay(), w, h); + for (int yy = 0; yy < h; yy++) + { + for (int xx = 0; xx < w; xx++) + { + int rgb = bi.getRGB(xx, yy); + zpixmap.set(xx, yy, rgb); + } + } + xdrawable.put_image(xgc, zpixmap, x, y); + imageCache.put(image, zpixmap); + } else { + + // TODO optimize reusing the rectangles + Rectangle source = + new Rectangle(0, 0, xdrawable.width, xdrawable.height); + Rectangle target = new Rectangle(x, y, w, h); + + Rectangle destination = source.intersection(target); + + x = destination.x; + y = destination.y; + w = destination.width; + h = destination.height; + + ZPixmap zpixmap = + (ZPixmap) xdrawable.image(x, y, w, h, + 0xffffffff, + gnu.x11.image.Image.Format.ZPIXMAP); + for (int yy = 0; yy < h; yy++) + { + for (int xx = 0; xx < w; xx++) + { + int rgb = bi.getRGB(xx, yy); + int alpha = 0xff & (rgb >> 24); + if (alpha == 0) + { + // Completely translucent. + rgb = zpixmap.get_red(xx, yy) << 16 + | zpixmap.get_green(xx, yy) << 8 + | zpixmap.get_blue(xx, yy); + } + else if (alpha < 255) + { + // Composite pixels. + int red = 0xff & (rgb >> 16); + red = red * alpha + + (255 - alpha) * zpixmap.get_red(xx, yy); + red = red / 255; + int green = 0xff & (rgb >> 8); + green = green * alpha + + (255 - alpha) * zpixmap.get_green(xx, yy); + green = green / 255; + int blue = 0xff & rgb; + blue = blue * alpha + + (255 - alpha) * zpixmap.get_blue(xx, yy); + blue = blue / 255; + rgb = red << 16 | green << 8 | blue; + } + // else keep rgb value from source image. + + zpixmap.set(xx, yy, rgb); + } + } + xdrawable.put_image(xgc, zpixmap, x, y); + // We can't cache prerendered translucent images, because + // we never know how the background changes. + } + ret = true; + } + } + else + { + ret = super.rawDrawImage(image, x, y, obs); + } + return ret; + } + + public void setFont(Font f) + { + super.setFont(f); + FontPeer p = getFont().getPeer(); + if (p instanceof XFontPeer) + { + XFontPeer xFontPeer = (XFontPeer) p; + xgc.set_font(xFontPeer.getXFont()); + } + } + + public void drawString(String s, int x, int y) + { + FontPeer p = getFont().getPeer(); + if (p instanceof XFontPeer) + { + int tx = (int) transform.getTranslateX(); + int ty = (int) transform.getTranslateY(); + xdrawable.text(xgc, x + tx, y + ty, s); + } + else + { + super.drawString(s, x, y); + } + } + + /** + * Extracts an image instance out of an AsyncImage. If the image isn't + * an AsyncImage, then the original instance is returned. + * + * @param im the image + * + * @return the image to render + */ + private Image unwrap(Image im) + { + Image image = im; + if (image instanceof AsyncImage) + { + AsyncImage aIm = (AsyncImage) image; + image = aIm.getRealImage(); + } + return image; + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/x/XGraphicsConfiguration.java b/libjava/classpath/gnu/java/awt/peer/x/XGraphicsConfiguration.java new file mode 100644 index 000000000..aed11a3af --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/x/XGraphicsConfiguration.java @@ -0,0 +1,200 @@ +/* XGraphicsConfiguration.java -- GraphicsConfiguration for X + 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.x; + +import gnu.x11.Display; +import gnu.x11.Screen; + +import java.awt.Dimension; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ComponentColorModel; +import java.awt.image.ComponentSampleModel; +import java.awt.image.DataBuffer; +import java.awt.image.Raster; +import java.awt.image.SampleModel; +import java.awt.image.VolatileImage; +import java.awt.image.WritableRaster; + +public class XGraphicsConfiguration + extends GraphicsConfiguration +{ + + XGraphicsDevice device; + + XGraphicsConfiguration(XGraphicsDevice dev) + { + device = dev; + } + + public GraphicsDevice getDevice() + { + return device; + } + + public BufferedImage createCompatibleImage(int w, int h) + { + return createCompatibleImage(w, h, Transparency.OPAQUE); + } + + public BufferedImage createCompatibleImage(int w, int h, int transparency) + { + BufferedImage bi; + switch (transparency) + { + case Transparency.OPAQUE: + DataBuffer buffer = new ZPixmapDataBuffer(w, h); + SampleModel sm = new ComponentSampleModel(DataBuffer.TYPE_BYTE, w, h, + 4, w * 4, + new int[]{0, 1, 2, 3 }); + ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB); + ColorModel cm = new ComponentColorModel(cs, true, false, + Transparency.OPAQUE, + DataBuffer.TYPE_BYTE); + WritableRaster raster = Raster.createWritableRaster(sm, buffer, + new Point(0, 0)); + bi = new BufferedImage(cm, raster, false, null); + break; + case Transparency.BITMASK: + case Transparency.TRANSLUCENT: + bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); + break; + default: + throw new IllegalArgumentException("Illegal transparency: " + + transparency); + } + return bi; + } + + public VolatileImage createCompatibleVolatileImage(int w, int h) + { + return createCompatibleVolatileImage(w, h, Transparency.OPAQUE); + } + + public VolatileImage createCompatibleVolatileImage(int width, int height, + int transparency) + { + VolatileImage im; + switch (transparency) + { + case Transparency.OPAQUE: + im = new PixmapVolatileImage(width, height); + break; + case Transparency.BITMASK: + case Transparency.TRANSLUCENT: + throw new UnsupportedOperationException("Not yet implemented"); + default: + throw new IllegalArgumentException("Unknown transparency type: " + + transparency); + } + return im; + } + + public ColorModel getColorModel() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public ColorModel getColorModel(int transparency) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public AffineTransform getDefaultTransform() + { + return new AffineTransform(); + } + + public AffineTransform getNormalizingTransform() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public Rectangle getBounds() + { + Display d = device.getDisplay(); + Screen screen = d.default_screen; + + return new Rectangle(0, 0, screen.width, screen.height); + } + + /** + * Determines the size of the primary screen. + * + * @return the size of the primary screen + */ + Dimension getSize() + { + // TODO: A GraphicsConfiguration should correspond to a Screen instance. + Display d = device.getDisplay(); + Screen screen = d.default_screen; + int w = screen.width; + int h = screen.height; + return new Dimension(w, h); + } + + /** + * Determines the resolution of the primary screen in pixel-per-inch. + * + * @returnthe resolution of the primary screen in pixel-per-inch + */ + int getResolution() + { + Display d = device.getDisplay(); + Screen screen = d.default_screen; + int w = screen.width * 254; + int h = screen.height * 254; + int wmm = screen.width_in_mm * 10; + int hmm = screen.height_in_mm * 10; + int xdpi = w / wmm; + int ydpi = h / hmm; + int dpi = (xdpi + ydpi) / 2; + return dpi; + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/x/XGraphicsDevice.java b/libjava/classpath/gnu/java/awt/peer/x/XGraphicsDevice.java new file mode 100644 index 000000000..6b65e14ed --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/x/XGraphicsDevice.java @@ -0,0 +1,200 @@ +/* XGraphicsDevice.java -- GraphicsDevice for X + 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.x; + +import gnu.classpath.SystemProperties; +import gnu.x11.Display; +import gnu.x11.EscherServerConnectionException; + +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.lang.reflect.Constructor; +import java.net.Socket; + +/** + * This class represents an X Display. The actual connection is established + * lazily when it is first needed. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class XGraphicsDevice + extends GraphicsDevice +{ + + private XGraphicsConfiguration defaultConfiguration; + + /** + * The X display associated with the XGraphicsDevice. This is established + * when {@link #getDisplay} is first called. + */ + private Display display; + + /** + * The display name from which the display will be initialized. + */ + private Display.Name displayName; + + /** + * The event pump for this X Display. + */ + private XEventPump eventPump; + + /** + * Creates a new XGraphicsDevice. + */ + XGraphicsDevice(Display.Name dn) + { + displayName = dn; + } + + public int getType() + { + return TYPE_RASTER_SCREEN; + } + + public String getIDstring() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public GraphicsConfiguration[] getConfigurations() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public GraphicsConfiguration getDefaultConfiguration() + { + if (defaultConfiguration == null) + defaultConfiguration = new XGraphicsConfiguration(this); + return defaultConfiguration; + } + + /** + * Returns the X Display associated with this XGraphicsDevice. + * This establishes the connection to the X server on the first invocation. + * + * @return the X Display associated with this XGraphicsDevice + */ + Display getDisplay() + { + if (display == null) + { + if (displayName.hostname.equals("")) + displayName.hostname = "localhost"; + if (XToolkit.DEBUG) + System.err.println("connecting to : " + displayName); + // Try to connect via unix domain sockets when host == localhost. + if ((displayName.hostname.equals("localhost") + || displayName.hostname.equals("")) + && SystemProperties.getProperty("gnu.xawt.no_local_sockets") == null) + { + Socket socket = createLocalSocket(); + if (socket != null) + { + try + { + display = new Display(socket, "localhost", + displayName.display_no, + displayName.screen_no); + } + catch (EscherServerConnectionException e) + { + throw new RuntimeException(e.getCause()); + } + } + } + + // The following happens when we are configured to use plain sockets, + // when the connection is probably remote or when we couldn't load + // the LocalSocket class stuff. + if (display == null) + { + try + { + display = new Display(displayName); + } + catch (EscherServerConnectionException e) + { + throw new RuntimeException(e.getCause()); + } + } + + eventPump = new XEventPump(display); + } + return display; + } + + XEventPump getEventPump() + { + return eventPump; + } + + /** + * Tries to load the LocalSocket class and initiate a connection to the + * local X server. + */ + private Socket createLocalSocket() + { + Socket socket = null; + try + { + // TODO: Is this 100% ok? + String sockPath = "/tmp/.X11-unix/X" + displayName.display_no; + Class localSocketAddressClass = + Class.forName("gnu.java.net.local.LocalSocketAddress"); + Constructor localSocketAddressConstr = + localSocketAddressClass.getConstructor(new Class[]{ String.class }); + Object addr = + localSocketAddressConstr.newInstance(new Object[]{ sockPath }); + Class localSocketClass = + Class.forName("gnu.java.net.local.LocalSocket"); + Constructor localSocketConstructor = + localSocketClass.getConstructor(new Class[]{localSocketAddressClass}); + Object localSocket = + localSocketConstructor.newInstance(new Object[]{ addr }); + socket = (Socket) localSocket; + } + catch (Exception ex) + { + // Whatever goes wrong here, we return null. + } + return socket; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/x/XGraphicsEnvironment.java b/libjava/classpath/gnu/java/awt/peer/x/XGraphicsEnvironment.java new file mode 100644 index 000000000..7b1d82fee --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/x/XGraphicsEnvironment.java @@ -0,0 +1,203 @@ +/* XGraphicsEnvironment.java -- Represents the X environment + 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.x; + +import gnu.java.awt.font.OpenTypeFontPeer; +import gnu.java.awt.java2d.RasterGraphics; +import gnu.x11.Display; + +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Locale; +import java.util.Properties; + +/** + * Represents the X environment for AWT. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class XGraphicsEnvironment + extends GraphicsEnvironment +{ + + /** + * The default graphics device. This is normally the local main X + * Display, but can be configured to be any X connection. + */ + private XGraphicsDevice defaultDevice; + + /** + * All configured devices. + */ + private XGraphicsDevice[] devices; + + /** + * Creates a new XGraphicsEnvironment. This loads the configuration if + * there is one present and initializes the XGraphicsDevices in the + * environment. If there is no configuration, then there is one + * default device initialized with the local main X device. + */ + public XGraphicsEnvironment() + { + // Initiliaze the devices. + Properties props = new Properties(); + File config = new File(System.getProperty("user.home"), + ".xawt.properties"); + + try + { + FileInputStream configIn = new FileInputStream(config); + props.load(configIn); + int dev = 1; + ArrayList deviceList = new ArrayList(); + while (true) + { + String propName = "display." + dev; + String propValue = props.getProperty(propName); + if (propValue != null) + { + Display.Name displayName = new Display.Name(propValue); + XGraphicsDevice device = new XGraphicsDevice(displayName); + if (dev == 1) + defaultDevice = device; + deviceList.add(device); + dev++; + } + else + { + if (dev == 1) + { + defaultDevice = initDefaultDevice(); + deviceList.add(defaultDevice); + } + break; + } + } + devices = (XGraphicsDevice[]) deviceList.toArray + (new XGraphicsDevice[deviceList.size()]); + } + catch (FileNotFoundException ex) + { + defaultDevice = initDefaultDevice(); + devices = new XGraphicsDevice[]{ defaultDevice }; + } + catch (IOException ex) + { + defaultDevice = initDefaultDevice(); + devices = new XGraphicsDevice[]{ defaultDevice }; + } + + } + + /** + * Helper method that initializes the default device in the case when there + * is no configuration for the default. + */ + private XGraphicsDevice initDefaultDevice() + { + String display = System.getenv("DISPLAY"); + if (display == null) + display = ":0.0"; + Display.Name displayName = new Display.Name(display); + return new XGraphicsDevice(displayName); + } + + /** + * Returns all configured screen devices. + * + * @return all configured screen devices + */ + public GraphicsDevice[] getScreenDevices() + { + // We return a copy so that nobody can fiddle with our devices. + XGraphicsDevice[] copy = new XGraphicsDevice[devices.length]; + System.arraycopy(devices, 0, copy, 0, devices.length); + return copy; + } + + /** + * Returns the default screen device. + * + * @return the default screen device + */ + public GraphicsDevice getDefaultScreenDevice() + { + return defaultDevice; + } + + /** + * Returns a Graphics instance suitable for drawing on top of the + * BufferedImage. + * + * @param image the buffered image to create a graphics for + * + * @return a Graphics2D instance for drawing on the BufferedImage + */ + public Graphics2D createGraphics(BufferedImage image) + { + return new RasterGraphics(image.getRaster(), image.getColorModel()); + } + + public Font[] getAllFonts() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public String[] getAvailableFontFamilyNames() + { + return getAvailableFontFamilyNames(Locale.getDefault()); + } + + public String[] getAvailableFontFamilyNames(Locale l) + { + // TODO: This doesn't work when we are using X fonts. + // Fix this. + return OpenTypeFontPeer.getAvailableFontFamilyNames(l); + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/x/XImage.java b/libjava/classpath/gnu/java/awt/peer/x/XImage.java new file mode 100644 index 000000000..f3df89f4d --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/x/XImage.java @@ -0,0 +1,178 @@ +/* XImage.java -- Image impl for X Pixmaps + 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.x; + +import gnu.x11.Pixmap; +import gnu.x11.image.ZPixmap; + +import java.awt.Graphics; +import java.awt.GraphicsEnvironment; +import java.awt.Image; + +import java.awt.image.ColorModel; +import java.awt.image.ImageConsumer; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; + +import java.util.Hashtable; +import java.util.Vector; + +public class XImage + extends Image +{ + + Pixmap pixmap; + + private Hashtable properties; + + XImage(int w, int h) + { + GraphicsEnvironment env = + GraphicsEnvironment.getLocalGraphicsEnvironment(); + XGraphicsDevice dev = (XGraphicsDevice) env.getDefaultScreenDevice(); + pixmap = new Pixmap(dev.getDisplay(), w, h); + } + + public int getWidth(ImageObserver observer) + { + return pixmap.width; + } + + public int getHeight(ImageObserver observer) + { + return pixmap.height; + } + + public ImageProducer getSource() + { + return new XImageProducer(); + } + + /** + * Creates an XGraphics for drawing on this XImage. + * + * @return an XGraphics for drawing on this XImage + */ + public Graphics getGraphics() + { + XGraphics2D g = new XGraphics2D(pixmap); + return g; + } + + public Object getProperty(String name, ImageObserver observer) + { + Object val = null; + if (properties != null) + val = properties.get(val); + return val; + } + + public void flush() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected void finalize() + { + pixmap.free(); + } + + protected class XImageProducer implements ImageProducer + { + private Vector consumers = new Vector(); + + public void addConsumer(ImageConsumer ic) + { + if (ic != null && !isConsumer(ic)) + this.consumers.add(ic); + } + + public boolean isConsumer(ImageConsumer ic) + { + return this.consumers.contains(ic); + } + + public void removeConsumer(ImageConsumer ic) + { + if (ic != null) + this.consumers.remove(ic); + } + + public void requestTopDownLeftRightResend(ImageConsumer ic) + { + /* just ignore the call */ + } + + public void startProduction(ImageConsumer ic) + { + this.addConsumer(ic); + + for (ImageConsumer consumer : this.consumers) + { + int width = XImage.this.getWidth(null); + int height = XImage.this.getHeight(null); + + XGraphics2D graphics = (XGraphics2D) getGraphics(); + ColorModel model = graphics.getColorModel(); + graphics.dispose(); + + ZPixmap zpixmap = (ZPixmap) + XImage.this.pixmap.image(0, 0, width, height, + 0xffffffff, + gnu.x11.image.Image.Format.ZPIXMAP); + + int size = zpixmap.get_data_length(); + System.out.println("size: " + size + ", w = " + width + ", h = " + height); + + int [] pixel = new int[size]; + for (int i = 0; i < size; i++) + pixel[i] = zpixmap.get_data_element(i); + + consumer.setHints(ImageConsumer.SINGLEPASS); + + consumer.setDimensions(width, height); + consumer.setPixels(0, 0, width, height, model, pixel, 0, width); + consumer.imageComplete(ImageConsumer.STATICIMAGEDONE); + } + + System.out.println("done!"); + } + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/x/XToolkit.java b/libjava/classpath/gnu/java/awt/peer/x/XToolkit.java new file mode 100644 index 000000000..a3eeb0f53 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/x/XToolkit.java @@ -0,0 +1,667 @@ +/* XToolkit.java -- The central AWT Toolkit for the X 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.x; + +import java.awt.AWTException; +import java.awt.Button; +import java.awt.Canvas; +import java.awt.Checkbox; +import java.awt.CheckboxMenuItem; +import java.awt.Choice; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FileDialog; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Frame; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.HeadlessException; +import java.awt.Image; +import java.awt.Label; +import java.awt.List; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.PopupMenu; +import java.awt.PrintJob; +import java.awt.ScrollPane; +import java.awt.Scrollbar; +import java.awt.TextArea; +import java.awt.TextField; +import java.awt.Transparency; +import java.awt.Window; +import java.awt.Dialog.ModalExclusionType; +import java.awt.Dialog.ModalityType; +import java.awt.datatransfer.Clipboard; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.peer.DragSourceContextPeer; +import java.awt.im.InputMethodHighlight; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.DirectColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.peer.ButtonPeer; +import java.awt.peer.CanvasPeer; +import java.awt.peer.CheckboxMenuItemPeer; +import java.awt.peer.CheckboxPeer; +import java.awt.peer.ChoicePeer; +import java.awt.peer.DialogPeer; +import java.awt.peer.FileDialogPeer; +import java.awt.peer.FontPeer; +import java.awt.peer.FramePeer; +import java.awt.peer.LabelPeer; +import java.awt.peer.ListPeer; +import java.awt.peer.MenuBarPeer; +import java.awt.peer.MenuItemPeer; +import java.awt.peer.MenuPeer; +import java.awt.peer.PanelPeer; +import java.awt.peer.PopupMenuPeer; +import java.awt.peer.RobotPeer; +import java.awt.peer.ScrollPanePeer; +import java.awt.peer.ScrollbarPeer; +import java.awt.peer.TextAreaPeer; +import java.awt.peer.TextFieldPeer; +import java.awt.peer.WindowPeer; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.WeakHashMap; + +import javax.imageio.ImageIO; + +import gnu.classpath.SystemProperties; +import gnu.java.awt.ClasspathToolkit; +import gnu.java.awt.EmbeddedWindow; +import gnu.java.awt.font.OpenTypeFontPeer; +import gnu.java.awt.image.ImageConverter; +import gnu.java.awt.java2d.AbstractGraphics2D; +import gnu.java.awt.peer.ClasspathFontPeer; +import gnu.java.awt.peer.EmbeddedWindowPeer; +import gnu.java.awt.peer.swing.SwingButtonPeer; +import gnu.java.awt.peer.swing.SwingCanvasPeer; +import gnu.java.awt.peer.swing.SwingCheckboxPeer; +import gnu.java.awt.peer.swing.SwingLabelPeer; +import gnu.java.awt.peer.swing.SwingPanelPeer; +import gnu.java.awt.peer.swing.SwingTextAreaPeer; +import gnu.java.awt.peer.swing.SwingTextFieldPeer; + +public class XToolkit + extends ClasspathToolkit +{ + + /** + * Set to true to enable debug output. + */ + static boolean DEBUG = false; + + /** + * Maps AWT colors to X colors. + */ + HashMap colorMap = new HashMap(); + + /** + * The system event queue. + */ + private EventQueue eventQueue; + + /** + * The default color model of this toolkit. + */ + private ColorModel colorModel; + + /** + * Maps image URLs to Image instances. + */ + private HashMap imageCache = new HashMap(); + + /** + * The cached fonts. + */ + private WeakHashMap fontCache = + new WeakHashMap(); + + public XToolkit() + { + SystemProperties.setProperty("gnu.javax.swing.noGraphics2D", "true"); + SystemProperties.setProperty("java.awt.graphicsenv", + "gnu.java.awt.peer.x.XGraphicsEnvironment"); + } + + public GraphicsEnvironment getLocalGraphicsEnvironment() + { + return new XGraphicsEnvironment(); + } + + /** + * Returns the font peer for a font with the specified name and attributes. + * + * @param name the font name + * @param attrs the font attributes + * + * @return the font peer for a font with the specified name and attributes + */ + public ClasspathFontPeer getClasspathFontPeer(String name, Map attrs) + { + ClasspathFontPeer font; + if ("true".equals(System.getProperty("escherpeer.usexfonts"))) + { + String canonical = XFontPeer.encodeFont(name, attrs); + if (!fontCache.containsKey(canonical)) + { + font = new XFontPeer(name, attrs); + fontCache.put(canonical, font); + } + else + { + font = fontCache.get(canonical); + } + } + else + { + String canonical = OpenTypeFontPeer.encodeFont(name, attrs); + if (!fontCache.containsKey(canonical)) + { + font = new OpenTypeFontPeer(name, attrs); + fontCache.put(canonical, font); + } + else + { + font = fontCache.get(canonical); + } + } + return font; + } + + public Font createFont(int format, InputStream stream) + { + return null; + } + + public RobotPeer createRobot(GraphicsDevice screen) throws AWTException + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public EmbeddedWindowPeer createEmbeddedWindow(EmbeddedWindow w) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected ButtonPeer createButton(Button target) + { + checkHeadLess("No ButtonPeer can be created in an headless" + + "graphics environment."); + + return new SwingButtonPeer(target); + } + + protected TextFieldPeer createTextField(TextField target) + { + checkHeadLess("No TextFieldPeer can be created in an headless " + + "graphics environment."); + + return new SwingTextFieldPeer(target); + } + + protected LabelPeer createLabel(Label target) + { + checkHeadLess("No LabelPeer can be created in an headless graphics " + + "environment."); + return new SwingLabelPeer(target); + } + + protected ListPeer createList(List target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected CheckboxPeer createCheckbox(Checkbox target) + { + checkHeadLess("No CheckboxPeer can be created in an headless graphics " + + "environment."); + + return new SwingCheckboxPeer(target); + } + + protected ScrollbarPeer createScrollbar(Scrollbar target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected ScrollPanePeer createScrollPane(ScrollPane target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected TextAreaPeer createTextArea(TextArea target) + { + checkHeadLess("No TextAreaPeer can be created in an headless graphics " + + "environment."); + + return new SwingTextAreaPeer(target); + } + + protected ChoicePeer createChoice(Choice target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected FramePeer createFrame(Frame target) + { + XFramePeer frame = new XFramePeer(target); + return frame; + } + + protected CanvasPeer createCanvas(Canvas target) + { + return new SwingCanvasPeer(target); + } + + protected PanelPeer createPanel(Panel target) + { + return new SwingPanelPeer(target); + } + + protected WindowPeer createWindow(Window target) + { + return new XWindowPeer(target); + } + + protected DialogPeer createDialog(Dialog target) + { + return new XDialogPeer(target); + } + + protected MenuBarPeer createMenuBar(MenuBar target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected MenuPeer createMenu(Menu target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected PopupMenuPeer createPopupMenu(PopupMenu target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected MenuItemPeer createMenuItem(MenuItem target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected FileDialogPeer createFileDialog(FileDialog target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected FontPeer getFontPeer(String name, int style) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public Dimension getScreenSize() + { + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice gd = ge.getDefaultScreenDevice(); + GraphicsConfiguration gc = gd.getDefaultConfiguration(); + XGraphicsConfiguration xgc = (XGraphicsConfiguration) gc; + + return xgc.getSize(); + } + + public int getScreenResolution() + { + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice gd = ge.getDefaultScreenDevice(); + GraphicsConfiguration gc = gd.getDefaultConfiguration(); + XGraphicsConfiguration xgc = (XGraphicsConfiguration) gc; + + return xgc.getResolution(); + } + + /** + * Returns the color model used by this toolkit. + * + * @return the color model used by this toolkit + */ + public ColorModel getColorModel() + { + // TODO: I assume 24 bit depth here, we can do this better. + if (colorModel == null) + colorModel = new DirectColorModel(24, 0xFF0000, 0xFF00, 0xFF); + return colorModel; + } + + public String[] getFontList() + { + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + return ge.getAvailableFontFamilyNames(); + } + + public FontMetrics getFontMetrics(Font name) + { + ClasspathFontPeer peer = (ClasspathFontPeer) name.getPeer(); + return peer.getFontMetrics(name); + } + + public void sync() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + /** + * Returns an image that has its pixel data loaded from a file with the + * specified name. If that file doesn't exist, an empty or error image + * is returned instead. + * + * @param name the filename of the file that contains the pixel data + * + * @return the image + */ + public Image getImage(String name) + { + Image image; + try + { + File file = new File(name); + image = getImage(file.toURL()); + } + catch (MalformedURLException ex) + { + // TODO: Replace by a more meaningful error image instead. + image = null; + } + return image; + } + + /** + * Returns an image that has its pixel data loaded from the specified URL. + * If the image cannot be loaded for some reason, an empty or error image + * is returned instead. + * + * @param url the URL to the image data + * + * @return the image + */ + public Image getImage(URL url) + { + Image image; + if (imageCache.containsKey(url)) + { + image = (Image) imageCache.get(url); + } + else + { + image = createImage(url); + imageCache.put(url, image); + } + return image; + } + + /** + * Returns an image that has its pixel data loaded from a file with the + * specified name. If that file doesn't exist, an empty or error image + * is returned instead. + * + * @param filename the filename of the file that contains the pixel data + * + * @return the image + */ + public Image createImage(String filename) + { + Image im; + try + { + File file = new File(filename); + URL url = file.toURL(); + im = createImage(url); + } + catch (MalformedURLException ex) + { + im = createErrorImage(); + } + return im; + } + + /** + * Returns an image that has its pixel data loaded from the specified URL. + * If the image cannot be loaded for some reason, an empty or error image + * is returned instead. + * + * @param url the URL to the image data + * + * @return the image + */ + public Image createImage(URL url) + { + Image image; + try + { + image = createImage(url.openStream()); + } + catch (IOException ex) + { + image = createErrorImage(); + } + return image; + } + + /** + * Creates an image that is returned when calls to createImage() yields an + * error. + * + * @return an image that is returned when calls to createImage() yields an + * error + */ + private Image createErrorImage() + { + // TODO: Create better error image. + return new XImage(1, 1); + } + + public boolean prepareImage(Image image, int width, int height, ImageObserver observer) + { + Image scaled = AbstractGraphics2D.prepareImage(image, width, height); + return checkImage(image, width, height, observer) == ImageObserver.ALLBITS; + } + + public int checkImage(Image image, int width, int height, ImageObserver observer) + { + // Images are loaded synchronously, so we don't bother and return true. + return ImageObserver.ALLBITS; + } + + public Image createImage(ImageProducer producer) + { + ImageConverter conv = new ImageConverter(); + producer.startProduction(conv); + Image image = conv.getImage(); + return image; + } + + public Image createImage(byte[] data, int offset, int len) + { + Image image; + try + { + ByteArrayInputStream i = new ByteArrayInputStream(data, offset, len); + image = createImage(i); + } + catch (IOException ex) + { + image = createErrorImage(); + } + return image; + } + + private Image createImage(InputStream i) + throws IOException + { + Image image; + BufferedImage buffered = ImageIO.read(i); + // If the bufferedimage is opaque, then we can copy it over to an + // X Pixmap for faster drawing. + if (buffered != null && buffered.getTransparency() == Transparency.OPAQUE) + { + ImageProducer source = buffered.getSource(); + image = createImage(source); + } + else if (buffered != null) + { + image = buffered; + } + else + { + image = createErrorImage(); + } + return image; + } + + public PrintJob getPrintJob(Frame frame, String title, Properties props) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public void beep() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public Clipboard getSystemClipboard() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + /** + * Returns the eventqueue used by the XLib peers. + * + * @return the eventqueue used by the XLib peers + */ + protected EventQueue getSystemEventQueueImpl() + { + if (eventQueue == null) + eventQueue = new EventQueue(); + return eventQueue; + } + + public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent e) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public Map mapInputMethodHighlight(InputMethodHighlight highlight) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + /** + * Helper method to quickly fetch the default device (X Display). + * + * @return the default XGraphicsDevice + */ + static XGraphicsDevice getDefaultDevice() + { + XGraphicsEnvironment env = (XGraphicsEnvironment) + XGraphicsEnvironment.getLocalGraphicsEnvironment(); + return (XGraphicsDevice) env.getDefaultScreenDevice(); + } + + @Override + public boolean isModalExclusionTypeSupported(ModalExclusionType modalExclusionType) + { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean isModalityTypeSupported(ModalityType modalityType) + { + // TODO Auto-generated method stub + return false; + } + + private void checkHeadLess(String message) throws HeadlessException + { + if(GraphicsEnvironment.isHeadless()) + { + if(message == null) + message = "This method cannot be called in headless mode."; + + throw new HeadlessException(message); + } + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/x/XWindowPeer.java b/libjava/classpath/gnu/java/awt/peer/x/XWindowPeer.java new file mode 100644 index 000000000..541eb74fa --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/x/XWindowPeer.java @@ -0,0 +1,303 @@ +/* XWindowPeer.java -- Window peer for X + 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.x; + +import java.awt.Component; +import java.awt.Dialog; +import java.awt.EventQueue; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.PaintEvent; +import java.awt.event.WindowEvent; +import java.awt.image.VolatileImage; + +import gnu.x11.Atom; +import gnu.x11.Window; +import gnu.x11.event.Event; + +import gnu.java.awt.font.OpenTypeFontPeer; +import gnu.java.awt.peer.ClasspathFontPeer; +import gnu.java.awt.peer.swing.SwingWindowPeer; + +public class XWindowPeer + extends SwingWindowPeer +{ + + private static int standardSelect = Event.BUTTON_PRESS_MASK + | Event.BUTTON_RELEASE_MASK + | Event.POINTER_MOTION_MASK + // | Event.RESIZE_REDIRECT_MASK // + | Event.EXPOSURE_MASK + | Event.PROPERTY_CHANGE_MASK + //| Event.STRUCTURE_NOTIFY_MASK + //| Event.SUBSTRUCTURE_NOTIFY_MASK + | Event.KEY_PRESS_MASK + | Event.KEY_RELEASE_MASK + //| Event.VISIBILITY_CHANGE_MASK // + ; + + /** + * The X window. + */ + protected Window xwindow; + + /** + * The frame insets. These get updated in {@link #show()}. + */ + private Insets insets; + + XWindowPeer(java.awt.Window window) + { + super(window); + XGraphicsDevice dev = XToolkit.getDefaultDevice(); + + // TODO: Maybe initialize lazily in show(). + Window.Attributes atts = new Window.Attributes(); + // FIXME: Howto generate a Window without decorations? + int x = Math.max(window.getX(), 0); + int y = Math.max(window.getY(), 0); + int w = Math.max(window.getWidth(), 1); + int h = Math.max(window.getHeight(), 1); + xwindow = new Window(dev.getDisplay().default_root, x, y, w, h, 0, atts); + xwindow.select_input(standardSelect); + + dev.getEventPump().registerWindow(xwindow, window); + xwindow.set_wm_delete_window(); + + boolean undecorated; + if (awtComponent instanceof Frame) + { + Frame f = (Frame) awtComponent; + undecorated = f.isUndecorated(); + } + else if (awtComponent instanceof Dialog) + { + Dialog d = (Dialog) awtComponent; + undecorated = d.isUndecorated(); + } + else + { + undecorated = true; + } + if (undecorated) + { + // First try the Motif implementation of undecorated frames. This + // is semantically closest and supported by all major window + // managers. + // TODO: At the time of writing this, there's no freedesktop.org + // standard extension that matches the required semantic. Maybe + // undecorated frames are added in the future, if so, then use these. + Atom at = Atom.intern(dev.getDisplay(), "_MOTIF_WM_HINTS"); + if (at != null) + { + xwindow.change_property(Window.REPLACE, at, at, 32, + new int[]{1 << 1, 0, 0, 0, 0}, 0, 5); + } + } + insets = new Insets(0, 0, 0, 0); + } + + public void toBack() + { + // TODO Auto-generated method stub + + } + + public void toFront() + { + // TODO Auto-generated method stub + + } + + public void updateAlwaysOnTop() + { + // TODO Auto-generated method stub + + } + + public boolean requestWindowFocus() + { + // TODO Auto-generated method stub + return false; + } + + public Point getLocationOnScreen() + { + return new Point(xwindow.x, xwindow.y); + } + + /** + * Returns a XGraphics suitable for drawing on this frame. + * + * @return a XGraphics suitable for drawing on this frame + */ + public Graphics getGraphics() + { + XGraphics2D xg2d = new XGraphics2D(xwindow); + xg2d.setColor(awtComponent.getForeground()); + xg2d.setBackground(awtComponent.getBackground()); + xg2d.setFont(awtComponent.getFont()); + return xg2d; + } + + public Image createImage(int w, int h) + { + // FIXME: Should return a buffered image. + return createVolatileImage(w, h); + } + + @Override + public VolatileImage createVolatileImage(int width, int height) + { + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice gd = ge.getDefaultScreenDevice(); + GraphicsConfiguration gc = gd.getDefaultConfiguration(); + return gc.createCompatibleVolatileImage(width, height); + } + + /** + * 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() + { + // Prevent ResizeRedirect events. + //xwindow.select_input(Event.NO_EVENT_MASK); + //xwindow.select_input(noResizeRedirectSelect); + + XGraphicsDevice dev = XToolkit.getDefaultDevice(); + xwindow.map(); + EventQueue eq = XToolkit.getDefaultToolkit().getSystemEventQueue(); + java.awt.Window w = (java.awt.Window) super.awtComponent; + eq.postEvent(new WindowEvent(w, WindowEvent.WINDOW_OPENED)); + eq.postEvent(new PaintEvent(w, PaintEvent.PAINT, + new Rectangle(0, 0, w.getWidth(), + w.getHeight()))); + + Graphics g = getGraphics(); + g.clearRect(0, 0, awtComponent.getWidth(), awtComponent.getHeight()); + g.dispose(); +// // Reset input selection. +// atts.set_override_redirect(false); +// xwindow.change_attributes(atts); + + // Determine the frame insets. + Atom atom = (Atom) Atom.intern(dev.getDisplay(), "_NET_FRAME_EXTENTS"); + Window.Property p = xwindow.get_property(false, atom, Atom.CARDINAL, 0, + Window.MAX_WM_LENGTH); + if (p.format() != 0) + { + insets = new Insets(p.value(0), p.value(1), p.value(2), p.value(3)); + Window.Changes ch = new Window.Changes(); + ch.width(awtComponent.getWidth() - insets.left - insets.top); + ch.height(awtComponent.getHeight() - insets.top - insets.bottom); + xwindow.configure(ch); + } + + } + + /** + * 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() + { + xwindow.unmap(); + } + + /** + * 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) + { + Insets i = insets; + xwindow.move_resize(x - i.left, y - i.right, width - i.left - i.right, + height - i.top - i.bottom); + } + + public Insets insets() + { + return (Insets) insets.clone(); + } + + /** + * Returns the font metrics for the specified font. + * + * @return the font metrics for the specified font + */ + public FontMetrics getFontMetrics(Font font) + { + ClasspathFontPeer fontPeer = (ClasspathFontPeer) font.getPeer(); + return fontPeer.getFontMetrics(font); + } + + /** + * Unregisters the window in the event pump when it is closed. + */ + protected void finalize() + { + XGraphicsDevice dev = XToolkit.getDefaultDevice(); + dev.getEventPump().unregisterWindow(xwindow); + } + + public Window getXwindow() + { + return xwindow; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/x/ZPixmapDataBuffer.java b/libjava/classpath/gnu/java/awt/peer/x/ZPixmapDataBuffer.java new file mode 100644 index 000000000..cf40f4d69 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/x/ZPixmapDataBuffer.java @@ -0,0 +1,67 @@ +package gnu.java.awt.peer.x; + +import gnu.x11.Display; +import gnu.x11.image.ZPixmap; + +import java.awt.GraphicsEnvironment; +import java.awt.image.DataBuffer; + +/** + * A DataBuffer implementation that is based on a ZPixmap. This is used + * as backing store for BufferedImages. + */ +class ZPixmapDataBuffer + extends DataBuffer +{ + + /** + * The backing ZPixmap. + */ + private ZPixmap zpixmap; + + /** + * Creates a new ZPixmapDataBuffer with a specified width and height. + * + * @param d the X display + * @param w the width + * @param h the height + */ + ZPixmapDataBuffer(int w, int h) + { + super(TYPE_BYTE, w * h * 3); // TODO: Support non-24-bit-resolutions. + GraphicsEnvironment env = + GraphicsEnvironment.getLocalGraphicsEnvironment(); + XGraphicsDevice dev = (XGraphicsDevice) env.getDefaultScreenDevice(); + Display d = dev.getDisplay(); + zpixmap = new ZPixmap(d, w, h, d.default_pixmap_format); + } + + /** + * Creates a ZPixmapDataBuffer from an existing ZPixmap. + * + * @param zpixmap the ZPixmap to wrap + */ + ZPixmapDataBuffer(ZPixmap zpixmap) + { + super(TYPE_BYTE, zpixmap.get_data_length()); + this.zpixmap = zpixmap; + } + + @Override + public int getElem(int bank, int i) + { + return 0xff & zpixmap.get_data_element(i); + } + + @Override + public void setElem(int bank, int i, int val) + { + zpixmap.set_data_element(i, (byte) val); + } + + ZPixmap getZPixmap() + { + return zpixmap; + } + +} diff --git a/libjava/classpath/gnu/java/awt/print/JavaPrinterGraphics.java b/libjava/classpath/gnu/java/awt/print/JavaPrinterGraphics.java new file mode 100644 index 000000000..64d197cd0 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/print/JavaPrinterGraphics.java @@ -0,0 +1,518 @@ +/* JavaPrinterGraphics.java -- AWT printer rendering class. + 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.print; + +import gnu.java.awt.peer.gtk.CairoSurface; + +import java.awt.Color; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.image.ImageObserver; +import java.awt.image.PixelGrabber; +import java.awt.print.PageFormat; +import java.awt.print.Pageable; +import java.awt.print.Paper; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterGraphics; +import java.awt.print.PrinterJob; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.text.AttributedCharacterIterator; + +/** + * Graphics context to draw to PostScript. + * + * @author Sven de Marothy + */ +public class JavaPrinterGraphics extends Graphics implements PrinterGraphics +{ + + /** + * The used graphics context. + */ + private Graphics g; + + /** + * The associated printer job. + */ + private PrinterJob printerJob; + + /** + * Rendering resolution + */ + private static final double DPI = 72.0; + + /** + * Rendered image size. + */ + private int xSize, ySize; + + /** + * The image to render to. + */ + private Image image; + + public JavaPrinterGraphics( PrinterJob printerJob ) + { + this.printerJob = printerJob; + } + + /** + * Spool a document to PostScript. + * If Pageable is non-null, it will print that, otherwise it will use + * the supplied printable and pageFormat. + */ + public SpooledDocument spoolPostScript(Printable printable, + PageFormat pageFormat, + Pageable pageable) + throws PrinterException + { + try + { + // spool to a temporary file + File temp = File.createTempFile("cpspool", ".ps"); + temp.deleteOnExit(); + + PrintWriter out = new PrintWriter + (new BufferedWriter + (new OutputStreamWriter + (new FileOutputStream(temp), "ISO8859_1"), 1000000)); + + writePSHeader(out); + + if(pageable != null) + { + for(int index = 0; index < pageable.getNumberOfPages(); index++) + spoolPage(out, pageable.getPrintable(index), + pageable.getPageFormat(index), index); + } + else + { + int index = 0; + while(spoolPage(out, printable, pageFormat, index++) == + Printable.PAGE_EXISTS) + ; + } + out.println("%%Trailer"); + out.println("%%EOF"); + out.close(); + return new SpooledDocument( temp ); + } + catch (IOException e) + { + PrinterException pe = new PrinterException(); + pe.initCause(e); + throw pe; + } + } + + /** + * Spools a single page, returns NO_SUCH_PAGE unsuccessful, + * PAGE_EXISTS if it was. + */ + public int spoolPage(PrintWriter out, + Printable printable, + PageFormat pageFormat, + int index) throws IOException, PrinterException + { + initImage( pageFormat ); + if(printable.print(this, pageFormat, index) == Printable.NO_SUCH_PAGE) + return Printable.NO_SUCH_PAGE; + g.dispose(); + g = null; + writePage( out, pageFormat ); + return Printable.PAGE_EXISTS; + } + + private void initImage(PageFormat pageFormat) + { + // Create a really big image and draw to that. + xSize = (int)(DPI*pageFormat.getWidth()/72.0); + ySize = (int)(DPI*pageFormat.getHeight()/72.0); + + // Swap X and Y sizes if it's a Landscape page. + if( pageFormat.getOrientation() != PageFormat.PORTRAIT ) + { + int t = xSize; + xSize = ySize; + ySize = t; + } + + // FIXME: This should at least be BufferedImage. + // Fix once we have a working B.I. + // Graphics2D should also be supported of course. + image = CairoSurface.getBufferedImage(xSize, ySize); + + g = image.getGraphics(); + setColor(Color.white); + fillRect(0, 0, xSize, ySize); + setColor(Color.black); + } + + private void writePSHeader(PrintWriter out) + { + out.println("%!PS-Adobe-3.0"); + out.println("%%Title: "+printerJob.getJobName()); + out.println("%%Creator: GNU Classpath "); + out.println("%%DocumentData: Clean8Bit"); + + out.println("%%DocumentNeededResources: font Times-Roman Helvetica Courier"); + // out.println("%%Pages: "+); // FIXME # pages. + out.println("%%EndComments"); + + out.println("%%BeginProlog"); + out.println("%%EndProlog"); + out.println("%%BeginSetup"); + + // FIXME: Paper name + // E.g. "A4" "Letter" + // out.println("%%BeginFeature: *PageSize A4"); + + out.println("%%EndFeature"); + + out.println("%%EndSetup"); + + // out.println("%%Page: 1 1"); + } + + private void writePage(PrintWriter out, PageFormat pageFormat) + { + out.println("%%BeginPageSetup"); + + Paper p = pageFormat.getPaper(); + double pWidth = p.getWidth(); + double pHeight = p.getHeight(); + + if( pageFormat.getOrientation() == PageFormat.PORTRAIT ) + out.println( "%%Orientation: Portrait" ); + else + { + out.println( "%%Orientation: Landscape" ); + double t = pWidth; + pWidth = pHeight; + pHeight = t; + } + + out.println("gsave % first save"); + + // 595x842; 612x792 respectively + out.println("<< /PageSize [" +pWidth + " "+pHeight+ "] >> setpagedevice"); + + // invert the Y axis so that we get screen-like coordinates instead. + AffineTransform pageTransform = new AffineTransform(); + if( pageFormat.getOrientation() == PageFormat.REVERSE_LANDSCAPE ) + { + pageTransform.translate(pWidth, pHeight); + pageTransform.scale(-1.0, -1.0); + } + concatCTM(out, pageTransform); + out.println("%%EndPageSetup"); + + out.println("gsave"); + + + // Draw the image + out.println(xSize+" "+ySize+" 8 [1 0 0 -1 0 "+ySize+" ]"); + out.println("{currentfile 3 string readhexstring pop} bind"); + out.println("false 3 colorimage"); + int[] pixels = new int[xSize * ySize]; + PixelGrabber pg = new PixelGrabber(image, 0, 0, xSize, ySize, pixels, 0, xSize); + + try { + pg.grabPixels(); + } catch (InterruptedException e) { + out.println("% Bug getting pixels!"); + } + + int n = 0; + for (int j = 0; j < ySize; j++) { + for (int i = 0; i < xSize; i++) { + out.print( colorTripleHex(pixels[j * xSize + i]) ); + if(((++n)%11) == 0) out.println(); + } + } + + out.println(); + out.println("%%EOF"); + out.println("grestore"); + out.println("showpage"); + } + + /** + * Get a nonsperated hex RGB triple, e.g. FFFFFF = white + */ + private String colorTripleHex(int num){ + String s = ""; + + try { + s = Integer.toHexString( ( num & 0x00FFFFFF ) ); + if( s.length() < 6 ) + { + s = "000000"+s; + return s.substring(s.length()-6); + } + } catch (Exception e){ + s = "FFFFFF"; + } + + return s; + } + + private void concatCTM(PrintWriter out, AffineTransform Tx){ + double[] matrixElements = new double[6]; + Tx.getMatrix(matrixElements); + + out.print("[ "); + for(int i=0;i<6;i++) + out.print(matrixElements[i]+" "); + out.println("] concat"); + } + + //----------------------------------------------------------------------------- + /** + * PrinterGraphics method - Returns the printer job associated with this object. + */ + public PrinterJob getPrinterJob() + { + return printerJob; + } + + /** + * The rest of the methods here are just pass-throughs to g. + */ + public void clearRect(int x, int y, int width, int height) + { + g.clearRect(x, y, width, height); + } + + public void clipRect(int x, int y, int width, int height) + { + g.clipRect(x, y, width, height); + } + + public void copyArea(int x, int y, int width, int height, int dx, int dy) + { + g.copyArea(x, y, width, height, dx, dy); + } + + public Graphics create() + { + return g.create(); + } + + public void dispose() + { + } + + public void drawArc(int x, int y, int width, int height, int startAngle, + int arcAngle) + { + g.drawArc(x, y, width, height, startAngle, arcAngle); + } + + public boolean drawImage(Image img, int x, int y, Color bgcolor, + ImageObserver observer) + { + return g.drawImage(img, x, y, bgcolor, observer); + } + + public boolean drawImage(Image img, int x, int y, ImageObserver observer) + { + return g.drawImage(img, x, y, observer); + } + + public boolean drawImage(Image img, int x, int y, int width, int height, + Color bgcolor, ImageObserver observer) + { + return g.drawImage(img, x, y, width, height, bgcolor, observer); + } + + public boolean drawImage(Image img, int x, int y, int width, int height, + ImageObserver observer) + { + return g.drawImage(img, x, y, width, height, observer); + } + + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, Color bgcolor, + ImageObserver observer) + { + return g.drawImage(img, dx1, dy1, dx2, dy2, + sx1, sy1, sx2, sy2, bgcolor, observer); + } + + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, ImageObserver observer) + { + return g.drawImage(img, dx1, dy1, dx2, dy2, + sx1, sy1, sx2, sy2, observer); + } + + public void drawLine(int x1, int y1, int x2, int y2) + { + g.drawLine(x1, y1, x2, y2); + } + + public void drawOval(int x, int y, int width, int height) + { + g.drawOval(x, y, width, height); + } + + public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) + { + g.drawPolygon(xPoints, yPoints, nPoints); + } + + public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) + { + g.drawPolyline(xPoints, yPoints, nPoints); + } + + public void drawRoundRect(int x, int y, int width, int height, + int arcWidth, int arcHeight) + { + g.drawRoundRect(x, y, width, height, arcWidth, arcHeight); + } + + public void drawString(AttributedCharacterIterator iterator, int x, int y) + { + g.drawString(iterator, x, y); + } + + public void drawString(String str, int x, int y) + { + g.drawString(str, x, y); + } + + public void fillArc(int x, int y, int width, int height, + int startAngle, int arcAngle) + { + g.fillArc(x, y, width, height, startAngle, arcAngle); + } + + public void fillOval(int x, int y, int width, int height) + { + g.fillOval(x, y, width, height); + } + + public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) + { + g.fillPolygon(xPoints, yPoints, nPoints); + } + + public void fillRect(int x, int y, int width, int height) + { + g.fillRect(x, y, width, height); + } + + public void fillRoundRect(int x, int y, int width, int height, + int arcWidth, int arcHeight) + { + g.fillRoundRect(x, y, width, height, arcWidth, arcHeight); + } + + public Shape getClip() + { + return g.getClip(); + } + + public Rectangle getClipBounds() + { + return g.getClipBounds(); + } + + public Color getColor() + { + return g.getColor(); + } + + public Font getFont() + { + return g.getFont(); + } + + public FontMetrics getFontMetrics(Font f) + { + return g.getFontMetrics(f); + } + + public void setClip(int x, int y, int width, int height) + { + g.setClip(x, y, width, height); + } + + public void setClip(Shape clip) + { + g.setClip(clip); + } + + public void setColor(Color c) + { + g.setColor(c); + } + + public void setFont(Font font) + { + g.setFont(font); + } + + public void setPaintMode() + { + g.setPaintMode(); + } + + public void setXORMode(Color c1) + { + g.setXORMode(c1); + } + + public void translate(int x, int y) + { + g.translate(x, y); + } +} diff --git a/libjava/classpath/gnu/java/awt/print/JavaPrinterJob.java b/libjava/classpath/gnu/java/awt/print/JavaPrinterJob.java new file mode 100644 index 000000000..295d231cb --- /dev/null +++ b/libjava/classpath/gnu/java/awt/print/JavaPrinterJob.java @@ -0,0 +1,403 @@ +/* JavaPrinterJob.java -- AWT printing implemented on javax.print. + 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.print; + +import java.awt.HeadlessException; +import java.awt.print.PageFormat; +import java.awt.print.Pageable; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterJob; +import java.util.Locale; + +import javax.print.CancelablePrintJob; +import javax.print.DocFlavor; +import javax.print.DocPrintJob; +import javax.print.PrintException; +import javax.print.PrintService; +import javax.print.PrintServiceLookup; +import javax.print.ServiceUI; +import javax.print.attribute.HashPrintRequestAttributeSet; +import javax.print.attribute.IntegerSyntax; +import javax.print.attribute.PrintRequestAttributeSet; +import javax.print.attribute.TextSyntax; +import javax.print.attribute.standard.Copies; +import javax.print.attribute.standard.JobName; +import javax.print.attribute.standard.OrientationRequested; +import javax.print.attribute.standard.RequestingUserName; + +/** + * This is the default implementation of PrinterJob + * + * @author Sven de Marothy + */ +public class JavaPrinterJob extends PrinterJob +{ + /** + * The print service associated with this job + */ + private PrintService printer = null; + + /** + * Printing options; + */ + private PrintRequestAttributeSet attributes; + + /** + * Available print services + */ + private static PrintService[] services; + + /** + * The actual print job. + */ + private DocPrintJob printJob; + + /** + * The Printable object to print. + */ + private Printable printable; + + /** + * Page format. + */ + private PageFormat pageFormat; + + /** + * A pageable, or null + */ + private Pageable pageable = null; + + /** + * Cancelled or not + */ + private boolean cancelled = false; + + static + { + // lookup all services without any constraints + services = PrintServiceLookup.lookupPrintServices + (DocFlavor.INPUT_STREAM.POSTSCRIPT, null); + } + + private static final Class copyClass = (new Copies(1)).getClass(); + private static final Class jobNameClass = (new JobName("", null)).getClass(); + private static final Class userNameClass = (new RequestingUserName("", null)).getClass(); + + /** + * Initializes a new instance of PrinterJob. + */ + public JavaPrinterJob() + { + attributes = new HashPrintRequestAttributeSet(); + setCopies(1); + setJobName("Java Printing"); + pageFormat = new PageFormat(); // default page format. + } + + private void getPageAttributes() + { + OrientationRequested orientation = (OrientationRequested) + attributes.get( OrientationRequested.LANDSCAPE.getCategory() ); + if( orientation == null) + return; + + if( orientation.equals(OrientationRequested.PORTRAIT) ) + pageFormat.setOrientation(PageFormat.PORTRAIT); + else if( orientation.equals(OrientationRequested.LANDSCAPE) ) + pageFormat.setOrientation(PageFormat.LANDSCAPE); + else if( orientation.equals(OrientationRequested.REVERSE_LANDSCAPE) ) + pageFormat.setOrientation(PageFormat.REVERSE_LANDSCAPE); + } + + /** + * Returns the number of copies to be printed. + * + * @return The number of copies to be printed. + */ + public int getCopies() + { + return ((IntegerSyntax)attributes.get( jobNameClass )).getValue(); + } + + /** + * Sets the number of copies to be printed. + * + * @param copies The number of copies to be printed. + */ + public void setCopies(int copies) + { + attributes.add( new Copies( copies ) ); + } + + /** + * Returns the name of the print job. + * + * @return The name of the print job. + */ + public String getJobName() + { + return ((TextSyntax)attributes.get( jobNameClass )).getValue(); + } + + /** + * Sets the name of the print job. + * + * @param job_name The name of the print job. + */ + public void setJobName(String job_name) + { + attributes.add( new JobName(job_name, Locale.getDefault()) ); + } + + /** + * Returns the printing user name. + * + * @return The printing username. + */ + public String getUserName() + { + return ((TextSyntax)attributes.get( userNameClass )).getValue(); + } + + /** + * Cancels an in progress print job. + */ + public void cancel() + { + try + { + if(printJob != null && (printJob instanceof CancelablePrintJob)) + { + ((CancelablePrintJob)printJob).cancel(); + cancelled = true; + } + } + catch(PrintException pe) + { + } + } + + /** + * Tests whether or not this job has been cancelled. + * + * @return true if this job has been cancelled, false + * otherwise. + */ + public boolean isCancelled() + { + return cancelled; + } + + /** + * Clones the specified PageFormat object then alters the + * clone so that it represents the default page format. + * + * @param page_format The PageFormat to clone. + * + * @return A new default page format. + */ + public PageFormat defaultPage(PageFormat page_format) + { + return new PageFormat(); + } + + /** + * Displays a dialog box to the user which allows the page format + * attributes to be modified. + * + * @param page_format The PageFormat object to modify. + * + * @return The modified PageFormat. + */ + public PageFormat pageDialog(PageFormat page_format) + throws HeadlessException + { + return defaultPage(null); + } + + /** + * Prints the pages. + */ + public void print() throws PrinterException + { + if( printable == null && pageable == null ) // nothing to print? + return; + + PostScriptGraphics2D pg = new PostScriptGraphics2D( this ); + SpooledDocument doc = pg.spoolPostScript( printable, pageFormat, + pageable ); + + cancelled = false; + printJob = printer.createPrintJob(); + try + { + printJob.print(doc, attributes); + } + catch (PrintException pe) + { + PrinterException p = new PrinterException(); + p.initCause(pe); + throw p; + } + // no printjob active. + printJob = null; + } + + /** + * Prints the page with given attributes. + */ + public void print (PrintRequestAttributeSet attributes) + throws PrinterException + { + this.attributes = attributes; + print(); + } + + /** + * Displays a dialog box to the user which allows the print job + * attributes to be modified. + * + * @return false if the user cancels the dialog box, + * true otherwise. + */ + public boolean printDialog() throws HeadlessException + { + return printDialog( attributes ); + } + + /** + * Displays a dialog box to the user which allows the print job + * attributes to be modified. + * + * @return false if the user cancels the dialog box, + * true otherwise. + */ + public boolean printDialog(PrintRequestAttributeSet attributes) + throws HeadlessException + { + PrintService chosenPrinter = ServiceUI.printDialog + (null, 50, 50, services, null, + DocFlavor.INPUT_STREAM.POSTSCRIPT, attributes); + + getPageAttributes(); + + if( chosenPrinter != null ) + { + try + { + setPrintService( chosenPrinter ); + } + catch(PrinterException pe) + { + // Should not happen. + } + return true; + } + return false; + } + + /** + * This sets the pages that are to be printed. + * + * @param pageable The pages to be printed, which may not be null. + */ + public void setPageable(Pageable pageable) + { + if( pageable == null ) + throw new NullPointerException("Pageable cannot be null."); + this.pageable = pageable; + } + + /** + * Sets this specified Printable as the one to use for + * rendering the pages on the print device. + * + * @param printable The Printable for the print job. + */ + public void setPrintable(Printable printable) + { + this.printable = printable; + } + + /** + * Sets the Printable and the page format for the pages + * to be printed. + * + * @param printable The Printable for the print job. + * @param page_format The PageFormat for the print job. + */ + public void setPrintable(Printable printable, PageFormat page_format) + { + this.printable = printable; + this.pageFormat = page_format; + } + + /** + * Makes any alterations to the specified PageFormat + * necessary to make it work with the current printer. The alterations + * are made to a clone of the input object, which is then returned. + * + * @param page_format The PageFormat to validate. + * + * @return The validated PageFormat. + */ + public PageFormat validatePage(PageFormat page_format) + { + // FIXME + return page_format; + } + + /** + * Change the printer for this print job to service. Subclasses that + * support setting the print service override this method. Throws + * PrinterException when the class doesn't support setting the printer, + * the service doesn't support Pageable or Printable interfaces for 2D + * print output. + * @param service The new printer to use. + * @throws PrinterException if service is not valid. + */ + public void setPrintService(PrintService service) + throws PrinterException + { + if(!service.isDocFlavorSupported(DocFlavor.INPUT_STREAM.POSTSCRIPT)) + throw new PrinterException("This printer service is not supported."); + printer = service; + } +} diff --git a/libjava/classpath/gnu/java/awt/print/PostScriptGraphics2D.java b/libjava/classpath/gnu/java/awt/print/PostScriptGraphics2D.java new file mode 100644 index 000000000..10fc25c2f --- /dev/null +++ b/libjava/classpath/gnu/java/awt/print/PostScriptGraphics2D.java @@ -0,0 +1,1349 @@ +/* PostScriptGraphics2D.java -- AWT printer rendering class. + 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.print; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Paint; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.GradientPaint; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.geom.AffineTransform; +import java.awt.geom.Arc2D; +import java.awt.geom.Ellipse2D; +import java.awt.geom.RoundRectangle2D; +import java.awt.geom.PathIterator; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.font.TextLayout; +import java.awt.image.BufferedImage; +import java.awt.image.BufferedImageOp; +import java.awt.image.renderable.RenderableImage; +import java.awt.image.RenderedImage; +import java.awt.image.ImageObserver; +import java.awt.image.PixelGrabber; +import java.awt.print.PageFormat; +import java.awt.print.Pageable; +import java.awt.print.Paper; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterJob; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.text.AttributedCharacterIterator; +import java.util.Map; + +/** + * Class PostScriptGraphics2D - Class that implements the Graphics2D object, + * writing the output to a PostScript or EPS file + * + * @author Sven de Marothy + * + */ +class PostScriptGraphics2D extends Graphics2D +{ + /** + * The associated printer job. + */ + private PrinterJob printerJob; + + /** + * Output file. + */ + private PrintWriter out; + + // Graphics data + private AffineTransform currentTransform = new AffineTransform(); + private AffineTransform pageTransform; + private RenderingHints renderingHints; + private Paint currentPaint = null; + private Shape clipShape = null; + private Font currentFont = null; + private Color currentColor = Color.black; + private Color backgroundColor = Color.white; + private Stroke currentStroke = null; + private static Stroke ordinaryStroke = new BasicStroke(0.0f, + BasicStroke.CAP_BUTT, + BasicStroke.JOIN_MITER); + private float cx; // current drawing position + private float cy; // current drawing position + private boolean currentFontIsPS; // set if currentFont is one of the above + + // settings + private double pageX = 595; + private double pageY = 842; + private double Y = pageY; + private boolean gradientOn = false; + + /** + * Constructor + * + */ + public PostScriptGraphics2D( PrinterJob pg ) + { + printerJob = pg; + // create transform objects + pageTransform = new AffineTransform(); + currentTransform = new AffineTransform(); + + /* + Create Rendering hints + No text aliasing + Quality color and rendering + Bicubic interpolation + Fractional metrics supported + */ + renderingHints = new RenderingHints(null); + renderingHints.put(RenderingHints.KEY_RENDERING, + RenderingHints.VALUE_RENDER_QUALITY); + renderingHints.put(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); + renderingHints.put(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BICUBIC); + renderingHints.put(RenderingHints.KEY_FRACTIONALMETRICS, + RenderingHints.VALUE_FRACTIONALMETRICS_ON); + renderingHints.put(RenderingHints.KEY_COLOR_RENDERING, + RenderingHints.VALUE_COLOR_RENDER_QUALITY); + } + + /** + * Spool a document to PostScript. + * If Pageable is non-null, it will print that, otherwise it will use + * the supplied printable and pageFormat. + */ + public SpooledDocument spoolPostScript(Printable printable, + PageFormat pageFormat, + Pageable pageable) + throws PrinterException + { + try + { + // spool to a temporary file + File temp = File.createTempFile("cpspool", ".ps"); + temp.deleteOnExit(); + + out = new PrintWriter(new BufferedWriter + (new OutputStreamWriter + (new FileOutputStream(temp), + "ISO8859_1"), 1000000)); + + writePSHeader(); + + if(pageable != null) + { + for(int index = 0; index < pageable.getNumberOfPages(); index++) + spoolPage(out, pageable.getPrintable(index), + pageable.getPageFormat(index), index); + } + else + { + int index = 0; + while(spoolPage(out, printable, pageFormat, index++) == + Printable.PAGE_EXISTS) + ; + } + out.println("%%Trailer"); + out.println("%%EOF"); + out.close(); + return new SpooledDocument( temp ); + } + catch (IOException e) + { + PrinterException pe = new PrinterException(); + pe.initCause(e); + throw pe; + } + } + + //-------------------------------------------------------------------------- + + /** + * Write the postscript file header, + * setup the page format and transforms. + */ + private void writePSHeader() + { + out.println("%!PS-Adobe-3.0"); + out.println("%%Title: "+printerJob.getJobName()); + out.println("%%Creator: GNU Classpath "); + out.println("%%DocumentData: Clean8Bit"); + + out.println("%%DocumentNeededResources: font Times-Roman Helvetica Courier"); + out.println("%%EndComments"); + + out.println("%%BeginProlog"); + out.println("%%EndProlog"); + out.println("%%BeginSetup"); + + out.println("%%EndFeature"); + setupFonts(); + out.println("%%EndSetup"); + + // set default fonts and colors + setFont( new Font("Dialog", Font.PLAIN, 12) ); + currentColor = Color.white; + currentStroke = new BasicStroke(); + setPaint(currentColor); + setStroke(currentStroke); + } + + /** + * setupFonts - set up the font dictionaries for + * helvetica, times and courier + */ + private void setupFonts() + { + out.println("/helveticaISO"); + out.println("/Helvetica findfont dup length dict begin"); + out.println("{ 1 index /FID eq { pop pop } { def } ifelse } forall"); + out.println("/Encoding ISOLatin1Encoding def"); + out.println("currentdict end definefont pop"); + + out.println("/timesISO"); + out.println("/Times-Roman findfont dup length dict begin"); + out.println("{ 1 index /FID eq { pop pop } { def } ifelse } forall"); + out.println("/Encoding ISOLatin1Encoding def"); + out.println("currentdict end definefont pop"); + + out.println("/courierISO"); + out.println("/Courier findfont dup length dict begin"); + out.println("{ 1 index /FID eq { pop pop } { def } ifelse } forall"); + out.println("/Encoding ISOLatin1Encoding def"); + out.println("currentdict end definefont pop"); + } + + /** + * Spools a single page, returns NO_SUCH_PAGE unsuccessful, + * PAGE_EXISTS if it was. + */ + public int spoolPage(PrintWriter out, + Printable printable, + PageFormat pageFormat, + int index) throws IOException, PrinterException + { + out.println("%%BeginPageSetup"); + + Paper p = pageFormat.getPaper(); + pageX = p.getWidth(); + pageY = p.getHeight(); + + if( pageFormat.getOrientation() == PageFormat.PORTRAIT ) + out.println( "%%Orientation: Portrait" ); + else + { + out.println( "%%Orientation: Landscape" ); + double t = pageX; + pageX = pageY; + pageY = t; + } + + setClip(0, 0, (int)pageX, (int)pageY); + + out.println("gsave % first save"); + + // 595x842; 612x792 respectively + out.println("<< /PageSize [" +pageX + " "+pageY+ "] >> setpagedevice"); + + if( pageFormat.getOrientation() != PageFormat.LANDSCAPE ) + { + pageTransform.translate(pageX, 0); + pageTransform.scale(-1.0, 1.0); + } + + // save the original CTM + pushCTM(); + concatCTM(pageTransform); + setTransform(new AffineTransform()); + + out.println("%%EndPageSetup"); + + out.println("gsave"); + + if( printable.print(this, pageFormat, index) == Printable.NO_SUCH_PAGE ) + return Printable.NO_SUCH_PAGE; + + out.println("grestore"); + out.println("showpage"); + + return Printable.PAGE_EXISTS; + } + + /** push the Current Transformation Matrix onto the PS stack */ + private void pushCTM() + { + out.println("matrix currentmatrix % pushCTM()"); + } + + /** pop the Current Transformation Matrix from the PS stack */ + private void popCTM() + { + out.println("setmatrix % restore CTM"); + } + + /////////////////////////////////////////////////////////////////////////// + + public Graphics create() + { + return null; + } + + public void drawOval(int x, int y, int width, int height) + { + out.println("% drawOval()"); + setStroke(ordinaryStroke); + draw(new Ellipse2D.Double(x, y, width, height)); + setStroke(currentStroke); + } + + public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) + { + if (nPoints <= 0 || xPoints.length < nPoints || yPoints.length < nPoints) + return; + out.println("newpath % drawPolyLine()"); + out.println(xPoints[0] + " " + yPoints[0] + " moveto"); + for (int i = 1; i < nPoints; i++) + out.println(xPoints[i] + " " + yPoints[i] + " lineto"); + out.println("closepath"); + out.println("stroke"); + } + + public void drawRoundRect(int x, int y, int width, int height, int arcWidth, + int arcHeight) + { + out.println("% drawRoundRect()"); + RoundRectangle2D.Double rr = new RoundRectangle2D.Double(x, y, width, + height, arcWidth, + arcHeight); + setStroke(ordinaryStroke); + draw(rr); + setStroke(currentStroke); + } + + public void fillRoundRect(int x, int y, int width, int height, int arcWidth, + int arcHeight) + { + out.println("% fillRoundRect()"); + RoundRectangle2D.Double rr = new RoundRectangle2D.Double(x, y, width, + height, arcWidth, + arcHeight); + fill(rr); + } + + public void drawArc(int x, int y, int width, int height, int startAngle, + int arcAngle) + { + setStroke(ordinaryStroke); + draw(new Arc2D.Double(x, y, width, height, startAngle, arcAngle, Arc2D.OPEN)); + setStroke(currentStroke); + } + + public void fillArc(int x, int y, int width, int height, int startAngle, + int arcAngle) + { + fill(new Arc2D.Double(x, y, width, height, startAngle, arcAngle, Arc2D.PIE)); + } + + public void fillOval(int x, int y, int width, int height) + { + out.println("% fillOval()"); + fill( new Ellipse2D.Double(x, y, width, height) ); + } + + public void fillPolygon(int[] x, int[] y, int nPoints) + { + out.println("% fillPolygon()"); + fill( new Polygon(x, y, nPoints) ); + } + + public void drawLine(int x1, int y1, int x2, int y2) + { + out.println("% drawLine()"); + setStroke(ordinaryStroke); + out.println("newpath"); + out.println(x1 + " " + (y1) + " moveto"); + out.println(x2 + " " + (y2) + " lineto"); + out.println("stroke"); + setStroke(currentStroke); + } + + //--------------- Image drawing ------------------------------------------ + public boolean drawImage(Image img, int x, int y, Color bgcolor, + ImageObserver observer) + { + int w = img.getWidth(null); + int h = img.getHeight(null); + + return drawImage(img, x, y, x + w, y + h, 0, 0, w - 1, h - 1, bgcolor, + observer); + } + + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, Color bgcolor, + ImageObserver observer) + { + int n = 0; + boolean flipx = false; + boolean flipy = false; + + // swap X and Y's + if (sx1 > sx2) + { + n = sx1; + sx1 = sx2; + sx2 = n; + flipx = ! flipx; + } + if (sy1 > sy2) + { + n = sy1; + sy1 = sy2; + sy2 = n; + flipy = ! flipy; + } + if (dx1 > dx2) + { + n = dx1; + dx1 = dx2; + dx2 = n; + flipx = ! flipx; + } + if (dy1 > dy2) + { + n = dy1; + dy1 = dy2; + dy2 = n; + flipy = ! flipy; + } + n = 0; + int sw = sx2 - sx1; // source width + int sh = sy2 - sy1; // source height + int[] pixels = new int[sw * sh]; // pixel buffer + int dw = dx2 - dx1; // destination width + int dh = dy2 - dy1; // destination height + double x_scale = ((double) dw) / ((double) sw); + double y_scale = ((double) dh) / ((double) sh); + + out.println("% drawImage() 2"); + out.println("gsave"); + out.println(dx1 + " " + dy1 + " translate"); + out.println(dw + " " + dh + " scale"); + out.println(sw + " " + sh + " 8 [" + (flipx ? -sw : sw) + " 0 0 " + + (flipy ? -sh : sh) + " " + (flipx ? sw : 0) + " " + + (flipy ? sh : 0) + " ]"); + out.println("{currentfile 3 string readhexstring pop} bind"); + out.println("false 3 colorimage"); + + PixelGrabber pg = new PixelGrabber(img, sx1, sy1, sw, sh, pixels, 0, sw); + try + { + pg.grabPixels(); + } + catch (InterruptedException e) + { + System.err.println("interrupted waiting for pixels!"); + return (false); + } + + if ((pg.getStatus() & ImageObserver.ABORT) != 0) + { + System.err.println("image fetch aborted or errored"); + return (false); + } + + for (int j = 0; j < sh; j++) + { + for (int i = 0; i < sw; i++) + { + out.print(colorTripleHex(new Color(pixels[j * sw + i]))); + if (((++n) % 11) == 0) + out.println(); + } + } + + out.println(); + out.println("%%EOF"); + out.println("grestore"); + return true; + } + + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, + ImageObserver observer) + { + return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null, + observer); + } + + public boolean drawImage(Image img, int x, int y, ImageObserver observer) + { + return drawImage(img, x, y, null, observer); + } + + public boolean drawImage(Image img, int x, int y, int width, int height, + Color bgcolor, ImageObserver observer) + { + int sw = img.getWidth(null); + int sh = img.getHeight(null); + return drawImage(img, x, y, x + width, y + height, /* destination */ + 0, 0, sw - 1, sh - 1, /* source */ + bgcolor, observer); + // correct? + } + + public boolean drawImage(Image img, int x, int y, int width, int height, + ImageObserver observer) + { + return drawImage(img, x, y, width, height, null, observer); + } + + /** Renders a BufferedImage that is filtered with a BufferedImageOp. */ + public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) + { + BufferedImage result = op.filter(img, null); + drawImage(result, x, y, null); + } + + /** Renders an image, applying a transform from image space + into user space before drawing. */ + public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) + { + AffineTransform oldTransform = new AffineTransform(currentTransform); + boolean ret; + + transform(xform); + ret = drawImage(img, 0, 0, null, obs); + setTransform(oldTransform); + + return ret; + } + + /** Renders a RenderableImage, applying a transform from image + space into user space before drawing. */ + public void drawRenderableImage(RenderableImage img, AffineTransform xform) + { + // FIXME + } + + /** Renders a RenderedImage, applying a transform from + image space into user space before drawing. */ + public void drawRenderedImage(RenderedImage img, AffineTransform xform) + { + // FIXME + } + + //------------------------------------------------------------------------- + public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) + { + setStroke(ordinaryStroke); + draw(new Polygon(xPoints, yPoints, nPoints)); + setStroke(currentStroke); + } + + public void drawString(String str, int x, int y) + { + drawString(str, (float) x, (float) y); + } + + public void drawString(String str, float x, float y) + { + if( str.trim().equals("") ) + return; // don't draw whitespace, silly! + + if( currentFontIsPS ) + { + drawStringPSFont(str, x, y); + return; + } + + TextLayout text = new TextLayout(str, currentFont, getFontRenderContext()); + Shape s = text.getOutline(AffineTransform.getTranslateInstance(x, y)); + drawStringShape(s); + } + + private void drawStringPSFont(String str, float x, float y) + { + out.println("% drawString PS font"); + out.println(x + " " + y + " moveto"); + saveAndInvertAxis(); + out.println("(" + str + ") show"); + restoreAxis(); + } + + private void saveAndInvertAxis() + { + // Invert the Y axis of the CTM. + popCTM(); + pushCTM(); + + double[] test = + { + pageTransform.getScaleX(), pageTransform.getShearY(), + pageTransform.getShearX(), pageTransform.getScaleY(), + pageTransform.getTranslateX(), + -pageTransform.getTranslateY() + pageY + }; + + double[] test2 = + { + currentTransform.getScaleX(), + currentTransform.getShearY(), + -currentTransform.getShearX(), + -currentTransform.getScaleY(), + currentTransform.getTranslateX(), + currentTransform.getTranslateY() + }; + + AffineTransform total = new AffineTransform(test); + total.concatenate(new AffineTransform(test2)); + concatCTM(total); + } + + private void restoreAxis() + { + // reset the CTM + popCTM(); + pushCTM(); + AffineTransform total = new AffineTransform(pageTransform); + total.concatenate(currentTransform); + concatCTM(total); + } + + /** + * special drawing routine for string shapes, + * which need to be drawn with the Y axis uninverted. + */ + private void drawStringShape(Shape s) + { + saveAndInvertAxis(); + + // draw the shape s with an inverted Y axis. + PathIterator pi = s.getPathIterator(null); + float[] coords = new float[6]; + + while (! pi.isDone()) + { + switch (pi.currentSegment(coords)) + { + case PathIterator.SEG_MOVETO: + out.println((coords[0]) + " " + (Y - coords[1]) + " moveto"); + cx = coords[0]; + cy = coords[1]; + break; + case PathIterator.SEG_LINETO: + out.println((coords[0]) + " " + (Y - coords[1]) + " lineto"); + cx = coords[0]; + cy = coords[1]; + break; + case PathIterator.SEG_QUADTO: + // convert to cubic bezier points + float x1 = (cx + 2 * coords[0]) / 3; + float y1 = (cy + 2 * coords[1]) / 3; + float x2 = (2 * coords[2] + coords[0]) / 3; + float y2 = (2 * coords[3] + coords[1]) / 3; + + out.print((x1) + " " + (Y - y1) + " "); + out.print((x2) + " " + (Y - y2) + " "); + out.println((coords[2]) + " " + (Y - coords[3]) + " curveto"); + cx = coords[2]; + cy = coords[3]; + break; + case PathIterator.SEG_CUBICTO: + out.print((coords[0]) + " " + (Y - coords[1]) + " "); + out.print((coords[2]) + " " + (Y - coords[3]) + " "); + out.println((coords[4]) + " " + (Y - coords[5]) + " curveto"); + cx = coords[4]; + cy = coords[5]; + break; + case PathIterator.SEG_CLOSE: + out.println("closepath"); + break; + } + pi.next(); + } + out.println("fill"); + + restoreAxis(); + } + + public void setColor(Color c) + { + /* don't set the color if it's already set */ + if (c.equals(currentColor)) + return; + gradientOn = false; + currentColor = c; + currentPaint = c; // Graphics2D extends colors to paint + + out.println(colorTriple(c) + " setrgbcolor"); + } + + public void clearRect(int x, int y, int width, int height) + { + out.println("% clearRect"); + Color c = currentColor; + setColor(backgroundColor); + fill(new Rectangle2D.Double(x, y, width, height)); + setColor(c); + } + + public void clipRect(int x, int y, int width, int height) + { + clip(new Rectangle2D.Double(x, y, width, height)); + } + + public void copyArea(int x, int y, int width, int height, int dx, int dy) + { + // FIXME + } + + public void fillRect(int x, int y, int width, int height) + { + fill(new Rectangle2D.Double(x, y, width, height)); + } + + public void dispose() + { + } + + public void setClip(int x, int y, int width, int height) + { + out.println("% setClip()"); + setClip(new Rectangle2D.Double(x, y, width, height)); + } + + public void setClip(Shape s) + { + clip(s); + } + + public Shape getClip() + { + return clipShape; + } + + public Rectangle getClipBounds() + { + return clipShape.getBounds(); + } + + public Color getColor() + { + return currentColor; + } + + public Font getFont() + { + return currentFont; + } + + public FontMetrics getFontMetrics() + { + return getFontMetrics(currentFont); + } + + public FontMetrics getFontMetrics(Font f) + { + // FIXME + return null; + } + + public void setFont(Font font) + { + out.println("% setfont()"); + if (font == null) + // use the default font + font = new Font("Dialog", Font.PLAIN, 12); + currentFont = font; + setPSFont(); // set up the PostScript fonts + } + + /** + * Setup the postscript font if the current font is one + */ + private void setPSFont() + { + currentFontIsPS = false; + + String s = currentFont.getName(); + out.println("% setPSFont: Fontname: " + s); + if (s.equalsIgnoreCase("Helvetica") || s.equalsIgnoreCase("SansSerif")) + out.print("/helveticaISO findfont "); + else if (s.equalsIgnoreCase("Times New Roman")) + out.print("/timesISO findfont "); + else if (s.equalsIgnoreCase("Courier")) + out.print("/courierISO findfont "); + else + return; + + currentFontIsPS = true; + + out.print(currentFont.getSize() + " scalefont "); + out.println("setfont"); + } + + /** XOR mode is not supported */ + public void setPaintMode() + { + } + + /** XOR mode is not supported */ + public void setXORMode(Color c1) + { + } + + public void close() + { + out.println("showpage"); + out.println("%%Trailer"); + out.println("grestore % restore original stuff"); + out.println("%%EOF"); + + try + { + out.close(); + } + catch (Exception e) + { + } + out = null; + } + + //---------------------------------------------------------------- + // Graphics2D stuff ---------------------------------------------- + + /** Sets the values of an arbitrary number of + preferences for the rendering algorithms. */ + public void addRenderingHints(Map hints) + { + /* rendering hint changes are disallowed */ + } + + /** write a shape to the file */ + private void writeShape(Shape s) + { + PathIterator pi = s.getPathIterator(null); + float[] coords = new float[6]; + + while (! pi.isDone()) + { + switch (pi.currentSegment(coords)) + { + case PathIterator.SEG_MOVETO: + out.println(coords[0] + " " + (coords[1]) + " moveto"); + cx = coords[0]; + cy = coords[1]; + break; + case PathIterator.SEG_LINETO: + out.println(coords[0] + " " + (coords[1]) + " lineto"); + cx = coords[0]; + cy = coords[1]; + break; + case PathIterator.SEG_QUADTO: + // convert to cubic bezier points + float x1 = (cx + 2 * coords[0]) / 3; + float y1 = (cy + 2 * coords[1]) / 3; + float x2 = (2 * coords[2] + coords[0]) / 3; + float y2 = (2 * coords[3] + coords[1]) / 3; + + out.print(x1 + " " + (Y - y1) + " "); + out.print(x2 + " " + (Y - y2) + " "); + out.println(coords[2] + " " + (Y - coords[3]) + " curveto"); + cx = coords[2]; + cy = coords[3]; + break; + case PathIterator.SEG_CUBICTO: + out.print(coords[0] + " " + coords[1] + " "); + out.print(coords[2] + " " + coords[3] + " "); + out.println(coords[4] + " " + coords[5] + " curveto"); + cx = coords[4]; + cy = coords[5]; + break; + case PathIterator.SEG_CLOSE: + out.println("closepath"); + break; + } + pi.next(); + } + } + + /** Intersects the current Clip with the interior of + the specified Shape and sets the Clip to the resulting intersection. */ + public void clip(Shape s) + { + clipShape = s; + out.println("% clip INACTIVE"); + // writeShape(s); + // out.println("clip"); + } + + /** Strokes the outline of a Shape using the + settings of the current Graphics2D context.*/ + public void draw(Shape s) + { + if(!(currentStroke instanceof BasicStroke)) + fill(currentStroke.createStrokedShape(s)); + + out.println("% draw"); + writeShape(s); + out.println("stroke"); + } + + /** Renders the text of the specified GlyphVector using the + Graphics2D context's rendering attributes. */ + public void drawGlyphVector(GlyphVector gv, float x, float y) + { + out.println("% drawGlyphVector"); + Shape s = gv.getOutline(); + drawStringShape(AffineTransform.getTranslateInstance(x, y) + .createTransformedShape(s)); + } + + /** Renders the text of the specified iterator, + using the Graphics2D context's current Paint.*/ + public void drawString(AttributedCharacterIterator iterator, float x, float y) + { + TextLayout text = new TextLayout(iterator, getFontRenderContext()); + Shape s = text.getOutline(AffineTransform.getTranslateInstance(x, y)); + drawStringShape(s); + } + + /** Renders the text of the specified iterator, + using the Graphics2D context's current Paint. */ + public void drawString(AttributedCharacterIterator iterator, int x, int y) + { + drawString(iterator, (float) x, (float) y); + } + + /** Fills the interior of a Shape using the settings of the Graphics2D context. */ + public void fill(Shape s) + { + out.println("% fill"); + if (! gradientOn) + { + writeShape(s); + out.println("fill"); + } + else + { + out.println("gsave"); + writeShape(s); + out.println("clip"); + writeGradient(); + out.println("shfill"); + out.println("grestore"); + } + } + + /** Returns the background color used for clearing a region. */ + public Color getBackground() + { + return backgroundColor; + } + + /** Returns the current Composite in the Graphics2D context. */ + public Composite getComposite() + { + // FIXME + return null; + } + + /** Returns the device configuration associated with this Graphics2D. */ + public GraphicsConfiguration getDeviceConfiguration() + { + // FIXME + out.println("% getDeviceConfiguration()"); + return null; + } + + /** Get the rendering context of the Font within this Graphics2D context. */ + public FontRenderContext getFontRenderContext() + { + out.println("% getFontRenderContext()"); + + double[] scaling = + { + pageTransform.getScaleX(), 0, 0, + -pageTransform.getScaleY(), 0, 0 + }; + + return (new FontRenderContext(new AffineTransform(scaling), false, true)); + } + + /** Returns the current Paint of the Graphics2D context. */ + public Paint getPaint() + { + return currentPaint; + } + + /** Returns the value of a single preference for the rendering algorithms. */ + public Object getRenderingHint(RenderingHints.Key hintKey) + { + return renderingHints.get(hintKey); + } + + /** Gets the preferences for the rendering algorithms. */ + public RenderingHints getRenderingHints() + { + return renderingHints; + } + + /** Returns the current Stroke in the Graphics2D context. */ + public Stroke getStroke() + { + return currentStroke; + } + + /** Returns a copy of the current Transform in the Graphics2D context. */ + public AffineTransform getTransform() + { + return currentTransform; + } + + /** + * Checks whether or not the specified Shape intersects + * the specified Rectangle, which is in device space. + */ + public boolean hit(Rectangle rect, Shape s, boolean onStroke) + { + Rectangle2D.Double r = new Rectangle2D.Double(rect.getX(), rect.getY(), + rect.getWidth(), + rect.getHeight()); + return s.intersects(r); + } + + /** Sets the background color for the Graphics2D context.*/ + public void setBackground(Color color) + { + out.println("% setBackground(" + color + ")"); + backgroundColor = color; + } + + /** Sets the Composite for the Graphics2D context. + Not supported. */ + public void setComposite(Composite comp) + { + } + + /** Sets the Paint attribute for the Graphics2D context.*/ + public void setPaint(Paint paint) + { + currentPaint = paint; + gradientOn = false; + if (paint instanceof Color) + { + setColor((Color) paint); + return; + } + if (paint instanceof GradientPaint) + { + gradientOn = true; + return; + } + } + + /* get a space seperated 0.0 - 1.0 color RGB triple */ + private String colorTriple(Color c) + { + return (((double) c.getRed() / 255.0) + " " + + ((double) c.getGreen() / 255.0) + " " + + ((double) c.getBlue() / 255.0)); + } + + /** + * Get a nonsperated hex RGB triple, eg FFFFFF = white + * used by writeGradient and drawImage + */ + private String colorTripleHex(Color c) + { + String r = "00" + Integer.toHexString(c.getRed()); + r = r.substring(r.length() - 2); + String g = "00" + Integer.toHexString(c.getGreen()); + g = g.substring(g.length() - 2); + String b = "00" + Integer.toHexString(c.getBlue()); + b = b.substring(b.length() - 2); + return r + g + b; + } + + /* write the current gradient fill */ + private void writeGradient() + { + GradientPaint paint = (GradientPaint) currentPaint; + out.println("% writeGradient()"); + + int n = 1; + double x; + double y; + double dx; + double dy; + Point2D p1 = currentTransform.transform(paint.getPoint1(), null); + Point2D p2 = currentTransform.transform(paint.getPoint2(), null); + x = p1.getX(); + y = p1.getY(); + dx = p2.getX() - x; + dy = p2.getY() - y; + + // get number of repetitions + while (x + n * dx < pageY && y + n * dy < pageX && x + n * dx > 0 + && y + n * dy > 0) + n++; + + out.println("<<"); // start + out.println("/ShadingType 2"); // gradient fill + out.println("/ColorSpace [ /DeviceRGB ]"); // RGB colors + out.print("/Coords ["); + out.print(x + " " + y + " " + (x + n * dx) + " " + (y + n * dy) + " "); + out.println("]"); // coordinates defining the axis + out.println("/Function <<"); + out.println("/FunctionType 0"); + out.println("/Order 1"); + out.println("/Domain [ 0 1 ]"); + out.println("/Range [ 0 1 0 1 0 1 ]"); + out.println("/BitsPerSample 8"); + out.println("/Size [ " + (1 + n) + " ]"); + out.print("/DataSource < " + colorTripleHex(paint.getColor1()) + " " + + colorTripleHex(paint.getColor2()) + " "); + for (; n > 1; n--) + if (paint.isCyclic()) + { + if ((n % 2) == 1) + out.print(colorTripleHex(paint.getColor1()) + " "); + else + out.print(colorTripleHex(paint.getColor2()) + " "); + } + else + out.print(colorTripleHex(paint.getColor2()) + " "); + out.println(">"); + out.println(">>"); + out.println(">>"); + } + + /** Sets the value of a single preference for the rendering algorithms. */ + public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue) + { + /* we don't allow the changing of rendering hints. */ + } + + /** Replaces the values of all preferences for the rendering algorithms + with the specified hints. */ + public void setRenderingHints(Map hints) + { + /* we don't allow the changing of rendering hints. */ + } + + /** + * Sets the Stroke for the Graphics2D context. BasicStroke fully implemented. + */ + public void setStroke(Stroke s) + { + currentStroke = s; + + if (! (s instanceof BasicStroke)) + return; + + BasicStroke bs = (BasicStroke) s; + out.println("% setStroke()"); + try + { + // set the line width + out.println(bs.getLineWidth() + " setlinewidth"); + + // set the line dash + float[] dashArray = bs.getDashArray(); + if (dashArray != null) + { + out.print("[ "); + for (int i = 0; i < dashArray.length; i++) + out.print(dashArray[i] + " "); + out.println("] " + bs.getDashPhase() + " setdash"); + } + else + out.println("[] 0 setdash"); // set solid + + // set the line cap + switch (bs.getEndCap()) + { + case BasicStroke.CAP_BUTT: + out.println("0 setlinecap"); + break; + case BasicStroke.CAP_ROUND: + out.println("1 setlinecap"); + break; + case BasicStroke.CAP_SQUARE: + out.println("2 setlinecap"); + break; + } + + // set the line join + switch (bs.getLineJoin()) + { + case BasicStroke.JOIN_BEVEL: + out.println("2 setlinejoin"); + break; + case BasicStroke.JOIN_MITER: + out.println("0 setlinejoin"); + out.println(bs.getMiterLimit() + " setmiterlimit"); + break; + case BasicStroke.JOIN_ROUND: + out.println("1 setlinejoin"); + break; + } + } + catch (Exception e) + { + out.println("% Exception in setStroke()"); + } + } + + //////////////////// TRANSFORM SETTING ///////////////////////////////////// + private void concatCTM(AffineTransform Tx) + { + double[] matrixElements = new double[6]; + Tx.getMatrix(matrixElements); + + out.print("[ "); + for (int i = 0; i < 6; i++) + out.print(matrixElements[i] + " "); + out.println("] concat"); + } + + /** Sets the Transform in the Graphics2D context. */ + public void setTransform(AffineTransform Tx) + { + // set the transformation matrix; + currentTransform = Tx; + + // concatenate the current transform and the page transform + AffineTransform totalTransform = new AffineTransform(pageTransform); + totalTransform.concatenate(currentTransform); + out.println("% setTransform()"); + out.println("% pageTransform:" + pageTransform); + out.println("% currentTransform:" + currentTransform); + out.println("% totalTransform:" + totalTransform); + + popCTM(); + pushCTM(); // set the CTM to it's original state + concatCTM(totalTransform); // apply our transforms + } + + /** Composes an AffineTransform object with the Transform + in this Graphics2D according to the rule last-specified-first-applied. */ + public void transform(AffineTransform Tx) + { + // concatenate the current transform + currentTransform.concatenate(Tx); + // and the PS CTM + concatCTM(Tx); + } + + ////////////////////////// TRANSFORMS ////////////////////////////////////// + + /** shear transform */ + public void shear(double shx, double shy) + { + out.println("% shear()"); + AffineTransform Tx = new AffineTransform(); + Tx.shear(shx, shy); + transform(Tx); + } + + /** Translates the origin of the Graphics2D context + to the point (x, y) in the current coordinate system. */ + public void translate(int x, int y) + { + out.println("% translate()"); + AffineTransform Tx = new AffineTransform(); + Tx.translate(x, y); + transform(Tx); + } + + /** Translates the origin of the Graphics2D context + to the point (x, y) in the current coordinate system. */ + public void translate(double x, double y) + { + out.println("% translate(" + x + ", " + y + ")"); + AffineTransform Tx = new AffineTransform(); + Tx.translate(x, y); + transform(Tx); + } + + /** Concatenates the current Graphics2D Transform with a rotation transform.*/ + public void rotate(double theta) + { + out.println("% rotate(" + theta + ")"); + AffineTransform Tx = new AffineTransform(); + Tx.rotate(theta); + transform(Tx); + } + + /** Concatenates the current Graphics2D Transform with + a translated rotation transform.*/ + public void rotate(double theta, double x, double y) + { + out.println("% rotate()"); + AffineTransform Tx = new AffineTransform(); + Tx.rotate(theta, x, y); + transform(Tx); + } + + /** Concatenates the current Graphics2D Transform with a scaling + transformation Subsequent rendering is resized according to the + specified scaling factors relative to the previous scaling.*/ + public void scale(double sx, double sy) + { + out.println("% scale(" + sx + ", " + sy + ")"); + AffineTransform Tx = new AffineTransform(); + Tx.scale(sx, sy); + transform(Tx); + } +} diff --git a/libjava/classpath/gnu/java/awt/print/SpooledDocument.java b/libjava/classpath/gnu/java/awt/print/SpooledDocument.java new file mode 100644 index 000000000..54819984f --- /dev/null +++ b/libjava/classpath/gnu/java/awt/print/SpooledDocument.java @@ -0,0 +1,90 @@ +/* SpooledDocument.java -- Reurgitate a spooled PostScript file + 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.print; + +import javax.print.Doc; +import javax.print.DocFlavor; +import javax.print.attribute.DocAttributeSet; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.Reader; +import java.io.InputStream; +import java.io.InputStreamReader; + +public class SpooledDocument implements Doc +{ + private FileInputStream fis; + + public SpooledDocument(File file) + { + try + { + fis = new FileInputStream(file); + } + catch (FileNotFoundException ffne) + { + // Shouldn't happen. + } + } + + public DocAttributeSet getAttributes() + { + return null; + } + + public DocFlavor getDocFlavor() + { + return DocFlavor.INPUT_STREAM.POSTSCRIPT; + } + + public Object getPrintData() + { + return fis; + } + + public Reader getReaderForText() + { + return new InputStreamReader(fis); + } + + public InputStream getStreamForBytes() + { + return fis; + } +} diff --git a/libjava/classpath/gnu/java/beans/BeanInfoEmbryo.java b/libjava/classpath/gnu/java/beans/BeanInfoEmbryo.java new file mode 100644 index 000000000..cc474e817 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/BeanInfoEmbryo.java @@ -0,0 +1,171 @@ +/* gnu.java.beans.BeanInfoEmbryo + Copyright (C) 1998, 2002 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.BeanDescriptor; +import java.beans.BeanInfo; +import java.beans.EventSetDescriptor; +import java.beans.IndexedPropertyDescriptor; +import java.beans.MethodDescriptor; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; +import java.util.TreeMap; +import java.util.Vector; + +/** + ** A BeanInfoEmbryo accumulates information about a Bean + ** while it is in the process of being created, and then + ** when you are done accumulating the information, the + ** getBeanInfo() method may be called to create a BeanInfo + ** object based on the information.

+ ** + ** This class is not well-synchronized. (It can be, it + ** just isn't yet.) + ** + ** @author John Keiser + ** @version 1.1.0, 30 Jul 1998 + ** @see java.beans.BeanInfo + **/ + +public class BeanInfoEmbryo { + + // by using a TreeMap the properties will be sorted alphabetically by name + // which matches the (undocumented) behavior of jdk + TreeMap properties = new TreeMap(); + Hashtable events = new Hashtable(); + Vector methods = new Vector(); + + BeanDescriptor beanDescriptor; + BeanInfo[] additionalBeanInfo; + java.awt.Image[] im; + String defaultPropertyName; + String defaultEventName; + + public BeanInfoEmbryo() { + } + + public BeanInfo getBeanInfo() { + int defaultProperty = -1; + int defaultEvent = -1; + + PropertyDescriptor[] Aproperties = new PropertyDescriptor[properties.size()]; + int i = 0; + Iterator it = properties.entrySet().iterator(); + while (it.hasNext()) { + Aproperties[i] = (PropertyDescriptor) (((Map.Entry)it.next()).getValue()); + if(defaultPropertyName != null && Aproperties[i].getName().equals(defaultPropertyName)) { + defaultProperty = i; + } + i++; + } + + EventSetDescriptor[] Aevents = new EventSetDescriptor[events.size()]; + i = 0; + Enumeration e = events.elements(); + while (e.hasMoreElements()) { + Aevents[i] = (EventSetDescriptor) e.nextElement(); + if(defaultEventName != null && Aevents[i].getName().equals(defaultEventName)) { + defaultEvent = i; + } + i++; + } + + MethodDescriptor[] Amethods = new MethodDescriptor[methods.size()]; + methods.copyInto(Amethods); + + return new ExplicitBeanInfo(beanDescriptor,additionalBeanInfo,Aproperties,defaultProperty,Aevents,defaultEvent,Amethods,im); + } + + public void setBeanDescriptor(BeanDescriptor b) { + beanDescriptor = b; + } + + public void setAdditionalBeanInfo(BeanInfo[] b) { + additionalBeanInfo = b; + } + + public boolean hasProperty(PropertyDescriptor p) { + return properties.get(p.getName()) != null; + } + public void addProperty(PropertyDescriptor p) { + properties.put(p.getName(),p); + } + public void addIndexedProperty(IndexedPropertyDescriptor p) { + properties.put(p.getName(),p); + } + + public boolean hasEvent(EventSetDescriptor e) { + return events.get(e.getName()) != null; + } + public void addEvent(EventSetDescriptor e) { + events.put(e.getName(),e); + } + + public boolean hasMethod(MethodDescriptor m) { + for(int i=0;iExceptionListener 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/libjava/classpath/gnu/java/beans/DummyAppletContext.java b/libjava/classpath/gnu/java/beans/DummyAppletContext.java new file mode 100644 index 000000000..583d2f5cb --- /dev/null +++ b/libjava/classpath/gnu/java/beans/DummyAppletContext.java @@ -0,0 +1,165 @@ +/* gnu.java.beans.DummyAppletContext + Copyright (C) 2004, 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.java.beans; + +import java.applet.Applet; +import java.applet.AppletContext; +import java.applet.AudioClip; +import java.awt.Image; +import java.awt.Toolkit; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Iterator; + +/** A placeholder AppletContext implementation that does nothing. + * + *

This is the default implementation for GNU Classpath and is used for Applet + * beans being created with {@link java.beans.Beans.instantiate}.

+ * + *

It has no functionality in order to allow it to be used without any dependencies + * (e.g. sound, network access, ...).

+ * + * @author Robert Schuster + */ +class DummyAppletContext implements AppletContext +{ + private static final Enumeration EMPTY_ENUMERATION = Collections.enumeration(Collections.EMPTY_SET); + + DummyAppletContext() + { + } + + /** Implementation is VM neutral and returns a dummy {@link AudioClip} instance + * for every URL that returns a non-null object on + * URL.openConnection(). + * + * @see java.applet.AppletContext#getAudioClip(java.net.URL) + * + * FIXME: When Java Sound API (javax.sound) is included in Classpath or URL is able to handle + * sampled sound this should be adjusted. + */ + public AudioClip getAudioClip(URL url) + { + return Applet.newAudioClip(url); + } + + /** Loads the Image instance by delegating to + * {@link java.awt.Toolkit.createImage(URL) }. + * + * @see java.applet.AppletContext#getImage(java.net.URL) + * @see java.awt.Toolkit#createImage(java.net.URL) + */ + public Image getImage(URL url) + { + return Toolkit.getDefaultToolkit().createImage(url); + } + + /** Returns null for every argument. + * + * @see java.applet.AppletContext#getApplet(java.lang.String) + */ + public Applet getApplet(String name) + { + return null; + } + + /** Returns always an empty Enumeration. + * + * @see java.applet.AppletContext#getApplets() + */ + public Enumeration getApplets() + { + return EMPTY_ENUMERATION; + } + + /** Does nothing. + * + * @see java.applet.AppletContext#showDocument(java.net.URL) + */ + public void showDocument(URL url) + { + } + + /** Does nothing. + * + * @see java.applet.AppletContext#showDocument(java.net.URL, java.lang.String) + */ + public void showDocument(URL url, String target) + { + } + + /** Does nothing. + * + * @see java.applet.AppletContext#showStatus(java.lang.String) + */ + public void showStatus(String message) + { + } + + /** Does nothing. + * + * @see java.applet.AppletContext#setStream(java.lang.String, java.io.InputStream) + */ + public void setStream(String key, InputStream stream) + throws IOException + { + throw new IOException("Dummy implementation imposes zero InputStream associations."); + } + + /** Returns null for every argument. + * + * @see java.applet.AppletContext#getStream(java.lang.String) + */ + public InputStream getStream(String key) + { + return null; + } + + /** Returns always an empty iterator. + * + * @see java.applet.AppletContext#getStreamKeys() + */ + public Iterator getStreamKeys() + { + return Collections.EMPTY_SET.iterator(); + } +} diff --git a/libjava/classpath/gnu/java/beans/DummyAppletStub.java b/libjava/classpath/gnu/java/beans/DummyAppletStub.java new file mode 100644 index 000000000..3bcb43534 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/DummyAppletStub.java @@ -0,0 +1,115 @@ +/* gnu.java.beans.DummyAppletStub + Copyright (C) 2004, 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.java.beans; + +import java.applet.AppletContext; +import java.applet.AppletStub; +import java.net.URL; + +/** Placeholder implementation of AppletStub providing no functionality. + *

This class is used for Applet being created with + * {@link java.beans.Bean.instantiate}.

+ * + * @author Robert Schuster + */ +public class DummyAppletStub implements AppletStub +{ + private URL documentBase; + private URL codeBase; + private DummyAppletContext context; + + public DummyAppletStub(URL newCodeBase, URL newDocumentBase) + { + codeBase = newCodeBase; + documentBase = newDocumentBase; + + context = new DummyAppletContext(); + } + + /** Returns always true. + * + * @see java.applet.AppletStub#isActive() + */ + public boolean isActive() + { + return true; + } + + /** + * @see java.applet.AppletStub#getDocumentBase() + */ + public URL getDocumentBase() + { + return documentBase; + } + + /** + * @see java.applet.AppletStub#getCodeBase() + */ + public URL getCodeBase() + { + return codeBase; + } + + /** Implementation returns null for every parameter name. + * + * @see java.applet.AppletStub#getParameter(java.lang.String) + */ + public String getParameter(String name) + { + return null; + } + + /** Returns a non-functional context instance. + * + * @see java.applet.AppletStub#getAppletContext() + */ + public AppletContext getAppletContext() + { + return context; + } + + /** Does nothing. + * + * @see java.applet.AppletStub#appletResize(int, int) + */ + public void appletResize(int width, int height) + { + } +} diff --git a/libjava/classpath/gnu/java/beans/ExplicitBeanInfo.java b/libjava/classpath/gnu/java/beans/ExplicitBeanInfo.java new file mode 100644 index 000000000..30f1de4fc --- /dev/null +++ b/libjava/classpath/gnu/java/beans/ExplicitBeanInfo.java @@ -0,0 +1,149 @@ +/* ExplicitBeanInfo.java -- + Copyright (C) 1998, 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; + +import java.awt.Image; +import java.beans.BeanDescriptor; +import java.beans.BeanInfo; +import java.beans.EventSetDescriptor; +import java.beans.MethodDescriptor; +import java.beans.PropertyDescriptor; + +/** + ** ExplicitBeanInfo lets you specify in the constructor + ** all the various parts of the BeanInfo. + ** + ** @author John Keiser + ** @version 1.1.0, 30 Jul 1998 + ** @see java.beans.BeanInfo + **/ + +public class ExplicitBeanInfo implements BeanInfo { + /** The BeanDescriptor returned by getBeanDescriptor. **/ + protected BeanDescriptor beanDescriptor; + + /** The EventSetDescriptor array returned by + ** getEventSetDescriptors(). + **/ + protected EventSetDescriptor[] eventSetDescriptors = new EventSetDescriptor[0]; + + /** The PropertyDescriptor array returned by + ** getPropertyDescriptors(). + **/ + protected PropertyDescriptor[] propertyDescriptors = new PropertyDescriptor[0]; + + /** The MethodDescriptor array returned by + ** getMethodDescriptors(). + **/ + protected MethodDescriptor[] methodDescriptors; + + /** The default property index. **/ + protected int defaultPropertyIndex; + + /** The default event index. **/ + protected int defaultEventIndex; + + /** The BeanInfo array returned by + ** getAdditionalBeanInfo(). + **/ + protected BeanInfo[] additionalBeanInfo; + + /** The set of icons. **/ + protected Image[] icons; + + public ExplicitBeanInfo(BeanDescriptor beanDescriptor, + BeanInfo[] additionalBeanInfo, + PropertyDescriptor[] propertyDescriptors, + int defaultPropertyIndex, + EventSetDescriptor[] eventSetDescriptors, + int defaultEventIndex, + MethodDescriptor[] methodDescriptors, + Image[] icons) { + this.beanDescriptor = beanDescriptor; + this.additionalBeanInfo = additionalBeanInfo; + this.propertyDescriptors = propertyDescriptors; + this.defaultPropertyIndex = defaultPropertyIndex; + this.eventSetDescriptors = eventSetDescriptors; + this.defaultEventIndex = defaultEventIndex; + this.methodDescriptors = methodDescriptors; + this.icons = icons; + } + + /** Get Bean descriptor. **/ + public BeanDescriptor getBeanDescriptor() { + return beanDescriptor; + } + + /** Get Bean events. **/ + public EventSetDescriptor[] getEventSetDescriptors() { + return eventSetDescriptors; + } + + /** Get default event set. **/ + public int getDefaultEventIndex() { + return defaultEventIndex; + } + + /** Get Bean properties. **/ + public PropertyDescriptor[] getPropertyDescriptors() { + return propertyDescriptors; + } + + /** Get "default" property. **/ + public int getDefaultPropertyIndex() { + return defaultPropertyIndex; + } + + /** Get Bean methods. **/ + public MethodDescriptor[] getMethodDescriptors() { + return methodDescriptors; + } + + /** Get additional Bean info. **/ + public BeanInfo[] getAdditionalBeanInfo() { + return additionalBeanInfo; + } + + /** Get Bean icons. + ** @param iconType the type of icon + **/ + public Image getIcon(int iconType) { + return icons != null ? icons[iconType - 1] : null; + } +} diff --git a/libjava/classpath/gnu/java/beans/IntrospectionIncubator.java b/libjava/classpath/gnu/java/beans/IntrospectionIncubator.java new file mode 100644 index 000000000..978429a1e --- /dev/null +++ b/libjava/classpath/gnu/java/beans/IntrospectionIncubator.java @@ -0,0 +1,441 @@ +/* gnu.java.beans.IntrospectionIncubator + Copyright (C) 1998, 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; + +import gnu.java.lang.ArrayHelper; +import gnu.java.lang.ClassHelper; + +import java.beans.BeanInfo; +import java.beans.EventSetDescriptor; +import java.beans.IndexedPropertyDescriptor; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.MethodDescriptor; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +/** + ** IntrospectionIncubator takes in a bunch of Methods, and + ** Introspects only those Methods you give it.
+ ** + ** See {@link addMethod(Method)} for details which rules apply to + ** the methods. + ** + ** @author John Keiser + ** @author Robert Schuster + ** @see gnu.java.beans.ExplicitBeanInfo + ** @see java.beans.BeanInfo + **/ + +public class IntrospectionIncubator { + Hashtable propertyMethods = new Hashtable(); + Hashtable listenerMethods = new Hashtable(); + Vector otherMethods = new Vector(); + + Class propertyStopClass; + Class eventStopClass; + Class methodStopClass; + + public IntrospectionIncubator() { + } + + /** Examines the given method and files it in a suitable collection. + * It files the method as a property method if it finds: + *
    + *
  • boolean "is" getter
  • + *
  • "get" style getter
  • + *
  • single argument setter
  • + *
  • indiced setter and getter
  • + *
+ * It files the method as a listener method if all of these rules apply: + *
    + *
  • the method name starts with "add" or "remove"
  • + *
  • there is only a single argument
  • + *
  • the argument type is a subclass of java.util.EventListener
  • + *
+ * All public methods are filed as such. + * + * @param method The method instance to examine. + */ + public void addMethod(Method method) { + if(Modifier.isPublic(method.getModifiers())) { + String name = ClassHelper.getTruncatedName(method.getName()); + Class retType = method.getReturnType(); + Class[] params = method.getParameterTypes(); + boolean isVoid = retType.equals(java.lang.Void.TYPE); + Class methodClass = method.getDeclaringClass(); + + /* Accepts the method for examination if no stop class is given or the method is declared in a subclass of the stop class. + * The rules for this are described in {@link java.beans.Introspector.getBeanInfo(Class, Class)}. + * This block finds out whether the method is a suitable getter or setter method (or read/write method). + */ + if(isReachable(propertyStopClass, methodClass)) { + /* At this point a method may regarded as a property's read or write method if its name + * starts with "is", "get" or "set". However, if a method is static it cannot be part + * of a property. + */ + if(Modifier.isStatic(method.getModifiers())) { + // files method as other because it is static + otherMethods.addElement(method); + } else if(name.startsWith("is") + && retType.equals(java.lang.Boolean.TYPE) + && params.length == 0) { + // files method as boolean "is" style getter + addToPropertyHash(name,method,IS); + } else if(name.startsWith("get") && !isVoid) { + if(params.length == 0) { + // files as legal non-argument getter + addToPropertyHash(name,method,GET); + } else if(params.length == 1 && params[0].equals(java.lang.Integer.TYPE)) { + // files as legal indiced getter + addToPropertyHash(name,method,GET_I); + } else { + // files as other because the method's signature is not Bean-like + otherMethods.addElement(method); + } + } else if(name.startsWith("set") && isVoid) { + if(params.length == 1) { + // files as legal single-argument setter method + addToPropertyHash(name,method,SET); + } else if(params.length == 2 && params[0].equals(java.lang.Integer.TYPE)) { + // files as legal indiced setter method + addToPropertyHash(name,method,SET_I); + } else { + // files as other because the method's signature is not Bean-like + otherMethods.addElement(method); + } + } + } + + if(isReachable(eventStopClass, methodClass)) { + if(name.startsWith("add") + && isVoid + && params.length == 1 + && java.util.EventListener.class.isAssignableFrom(params[0])) { + addToListenerHash(name,method,ADD); + } else if(name.startsWith("remove") + && isVoid + && params.length == 1 + && java.util.EventListener.class.isAssignableFrom(params[0])) { + addToListenerHash(name,method,REMOVE); + } + } + + if(isReachable(methodStopClass, methodClass)) { + // files as reachable public method + otherMethods.addElement(method); + } + + } + } + + public void addMethods(Method[] m) { + for(int i=0;istopClass is null + * or declaringClass is a true subclass of stopClass. + * This expression is useful to detect whether a method should be introspected or not. + * The rules for this are described in {@link java.beans.Introspector.getBeanInfo(Class, Class)}. + */ + static boolean isReachable(Class stopClass, Class declaringClass) { + return stopClass == null || (stopClass.isAssignableFrom(declaringClass) && !stopClass.equals(declaringClass)); + } + + /** Transforms a property name into a part of a method name. + * E.g. "value" becomes "Value" which can then concatenated with + * "set", "get" or "is" to form a valid method name. + * + * Implementation notes: + * If "" is the argument, it is returned without changes. + * If null is the argument, null is returned. + * + * @param name Name of a property. + * @return Part of a method name of a property. + */ + static String capitalize(String name) { + try { + if(Character.isUpperCase(name.charAt(0))) { + return name; + } else { + char[] c = name.toCharArray(); + c[0] = Character.toLowerCase(c[0]); + return new String(c); + } + } catch(StringIndexOutOfBoundsException E) { + return name; + } catch(NullPointerException E) { + return null; + } + } +} + +/** This class is a hashmap key that consists of a Class and a + * String element. + * + * It is used for XXX: find out what this is used for + * + * @author John Keiser + * @author Robert Schuster + */ +class DoubleKey { + Class type; + String name; + + DoubleKey(Class type, String name) { + this.type = type; + this.name = name; + } + + Class getType() { + return type; + } + + String getName() { + return name; + } + + public boolean equals(Object o) { + if(o instanceof DoubleKey) { + DoubleKey d = (DoubleKey)o; + return d.type.equals(type) && d.name.equals(name); + } else { + return false; + } + } + + public int hashCode() { + return type.hashCode() ^ name.hashCode(); + } +} diff --git a/libjava/classpath/gnu/java/beans/TODO b/libjava/classpath/gnu/java/beans/TODO new file mode 100644 index 000000000..9112806ba --- /dev/null +++ b/libjava/classpath/gnu/java/beans/TODO @@ -0,0 +1 @@ +- overhaul efficiency diff --git a/libjava/classpath/gnu/java/beans/decoder/AbstractContext.java b/libjava/classpath/gnu/java/beans/decoder/AbstractContext.java new file mode 100644 index 000000000..e6f90e21f --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/AbstractContext.java @@ -0,0 +1,70 @@ +/* gnu.java.beans.decoder.AbstractContext + 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; + + +/** AbstractContext implements some basic functionality of the Context + * interface and is therefore the base of all Context implementations. + * + * @author Robert Schuster + */ +abstract class AbstractContext implements Context +{ + private boolean isStatement; + private String id; + + public String getId() + { + return id; + } + + public void setId(String newId) + { + id = newId; + } + + public boolean isStatement() + { + return isStatement; + } + + public void setStatement(boolean b) + { + isStatement = b; + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/AbstractCreatableObjectContext.java b/libjava/classpath/gnu/java/beans/decoder/AbstractCreatableObjectContext.java new file mode 100644 index 000000000..d108f191c --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/AbstractCreatableObjectContext.java @@ -0,0 +1,113 @@ +/* gnu.java.beans.decoder.AbstractCreatableContext + 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; + + +/** AbstractCreatableObjectContext is the base class for all Context implementations + * which create a result object in their lifetime. It provides means for preventing + * to create the object twice. + * + * @author Robert Schuster + * + */ +abstract class AbstractCreatableObjectContext extends AbstractObjectContext +{ + AbstractCreatableObjectContext() + { + } + + /** Adds a parameter object to this Context if the result object has not been + * created yet. Otherwise an AssemblyException is thrown that indicates a wrong + * behavior of the decoder. + */ + public final void addParameterObject(Object o) throws AssemblyException + { + if (object == null) + addParameterObjectImpl(o); + else + throw new AssemblyException(new IllegalStateException("No more parameter objects are allowed when the object as already been created.")); + } + + /** Adds a parameter object to this Context. Implement this without caring + * for illegal states because this has been done already. + * + * @param obj The parameter object to be added. + */ + protected abstract void addParameterObjectImpl(Object obj); + + /** Creates the result object if it does not exist already. + */ + public final void notifyStatement(Context outerContext) + throws AssemblyException + { + if (object != null) + return; + + object = createObject(outerContext); + } + + /** Creates the result object. This method is called only once. Implement this + * without checking for double invocations as this is already being prevented. + * + * @param outerContext The Context that exists around this one. + * @return The result object. + * @throws AssemblerException if the object creation fails somehow. + */ + protected abstract Object createObject(Context outerContext) + throws AssemblyException; + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#endContext(gnu.java.beans.decoder.Context) + */ + public final Object endContext(Context outerContext) + throws AssemblyException + { + notifyStatement(outerContext); + return object; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#subContextFailed() + */ + public boolean subContextFailed() + { + /* Returns true when the AbstractCreatableObjectContext has not created the result object yet + * (A failed subcontext automatically lets this context fail too.) + */ + return object == null; + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/AbstractElementHandler.java b/libjava/classpath/gnu/java/beans/decoder/AbstractElementHandler.java new file mode 100644 index 000000000..51765658f --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/AbstractElementHandler.java @@ -0,0 +1,316 @@ +/* gnu.java.beans.decoder.AbstractElementHandler + 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; + +import org.xml.sax.Attributes; + +/** ElementHandler manages a Context instance and interacts with + * its parent and child handlers. + * + * @author Robert Schuster + */ +abstract class AbstractElementHandler implements ElementHandler +{ + /** The Context instance of this handler. The instance is available after the startElement() + * method was called. Otherwise the handler is marked as failed. + */ + private Context context; + + /** The parent handler. */ + private ElementHandler parent; + + /** Stores whether this handler is marked as failed. */ + private boolean hasFailed; + + /** Stores the character data which is contained in the body of the XML tag. */ + private StringBuffer buffer = new StringBuffer(); + + /** Stores whether this ElementHandler can have subelements. The information for this is taken from + * javabeans.dtd which can be found here: + * Java Persistence Article + */ + private boolean allowsSubelements; + + /** Creates a new ElementHandler with the given ElementHandler instance + * as parent. + * + * @param parentHandler The parent handler. + */ + protected AbstractElementHandler(ElementHandler parentHandler, + boolean allowsSubs) + { + parent = parentHandler; + allowsSubelements = allowsSubs; + } + + /** Evaluates the attributes and creates a Context instance. + * If the creation of the Context instance fails the ElementHandler + * is marked as failed which may affect the parent handler other. + * + * @param attributes Attributes of the XML tag. + */ + public final void start(Attributes attributes, + ExceptionListener exceptionListener) + { + try + { + // lets the subclass create the appropriate Context instance + context = startElement(attributes, exceptionListener); + } + catch (AssemblyException pe) + { + Throwable t = pe.getCause(); + + if (t instanceof Exception) + exceptionListener.exceptionThrown((Exception) t); + else + throw new InternalError("Unexpected Throwable type in AssemblerException. Please file a bug report."); + + notifyContextFailed(); + + return; + } + } + + /** Analyses the content of the Attributes instance and creates a Context + * object accordingly. + * An AssemblerException is thrown when the Context instance could not + * be created. + * + * @param attributes Attributes of the XML tag. + * @return A Context instance. + * @throws AssemblerException when Context instance could not be created. + */ + protected abstract Context startElement(Attributes attributes, ExceptionListener exceptionListener) + throws AssemblyException; + + /** Post-processes the Context. + */ + public final void end(ExceptionListener exceptionListener) + { + // skips processing if the handler is marked as failed (because the Context + // is then invalid or may not exist at all) + if (!hasFailed) + { + try + { + // note: the order of operations is very important here + // sends the stored character data to the Context + endElement(buffer.toString()); + + // reports to the parent handler if this handler's Context is a + // statement (returning no value BACK to the parent's Context) + if (context.isStatement()) + { + // This may create a valid result in the parent's Context + // or let it fail + parent.notifyStatement(exceptionListener); + + // skips any further processing if the parent handler is now marked + // as failed + if (parent.hasFailed()) + return; + } + + // processes the Context and stores the result + putObject(context.getId(), context.endContext(parent.getContext())); + + // transfers the Context's results to the parent's Context + // if it is an expression (rather than a statement) + if (! context.isStatement()) + parent.getContext().addParameterObject(context.getResult()); + } + catch (AssemblyException pe) + { + // notifies that an exception was thrown in this handler's Context + Throwable t = pe.getCause(); + + if (t instanceof Exception) + exceptionListener.exceptionThrown((Exception) t); + else + throw (InternalError) new InternalError("Severe problem while decoding XML data.") + .initCause(t); + + // marks the handler as failed + notifyContextFailed(); + } + } + } + + /** Notifies the handler's Context that its child Context will not return + * a value back. Some Context variants need this information to know when + * a method or a constructor call can be made. + * + * This method is called by a child handler. + */ + public void notifyStatement(ExceptionListener exceptionListener) + { + try + { + + // propagates to parent handler first to generate objects + // needed by this Context instance + if(context.isStatement()) + { + parent.notifyStatement(exceptionListener); + } + + // Some Context instances do stuff which can fail now. If that + // happens this handler is marked as failed. + context.notifyStatement(parent.getContext()); + } + catch (AssemblyException ae) + { + // notifies that an exception was thrown in this handler's Context + Throwable t = ae.getCause(); + + if (t instanceof Exception) + exceptionListener.exceptionThrown((Exception) t); + else + throw (InternalError) new InternalError("Severe problem while decoding XML data.") + .initCause(t); + + // marks the handler as failed + notifyContextFailed(); + } + } + + /** Marks this and any depending parent handlers as failed. Which means that on their end + * no result is calculated. + * + * When a handler has failed no more handlers are accepted within it. + */ + public final void notifyContextFailed() + { + hasFailed = true; + + // marks the parent handler as failed if its Context + // is affected by the failure of this handler's Context + if (parent.getContext().subContextFailed()) + parent.notifyContextFailed(); + } + + /** Returns whether this handler has failed. + * + * This is used to skip child elements. + * + * @return Whether this handler has failed. + */ + public final boolean hasFailed() + { + return hasFailed; + } + + /** Processes the character data when the element ends. + * + * The default implementation does nothing for convenience. + * + * @param characters + * @throws AssemblerException + */ + protected void endElement(String characters) throws AssemblyException + { + // XXX: throw an exception when unexpected character data is available? + } + + /** Adds characters from the body of the XML tag to the buffer. + * + * @param ch + * @param start + * @param length + * @throws SAXException + */ + public final void characters(char[] ch, int start, int length) + { + // simply appends character data + buffer.append(ch, start, length); + } + + /** Stores an object globally under a unique id. If the id is + * null the object is not stored. + * + * @param objectId + * @param o + */ + public void putObject(String objectId, Object o) + { + if (objectId != null) + parent.putObject(objectId, o); + } + + /** Returns a previously stored object. If the id is null the + * result is null, too. + * + * @param objectId + * @return Returns a previously stored object or null. + */ + public Object getObject(String objectId) throws AssemblyException + { + return objectId == null ? null : parent.getObject(objectId); + } + + /** Returns the Class instance as if called Class.forName() but + * uses a ClassLoader given by the user. + * + * @param className + * @return + * @throws ClassNotFoundException + */ + public Class instantiateClass(String className) + throws ClassNotFoundException + { + return parent.instantiateClass(className); + } + + public final boolean isSubelementAllowed(String subElementName) + { + return allowsSubelements && ! subElementName.equals("java"); + } + + public final Context getContext() + { + return context; + } + + public final ElementHandler getParent() + { + return parent; + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/AbstractObjectContext.java b/libjava/classpath/gnu/java/beans/decoder/AbstractObjectContext.java new file mode 100644 index 000000000..963ef0905 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/AbstractObjectContext.java @@ -0,0 +1,127 @@ +/* gnu.java.beans.decoder.AbstractObjectContext + 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.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** AbstractObjectContext is the base for all Context implementations which + * create or provide a result object during their lifetime. + * + *

This class provides the implementation for an indexed get and set method. + * But this does not mean that the result object supports these operation.

+ * + * @author Robert Schuster + * + */ +abstract class AbstractObjectContext extends AbstractContext +{ + protected Object object; + + AbstractObjectContext() + {} + + /** Sets the result object of the Context. + * + * @param obj The result object to be set. + */ + protected final void setObject(Object obj) + { + object = obj; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#set(int, java.lang.Object) + */ + public final void set(int index, Object o) throws AssemblyException + { + try + { + Method method = + object.getClass().getMethod( + "set", + new Class[] { Integer.TYPE, Object.class }); + + method.invoke(object, new Object[] { new Integer(index), o }); + } + catch (NoSuchMethodException nsme) + { + throw new AssemblyException(nsme); + } + catch (InvocationTargetException ite) + { + throw new AssemblyException(ite.getCause()); + } + catch (IllegalAccessException iae) + { + throw new AssemblyException(iae); + } + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#get(int) + */ + public final Object get(int index) throws AssemblyException + { + try + { + Method method = + object.getClass().getMethod( + "get", + new Class[] { Integer.TYPE }); + + return method.invoke(object, new Object[] { new Integer(index)}); + } + catch (NoSuchMethodException nsme) + { + throw new AssemblyException(nsme); + } + catch (InvocationTargetException ite) + { + throw new AssemblyException(ite.getCause()); + } + catch (IllegalAccessException iae) + { + throw new AssemblyException(iae); + } + } + + public final Object getResult() + { + return object; + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/ArrayContext.java b/libjava/classpath/gnu/java/beans/decoder/ArrayContext.java new file mode 100644 index 000000000..bdec1c647 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/ArrayContext.java @@ -0,0 +1,122 @@ +/* gnu.java.beans.decoder.ArrayContext + 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.lang.reflect.Array; + +/** A Context implementation for a fixed size array. The array + * elements have to be set using IndexContext instances. + * + * @author Robert Schuster + */ +class ArrayContext extends AbstractContext +{ + private Object array; + + ArrayContext(String id, Class klass, int length) + { + setId(id); + array = Array.newInstance(klass, length); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#addObject(java.lang.Object) + */ + public void addParameterObject(Object o) throws AssemblyException + { + throw new AssemblyException(new IllegalStateException("Adding objects without an index to a fixed array is not possible.")); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#reportStatement() + */ + public void notifyStatement(Context outerContext) + { + // method call intentionally ignored because there is not any useful effect + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#endContext(gnu.java.beans.decoder.Context) + */ + public Object endContext(Context outerContext) throws AssemblyException + { + return array; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#subContextFailed() + */ + public boolean subContextFailed() + { + // returns false to indicate that assembling the array does not fail only because + // a subelement failed. + return false; + } + + public void set(int index, Object o) throws AssemblyException + { + try + { + Array.set(array, index, o); + } + catch (ArrayIndexOutOfBoundsException aioobe) + { + throw new AssemblyException(aioobe); + } + } + + public Object get(int index) throws AssemblyException + { + try + { + return Array.get(array, index); + } + catch (ArrayIndexOutOfBoundsException aioobe) + { + throw new AssemblyException(aioobe); + } + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#getResult() + */ + public Object getResult() + { + return array; + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/ArrayHandler.java b/libjava/classpath/gnu/java/beans/decoder/ArrayHandler.java new file mode 100644 index 000000000..28930f519 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/ArrayHandler.java @@ -0,0 +1,118 @@ +/* gnu.java.beans.decoder.ArrayHandler + 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; +import java.util.HashMap; + +import org.xml.sax.Attributes; + +/** ArrayHandler processes the <array> tag. Depending on the existance of the 'length' attribute a Context for + * a fixed-size or growable array is created. + * + * @author Robert Schuster + */ +class ArrayHandler extends AbstractElementHandler +{ + /** Contains a mapping between a textual description of a primitive type (like "byte") and + * its corresponding wrapper class. This allows it to easily construct Array objects for + * primitive data types. + */ + private static HashMap typeMap = new HashMap(); + + static + { + typeMap.put("byte", Byte.TYPE); + typeMap.put("short", Short.TYPE); + typeMap.put("int", Integer.TYPE); + typeMap.put("long", Long.TYPE); + + typeMap.put("float", Float.TYPE); + typeMap.put("double", Double.TYPE); + + typeMap.put("boolean", Boolean.TYPE); + + typeMap.put("char", Character.TYPE); + } + + /** + * @param PersistenceParser + */ + ArrayHandler(ElementHandler parent) + { + super(parent, true); + } + + protected Context startElement(Attributes attributes, ExceptionListener exceptionListener) + throws AssemblyException, AssemblyException + { + String id = attributes.getValue("id"); + String className = attributes.getValue("class"); + + if (className != null) + { + try + { + Class klass; + + if (typeMap.containsKey(className)) + klass = (Class) typeMap.get(className); + else + klass = instantiateClass(className); + + String length = attributes.getValue("length"); + if (length != null) + // creates Array with predefined length + return new ArrayContext(id, klass, Integer.parseInt(length)); + else + // creates Array without length restriction + return new GrowableArrayContext(id, klass); + } + catch (ClassNotFoundException cnfe) + { + throw new AssemblyException(cnfe); + } + catch (NumberFormatException nfe) + { + throw new AssemblyException(nfe); + } + } + + throw new AssemblyException(new IllegalArgumentException("Missing 'class' attribute in tag.")); + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/AssemblyException.java b/libjava/classpath/gnu/java/beans/decoder/AssemblyException.java new file mode 100644 index 000000000..206c5841b --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/AssemblyException.java @@ -0,0 +1,57 @@ +/* gnu.java.beans.decoder.AssemblyException + 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; + + +/** The AssemblyException is used to wrap the cause of problems when assembling objects. + * In all cases only the wrapped exception is given to the PersistenceParser's + * ExceptionListener instance (never the AssemblyException itself). + * + *

Note: Often multiple steps are needed to construct a fully usuable object instance. + * Such a construction can be called assembly and thats why this exception was + * named AssemblyException.

+ * + * @author Robert Schuster + */ +class AssemblyException extends Exception +{ + AssemblyException(Throwable cause) + { + super(cause); + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/BooleanHandler.java b/libjava/classpath/gnu/java/beans/decoder/BooleanHandler.java new file mode 100644 index 000000000..20aed9a3f --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/BooleanHandler.java @@ -0,0 +1,67 @@ +/* gnu.java.beans.decoder.BooleanHandler + 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; + + +/** Creates a Boolean instance from the character data in a <boolean> tag. + * + * @author Robert Schuster + */ +class BooleanHandler extends SimpleHandler +{ + /** + * @param PersistenceParser + */ + BooleanHandler(ElementHandler parent) + { + super(parent); + + // TODO Auto-generated constructor stub + } + + protected Object parse(String number) throws AssemblyException + { + if (number.equals("true")) + return Boolean.TRUE; + + if (number.equals("false")) + return Boolean.FALSE; + + throw new AssemblyException(new IllegalArgumentException("Element contained no valid boolean value.")); + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/ByteHandler.java b/libjava/classpath/gnu/java/beans/decoder/ByteHandler.java new file mode 100644 index 000000000..830bbc747 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/ByteHandler.java @@ -0,0 +1,59 @@ +/* gnu.java.beans.decoder.ByteHandler + 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; + + +/** Creates a Byte instance from the character data in a <byte> tag. + * + * @author Robert Schuster + */ +class ByteHandler extends SimpleHandler +{ + /** + * @param PersistenceParser + */ + ByteHandler(ElementHandler parent) + { + super(parent); + } + + protected Object parse(String number) throws NumberFormatException + { + return Byte.valueOf(number); + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/CharHandler.java b/libjava/classpath/gnu/java/beans/decoder/CharHandler.java new file mode 100644 index 000000000..114df8b79 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/CharHandler.java @@ -0,0 +1,62 @@ +/* gnu.java.beans.decoder.CharHandler + 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; + + +/** Creates a Character instance from the character data in a <char> tag. + * + * @author Robert Schuster + */ +class CharHandler extends SimpleHandler +{ + /** + * @param PersistenceParser + */ + CharHandler(ElementHandler parent) + { + super(parent); + } + + protected Object parse(String number) throws AssemblyException + { + if (number.length() > 1) + throw new AssemblyException(new IllegalArgumentException("Element contained no valid character.")); + + return new Character(number.charAt(0)); + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/ClassHandler.java b/libjava/classpath/gnu/java/beans/decoder/ClassHandler.java new file mode 100644 index 000000000..c67a79a48 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/ClassHandler.java @@ -0,0 +1,66 @@ +/* gnu.java.beans.decoder.ClassHandler + 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; + + +/** Creates a Class instance from the character data in a <class> tag. + * + * @author Robert Schuster + */ +class ClassHandler extends SimpleHandler +{ + /** + * @param PersistenceParser + */ + ClassHandler(ElementHandler parent) + { + super(parent); + } + + protected Object parse(String characters) throws AssemblyException + { + try + { + return instantiateClass(characters); + } + catch (ClassNotFoundException cnfe) + { + throw new AssemblyException(cnfe); + } + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/ConstructorContext.java b/libjava/classpath/gnu/java/beans/decoder/ConstructorContext.java new file mode 100644 index 000000000..32365eef4 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/ConstructorContext.java @@ -0,0 +1,102 @@ +/* gnu.java.beans.decoder.ConstructorContext + 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.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; + +/** A ConstructorContext is a {@link Context} implementation which collects the parameters for a constructor + * call and instantiates the result object using that constructor. After that sub-contexts can invoke + * methods on the result object. + * + *

The constructor is invoked when a sub-context is a statement or the Context ends.

+ * + * @author Robert Schuster + */ +class ConstructorContext extends AbstractCreatableObjectContext +{ + private ArrayList arguments = new ArrayList(); + private Class klass; + + ConstructorContext(String id, Class newClass) + { + setId(id); + // sets superclass field + klass = newClass; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#addObject(java.lang.Object) + */ + protected void addParameterObjectImpl(Object o) + { + arguments.add(o); + } + + protected Object createObject(Context outerContext) + throws AssemblyException + { + Object[] args = arguments.toArray(); + + try + { + Constructor constructor = MethodFinder.getConstructor(klass, args); + + // instantiates object (klass field gets re-set by superclass) + return constructor.newInstance(args); + } + catch (NoSuchMethodException nsme) + { + throw new AssemblyException(nsme); + } + catch (InvocationTargetException ite) + { + throw new AssemblyException(ite.getCause()); + } + catch (IllegalAccessException iae) + { + throw new AssemblyException(iae); + } + catch (InstantiationException ie) + { + throw new AssemblyException(ie); + } + } + +} diff --git a/libjava/classpath/gnu/java/beans/decoder/Context.java b/libjava/classpath/gnu/java/beans/decoder/Context.java new file mode 100644 index 000000000..4bdbc9ce5 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/Context.java @@ -0,0 +1,137 @@ +/* gnu.java.beans.decoder.Context + 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; + +/** A Context is the environment for an object which is being assembler. If there + * are no errors each handler creates one Context. + *

Depending on the result of isStatement() a Context can be statement or an + * expression. An expression returns a value to the Context of its parent handler, + * a statement does not. Whenever a Context is a statement the parent handler's + * Context is informed about that through the {@link notifyStatement}-method.

+ * + * @author Robert Schuster + */ +interface Context +{ + /** Adds a parameter object to the context. This method is used when + * sub-Contexts return their result. + * + * Some Contexts do not accept more than a certain amount of objects + * and throw an AssemblerException if the amount is exceeded. + * + * @param o The object added to this context. + */ + void addParameterObject(Object o) throws AssemblyException; + + /** Notifies that the next element is a statement. This can mean + * that an argument list is complete to be called. + * + */ + void notifyStatement(Context outerContext) throws AssemblyException; + + /** Notifies that the context ends and the returns the appropriate result + * object. + * + * @param outerContext + * @return + */ + Object endContext(Context outerContext) throws AssemblyException; + + /** Notifies that the assembly of a subcontext failed and returns + * whether this Context is affected in a way that it fails too. + * + * @return Whether the failure of a subcontext lets this context fail, too. + */ + boolean subContextFailed(); + + /** Calls an appropriate indexed set method if it is available or + * throws an AssemblerException if that is not allowed on this Context. + * + * The behaviour of this method is equal to List.set(int, Object). + * + * @param index Index position to be set. + * @param o Object to be set at the given index position. + * @throws AssemblerException Indexed set is not allowed or otherwise failed. + */ + void set(int index, Object o) throws AssemblyException; + + /** Calls an appropriate indexed get method if it is available or + * throws an AssemblerException if that is not allowed on this Context. + * + * The behaviour of this method is equal to List.get(int). + * + * @param index Index position of the object return. + * @throws AssemblerException Indexed get is not allowed or otherwise failed. + */ + Object get(int index) throws AssemblyException; + + /** Returns the result which was calculated by calling endContext() or reportStatement(). + * Its the handler's responsibility to care that any of these two methods was called. + * + * This is used by sub-Contexts to access this Context's result. + * + * @return + */ + Object getResult(); + + /** Gives this Context a unique id. For convenience the id may be null which means + * that no id exists at all. + * + * @param id + */ + void setId(String id); + + /** Returns this Context's unique id or null if does not have such an id. + * + * @return This Context's id or null. + */ + String getId(); + + /** Returns whether this Context is a statement (not returning result back + * to parent handler's Context) or not (= expression). + * + * @return + */ + boolean isStatement(); + + /** Sets whether this Context is a statement or not. + * + * @param b + */ + void setStatement(boolean b); +} diff --git a/libjava/classpath/gnu/java/beans/decoder/DecoderContext.java b/libjava/classpath/gnu/java/beans/decoder/DecoderContext.java new file mode 100644 index 000000000..174a3b71b --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/DecoderContext.java @@ -0,0 +1,124 @@ +/* gnu.java.beans.decoder.DecoderContext + 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.XMLDecoder; +import java.util.ArrayList; +import java.util.Iterator; + +/** DecoderContext is a Context implementation which allows access to + * the XMLDecoder instance itself. This is used for the <java> tag. + * + * @author Robert Schuster + */ +public class DecoderContext extends AbstractContext +{ + private XMLDecoder decoder; + + public DecoderContext(XMLDecoder xmlDecoder) + { + decoder = xmlDecoder; + } + + private ArrayList objects = new ArrayList(); + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#addObject(java.lang.Object) + */ + public void addParameterObject(Object o) throws AssemblyException + { + objects.add(o); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#reportStatement() + */ + public void notifyStatement(Context outerContext) throws AssemblyException + { + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#endContext(gnu.java.beans.decoder.Context) + */ + public Object endContext(Context outerContext) throws AssemblyException + { + return decoder; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#subContextFailed() + */ + public boolean subContextFailed() + { + return false; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#set(int, java.lang.Object) + */ + public void set(int index, Object o) throws AssemblyException + { + throw new AssemblyException(new IllegalArgumentException("Set method is not allowed in decoder context.")); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#get(int) + */ + public Object get(int index) throws AssemblyException + { + throw new AssemblyException(new IllegalArgumentException("Get method is not allowed in decoder context.")); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#getResult() + */ + public Object getResult() + { + return decoder; + } + + /** Returns an Iterator that retrieves the assembled objects. + * + * @return An Iterator retrieving assembled objects. + */ + public Iterator iterator() + { + return objects.iterator(); + } + +} diff --git a/libjava/classpath/gnu/java/beans/decoder/DoubleHandler.java b/libjava/classpath/gnu/java/beans/decoder/DoubleHandler.java new file mode 100644 index 000000000..1a14fbabf --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/DoubleHandler.java @@ -0,0 +1,59 @@ +/* gnu.java.beans.decoder.DoubleHandler + 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; + + +/** Creates a Double instance from the character data in a <double> tag. + * + * @author Robert Schuster + */ +class DoubleHandler extends SimpleHandler +{ + /** + * @param PersistenceParser + */ + DoubleHandler(ElementHandler parent) + { + super(parent); + } + + protected Object parse(String number) throws NumberFormatException + { + return Double.valueOf(number); + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/DummyContext.java b/libjava/classpath/gnu/java/beans/decoder/DummyContext.java new file mode 100644 index 000000000..03f209c8c --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/DummyContext.java @@ -0,0 +1,116 @@ +/* gnu.java.beans.decoder.DummyContext + 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; + +/** The DummyContext is used as the Context implementation for the DummyHandler. It + * just prevents having a null-reference. + * + *

When the implementation is correct none of this class' methods + * (except notifyStatement()) is called.

+ * + * @author Robert Schuster + */ +public class DummyContext extends AbstractContext +{ + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#addObject(java.lang.Object) + */ + public void addParameterObject(Object o) throws AssemblyException + { + fail(); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#reportStatement() + */ + public void notifyStatement(Context outerContext) throws AssemblyException + { + // intentionally ignored + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#endContext(gnu.java.beans.decoder.Context) + */ + public Object endContext(Context outerContext) throws AssemblyException + { + fail(); + return null; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#subContextFailed() + */ + public boolean subContextFailed() + { + fail(); + return false; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#set(int, java.lang.Object) + */ + public void set(int index, Object o) throws AssemblyException + { + fail(); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#get(int) + */ + public Object get(int index) throws AssemblyException + { + fail(); + return null; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#getResult() + */ + public Object getResult() + { + fail(); + return null; + } + + private void fail() + { + throw new InternalError("Invoking the DummyContext is not expected" + + " - Please file a bug report at" + + " http://www/gnu.org/software/classpath/."); + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/DummyHandler.java b/libjava/classpath/gnu/java/beans/decoder/DummyHandler.java new file mode 100644 index 000000000..f9c133e54 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/DummyHandler.java @@ -0,0 +1,156 @@ +/* gnu.java.beans.decoder.DummyHandler + 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; + +import org.xml.sax.Attributes; + +/** An ElementHandler implementation that is used as an artificial root + * element. This avoids having to check for a null element. + * + * @author Robert Schuster + */ +class DummyHandler implements ElementHandler +{ + /* (non-Javadoc) + * @see gnu.java.beans.decoder.ElementHandler#start(org.xml.sax.Attributes, java.beans.ExceptionListener) + */ + public void start( + Attributes attributes, + ExceptionListener exceptionListener) + { + fail(); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.ElementHandler#end(java.beans.ExceptionListener) + */ + public void end(ExceptionListener exceptionListener) + { + fail(); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.ElementHandler#characters(char[], int, int) + */ + public void characters(char[] ch, int start, int length) + { + fail(); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.ElementHandler#isSubelementAllowed(java.lang.String) + */ + public boolean isSubelementAllowed(String subElementName) + { + return true; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.ElementHandler#instantiateClass(java.lang.String) + */ + public Class instantiateClass(String className) + throws ClassNotFoundException + { + fail(); + return null; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.ElementHandler#reportStatement(java.beans.ExceptionListener) + */ + public void notifyStatement(ExceptionListener exceptionListener) + { + // ignore + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.ElementHandler#hasFailed() + */ + public boolean hasFailed() + { + return false; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.ElementHandler#getContext() + */ + public Context getContext() + { + return new DummyContext(); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.ElementHandler#contextFailed() + */ + public void notifyContextFailed() + { + fail(); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.ElementHandler#putObject(java.lang.String, java.lang.Object) + */ + public void putObject(String objectId, Object o) + { + fail(); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.ElementHandler#getObject(java.lang.String) + */ + public Object getObject(String objectId) + { + fail(); + return null; + } + + public ElementHandler getParent() + { + fail(); + return null; + } + + private void fail() + { + throw new InternalError("Invoking the DummyHandler is not expected" + + " - Please file a bug report at " + + " http://www.gnu.org/software/classpath/."); + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/ElementHandler.java b/libjava/classpath/gnu/java/beans/decoder/ElementHandler.java new file mode 100644 index 000000000..12e945bbf --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/ElementHandler.java @@ -0,0 +1,130 @@ +/* gnu.java.beans.decoder.ElementHandler + 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; + +import org.xml.sax.Attributes; + +/** ElementHandler manages a Context instance and interacts with + * its parent and child handlers. + * + * @author Robert Schuster + */ +interface ElementHandler +{ + /** Evaluates the attributes and creates a Context instance. + * If the creation of the Context instance fails the ElementHandler + * is marked as failed which may affect the parent handler other. + * + * @param attributes Attributes of the XML tag. + */ + void start(Attributes attributes, ExceptionListener exceptionListener); + + /** Post-processes the Context. + */ + void end(ExceptionListener exceptionListener); + + /** Adds characters from the body of the XML tag to the buffer. + * + * @param ch + * @param start + * @param length + * @throws SAXException + */ + void characters(char[] ch, int start, int length); + + /** Returns whether a subelement of the given name is allowed. The rules + * for evaluating this are derived from the javabeans.dtd which can be found + * here: Java Persistence Article. + * + * @param subElementName + * @return + */ + boolean isSubelementAllowed(String subElementName); + + /** Provides the same functionality as Class.forName() but allows the decoder + * to use a different class loader. + * + * @param className + * @return + * @throws ClassNotFoundException + */ + Class instantiateClass(String className) throws ClassNotFoundException; + + /** Notifies the handler's Context that its child Context will not return + * a value back. Some Context variants need this information to know when + * a method or a constructor call can be made. + * + * This method is called by a child handler. + */ + void notifyStatement(ExceptionListener exceptionListener); + + /** Returns whether this handler has failed. + * + * This is used to skip child elements. + * + * @return Whether this handler has failed. + */ + boolean hasFailed(); + + /** Returns the Context instance this handler is working on. + * + * @return The handler's Context instance. + */ + Context getContext(); + + /** Notifies the handler that its Context failed and starts a recursive + * invocation of the parent handler if it is affected by that failure. + * + * Although the method is a public API member it is only used internally. + */ + void notifyContextFailed(); + + /** Stores the object under the given id. The object is not stored if the + * id is null. + * + * @param objectId + * @param o + */ + void putObject(String objectId, Object o); + + Object getObject(String objectId) throws AssemblyException; + + ElementHandler getParent(); +} diff --git a/libjava/classpath/gnu/java/beans/decoder/FloatHandler.java b/libjava/classpath/gnu/java/beans/decoder/FloatHandler.java new file mode 100644 index 000000000..443f38f91 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/FloatHandler.java @@ -0,0 +1,59 @@ +/* gnu.java.beans.decoder.FloatHandler + 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; + + +/** Creates a Float instance from the character data in a <float> tag. + * + * @author Robert Schuster + */ +class FloatHandler extends SimpleHandler +{ + /** + * @param PersistenceParser + */ + FloatHandler(ElementHandler parent) + { + super(parent); + } + + protected Object parse(String number) throws NumberFormatException + { + return Float.valueOf(number); + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/GrowableArrayContext.java b/libjava/classpath/gnu/java/beans/decoder/GrowableArrayContext.java new file mode 100644 index 000000000..fb386d1d5 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/GrowableArrayContext.java @@ -0,0 +1,138 @@ +/* gnu.java.beans.decoder.GrowableArrayContext + 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.lang.reflect.Array; + +/** A Context implementation for a growable array. The array + * elements have to be set using expressions. + * + * @author Robert Schuster + */ +class GrowableArrayContext extends AbstractContext +{ + private static final int INITIAL_SIZE = 16; + + private Class klass; + private Object array; + private int length; + + GrowableArrayContext(String id, Class newClass) + { + setId(id); + klass = newClass; + array = Array.newInstance(klass, INITIAL_SIZE); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#addObject(java.lang.Object) + */ + public void addParameterObject(Object o) throws AssemblyException + { + if (length == Array.getLength(array)) + { + Object tmp = Array.newInstance(klass, length * 2); + System.arraycopy(array, 0, tmp, 0, length); + array = tmp; + } + + try { + Array.set(array, length++, o); + } catch(IllegalArgumentException iae) { + throw new AssemblyException(iae); + } + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#reportStatement() + */ + public void notifyStatement(Context outerContext) throws AssemblyException + { + throw new AssemblyException( + new IllegalArgumentException("Statements inside a growable array are not allowed.")); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#endContext(gnu.java.beans.decoder.Context) + */ + public Object endContext(Context outerContext) throws AssemblyException + { + if (length != Array.getLength(array)) + { + Object tmp = Array.newInstance(klass, length); + System.arraycopy(array, 0, tmp, 0, length); + array = tmp; + } + + return array; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#subContextFailed() + */ + public boolean subContextFailed() + { + // returns false to indicate that assembling the array does not fail only because + // a subelement failed + return false; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#set(int, java.lang.Object) + */ + public void set(int index, Object o) throws AssemblyException + { + try { + Array.set(array, index, o); + } catch(IllegalArgumentException iae) { + throw new AssemblyException(iae); + } + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#get(int) + */ + public Object get(int index) throws AssemblyException + { + return Array.get(array, index); + } + + public Object getResult() + { + return array; + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/IndexContext.java b/libjava/classpath/gnu/java/beans/decoder/IndexContext.java new file mode 100644 index 000000000..b5af9019f --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/IndexContext.java @@ -0,0 +1,130 @@ +/* gnu.java.beans.decoder.IndexContext + 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; + +/** IndexContext is Context implementation that senses whether it is an indexed get or set + * operation and invokes this operation. + * + *

An IndexContent is a get operation when no argument is provided and a set operation if one + * argument is provided.

+ * + * @author Robert Schuster + */ +class IndexContext extends AbstractContext +{ + private Object result; + private Object argument; + private int index; + private boolean isSetter; + + IndexContext(String id, int newIndex) + { + setId(id); + index = newIndex; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#addObject(java.lang.Object) + */ + public void addParameterObject(Object o) throws AssemblyException + { + if (! isSetter) + { + argument = o; + isSetter = true; + } + else + throw new AssemblyException(new IllegalStateException("More than one argument for indiced access is not possible.")); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#reportStatement() + */ + public void notifyStatement(Context outerContext) throws AssemblyException + { + throw new AssemblyException(new IllegalStateException("Statements inside indiced access are not allowed.")); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#endContext(gnu.java.beans.decoder.Context) + */ + public Object endContext(Context outerContext) throws AssemblyException + { + if (isSetter) + { + // setter + outerContext.set(index, argument); + + return null; + } + else + // getter + return result = outerContext.get(index); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#subContextFailed() + */ + public boolean subContextFailed() + { + // returns true to indicate that indiced access assembly fails when one of its + // argument could not be assembled + return true; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#set(int, java.lang.Object) + */ + public void set(int index, Object o) throws AssemblyException + { + throw new AssemblyException(new IllegalStateException("Setter is not allowed inside indiced access.")); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#get(int) + */ + public Object get(int index) throws AssemblyException + { + throw new AssemblyException(new IllegalStateException("getter is not allowed insided indiced access.")); + } + + public Object getResult() + { + return result; + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/IntHandler.java b/libjava/classpath/gnu/java/beans/decoder/IntHandler.java new file mode 100644 index 000000000..bbd3560d7 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/IntHandler.java @@ -0,0 +1,59 @@ +/* gnu.java.beans.decoder.IntHandler + 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; + + +/** Creates a Integer instance from the character data in a <int> tag. + * + * @author Robert Schuster + */ +class IntHandler extends SimpleHandler +{ + /** + * @param PersistenceParser + */ + IntHandler(ElementHandler parent) + { + super(parent); + } + + protected Object parse(String number) throws NumberFormatException + { + return Integer.valueOf(number); + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/JavaHandler.java b/libjava/classpath/gnu/java/beans/decoder/JavaHandler.java new file mode 100644 index 000000000..c4b4f92c5 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/JavaHandler.java @@ -0,0 +1,93 @@ +/* gnu.java.beans.decoder.JavaHandler + 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; +import java.util.HashMap; + +import org.xml.sax.Attributes; + +/** Wraps a DecoderContext instance. + * + * @author Robert Schuster + */ +public class JavaHandler extends AbstractElementHandler +{ + private Context context; + private HashMap objectMap = new HashMap(); + private ClassLoader classLoader; + + /** + * @param PersistenceParser + */ + JavaHandler(DummyHandler parent, Context decoderContext, + ClassLoader cl) + { + super(parent, true); + + classLoader = cl; + + context = decoderContext; + + } + + protected Context startElement(Attributes attributes, ExceptionListener exceptionListener) + throws AssemblyException + { + // may expect version and class attribute but it not used in JDK + // so we do either + return context; + } + + public Object getObject(String objectId) + { + return objectMap.get(objectId); + } + + public void putObject(String objectId, Object o) + { + if (objectId != null) + objectMap.put(objectId, o); + } + + public Class instantiateClass(String className) + throws ClassNotFoundException + { + return Class.forName(className, false, classLoader); + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/LongHandler.java b/libjava/classpath/gnu/java/beans/decoder/LongHandler.java new file mode 100644 index 000000000..13e0a8dde --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/LongHandler.java @@ -0,0 +1,59 @@ +/* gnu.java.beans.decoder.LongHandler + 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; + + +/** Creates a Long instance from the character data in a <long> tag. + * + * @author Robert Schuster + */ +class LongHandler extends SimpleHandler +{ + /** + * @param PersistenceParser + */ + LongHandler(ElementHandler parent) + { + super(parent); + } + + protected Object parse(String number) throws NumberFormatException + { + return Long.valueOf(number); + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/MethodContext.java b/libjava/classpath/gnu/java/beans/decoder/MethodContext.java new file mode 100644 index 000000000..84eead7a0 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/MethodContext.java @@ -0,0 +1,107 @@ +/* gnu.java.beans.decoder.MethodContext + 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.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; + +/** MethodContext collects arguments for a method call and creates the result object + * using it. The method is called using the result object of the parent Context. + * + *

When the result object is available methods can be called on it using sub-Contexts.

+ * + * @author Robert Schuster + */ +class MethodContext extends AbstractCreatableObjectContext +{ + private ArrayList arguments = new ArrayList(); + private String methodName; + + MethodContext(String id, String newMethodName) + { + setId(id); + setStatement(true); + methodName = newMethodName; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#addObject(java.lang.Object) + */ + public void addParameterObjectImpl(Object o) + { + arguments.add(o); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#endContext(gnu.java.beans.decoder.Context) + */ + protected Object createObject(Context outerContext) + throws AssemblyException + { + Object outerObject = outerContext.getResult(); + + if (outerObject == null) + throw new AssemblyException( + new NullPointerException( + "No object to invoke method " + methodName)); + + Object[] args = arguments.toArray(); + + try + { + Method method = + MethodFinder.getMethod( + outerObject.getClass(), + methodName, + args); + return method.invoke(outerObject, args); + } + catch (NoSuchMethodException nsme) + { + throw new AssemblyException(nsme); + } + catch (InvocationTargetException ite) + { + throw new AssemblyException(ite.getCause()); + } + catch (IllegalAccessException iae) + { + throw new AssemblyException(iae); + } + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/MethodFinder.java b/libjava/classpath/gnu/java/beans/decoder/MethodFinder.java new file mode 100644 index 000000000..82783fbde --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/MethodFinder.java @@ -0,0 +1,177 @@ +/* gnu.java.beans.decoder.MethodFinder + 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.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.HashMap; + +class MethodFinder +{ + /** Provides a mapping between a wrapper class and its corresponding primitive's type. */ + private static HashMap typeMapping = new HashMap(); + + static { + typeMapping.put(Byte.class, Byte.TYPE); + typeMapping.put(Short.class, Short.TYPE); + typeMapping.put(Integer.class, Integer.TYPE); + typeMapping.put(Long.class, Long.TYPE); + typeMapping.put(Float.class, Float.TYPE); + typeMapping.put(Double.class, Double.TYPE); + + typeMapping.put(Character.class, Character.TYPE); + typeMapping.put(Boolean.class, Boolean.TYPE); + } + + private MethodFinder() + { + } + + /** Searches a Method which can accept the given arguments. + * + * @param klass + * @param name + * @param arguments + * @return + * @throws NoSuchMethodException + */ + static Method getMethod(Class klass, String name, Object[] arguments) + throws NoSuchMethodException + { + // prepares array containing the types of the arguments + Class[] argumentTypes = getArgumentTypes(arguments); + + Method[] methods = klass.getMethods(); + + // iterates over all public methods + for (int i = 0; i < methods.length; i++) + { + if (methods[i].getName().equals(name)) + { + if (matchingArgumentTypes(methods[i].getParameterTypes(), + argumentTypes)) + return methods[i]; + } + } + + throw new NoSuchMethodException( + "Could not find a matching method named " + + name + + "() in class " + + klass); + } + + static Constructor getConstructor(Class klass, Object[] arguments) + throws NoSuchMethodException + { + Class[] argumentTypes = getArgumentTypes(arguments); + Constructor[] constructors = klass.getConstructors(); + + // iterates over all public methods + for (int i = 0; i < constructors.length; i++) + { + if (matchingArgumentTypes(constructors[i].getParameterTypes(), + argumentTypes)) + return constructors[i]; + } + + throw new NoSuchMethodException( + "Could not find a matching constructor in class " + klass); + } + + /** Transforms an array of argument objects into an array of argument types. + * For each argument being null the argument is null, too. An argument type + * being null means: Accepts everything (although this can be ambigous). + * + * @param arguments + * @return + */ + private static Class[] getArgumentTypes(Object[] arguments) + { + if (arguments == null) + return new Class[0]; + + // prepares array containing the types of the arguments + Class[] argumentTypes = new Class[arguments.length]; + for (int i = 0; i < arguments.length; i++) + argumentTypes[i] = + (arguments[i] == null) ? null : arguments[i].getClass(); + return argumentTypes; + } + + /** Tests whether the argument types supplied to the method argument types + * are assignable. In addition to the assignment specifications this method + * handles the primitive's wrapper classes as if they were of their + * primitive type (e.g Boolean.class equals Boolean.TYPE). + * When a supplied argument type is null it is assumed that no argument + * object was supplied for it and the test for this particular parameter will + * pass. + * + * @param methodArgTypes + * @param suppliedArgTypes + * @return + */ + private static boolean matchingArgumentTypes( + Class[] methodArgTypes, + Class[] suppliedArgTypes) + { + if (methodArgTypes.length != suppliedArgTypes.length) + return false; + + for (int i = 0; i < methodArgTypes.length; i++) + { + if (suppliedArgTypes[i] == null) + { + // by definition a non-existant argument type (null) can be converted to everything + continue; + } + else if (typeMapping.containsKey(suppliedArgTypes[i])) + { + Class primitiveType = + (Class) typeMapping.get(suppliedArgTypes[i]); + if (!(methodArgTypes[i].isAssignableFrom(suppliedArgTypes[i]) + || methodArgTypes[i].isAssignableFrom(primitiveType))) + return false; + } + else if (!methodArgTypes[i].isAssignableFrom(suppliedArgTypes[i])) + return false; + } + + return true; + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/NullHandler.java b/libjava/classpath/gnu/java/beans/decoder/NullHandler.java new file mode 100644 index 000000000..01c9727d4 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/NullHandler.java @@ -0,0 +1,62 @@ +/* gnu.java.beans.decoder.NullHandler + 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; + + +/** Just provides the 'null' object. + * + * @author Robert Schuster + */ +class NullHandler extends SimpleHandler +{ + /** + * @param PersistenceParser + */ + NullHandler(ElementHandler parent) + { + super(parent); + } + + protected Object parse(String characters) throws AssemblyException + { + if (! characters.equals("")) + throw new AssemblyException(new IllegalArgumentException("No characters inside tag allowed.")); + + return null; + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/ObjectContext.java b/libjava/classpath/gnu/java/beans/decoder/ObjectContext.java new file mode 100644 index 000000000..883c1d600 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/ObjectContext.java @@ -0,0 +1,100 @@ +/* gnu.java.beans.decoder.ObjectHandler + 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; + +/** ObjectContext is a {@link Context} implementation that wraps a simple Object instance. + * The instance can be provided when the Context is created (due to an 'idref' + * attribute) or later (eg. <int> tag) + * + *

The ObjectContext does not accept any parameter object and ignores notifications + * about sub-contexts being statements.

+ * + * @author Robert Schuster + */ +final class ObjectContext extends AbstractObjectContext +{ + ObjectContext(Object newObject) + { + setObject(newObject); + } + + ObjectContext(String id, Object newObject) + { + setId(id); + setObject(newObject); + } + + ObjectContext() + { + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#addObject(java.lang.Object) + */ + public void addParameterObject(Object o) throws AssemblyException + { + throw new AssemblyException(new IllegalArgumentException("Adding objects to an ObjectContext is not allowed.")); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#reportStatement() + */ + public void notifyStatement(Context outerContext) throws AssemblyException + { + // can ignore that + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#endContext(gnu.java.beans.decoder.Context) + */ + public Object endContext(Context outerContext) throws AssemblyException + { + // just returns the object which is encapsuled (may be null) + return getResult(); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#subContextFailed() + */ + public boolean subContextFailed() + { + // this context will not fail when a subcontext fails because the result is + // already available when the context is created. + return false; + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/ObjectHandler.java b/libjava/classpath/gnu/java/beans/decoder/ObjectHandler.java new file mode 100644 index 000000000..ececfbbe2 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/ObjectHandler.java @@ -0,0 +1,169 @@ +/* gnu.java.beans.decoder.ObjectHandler + 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; + +import org.xml.sax.Attributes; + +/** An ObjectHandler parses the <object> tag and thereby creates various + * Context implementations. + * + * @author Robert Schuster + * + */ +public class ObjectHandler extends AbstractElementHandler +{ + /** + * XXX: Can all results be stored with an object id? + * + * + * @param PersistenceParser + */ + ObjectHandler(ElementHandler parent) + { + super(parent, true); + } + + protected Context startElement(Attributes attributes, ExceptionListener exceptionListener) + throws AssemblyException + { + String className = attributes.getValue("class"); + String methodName = attributes.getValue("method"); + String fieldName = attributes.getValue("field"); + String index = attributes.getValue("index"); + String propertyName = attributes.getValue("property"); + String id = attributes.getValue("id"); + String idRef = attributes.getValue("idref"); + + /* first check if we just want to access an existing object (idref present) + * + * note: is not valid to call method "bar" + * on the object with id "foo". Instead this should return the object "foo" + * itself. The right way to this is: + * + * + * + * + * This means that if idref is present class, method, field, index and + * property are obsolete. + */ + if (idRef != null) + // reactivates an existing object and giving it another name if id exists + return new ObjectContext(id, getObject(idRef)); + + // decides whether we are in a static (className present) or dynamic context + if (className != null) + { + try + { + Class klass = instantiateClass(className); + + // class name exists which means that we are in a static context. + // so we may want to ... + // access a static field if the fieldName exists + if (fieldName != null) + { + try + { + return new ObjectContext(id, + klass.getField(fieldName).get(null)); + } + catch (NoSuchFieldException nsfe) + { + throw new AssemblyException(nsfe); + } + catch (IllegalAccessException iae) + { + throw new AssemblyException(iae); + } + } + + // (falling through is important!) + // run a constructor if methodName is "new" or null + if (methodName == null || methodName.equals("new")) + return new ConstructorContext(id, klass); + + // (falling through is important!) + // run a static method on the given class (if methodName exists, which is implied already) + return new StaticMethodContext(id, klass, methodName); + // XXX: should fail if unexpected attributes are present? + } + catch (ClassNotFoundException cnfe) + { + throw new AssemblyException(cnfe); + } + } + else + { + // className does not exist which means we are in the context of + // some object and want to ... + // access the get(int index) method if index != null + if (index != null) + { + try + { + // Note: http://java.sun.com/products/jfc/tsc/articles/persistence3/ says + // that will make up a get()-call. But this is wrong because + // tags never return values (to the surrounding context) + return new IndexContext(id, Integer.parseInt(index)); + } + catch (NumberFormatException nfe) + { + throw new AssemblyException(nfe); + } + } + + // access a method if methodName exists + if (methodName != null) + return new MethodContext(id, methodName); + + // (falling through is important!) + // access a property if a propertyName exists + if (propertyName != null && propertyName.length() > 0) + // this is reported as an ordinary method access where the propertyName is + // converted into a 'getter'-method name: convert first character of property name + // to upper case and prepend 'get' + // Note: This will be a getter-method because the tag implies that a return + // value is expected. + return new PropertyContext(id, propertyName); + } + + throw new AssemblyException(new IllegalArgumentException("Wrong or missing attributes for tag.")); + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/PersistenceParser.java b/libjava/classpath/gnu/java/beans/decoder/PersistenceParser.java new file mode 100644 index 000000000..c4c8866c3 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/PersistenceParser.java @@ -0,0 +1,485 @@ +/* gnu.java.beans.PersistenceParser + Copyright (C) 2004, 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.java.beans.decoder; + +import java.beans.ExceptionListener; +import java.beans.XMLDecoder; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import javax.xml.parsers.ParserConfigurationException; +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; + +/** The PersistenceParser parses an XML data stream and delegates actions to ElementHandler + * instances. The parser catches and recovers from all exception which reside from wrong usage + * of attributes and tags. + * + * @author Robert Schuster + */ +public class PersistenceParser extends DefaultHandler implements Context +{ + /** The ExceptionListener instance which is informed of non-critical parsing exceptions. + */ + private ExceptionListener exceptionListener; + + /** When an element was not usable all elements inside it should be skipped. + * This is done by skipping startElement() and endElement() invocations whenever + * this value is above 0. + */ + private int skipElement; + + /** Stores the Creator instances which can instantiate the appropriate handler implementation + * for a given element. + */ + private HashMap handlerCreators = new HashMap(); + + /** Denotes the current ElementHandler. To avoid checking for null-values it is pre-assigned + * with a DummyHandler instance which must not be used but acts as a root element. + */ + private ElementHandler currentHandler; + + /** The real root element that stores all objects created during parsing. + * Package-private to avoid an accessor method. + */ + JavaHandler javaHandler; + + /** Stores the decoded objects. */ + private List objects = new LinkedList(); + + /** The XMLDecoder instance that started this PersistenceParser */ + private XMLDecoder decoder; + + /** Creates a PersistenceParser which reads XML data from the given InputStream, reports + * exceptions to ExceptionListener instance, stores resulting object in the DecoderContext + * and uses the given ClassLoader to resolve classes. + * + * @param inputStream + * @param exceptionListener + * @param decoderContext + * @param cl + */ + public PersistenceParser( + InputStream inputStream, + ExceptionListener exceptionListener, + ClassLoader cl, + XMLDecoder decoder) + { + + this.exceptionListener = exceptionListener; + this.decoder = decoder; + + DummyHandler dummyHandler = new DummyHandler(); + currentHandler = dummyHandler; + javaHandler = new JavaHandler(dummyHandler, this, cl); + + SAXParserFactory factory = SAXParserFactory.newInstance(); + + SAXParser parser; + try + { + parser = factory.newSAXParser(); + } + catch (ParserConfigurationException pce) + { + // should not happen when a parser is available because we did + // not request any requirements on the XML parser + throw (InternalError) new InternalError( + "No SAX Parser available.").initCause( + pce); + } + catch (SAXException saxe) + { + // should not happen when a parser is available because we did + // not request any requirements on the XML parser + throw (InternalError) new InternalError( + "No SAX Parser available.").initCause( + saxe); + } + + // prepares a map of Creator instances which can instantiate a handler which is + // appropriate for the tag that is used as a key for the Creator + handlerCreators.put("java", new JavaHandlerCreator()); + + // calls methods (properties), constructors, access fields + handlerCreators.put("object", new ObjectHandlerCreator()); + handlerCreators.put("void", new VoidHandlerCreator()); + + handlerCreators.put("array", new ArrayHandlerCreator()); + + // these handler directly create an Object (or null) + handlerCreators.put("class", new ClassHandlerCreator()); + handlerCreators.put("null", new NullHandlerCreator()); + + handlerCreators.put("char", new CharHandlerCreator()); + handlerCreators.put("string", new StringHandlerCreator()); + handlerCreators.put("boolean", new BooleanHandlerCreator()); + handlerCreators.put("byte", new ByteHandlerCreator()); + handlerCreators.put("short", new ShortHandlerCreator()); + handlerCreators.put("int", new IntHandlerCreator()); + handlerCreators.put("long", new LongHandlerCreator()); + handlerCreators.put("float", new FloatHandlerCreator()); + handlerCreators.put("double", new DoubleHandlerCreator()); + + // parses the data and sends all exceptions to the ExceptionListener + try + { + parser.parse(inputStream, this); + } + catch (SAXException saxe) + { + exceptionListener.exceptionThrown( + new IllegalArgumentException("XML data not well-formed.")); + } + catch (IOException ioe) + { + exceptionListener.exceptionThrown(ioe); + } + } + + public void startElement( + String uri, + String localName, + String qName, + Attributes attributes) + throws SAXException + { + /* The element is skipped if + * a) the current handler has already failed or a previous error occured + * which makes all children obsolete + */ + if (currentHandler.hasFailed() || skipElement > 0) + { + exceptionListener.exceptionThrown( + new IllegalArgumentException( + "Element unusable due to previous error: " + qName)); + + skipElement++; + + return; + } + + /* b) Subelements are not allowed within the current ElementHandler. + */ + if (!currentHandler.isSubelementAllowed(qName)) + { + exceptionListener.exceptionThrown( + new IllegalArgumentException( + "Element is not allowed here: " + qName)); + + skipElement++; + + return; + } + + /* c) The tag name is not a key in the map of Creator instances. This means that + * either the XML data is of a newer version or simply contains a miss-spelled element. + */ + if (!handlerCreators.containsKey(qName)) + { + exceptionListener.exceptionThrown( + new IllegalArgumentException( + "Element unusable because tag is unknown: " + qName)); + + skipElement++; + + return; + } + + // creates a new handler for the new element + AbstractElementHandler handler = + ((Creator) handlerCreators.get(qName)).createHandler( + currentHandler); + + // makes it the current handler to receive character data + currentHandler = handler; + + // starts the handler + currentHandler.start(attributes, exceptionListener); + } + + public void endElement(String uri, String localName, String qName) + throws SAXException + { + // skips processing the current handler if we are parsing an element + // which was marked invalid (in startElement() ) + if (skipElement > 0) + { + skipElement--; + return; + } + + // invokes the handler's finishing method + currentHandler.end(exceptionListener); + + // removes the current handler and reactivates its parent + currentHandler = currentHandler.getParent(); + } + + /** Transfers character data to the current handler + */ + public void characters(char[] ch, int start, int length) + throws SAXException + { + // prevents sending character data of invalid elements + if (skipElement > 0) + return; + + currentHandler.characters(ch, start, length); + } + + /** Creator interface provided a mechanism to instantiate ElementHandler instances + * for the appropriate tag. + * + * @author Robert Schuster + */ + interface Creator + { + /** Creates an ElementHandler instance using the given ElementHandler as its parent. + * + * @param parent The parent ElementHandler of the result. + * @return A new ElementHandler instance. + */ + AbstractElementHandler createHandler(ElementHandler parent); + } + + class BooleanHandlerCreator implements Creator + { + public AbstractElementHandler createHandler(ElementHandler parent) + { + return new BooleanHandler(parent); + } + } + + class ByteHandlerCreator implements Creator + { + public AbstractElementHandler createHandler(ElementHandler parent) + { + return new ByteHandler(parent); + } + } + + class ShortHandlerCreator implements Creator + { + public AbstractElementHandler createHandler(ElementHandler parent) + { + return new ShortHandler(parent); + } + } + + class IntHandlerCreator implements Creator + { + public AbstractElementHandler createHandler(ElementHandler parent) + { + return new IntHandler(parent); + } + } + + class LongHandlerCreator implements Creator + { + public AbstractElementHandler createHandler(ElementHandler parent) + { + return new LongHandler(parent); + } + } + + class FloatHandlerCreator implements Creator + { + public AbstractElementHandler createHandler(ElementHandler parent) + { + return new FloatHandler(parent); + } + } + + class DoubleHandlerCreator implements Creator + { + public AbstractElementHandler createHandler(ElementHandler parent) + { + return new DoubleHandler(parent); + } + } + + class CharHandlerCreator implements Creator + { + public AbstractElementHandler createHandler(ElementHandler parent) + { + return new CharHandler(parent); + } + } + + class StringHandlerCreator implements Creator + { + public AbstractElementHandler createHandler(ElementHandler parent) + { + return new StringHandler(parent); + } + } + + class JavaHandlerCreator implements Creator + { + public AbstractElementHandler createHandler(ElementHandler parent) + { + return javaHandler; + } + } + + class ObjectHandlerCreator implements Creator + { + public AbstractElementHandler createHandler(ElementHandler parent) + { + return new ObjectHandler(parent); + } + } + + class VoidHandlerCreator implements Creator + { + public AbstractElementHandler createHandler(ElementHandler parent) + { + return new VoidHandler(parent); + } + } + + class ClassHandlerCreator implements Creator + { + public AbstractElementHandler createHandler(ElementHandler parent) + { + return new ClassHandler(parent); + } + } + + class NullHandlerCreator implements Creator + { + public AbstractElementHandler createHandler(ElementHandler parent) + { + return new NullHandler(parent); + } + } + + class ArrayHandlerCreator implements Creator + { + public AbstractElementHandler createHandler(ElementHandler parent) + { + return new ArrayHandler(parent); + } + } + + /** Adds a decoded object to the Context. */ + public void addParameterObject(Object o) throws AssemblyException + { + objects.add(o); + } + + public void notifyStatement(Context outerContext) throws AssemblyException + { + // can be ignored because theis Context does not react to statement and expressions + // differently + } + + public Object endContext(Context outerContext) throws AssemblyException + { + return null; + } + + public boolean subContextFailed() + { + // failing of subcontexts is no problem for the mother of all contexts + return false; + } + + public void set(int index, Object o) throws AssemblyException + { + // not supported + throw new AssemblyException( + new IllegalArgumentException("Set method is not allowed in decoder context.")); + } + + public Object get(int index) throws AssemblyException + { + // not supported + throw new AssemblyException( + new IllegalArgumentException("Get method is not allowed in decoder context.")); + } + + public Object getResult() + { + // returns the XMLDecoder instance which is requested by child contexts this way. + // That is needed to invoke methods on the decoder. + return decoder; + } + + public void setId(String id) + { + exceptionListener.exceptionThrown(new IllegalArgumentException("id attribute is not allowed for tag.")); + } + + public String getId() + { + // appears to have no id + return null; + } + + public boolean isStatement() + { + // this context is a statement by definition because it never returns anything to a parent because + // there is no such parent (DummyContext does not count!) + return true; + } + + public void setStatement(boolean b) + { + // ignores that because this Context is always a statement + } + + /** Returns an Iterator instance which returns the decoded objects. + * + * This method is used by the XMLDecoder directly. + */ + public Iterator iterator() + { + return objects.iterator(); + } + +} diff --git a/libjava/classpath/gnu/java/beans/decoder/PropertyContext.java b/libjava/classpath/gnu/java/beans/decoder/PropertyContext.java new file mode 100644 index 000000000..15751cdbc --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/PropertyContext.java @@ -0,0 +1,137 @@ +/* gnu.java.beans.decoder.PropertyContext + 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.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** PropertyContext is a Context implementation that is very similar to MethodContext + * and IndexContext. The sole purpose of PropertyContext to find out whether it should + * 'set' or 'get' a certain property. This decision is made using the number of + * arguments. + *

When the method call has to be made and there is no argument we 'get' the property. + * With one argument it is 'set'.

+ * + * @author Robert Schuster + */ +class PropertyContext extends AbstractObjectContext +{ + private Object argument; + private String propertyName; + private String prefix = "get"; + private boolean methodCalled; + + PropertyContext(String id, String newPropertyName) + { + setId(id); + propertyName = newPropertyName; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#addObject(java.lang.Object) + */ + public void addParameterObject(Object o) throws AssemblyException + { + if (methodCalled) + throw new AssemblyException(new IllegalArgumentException("Cannot add parameter object when method was already called.")); + + if (argument != null) + throw new AssemblyException(new IllegalArgumentException("Property attribut allows zero or one argument only.")); + + argument = o; + setStatement(true); + prefix = "set"; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#endContext(gnu.java.beans.decoder.Context) + */ + public void notifyStatement(Context outerContext) throws AssemblyException + { + if (methodCalled) + return; + methodCalled = true; + + Object outerObject = outerContext.getResult(); + + if (outerObject == null) + throw new AssemblyException(new NullPointerException("No object to access property " + + propertyName)); + + + // converts property name into a method name + String methodName = prefix + propertyName.substring(0, 1).toUpperCase() + + propertyName.substring(1); + + // prepares the argument + Object[] args = (argument != null) ? new Object[] { argument } : null; + + try + { + Method method = MethodFinder.getMethod(outerObject.getClass(), + methodName, args); + + // stores the result whether it is available or not + setObject(method.invoke(outerObject, args)); + } + catch (NoSuchMethodException nsme) + { + throw new AssemblyException(nsme); + } + catch (InvocationTargetException ite) + { + throw new AssemblyException(ite.getCause()); + } + catch (IllegalAccessException iae) + { + throw new AssemblyException(iae); + } + } + + public Object endContext(Context outerContext) throws AssemblyException + { + notifyStatement(outerContext); + + return getResult(); + } + + public boolean subContextFailed() + { + return ! methodCalled; + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/ShortHandler.java b/libjava/classpath/gnu/java/beans/decoder/ShortHandler.java new file mode 100644 index 000000000..c5de50ab9 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/ShortHandler.java @@ -0,0 +1,58 @@ +/* gnu.java.beans.decoder.ShortHandler + 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; + +/** Creates a Short instance from the character data in a <short> tag. + * + * @author Robert Schuster + */ +class ShortHandler extends SimpleHandler +{ + /** + * @param PersistenceParser + */ + ShortHandler(ElementHandler parent) + { + super(parent); + } + + protected Object parse(String number) throws NumberFormatException + { + return Short.valueOf(number); + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/SimpleHandler.java b/libjava/classpath/gnu/java/beans/decoder/SimpleHandler.java new file mode 100644 index 000000000..1c43bb0c7 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/SimpleHandler.java @@ -0,0 +1,111 @@ +/* gnu.java.beans.decoder.SimpleHandler + 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; + +import org.xml.sax.Attributes; + +/** XML element handler that is specialized on tags that contains a simple string in their + * body which has to be parsed in a specific way. + *

All of these tags have in common that they do not accept attributes. A warning is + * send to the parser's ExceptionListener when one or more attributes exist.

+ * + * @author Robert Schuster + */ +abstract class SimpleHandler extends AbstractElementHandler +{ + private ObjectContext context; + + /** + * @param PersistenceParser + */ + SimpleHandler(ElementHandler parent) + { + super(parent, false); + + // SimpleHandler do not accept any subelements + } + + protected final Context startElement(Attributes attributes, ExceptionListener exceptionListener) + throws AssemblyException + { + + // note: simple elements should not have any attributes. We inform + // the user of this syntactical but uncritical problem by sending + // an IllegalArgumentException for each unneccessary attribute + int size = attributes.getLength(); + for (int i = 0; i < size; i++) { + String attributeName = attributes.getQName(i); + Exception e = + new IllegalArgumentException( + "Unneccessary attribute '" + + attributeName + + "' discarded."); + exceptionListener.exceptionThrown(e); + } + + return context = new ObjectContext(); + } + + public void endElement(String characters) + throws AssemblyException, AssemblyException + { + // reports the number when the character data can be parsed + try + { + context.setObject(parse(characters)); + } + catch (NumberFormatException nfe) + { + throw new AssemblyException(nfe); + } + } + + /** Returns an object that is created from the given characters. If the string is + * converted into a number a NumberFormatException is cathed and reported + * appropriately. + * + * @param characters A string of characters that has to be processed in some way. + * @return An Object instance generated from the given data. + * @throws AssemblerException When the string was invalid. + * @throws NumberFormatException When the string could not be parsed into a number. + */ + protected abstract Object parse(String characters) + throws AssemblyException, NumberFormatException; +} diff --git a/libjava/classpath/gnu/java/beans/decoder/StaticMethodContext.java b/libjava/classpath/gnu/java/beans/decoder/StaticMethodContext.java new file mode 100644 index 000000000..b2cf0e602 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/StaticMethodContext.java @@ -0,0 +1,95 @@ +/* gnu.java.beans.decoder.StaticMethodContext + 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.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; + +/** + * @author Robert Schuster + */ +class StaticMethodContext extends AbstractCreatableObjectContext +{ + private ArrayList arguments = new ArrayList(); + private Class klass; + private String methodName; + + StaticMethodContext(String id, Class newClass, String newMethodName) + { + setId(id); + klass = newClass; + methodName = newMethodName; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#addObject(java.lang.Object) + */ + public void addParameterObjectImpl(Object o) + { + arguments.add(o); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#endContext(gnu.java.beans.decoder.Context) + */ + protected Object createObject(Context outerContext) + throws AssemblyException + { + Object[] args = arguments.toArray(); + + try + { + Method method = MethodFinder.getMethod(klass, methodName, args); + return method.invoke(null, args); + } + catch (NoSuchMethodException nsme) + { + throw new AssemblyException(nsme); + } + catch (InvocationTargetException ite) + { + // rethrows the reason for the InvocationTargetsException (ie. the exception in the called code) + throw new AssemblyException(ite.getCause()); + } + catch (IllegalAccessException iae) + { + throw new AssemblyException(iae); + } + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/StringHandler.java b/libjava/classpath/gnu/java/beans/decoder/StringHandler.java new file mode 100644 index 000000000..97fc57efd --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/StringHandler.java @@ -0,0 +1,54 @@ +/* gnu.java.beans.decoder.StringHandler + 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; + +class StringHandler extends SimpleHandler +{ + /** + * @param PersistenceParser + */ + StringHandler(ElementHandler parent) + { + super(parent); + } + + protected Object parse(String characters) + { + return characters; + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/VoidHandler.java b/libjava/classpath/gnu/java/beans/decoder/VoidHandler.java new file mode 100644 index 000000000..56f315639 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/VoidHandler.java @@ -0,0 +1,140 @@ +/* gnu.java.beans.decoder.VoidHandler + 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; + +import org.xml.sax.Attributes; + +public class VoidHandler extends AbstractElementHandler +{ + /** + * @param PersistenceParser + */ + VoidHandler(ElementHandler parent) + { + super(parent, true); + } + + protected Context startElement( + Attributes attributes, + ExceptionListener exceptionListener) + throws AssemblyException + { + Context ctx = startElementImpl(attributes); + ctx.setStatement(true); + + return ctx; + } + + private Context startElementImpl(Attributes attributes) + throws AssemblyException + { + String id = attributes.getValue("id"); + String className = attributes.getValue("class"); + String methodName = attributes.getValue("method"); + String propertyName = attributes.getValue("property"); + String index = attributes.getValue("index"); + + if (className != null) + { + try + { + Class klass = instantiateClass(className); + + // class name exists which means that we are in a static context. + // so we may want to ... + // run a constructor if methodName is "new" or null + if (methodName == null || methodName.equals("new")) + // if the id is null the result cannot be by the decoder accessed but the + // constructor may have side effects (e.g. registering itself in a global registry) + return new ConstructorContext(id, klass); + + // (falling through is important!) + // run a static method on the given class (if methodName exists, which is implied already) + return new StaticMethodContext(id, klass, methodName); + } + catch (ClassNotFoundException cnfe) + { + throw new AssemblyException(cnfe); + } + } + else + { + // className does not exist which means we are in the context of + // some object and want to ... + // access an element by index + if (index != null) + { + // note: whether this resolves into get(i) or set(i, o) depends on the + // number of arguments and is decided by the ObjectAssembler + try + { + return new IndexContext(id, Integer.parseInt(index)); + } + catch (NumberFormatException nfe) + { + throw new AssemblyException(nfe); + } + } + + // access a method if methodName exists + if (methodName != null) + return new MethodContext(id, methodName); + + // (falling through is important!) + // access a property if a propertyName exists + if (propertyName != null && propertyName.length() > 0) + // this is reported as an ordinary method invocation where the propertyName is + // converted into a 'setter'-method name: convert first character of property name + // to upper case and prepend 'set' + // Note: This will be a setter-method because the tag implies that no return + // value is expected (but a side effect) + return new PropertyContext(id, propertyName); + } + + // if code reaches this point the tag has wrong attributes. The following test + // does not make it better but can provide are more specific error message for + // a common mistake: tags are not allowed to have an idref attribute + throw new AssemblyException( + new IllegalArgumentException( + (attributes.getValue("idref") == null) + ? "Missing attributes for tag" + : " does not support 'idref' attribute.")); + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/package.html b/libjava/classpath/gnu/java/beans/decoder/package.html new file mode 100644 index 000000000..8fe65eeed --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.beans.decoder + + +

+ + + diff --git a/libjava/classpath/gnu/java/beans/editors/ColorEditor.java b/libjava/classpath/gnu/java/beans/editors/ColorEditor.java new file mode 100644 index 000000000..cb69344cb --- /dev/null +++ b/libjava/classpath/gnu/java/beans/editors/ColorEditor.java @@ -0,0 +1,100 @@ +/* gnu.java.beans.editors.ColorEditor + Copyright (C) 1998 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.editors; + +import java.awt.Color; +import java.beans.PropertyEditorSupport; + +/** + ** NativeByteEditor is a property editor for the + ** byte type. + ** + ** @author John Keiser + ** @version 1.1.0, 29 Jul 1998 + **/ + +public class ColorEditor extends PropertyEditorSupport { + Color[] stdColors = {Color.black,Color.blue,Color.cyan, + Color.darkGray,Color.gray,Color.green, + Color.lightGray,Color.magenta,Color.orange, + Color.pink,Color.red,Color.white, + Color.yellow}; + String[] stdColorNames = {"black","blue","cyan", + "dark gray","gray","green", + "light gray","magenta","orange", + "pink","red","white", + "yellow"}; + + /** setAsText for Color checks for standard color names + ** and then checks for a #RRGGBB value or just RRGGBB, + ** both in hex. + **/ + public void setAsText(String val) throws IllegalArgumentException { + if(val.length() == 0) { + throw new IllegalArgumentException("Tried to set empty value!"); + } + for(int i=0;iTo Do: Add custom font chooser + ** component. + ** + ** @author John Keiser + ** @version 1.1.0, 29 Jul 1998 + **/ + +public class FontEditor extends PropertyEditorSupport { + /** setAsText for Font calls Font.decode(). **/ + public void setAsText(String val) throws IllegalArgumentException { + setValue(Font.decode(val)); + } + + /** getAsText for Font returns a value in the format + ** expected by Font.decode(). + **/ + public String getAsText() { + Font f = (Font)getValue(); + if(f.isBold()) { + if(f.isItalic()) { + return f.getName()+"-bolditalic-"+f.getSize(); + } else { + return f.getName()+"-bold-"+f.getSize(); + } + } else if(f.isItalic()) { + return f.getName()+"-italic-"+f.getSize(); + } else { + return f.getName()+"-"+f.getSize(); + } + } +} diff --git a/libjava/classpath/gnu/java/beans/editors/NativeBooleanEditor.java b/libjava/classpath/gnu/java/beans/editors/NativeBooleanEditor.java new file mode 100644 index 000000000..1df94895a --- /dev/null +++ b/libjava/classpath/gnu/java/beans/editors/NativeBooleanEditor.java @@ -0,0 +1,76 @@ +/* gnu.java.beans.editors.NativeBooleanEditor + Copyright (C) 1998, 2002 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.editors; + +import java.beans.PropertyEditorSupport; + +/** + ** NativeBooleanEditor is a property editor for the + ** boolean type.

+ ** + ** To Do: add support for a checkbox + ** as the custom editor. + ** + ** @author John Keiser + ** @version 1.1.0, 29 Jul 1998 + **/ + +public class NativeBooleanEditor extends PropertyEditorSupport { + String[] tags = {"true","false"}; + + /** + * setAsText for boolean checks for true or false or t or f. + * "" also means false. + **/ + public void setAsText(String val) throws IllegalArgumentException { + if(val.equalsIgnoreCase("true") || val.equalsIgnoreCase("t")) { + setValue(Boolean.TRUE); + } else if(val.equalsIgnoreCase("false") || val.equalsIgnoreCase("f") || val.equals("")) { + setValue(Boolean.FALSE); + } else { + throw new IllegalArgumentException("Value must be true, false, t, f or empty."); + } + } + + + /** getAsText for boolean calls Boolean.toString(). **/ + public String getAsText() { + return getValue().toString(); + } +} diff --git a/libjava/classpath/gnu/java/beans/editors/NativeByteEditor.java b/libjava/classpath/gnu/java/beans/editors/NativeByteEditor.java new file mode 100644 index 000000000..d427a9e3f --- /dev/null +++ b/libjava/classpath/gnu/java/beans/editors/NativeByteEditor.java @@ -0,0 +1,61 @@ +/* gnu.java.beans.editors.NativeByteEditor + Copyright (C) 1998 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.editors; + +import java.beans.PropertyEditorSupport; + +/** + ** NativeByteEditor is a property editor for the + ** byte type. + ** + ** @author John Keiser + ** @version 1.1.0, 29 Jul 1998 + **/ + +public class NativeByteEditor extends PropertyEditorSupport { + /** setAsText for byte calls Byte.valueOf(). **/ + public void setAsText(String val) throws IllegalArgumentException { + setValue(Byte.valueOf(val)); + } + + /** getAsText for byte calls Byte.toString(). **/ + public String getAsText() { + return getValue().toString(); + } +} diff --git a/libjava/classpath/gnu/java/beans/editors/NativeDoubleEditor.java b/libjava/classpath/gnu/java/beans/editors/NativeDoubleEditor.java new file mode 100644 index 000000000..aa229fad7 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/editors/NativeDoubleEditor.java @@ -0,0 +1,61 @@ +/* gnu.java.beans.editors.NativeDoubleEditor + Copyright (C) 1998 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.editors; + +import java.beans.PropertyEditorSupport; + +/** + ** NativeDoubleEditor is a property editor for the + ** double type. + ** + ** @author John Keiser + ** @version 1.1.0, 29 Jul 1998 + **/ + +public class NativeDoubleEditor extends PropertyEditorSupport { + /** setAsText for double calls Double.valueOf(). **/ + public void setAsText(String val) throws IllegalArgumentException { + setValue(Double.valueOf(val)); + } + + /** getAsText for double calls Double.toString(). **/ + public String getAsText() { + return getValue().toString(); + } +} diff --git a/libjava/classpath/gnu/java/beans/editors/NativeFloatEditor.java b/libjava/classpath/gnu/java/beans/editors/NativeFloatEditor.java new file mode 100644 index 000000000..09f9d6b9c --- /dev/null +++ b/libjava/classpath/gnu/java/beans/editors/NativeFloatEditor.java @@ -0,0 +1,61 @@ +/* gnu.java.beans.editors.NativeFloatEditor + Copyright (C) 1998 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.editors; + +import java.beans.PropertyEditorSupport; + +/** + ** NativeFloatEditor is a property editor for the + ** float type. + ** + ** @author John Keiser + ** @version 1.1.0, 29 Jul 1998 + **/ + +public class NativeFloatEditor extends PropertyEditorSupport { + /** setAsText for float calls Float.valueOf(). **/ + public void setAsText(String val) throws IllegalArgumentException { + setValue(Float.valueOf(val)); + } + + /** getAsText for float calls Float.toString(). **/ + public String getAsText() { + return getValue().toString(); + } +} diff --git a/libjava/classpath/gnu/java/beans/editors/NativeIntEditor.java b/libjava/classpath/gnu/java/beans/editors/NativeIntEditor.java new file mode 100644 index 000000000..28b6a67d9 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/editors/NativeIntEditor.java @@ -0,0 +1,61 @@ +/* gnu.java.beans.editors.NativeIntEditor + Copyright (C) 1998 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.editors; + +import java.beans.PropertyEditorSupport; + +/** + ** NativeIntEditor is a property editor for the + ** int type. + ** + ** @author John Keiser + ** @version 1.1.0, 29 Jul 1998 + **/ + +public class NativeIntEditor extends PropertyEditorSupport { + /** setAsText for int calls Integer.valueOf(). **/ + public void setAsText(String val) throws IllegalArgumentException { + setValue(Integer.valueOf(val)); + } + + /** getAsText for int calls Integer.toString(). **/ + public String getAsText() { + return getValue().toString(); + } +} diff --git a/libjava/classpath/gnu/java/beans/editors/NativeLongEditor.java b/libjava/classpath/gnu/java/beans/editors/NativeLongEditor.java new file mode 100644 index 000000000..77223fbbc --- /dev/null +++ b/libjava/classpath/gnu/java/beans/editors/NativeLongEditor.java @@ -0,0 +1,61 @@ +/* gnu.java.beans.editors.NativeLongEditor + Copyright (C) 1998 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.editors; + +import java.beans.PropertyEditorSupport; + +/** + ** NativeLongEditor is a property editor for the + ** long type. + ** + ** @author John Keiser + ** @version 1.1.0, 29 Jul 1998 + **/ + +public class NativeLongEditor extends PropertyEditorSupport { + /** setAsText for long calls Long.valueOf(). **/ + public void setAsText(String val) throws IllegalArgumentException { + setValue(Long.valueOf(val)); + } + + /** getAsText for long calls Long.toString(). **/ + public String getAsText() { + return getValue().toString(); + } +} diff --git a/libjava/classpath/gnu/java/beans/editors/NativeShortEditor.java b/libjava/classpath/gnu/java/beans/editors/NativeShortEditor.java new file mode 100644 index 000000000..1d8845bde --- /dev/null +++ b/libjava/classpath/gnu/java/beans/editors/NativeShortEditor.java @@ -0,0 +1,61 @@ +/* gnu.java.beans.editors.NativeShortEditor + Copyright (C) 1998 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.editors; + +import java.beans.PropertyEditorSupport; + +/** + ** NativeShortEditor is a property editor for the + ** short type. + ** + ** @author John Keiser + ** @version 1.1.0, 29 Jul 1998 + **/ + +public class NativeShortEditor extends PropertyEditorSupport { + /** setAsText for short calls Short.valueOf(). **/ + public void setAsText(String val) throws IllegalArgumentException { + setValue(Short.valueOf(val)); + } + + /** getAsText for short calls Short.toString(). **/ + public String getAsText() { + return getValue().toString(); + } +} diff --git a/libjava/classpath/gnu/java/beans/editors/StringEditor.java b/libjava/classpath/gnu/java/beans/editors/StringEditor.java new file mode 100644 index 000000000..47fdce659 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/editors/StringEditor.java @@ -0,0 +1,61 @@ +/* gnu.java.beans.editors.StringEditor + Copyright (C) 1998 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.editors; + +import java.beans.PropertyEditorSupport; + +/** + ** NativeByteEditor is a property editor for the + ** byte type. + ** + ** @author John Keiser + ** @version 1.1.0, 29 Jul 1998 + **/ + +public class StringEditor extends PropertyEditorSupport { + /** setAsText just sets the value. **/ + public void setAsText(String val) throws IllegalArgumentException { + setValue(val); + } + + /** getAsText just returns the value. **/ + public String getAsText() { + return (String)getValue(); + } +} diff --git a/libjava/classpath/gnu/java/beans/editors/TODO b/libjava/classpath/gnu/java/beans/editors/TODO new file mode 100644 index 000000000..6877f4caf --- /dev/null +++ b/libjava/classpath/gnu/java/beans/editors/TODO @@ -0,0 +1,4 @@ +- write tests for all editors +- add some sort of ColorChooser as a custom editor for ColorEditor +- add a FileNameEditor +- add a FontChooser as a custom editor for FontEditor diff --git a/libjava/classpath/gnu/java/beans/editors/package.html b/libjava/classpath/gnu/java/beans/editors/package.html new file mode 100644 index 000000000..465f68d17 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/editors/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.beans.editors + + +

+ + + diff --git a/libjava/classpath/gnu/java/beans/encoder/ArrayPersistenceDelegate.java b/libjava/classpath/gnu/java/beans/encoder/ArrayPersistenceDelegate.java new file mode 100644 index 000000000..52fc45796 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/ArrayPersistenceDelegate.java @@ -0,0 +1,153 @@ +/* ArrayPersistenceDelegate.java - A PersistenceDelegate that handles arrays. + 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.java.beans.encoder; + +import java.beans.Encoder; +import java.beans.Expression; +import java.beans.PersistenceDelegate; +import java.beans.Statement; + +import java.lang.reflect.Array; +import java.util.HashMap; + +public class ArrayPersistenceDelegate extends PersistenceDelegate +{ + private static final HashMap NULL_VALUES = new HashMap(); + + static + { + NULL_VALUES.put(Boolean.TYPE, Boolean.FALSE); + NULL_VALUES.put(Byte.TYPE, Byte.valueOf((byte) 0)); + NULL_VALUES.put(Short.TYPE, Short.valueOf((short) 0)); + NULL_VALUES.put(Integer.TYPE, Integer.valueOf(0)); + NULL_VALUES.put(Long.TYPE, Long.valueOf(0)); + NULL_VALUES.put(Float.TYPE, Float.valueOf(0.0f)); + NULL_VALUES.put(Double.TYPE, Double.valueOf(0.0)); + } + + protected Expression instantiate(Object oldInstance, Encoder out) + { + Class type = oldInstance.getClass().getComponentType(); + + // oldInstance is expected to be an array, then + // getClass().getComponentType() should lead + // to its component type. + assert (type != null); + + // Not handling primitive types in a special way here + // causes that Class.forName("int") is built as an Expression + // later which would cause an exception if executed. A special + // handling to avoid the execution for primitive types can be + // java.beans.Encoder.writeExpression() . + return new Expression( + oldInstance, + Array.class, + "newInstance", + new Object[] { + type, + new Integer(Array.getLength(oldInstance)) }); + } + + protected void initialize(Class type, Object oldInstance, Object newInstance, + Encoder out) + { + int length = Array.getLength(oldInstance); + + // Compares the array value against a prototypical + // null value of the array's component type in order to skip + // writing the default values of an array. + + // Note: I have no idea why the persistence delegate for arrays writes + // an Expression that reads the value and then writes a Statement that sets + // the value. However it turned out that object arrays work better with the + // get-Expression and primitive array work fine with the set-Statement. + + type = type.getComponentType(); + if (type.isPrimitive()) + { + Object nullValue = NULL_VALUES.get(type); + + for (int i = 0; i < length; i++) + { + Object oldValue = Array.get(oldInstance, i); + + if (!oldValue.equals(nullValue)) + { + out.writeExpression(new Expression(Array.class, "get", + new Object[] { oldInstance, + Integer.valueOf(i), + })); + + out.writeStatement(new Statement(Array.class, "set", + new Object[] { + oldInstance, + Integer.valueOf(i), + oldValue + })); + } + } + + } + else + { + + for (int i = 0; i < length; i++) + { + Object oldValue = Array.get(oldInstance, i); + + if (oldValue != null) + { + out.writeExpression(new Expression(Array.class, "get", + new Object[] { oldInstance, + Integer.valueOf(i), + })); + + out.writeStatement(new Statement(Array.class, "set", + new Object[] { + oldInstance, + Integer.valueOf(i), + oldValue + })); + } + } + } + + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/ClassPersistenceDelegate.java b/libjava/classpath/gnu/java/beans/encoder/ClassPersistenceDelegate.java new file mode 100644 index 000000000..1430a6dbe --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/ClassPersistenceDelegate.java @@ -0,0 +1,80 @@ +/* ClassPersistenceDelegate.java - A PersistenceDelegate for the Class type. + 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.java.beans.encoder; + +import java.beans.Encoder; +import java.beans.Expression; +import java.beans.PersistenceDelegate; + +/**

The ClassPersistenceDelegate creates + * Expression instances which denote class resolutions.

+ * + *

The class resolution is always the last step when serializing a tree + * of objects. Due to the recursive nature of the algorithm we need a way + * to end the recursion. This is achieved by the implementation of this + * {@link instantiate} method. Arbitrary classes are described with a call + * to Class.forName. However for the Class class + * we call getClass() on a String.class instance. + * This in turn lead to the resolution of the String class which is always + * encoded as "".getClass(). Finally the Encoder + * treats strings in a special way so that the recursion ends here. + * + * @author Robert Schuster (robertschuster@fsfe.org) + */ +public class ClassPersistenceDelegate extends PersistenceDelegate +{ + + protected Expression instantiate(Object oldInstance, Encoder out) + { + Class oldClass = (Class) oldInstance; + + // Due to the special handling of String instances in the Encoder + // this Expression does not lead to further class resolutions. + if (oldClass == String.class) + return new Expression(oldClass, "", "getClass", null); + + // This Expression will lead to the class resolution of String.class. + if (oldClass == Class.class) + return new Expression(oldClass, String.class, "getClass", null); + + // This Expression will lead to the class resolution of Class.class. + return new Expression(oldClass, Class.class, "forName", + new Object[] { oldClass.getName() }); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/CollectionPersistenceDelegate.java b/libjava/classpath/gnu/java/beans/encoder/CollectionPersistenceDelegate.java new file mode 100644 index 000000000..bdf6fda62 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/CollectionPersistenceDelegate.java @@ -0,0 +1,84 @@ +/* CollectionPersistenceDelegate.java - A PersistenceDelegate for Collection subclasses. + 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.java.beans.encoder; + +import java.util.Collection; +import java.beans.Encoder; +import java.beans.Expression; +import java.beans.PersistenceDelegate; +import java.beans.Statement; + +import java.util.Iterator; + +/**

A PersistenceDelegate implementation that calls + * the no-argument constructor to create the Collection instance and + * uses an iterator to add all the objects it reaches through it.

+ * + *

It is used for Set and List + * implementations.

+ * + * @author Robert Schuster (robertschuster@fsfe.org) + */ +public class CollectionPersistenceDelegate extends PersistenceDelegate +{ + + protected Expression instantiate(Object oldInstance, Encoder out) + { + return new Expression( + oldInstance, + oldInstance.getClass(), + "new", + null); + } + + protected void initialize(Class type, Object oldInstance, Object newInstance, + Encoder out) + { + Iterator ite = ((Collection) oldInstance).iterator(); + + while (ite.hasNext()) + { + out.writeStatement(new Statement(oldInstance, "add", + new Object[] { ite.next() })); + + } + + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/Context.java b/libjava/classpath/gnu/java/beans/encoder/Context.java new file mode 100644 index 000000000..8acc4907b --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/Context.java @@ -0,0 +1,88 @@ +/* Context.java -- Provides calling context information to ScannerStates. + 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.java.beans.encoder; + +/** A Contect object describes the current state + * and the call number while processing the original object + * tree in the {@link ScanEngine}. + * + *

The class allows to distinguish the different calling states + * and is neccessary for the child element skipping feature of + * the {@link GenericScannerState}.

+ * + * @author Robert Schuster (robertschuster@fsfe.org) + * + */ +public class Context +{ + private String state; + + private int call; + + Context(String newState, int newCall) + { + state = newState; + call = newCall; + } + + public int hashCode() + { + int hc = 7; + hc = 31 * hc + state.hashCode(); + hc = 31 * hc + call; + + return hc; + } + + public boolean equals(Object o) + { + if (!(o instanceof Context)) + return false; + + Context that = (Context) o; + + return state.equals(that.state) + && call == that.call; + } + + public String toString() + { + return "Context [state=" + state + ", call=" + call + "]"; + } +} diff --git a/libjava/classpath/gnu/java/beans/encoder/GenericScannerState.java b/libjava/classpath/gnu/java/beans/encoder/GenericScannerState.java new file mode 100644 index 000000000..b07771dbe --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/GenericScannerState.java @@ -0,0 +1,257 @@ +/* GenericScannerState.java + 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.java.beans.encoder; + +import java.util.HashMap; + +import gnu.java.beans.encoder.elements.ArrayInstantiation; +import gnu.java.beans.encoder.elements.Array_Get; +import gnu.java.beans.encoder.elements.Array_Set; +import gnu.java.beans.encoder.elements.ClassResolution; +import gnu.java.beans.encoder.elements.Element; +import gnu.java.beans.encoder.elements.List_Get; +import gnu.java.beans.encoder.elements.List_Set; +import gnu.java.beans.encoder.elements.MethodInvocation; +import gnu.java.beans.encoder.elements.NullObject; +import gnu.java.beans.encoder.elements.ObjectInstantiation; +import gnu.java.beans.encoder.elements.ObjectReference; +import gnu.java.beans.encoder.elements.PrimitiveInstantiation; +import gnu.java.beans.encoder.elements.StaticFieldAccess; +import gnu.java.beans.encoder.elements.StaticMethodInvocation; +import gnu.java.beans.encoder.elements.StringReference; + +/** + * This class is a {@link ScannerState} implementation that creates + * suitable {@link gnu.java.beans.encoder.elements.Element} instances + * for each transition variant. + * + *

Furthermore it can optionally skip a certain number of child + * elements. The algorithm can cope with the fact that one + * GenericScannerState instance may be called at + * different levels of recursions.

+ * + * @author Robert Schuster (robertschuster@fsfe.org) + */ +class GenericScannerState extends ScannerState +{ + private int skipElements, initialSkipElements; + + final Root root; + + HashMap skipValues; + + GenericScannerState(Root newRoot) + { + root = newRoot; + } + + GenericScannerState(Root root, int skipElements) + { + this(root); + this.skipElements = initialSkipElements = skipElements; + + if (skipElements > 0) + skipValues = new HashMap(); + } + + protected void enterImpl(Context ctx) + { + if (skipValues != null) + { + Integer skip = (Integer) skipValues.get(ctx); + + if (skip == null) + { + skip = Integer.valueOf(initialSkipElements); + skipValues.put(ctx, skip); + } + + skipElements = skip.intValue(); + } + } + + void methodInvocation(String methodName) + { + if (skipValues != null && skipElements > 0) + return; + + root.addChild(new MethodInvocation(methodName)); + } + + void staticMethodInvocation(String className, String methodName) + { + if (skipValues != null && skipElements > 0) + return; + + root.addChild(new StaticMethodInvocation(className, methodName)); + } + + void staticFieldAccess(String className, String fieldName) + { + if (skipValues != null && skipElements > 0) + return; + + root.addChild(new StaticFieldAccess(className, fieldName)); + } + + void classResolution(String className) + { + if (skipValues != null && skipElements > 0) + return; + + root.addChild(new ClassResolution(className)); + } + + void objectInstantiation(String className, ObjectId objectId) + { + if (skipValues != null && skipElements > 0) + return; + + Element elem = new ObjectInstantiation(className); + elem.initId(objectId); + + root.addChild(elem); + } + + void primitiveInstantiation(String primitiveName, String valueAsString) + { + if (skipValues != null && skipElements > 0) + return; + + root.addChild(new PrimitiveInstantiation(primitiveName, valueAsString)); + } + + void objectArrayInstantiation(String arrayClassName, String lengthAsString, + ObjectId objectId) + { + if (skipValues != null && skipElements > 0) + return; + + Element elem = new ArrayInstantiation(arrayClassName, lengthAsString); + elem.initId(objectId); + + root.addChild(elem); + } + + void primitiveArrayInstantiation(String arrayClassName, String lengthAsString, + ObjectId objectId) + { + objectArrayInstantiation(arrayClassName, lengthAsString, objectId); + } + + void arraySet(String indexAsString) + { + if (skipValues != null && skipElements > 0) + return; + + root.addChild(new Array_Set(indexAsString)); + } + + void arrayGet(String indexAsString) + { + if (skipValues != null && skipElements > 0) + return; + + root.addChild(new Array_Get(indexAsString)); + } + + void listGet() + { + if (skipValues != null && skipElements > 0) + return; + + root.addChild(new List_Get()); + } + + void listSet() + { + if (skipValues != null && skipElements > 0) + return; + + root.addChild(new List_Set()); + } + + void nullObject() + { + if (skipValues != null && skipElements > 0) + return; + + root.addChild(new NullObject()); + } + + void stringReference(String string) + { + if (skipValues != null && skipElements > 0) + return; + + root.addChild(new StringReference(string)); + } + + void objectReference(ObjectId id) + { + if (skipValues != null && skipElements > 0) + return; + + root.addChild(new ObjectReference(id)); + } + + void end() + { + if (skipValues != null) + { + if (skipElements > 0) + skipElements--; + else + { + // Finishes the Element we are constructing. + root.end(); + } + skipValues.put(context(), Integer.valueOf(skipElements)); + } + else + root.end(); + + } + + void enter() + { + + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/IgnoringScannerState.java b/libjava/classpath/gnu/java/beans/encoder/IgnoringScannerState.java new file mode 100644 index 000000000..3ec78cdf9 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/IgnoringScannerState.java @@ -0,0 +1,133 @@ +/* IgnoringScannerState.java -- A ScannerState that does nothing. + 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.java.beans.encoder; + +/** A special {@link ScannerState} implementation that ignores all child + * elements. + * + *

Consider the call hierarchy: + * + * methodInvocation + * objectInstantiation + * classResolution* + * objectInstantiation + * classResolution + * + *

+ * + *

When the ignoring state is active one can filter the elements of + * one level. One has to set up the state machine that a transition + * via "class resolution" from a state that was reached via "object + * instantation" reaches an IgnoringScannerState.

+ * + *

Setting the default successor of a IgnoringScannerState + * to itself causes all elements of the call hierarchy to be skipped + * until another state is reached by going back.

+ * + * @author Robert Schuster (robertschuster@fsfe.org) + * + */ +class IgnoringScannerState extends ScannerState +{ + + void methodInvocation(String methodName) + { + } + + void staticMethodInvocation(String className, String methodName) + { + } + + void staticFieldAccess(String className, String fieldName) + { + } + + void classResolution(String className) + { + } + + void objectInstantiation(String className, ObjectId objectId) + { + } + + void primitiveInstantiation(String primitiveName, String valueAsString) + { + } + + void objectArrayInstantiation(String arrayClassName, String lengthAsString, ObjectId objectId) + { + } + + void primitiveArrayInstantiation(String arrayClassName, String lengthAsString, ObjectId objectId) + { + } + + void arraySet(String indexAsString) + { + } + + void arrayGet(String indexAsString) + { + } + + void listGet() + { + } + + void listSet() + { + } + + void nullObject() + { + } + + void stringReference(String string) + { + } + + void objectReference(ObjectId id) + { + } + + void end() + { + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/MapPersistenceDelegate.java b/libjava/classpath/gnu/java/beans/encoder/MapPersistenceDelegate.java new file mode 100644 index 000000000..9ffdb5686 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/MapPersistenceDelegate.java @@ -0,0 +1,81 @@ +/* MapPersistenceDelegate.java -- A PersistenceDelegate for Map subclasses. + + 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.java.beans.encoder; + +import java.util.Map; +import java.beans.Encoder; +import java.beans.Expression; +import java.beans.PersistenceDelegate; +import java.beans.Statement; + +import java.util.Iterator; + +/** + * @author Robert Schuster (robertschuster@fsfe.org) + */ +public class MapPersistenceDelegate extends PersistenceDelegate +{ + + protected Expression instantiate(Object oldInstance, Encoder out) + { + return new Expression( + oldInstance, + oldInstance.getClass(), + "new", + null); + } + + protected void initialize(Class type, Object oldInstance, Object newInstance, + Encoder out) + { + Map map = (Map) oldInstance; + Iterator ite = map.keySet().iterator(); + + while (ite.hasNext()) + { + Object key = ite.next(); + out.writeStatement(new Statement(oldInstance, "put", + new Object[] { key, map.get(key) })); + + } + + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/ObjectId.java b/libjava/classpath/gnu/java/beans/encoder/ObjectId.java new file mode 100644 index 000000000..13d75d6bb --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/ObjectId.java @@ -0,0 +1,132 @@ +/* ObjectId.java -- Simple object identification mechanism for XML encoding. + 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.java.beans.encoder; + +import java.util.HashMap; + +/** + *

+ * ObjectId provides an object identification mechanism which gives each object + * a name in the form <class><Nameindex>. + *

+ * + *

+ * Each id can be in an unused state which means that only one instance of the + * object is in use and a special id is not needed. Certain {@link + * gnu.java.beans.encoder.elements.Element} subclasses use this feature to find + * out whether they write the "id" attribute or not. + *

+ *

+ * An ObjectId instance is typically given to multiple objects. + * The second user should then invoke the {@link #init} method to generate the + * identification string and bring the id in the 'used' state. + *

+ * + * @author Robert Schuster (robertschuster@fsfe.org) + */ +public class ObjectId +{ + /** + * Stores the index an object of a specific type should be given. + */ + private static HashMap nameIndices = new HashMap(); + + private String id; + + private Class klass; + + ObjectId(Class klass) + { + this.klass = klass; + } + + public boolean isUnused() + { + return id == null; + } + + public String toString() + { + return (id != null) ? id : ""; + } + + /** + *

+ * Generates a simple Id by concatenating a class name with a self-increasing + * number. + *

+ */ + public void init() + { + assert (klass != null); + + if (id != null) + return; + + Integer count = (Integer) nameIndices.get(klass); + if (count == null) + { + count = Integer.valueOf(0); + } + + if (klass.isArray()) + { + Class ct = klass.getComponentType(); + if (ct == Boolean.TYPE) + id = "booleanArray" + count.intValue(); + else if (ct == Byte.TYPE) + id = "byteArray" + count.intValue(); + else if (ct == Short.TYPE) + id = "shortArray" + count.intValue(); + else if (ct == Integer.TYPE) + id = "intArray" + count.intValue(); + else if (ct == Long.TYPE) + id = "longArray" + count.intValue(); + else if (ct == Float.TYPE) + id = "floatArray" + count.intValue(); + else if (ct == Double.TYPE) + id = "doubleArray" + count.intValue(); + } + else + id = klass.getName() + count.intValue(); + + nameIndices.put(klass, Integer.valueOf(count.intValue() + 1)); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/PrimitivePersistenceDelegate.java b/libjava/classpath/gnu/java/beans/encoder/PrimitivePersistenceDelegate.java new file mode 100644 index 000000000..55626b512 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/PrimitivePersistenceDelegate.java @@ -0,0 +1,74 @@ +/* PrimitivePersistenceDelegate.java + -- A PersistenceDelegate for primitive data types. + 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.java.beans.encoder; + +import java.beans.Encoder; +import java.beans.Expression; +import java.beans.PersistenceDelegate; + +/** + * A shared PersistenceDelegate implementation for all primitive types. + * + * @author Robert Schuster (robertschuster@fsfe.org) + */ +public class PrimitivePersistenceDelegate extends PersistenceDelegate +{ + + protected Expression instantiate(Object oldInstance, Encoder out) + { + // The implementation relies on the fact that every primitive + // wrapper class has a constructor accepting a String argument. + // By using these constructors creating a primitive instance + // depends on the String class only. + return new Expression(oldInstance, oldInstance.getClass(), "new", + new Object[] { oldInstance.toString() }); + } + + protected void initialize(Class type, Object oldInstance, Object newInstance, Encoder out) + { + // This is a hack to make serializing primitive arrays work correctly. + // Instead of modifying an existing primitive instance to make it equal + // with another instance (which is not possible because primitives are + // immutable) we create a new instance. This is against the specification + // of the initialize method but make things work fine. + out.writeExpression(new Expression(oldInstance, oldInstance.getClass(), "new", + new Object[] { oldInstance.toString() })); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/ReportingScannerState.java b/libjava/classpath/gnu/java/beans/encoder/ReportingScannerState.java new file mode 100644 index 000000000..c91bb1567 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/ReportingScannerState.java @@ -0,0 +1,131 @@ +/* ReportingScannerState.java -- A state for debugging purposes. + 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.java.beans.encoder; + +/** + * A ScannerState implementation that prints useful details + * about its arguments. Use it when the XML encoding does not work correctly + * and you want to find out how things relate to each other. + * + * @author Robert Schuster (robertschuster@fsfe.org) + */ +class ReportingScannerState extends ScannerState +{ + + void methodInvocation(String methodName) + { + System.out.println("methodInvocation: " + methodName + "()"); + } + + void staticMethodInvocation(String className, String methodName) + { + System.out.println("staticMethodInvocation: " + className + "." + methodName + "()"); + } + + void staticFieldAccess(String className, String fieldName) + { + System.out.println("staticFieldAccess: " + className + "." + fieldName); + } + + void classResolution(String className) + { + System.out.println("classResolution: " + className); + } + + void objectInstantiation(String className, ObjectId objectId) + { + System.out.println("objectInstantiation: " + className); + } + + void primitiveInstantiation(String primitiveName, String valueAsString) + { + System.out.println("primitiveInstantiation: (" + primitiveName + ") " + valueAsString); + } + + void objectArrayInstantiation(String arrayClassName, String lengthAsString, ObjectId objectId) + { + System.out.println("objectArrayInstantiation: new " + arrayClassName + "[" + lengthAsString + "]"); + } + + void primitiveArrayInstantiation(String arrayClassName, String lengthAsString, ObjectId objectId) + { + System.out.println("primitiveArrayInstantiation: new " + arrayClassName + "[" + lengthAsString + "]"); + } + + void arraySet(String indexAsString) + { + System.out.println("arraySet: " + indexAsString); + } + + void arrayGet(String indexAsString) + { + System.out.println("arrayGet: " + indexAsString); + } + + void listGet() + { + System.out.println("listGet"); + } + + void listSet() + { + System.out.println("listSet"); + } + + void nullObject() + { + System.out.println("nullObject"); + } + + void stringReference(String string) + { + System.out.println("stringReference: " + string); + } + + void objectReference(ObjectId id) + { + System.out.println("objectReference: " + id); + } + + void end() + { + System.out.println("-close"); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/Root.java b/libjava/classpath/gnu/java/beans/encoder/Root.java new file mode 100644 index 000000000..a6410d716 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/Root.java @@ -0,0 +1,198 @@ +/* Root.java -- The root of an object tree. + 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.java.beans.encoder; + +import java.beans.XMLEncoder; +import java.util.Iterator; +import java.util.Stack; + +import gnu.java.beans.encoder.elements.Element; + +/**

Root provides a simple interface to a tree of + * objects.

+ * + *

Using an instance of this class a logical representation of + * the real object tree that is serialized can be built. When the + * actual data should be written as XML Root and + * {@link gnu.java.beans.encoder.elements.Element} class can provide + * context information which is used to write the best fitting + * XML representation.

+ * + * @author Robert Schuster (robertschuster@fsfe.org) + */ +public class Root +{ + private Stack parents = new Stack(); + + private Element rootElement, current; + + private boolean started; + + public Root() + { + rootElement = current = new RootElement(); + } + + /**

Adds another child element to the tree.

+ * + *

The new element automatically becomes the current + * element.

+ * + * @param elem The new child element. + */ + public void addChild(Element elem) + { + current.addChild(elem); + + parents.push(current); + current = elem; + } + + /** + *

Marks that the end of the current element + * is reached and that no more childs are added to + * it.

+ * + *

The behavior is to return to the nearest parent + * element.

+ */ + public void end() + { + current = (Element) parents.pop(); + } + + /** + *

Goes back to the nearest parent element but + * deletes the just created child.

+ * + *

This is used if something went wrong while + * processing the child element's {@link java.beans.Expression} + * or {@link java.beans.Statement}.

+ * + */ + public void deleteLast() + { + current = (Element) parents.pop(); + + current.removeLast(); + } + + /** + *

Traverses the elements in the object tree + * and creates their XML representation in the output + * stream of the given {@link Writer}.

+ * + *

Finally the Writer is flushed.

+ * + * @param writer The Writer instance that generates the XML representation. + */ + public void traverse(Writer writer) + { + if (!started) + { + writer.writePreamble(); + rootElement.writeStart(writer); + } + started = true; + + traverse(writer, rootElement.iterator()); + + rootElement.clear(); + + writer.flush(); + } + + /** Writes the closing element and closes the {@link Writer} + * + * @param writer The Writer instance that generates the XML representation. + */ + public void close(Writer writer) + { + rootElement.writeEnd(writer); + writer.close(); + } + + /** Recursively traverses the object tree. + * + * @param writer The Writer instance that generates the XML representation. + * @param ite An Iterator returning Element instances. + */ + private void traverse(Writer writer, Iterator ite) + { + while (ite.hasNext()) + { + Element e = (Element) ite.next(); + e.writeStart(writer); + + traverse(writer, e.iterator()); + + e.writeEnd(writer); + + e.clear(); + } + } + + /**

A special Element implementation that represents the + * encoder's context.

+ * + *

This element is written only once per Writer.

+ * + *

It is assumed that this element is never empty to simplify + * the implementation.

+ * + * @author Robert Schuster (robertschuster@fsfe.org); + * + */ + static class RootElement extends Element + { + public void writeStart(Writer writer) + { + writer.write("java", new String[] { "version", "class" }, + new String[] { System.getProperty("java.version"), + XMLEncoder.class.getName() }, false); + } + + public void writeEnd(Writer writer) + { + writer.writeEnd(false); + } + + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/ScanEngine.java b/libjava/classpath/gnu/java/beans/encoder/ScanEngine.java new file mode 100644 index 000000000..9ced143f0 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/ScanEngine.java @@ -0,0 +1,860 @@ +/* ScanEngine.java + -- Scans the input and generates an object tree that can be written as XML. + 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.java.beans.encoder; + +import java.beans.Expression; +import java.beans.Statement; +import java.io.OutputStream; +import java.lang.reflect.Array; +import java.util.HashMap; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Stack; + +/**

The ScanEngine is the main class of the backend of the + * XML persistence algorithm. It scans {@link java.beans.Expression} and + * {@link java.beans.Statement} instances and some raw objects via the + * {@link #writeObject} method and feeds it to a state machine. The + * state machine then constructs and object tree which is finally + * written as XML by a {@link Writer} implementation.

+ * + *

How does it work?

+ *

The ScanEngine sits below the {@link java.beans.XMLEncoder} + * class and is called by it exclusively. The XMLEncoder sends + * interpretive data by invoking {@link #writeExpression}, {@link #writeStatement} + * and {@link #writeObject}. The invocations of writeExpression and + * writeStatement are usually nested into each other and provide + * more information then necessary to generate the XML representation. + * Furthermore the meaning of certain Expressions differs + * depending on the enclosing elements or the inner elements have to be + * simply discarded.

+ * + *

To cope with this state dependant nature the ScanEngine + * contains a state machine which is programmed statically (no adjustments are + * needed, all ScanEngine engines use the same setup). The + * ScanEngine's job is to decode the Expressions, + * Statements and certain objects (namely String, + * null objects and instances which are repeatedly provided to + * the encoder) into 13 low-level (event) methods, which denote the meaning of the + * argument. For example an Expression can be an array + * instantiation which provokes a call to {@link arrayInstantiation} or + * it can be a class resolution leading to a call to {@link #classResolution}. + * For the state machione the 13 methods are the distinct way to transit + * from one state to another. Whenever the ScanEngine calls + * one of the event methods the current's state successor for that event + * is fetched from the state machine configuration, the successpr becomes + * the current state and then the event method is called in the new current + * state. The last step allows the state instance to do something meaningful + * to the object tree.

+ * + *

The state machine knows the concept of returning to the previous + * state. This is done using a stack of states which is popped every + * time a call to writeStatement, writeExpression + * in the XMLEncoder ends by calling the {@link #end} method. + * Note that due to the inheritance relationship of Encoder + * and XMLEncoder it is impossible for the + * ScanEngine itself to decide when an expression or statement + * ended. This can only be done in case of {@link #writeObject} calls because + * they are not nested.

+ * + *

When the XML persistence mechanism reaches an object twice (and more) + * it should generate an XML element using the "idref" attribute and add + * an "id" attribute to its first instantiation. This complicates things a bit + * because the first instantiation will always be part of the object tree + * as some {@link gnu.java.beans.encoder.elements.Element} subclass instance when the + * second and further objects accesses are written. Therefore the {@link ObjectId} + * class was introduced which is shared between all the object tree elements + * and has the notion of an "unused" state meaning that no identification + * is needed. The relationship between an object and its ObjectId + * instance is stored in the ScanEngine and gets cleared whenever + * the {@link #flush} method is called. This method also writes the currently + * built object tree and generates the XML representation.

+ * + * @author Robert Schuster (robertschuster@fsfe.org) + */ +public class ScanEngine +{ + + /** Change this to true to let the ScanEngine print state transition + * information. + */ + boolean DEBUG = false; + + /** + * Stores the scanner engine states as values and their names as keys. + */ + HashMap states = new HashMap(); + + /** + * Stores former scanner state and makes it possible to come back to them. + */ + Stack parents = new Stack(); + + /** + * The currently active scanner state. + */ + ScannerState current; + + /** + * The root of an object tree that is later written to XML. + */ + Root root; + + /** + * The Writer used to generate the XML output. + */ + Writer writer; + + /** Stores the relationship between objects and their {@link ObjectId} instance. + */ + IdentityHashMap objects = new IdentityHashMap(); + + public ScanEngine(OutputStream os) + { + // TODO: Provide another Writer implementation (e.g. one that does not use + // the XML APIs at all). + writer = new StAXWriter(os); + root = new Root(); + + final ScannerState start = current = new GenericScannerState(root); + ScannerState conf; + + // Use the ReportingScannerState to debug serialization issues. + register(ScannerState.DEFAULT_STATE_NAME, new IgnoringScannerState()); + + register("start", start); + + // Special dead-end state where all transitions are ignored. + register("ignoreAll", new IgnoringScannerState()) + .setDefaultSuccessor("ignoreAll"); + + // Object reference, string reference, null object + start.putSuccessor(ScannerState.TRANSITION_OBJECT_REFERENCE, "simple"); + start.putSuccessor(ScannerState.TRANSITION_STRING_REFERENCE, "simple"); + start.putSuccessor(ScannerState.TRANSITION_NULL_OBJECT, "simple"); + register("simple", new GenericScannerState(root)) + .setDefaultSuccessor("ignoreAll"); + + // Class resolution. + start.putSuccessor(ScannerState.TRANSITION_CLASS_RESOLUTION, "classRes0"); + register("classRes0", + new GenericScannerState(root)).setDefaultSuccessor("ignoreAll"); + + // Object instantiation. + start.putSuccessor(ScannerState.TRANSITION_OBJECT_INSTANTIATION, + "newObj0"); + conf = register("newObj0", new GenericScannerState(root)); + conf.setDefaultSuccessor("ignoreAll"); + + // Simply use the start state to encode method invocations inside of + // objects. + conf.putSuccessor(ScannerState.TRANSITION_METHOD_INVOCATION, "start"); + + // Primitive instantiations. + start.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION, + "newPrimitive0"); + register("newPrimitive0", + new GenericScannerState(root)).setDefaultSuccessor("ignoreAll"); + + // Object arrays use the ARRAY_GET transition to create setting the + // array values. + start.putSuccessor(ScannerState.TRANSITION_OBJECT_ARRAY_INSTANTIATION, + "newObjectArray"); + conf = register("newObjectArray", new GenericScannerState(root)); + conf.putSuccessor(ScannerState.TRANSITION_ARRAY_GET, "newOArrayGet"); + conf.putSuccessor(ScannerState.TRANSITION_ARRAY_SET, "ignoreAll"); + conf.putSuccessor(ScannerState.TRANSITION_CLASS_RESOLUTION, "ignoreAll"); + conf.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION, + "ignoreAll"); + + // Get here when a value is set in the array. + register("newOArrayGet", + conf = new GenericScannerState(root)); + + conf.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION, + "newOArrayGet_ignoreFirstInteger"); + + // "newArrayGet_ignoreFirstInteger" is set up mostly identical like the "start" + // state. Otherwise things would not behave the same when done inside + // arrays. + conf.putSuccessor(ScannerState.TRANSITION_OBJECT_REFERENCE, "simple"); + conf.putSuccessor(ScannerState.TRANSITION_STRING_REFERENCE, "simple"); + conf.putSuccessor(ScannerState.TRANSITION_NULL_OBJECT, "simple"); + conf.putSuccessor(ScannerState.TRANSITION_CLASS_RESOLUTION, "classRes0"); + conf.putSuccessor(ScannerState.TRANSITION_OBJECT_INSTANTIATION, "newObj0"); + conf.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_ARRAY_INSTANTIATION, + "newPrimitiveArray"); + conf.putSuccessor(ScannerState.TRANSITION_OBJECT_ARRAY_INSTANTIATION, + "newObjectArray"); + + conf = register("newOArrayGet_ignoreFirstInteger", + new GenericScannerState(root, 1)); + + // In non-int primitive arrays class resolutions can happen + // but they should be ignored. + conf.putSuccessor(ScannerState.TRANSITION_CLASS_RESOLUTION, "ignoreAll"); + + // Spurious object and string references occur when setting array + // elements. This suppresses them. + conf.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION, + "ignoreAll"); + conf.putSuccessor(ScannerState.TRANSITION_OBJECT_REFERENCE, "ignoreAll"); + conf.putSuccessor(ScannerState.TRANSITION_STRING_REFERENCE, "ignoreAll"); + + conf.setDefaultSuccessor("start"); + + // Primitive arrays use the ARRAY_SET transition to create setting the + // array values. This turned out to be the only working solution. + // When primitive arrays were handled by ARRAY_GET the values in boolean + // arrays were always skipped. + start.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_ARRAY_INSTANTIATION, + "newPrimitiveArray"); + conf = register("newPrimitiveArray", new GenericScannerState(root)); + conf.putSuccessor(ScannerState.TRANSITION_ARRAY_GET, "ignoreAll"); + conf.putSuccessor(ScannerState.TRANSITION_ARRAY_SET, "newPArraySet"); + conf.putSuccessor(ScannerState.TRANSITION_CLASS_RESOLUTION, "ignoreAll"); + conf.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION, + "ignoreAll"); + + conf = register("newPArraySet", new GenericScannerState(root)); + conf.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION, + "newPArraySet_ignoreFirstInteger"); + + // Primitive arrays ignore all kinds of non-primitive object information. + conf.putSuccessor(ScannerState.TRANSITION_OBJECT_REFERENCE, + "ignoreAll"); + conf.putSuccessor(ScannerState.TRANSITION_STRING_REFERENCE, "ignoreAll"); + conf.putSuccessor(ScannerState.TRANSITION_NULL_OBJECT, "ignoreAll"); + conf.putSuccessor(ScannerState.TRANSITION_CLASS_RESOLUTION, "ingoreAll"); + conf.putSuccessor(ScannerState.TRANSITION_OBJECT_INSTANTIATION, "ignoreAll"); + conf.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_ARRAY_INSTANTIATION, + "ignoreAll"); + conf.putSuccessor(ScannerState.TRANSITION_OBJECT_ARRAY_INSTANTIATION, + "ignoreAll"); + + conf = register("newPArraySet_ignoreFirstInteger", + new GenericScannerState(root, 1)); + + // In non-int primitive arrays class resolutions can happen + // but they should be ignored. + conf.putSuccessor(ScannerState.TRANSITION_CLASS_RESOLUTION, "ignoreAll"); + + // Spurious object and string references occur when setting array + // elements. This suppresses them. + conf.putSuccessor(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION, + "ignoreAll"); + conf.putSuccessor(ScannerState.TRANSITION_OBJECT_REFERENCE, "ignoreAll"); + conf.putSuccessor(ScannerState.TRANSITION_STRING_REFERENCE, "ignoreAll"); + conf.setDefaultSuccessor("start"); + + } + + /** Registers a ScannerState under a certain name. + * + * @param name Name of the state + * @param state The ScannerState instance. + * @return The second argument. + */ + private ScannerState register(String name, ScannerState state) + { + state.init(name); + + states.put(name, state); + + return state; + } + + /** Generates or returns an id for the given object which can be activated + * later if the object is suitable. + * + *

Objects are unsuitable if they are an instance of a primitive wrapper + * or String.

+ * + * @param value The object to retrieve an id for. + * @return The id for the object or null. + */ + private ObjectId retrieveId(Object value) + { + Class valueClass = value.getClass(); + ObjectId id = null; + + // Although multiple accesses to Class objects are not handled + // through ids we generate one for them, too. This allows us to detect + // second time references to such objects in the writeObject method + // and handle them in a special way. + if (valueClass != String.class + && valueClass.getSuperclass() != Number.class + && valueClass != Boolean.class) + { + if ((id = (ObjectId) objects.get(value)) == null) + { + id = new ObjectId(valueClass); + objects.put(value, id); + } + } + + return id; + } + + /** Scans the argument and calls one of event methods. See + * the introduction of this class for details. + * + * @param expr The expression to serialize. + */ + public void writeExpression(Expression expr) + { + String methodName = expr.getMethodName(); + Object[] args = expr.getArguments(); + Object target = expr.getTarget(); + Object value = null; + + try + { + value = expr.getValue(); + } + catch (Exception e) + { + throw (InternalError) + new InternalError( + "The Expression's value should be available at this point.") + .initCause(e); + } + + // TODO: What if the value is null? + ObjectId id; + Class valueClass = value.getClass(); + + if (target == Array.class) + { + if (methodName.equals("newInstance")) + { + id = retrieveId(value); + + Class ct = (Class) args[0]; + + if (ct.isPrimitive() || ct == Boolean.class || ct == Byte.class + || ct == Short.class || ct == Integer.class || ct == Long.class + || ct == Float.class || ct == Double.class) + primitiveArrayInstantiation(ct.getName(), + args[1].toString(), + id); + else + objectArrayInstantiation(ct.getName(), + args[1].toString(), + id); + + return; + } + else if (methodName.equals("get")) + { + arrayGet(args[1].toString()); + + // The encoder does not call the ScanEngine + // when an object is serialized that we already know. + // We test for this situation and insert the object reference + // manually. + // Since there is already a workaround for the Class class + // in writeObject we have to except it from this behavior. + id = (ObjectId) objects.get(value); + if (id != null && valueClass != Class.class) + { + objectReference(id); + end(); + } + + return; + } + else if (methodName.equals("set")) + { + arraySet(args[1].toString()); + return; + } + } + + id = retrieveId(value); + + if (target instanceof Class) + { + if (methodName.equals("new")) + { + Class targetClass = (Class) target; + + // All primitive types have short-hand forms for their + // constructors. + if (valueClass == Boolean.class) + primitiveInstantiation("boolean", args[0].toString()); + else if (valueClass == Byte.class) + primitiveInstantiation("byte", args[0].toString()); + else if (valueClass == Short.class) + primitiveInstantiation("short", args[0].toString()); + else if (valueClass == Integer.class) + primitiveInstantiation("int", args[0].toString()); + else if (valueClass == Long.class) + primitiveInstantiation("long", args[0].toString()); + else if (valueClass == Float.class) + primitiveInstantiation("float", args[0].toString()); + else if (valueClass == Double.class) + primitiveInstantiation("double", args[0].toString()); + else + objectInstantiation(targetClass.getName(), id); + + return; + } + else if (value instanceof Class) + { + String className = ((Class) value).getName(); + + // At this point we know that some *static* method will be called. + + if (methodName.equals("forName")) + { + // However "Class.forName" represents class resolution and has a + // special syntax. + classResolution(className); + return; + } + else if (methodName.equals("getField")) + { + // The same goes for "Class.getField". + // Note: The name of the wanted field is given in + // the argument array. + staticFieldAccess(className, args[0].toString()); + return; + } + else + { + // If nothing fits it is just a static method + // invocation which we decode as such. + staticMethodInvocation(className, methodName); + return; + } + } + } + else if (target instanceof List) + { + // Special behavior for indexed get and set method for list-style + // classes. + // The arguments are in the args array but we need them as subelements. + if (methodName.equals("get")) + { + listGet(); + return; + } + else if (methodName.equals("set")) + { + listSet(); + return; + } + } + + // If nothing else could be used then this is a normal + // method invocation. + methodInvocation(methodName); + } + + /** + * Ends the current state and returns to the last one. + */ + public void end() + { + current.end(); + + if (DEBUG) System.err.print("back from " + current.getName()); + + ScannerState oldCurrent = current; + current = (ScannerState) parents.pop(); + + if (DEBUG) System.err.println(" to " + current.getName()); + } + + /** + * Returns to the last state and deletes the last element in the object tree. + */ + public void revoke() + { + ScannerState oldCurrent = current; + current = (ScannerState) parents.pop(); + + root.deleteLast(); + } + + /** Scans the argument and calls one of event methods. See + * the introduction of this class for details. + * + * @param stmt The statement to serialize. + */ + public void writeStatement(Statement stmt) + { + // This is a simplified version of writeExpression. Everything + // that would not create something that is embedded in a tag + // is left out (instantiation, getters, ...). + // TODO: Is this the right thing to do? + + String methodName = stmt.getMethodName(); + Object target = stmt.getTarget(); + Object[] args = stmt.getArguments(); + + if (target == Array.class && methodName.equals("set")) + { + arraySet(args[1].toString()); + return; + } + + if (target instanceof List) + { + if (methodName.equals("set")) + { + listSet(); + return; + } + } + + // If nothing else could be used then this is a normal + // method invocation. + methodInvocation(methodName); + } + + /** Scans the argument and calls one of event methods. See + * the introduction of this class for details. + * + * @param o The object to serialize. + */ + public boolean writeObject(Object o) + { + ObjectId id = null; + + if (o == null) + { + // Handle null objects which have a special syntax. + nullObject(); + end(); + } + else if (o.getClass() == String.class) + { + // Handle strings which are treated extremely special + // in the encoder (they are never converted into a + // Expression). + stringReference((String) o); + end(); + } + else if ((id = (ObjectId) objects.get(o)) != null) + { + // Multiple references to a Class object do not generate + // an object reference but we use the id to detect that + // situation. + if (o.getClass() == Class.class) + { + classResolution(((Class) o).getName()); + end(); + return false; + } + + // If our object has a corresponding ObjectId instance + // then generate an objectReference. This will + // initialize the id (= brings it in the "used" state) + // when this is the first referal. + objectReference(id); + end(); + return false; + } + + return true; + } + + /** + * Writes the currently constructed object tree out as + * XML and clears the object to {@link ObjectId} relations. + */ + public void flush() + { + // Make all references unreachable. That means we have to generate + // new object ids. + objects.clear(); + + root.traverse(writer); + } + + /** Writes the final bits if the object tree and closes the stream + * afterwards. + */ + public void close() + { + flush(); + root.close(writer); + } + + /** + * Does a transition from one state to another using the given event. + * + *

This involves saving the current state, retrieving it's + * successor and setting it as the current state.

+ * + * @param transition One of {@link ScannerStates]'s transition constants. + */ + private void transition(int transition) + { + parents.push(current); + + String stateName = current.getSuccessor(transition); + + if (DEBUG) + { + System.err.println("from state: " + current.getName() + "\n\troute: " + + ScannerState.transitionNames[transition] + + "\n\t\tto state: " + + stateName); + } + + ScannerState newState = (ScannerState) states.get(stateName); + + newState.enter(new Context(current.getName(), current.getCalls())); + + assert (newState != null) : "State '" + stateName + "' was not defined."; + + current = newState; + } + + /** Event method that denotes a (non-static) method invocation. + * + *

More details about this method can be found in this + * class' introduction.

+ * + * @param methodName The name of the method which is called. + */ + void methodInvocation(String methodName) + { + transition(ScannerState.TRANSITION_METHOD_INVOCATION); + + current.methodInvocation(methodName); + } + + /** Event method that denotes a static method invocation. + * + *

More details about this method can be found in this + * class' introduction.

+ * + * @param methodName The name of the method which is called. + * @param className The name of the class in which the method is called. + */ + void staticMethodInvocation(String className, String methodName) + { + transition(ScannerState.TRANSITION_STATIC_METHOD_INVOCATION); + + current.staticMethodInvocation(className, methodName); + } + + /** Event method that denotes the retrieval of a static field's value. + * + *

More details about this method can be found in this + * class' introduction.

+ * + * @param fieldName The name of the field whose value is retrieved. + * @param className The name of the class in which the method is called. + */ + void staticFieldAccess(String className, String fieldName) + { + transition(ScannerState.TRANSITION_STATIC_FIELD_ACCESS); + + current.staticFieldAccess(className, fieldName); + } + + /** Event method that denotes the resolution of a class. + * + *

More details about this method can be found in this + * class' introduction.

+ * + * @param className The name of the class in which the method is called. + */ + void classResolution(String className) + { + transition(ScannerState.TRANSITION_CLASS_RESOLUTION); + + current.classResolution(className); + } + + /** Event method that denotes the instantiation of an object. + * + *

More details about this method can be found in this + * class' introduction.

+ * + * @param className The name of the class in which the method is called. + * @param objectId An ObjectId instance which can be activated later. + */ + void objectInstantiation(String className, ObjectId objectId) + { + transition(ScannerState.TRANSITION_OBJECT_INSTANTIATION); + + current.objectInstantiation(className, objectId); + } + + /** Event method that denotes the instantiation of a primitive. + * + *

More details about this method can be found in this + * class' introduction.

+ * + * @param primitiveName One of "boolean, "byte", "short", "int", "long" + * , "float" or "double" + * @param valueAsString The value of the primitive as a String. + */ + void primitiveInstantiation(String primitiveName, String valueAsString) + { + transition(ScannerState.TRANSITION_PRIMITIVE_INSTANTIATION); + + current.primitiveInstantiation(primitiveName, valueAsString); + } + + /** Event method that denotes the instantiation of an object array. + * + *

More details about this method can be found in this + * class' introduction.

+ * + * @param arrayClassName The array's class name. + * @param objectId An ObjectId instance which can be activated later. + * @param lengthAsString The array's length as String. + */ + void objectArrayInstantiation(String arrayClassName, String lengthAsString, + ObjectId objectId) + { + transition(ScannerState.TRANSITION_OBJECT_ARRAY_INSTANTIATION); + + current.objectArrayInstantiation(arrayClassName, lengthAsString, objectId); + } + + /** Event method that denotes the instantiation of a primitive array. + * + *

More details about this method can be found in this + * class' introduction.

+ * + * @param arrayClassName The array's class name. + * @param objectId An ObjectId instance which can be activated later. + * @param lengthAsString The array's length as String. + */ + void primitiveArrayInstantiation(String arrayClassName, String lengthAsString, + ObjectId objectId) + { + transition(ScannerState.TRANSITION_PRIMITIVE_ARRAY_INSTANTIATION); + + current.objectArrayInstantiation(arrayClassName, lengthAsString, objectId); + } + + /** Event method that denotes the setting of a value in an array. + * + *

More details about this method can be found in this + * class' introduction.

+ * + * @param indexAsString The index to as a String. + */ + void arraySet(String indexAsString) + { + transition(ScannerState.TRANSITION_ARRAY_SET); + + current.arraySet(indexAsString); + } + + /** Event method that denotes the retrieval of a value in an array. + * + *

More details about this method can be found in this + * class' introduction.

+ * + * @param indexAsString The index to as a String. + */ + void arrayGet(String indexAsString) + { + transition(ScannerState.TRANSITION_ARRAY_GET); + + current.arrayGet(indexAsString); + } + + /** Event method that denotes the setting of a value in a list. + * + *

More details about this method can be found in this + * class' introduction.

+ */ + void listSet() + { + transition(ScannerState.TRANSITION_LIST_SET); + + current.listSet(); + } + + /** Event method that denotes the retrieval of a value in a list. + * + *

More details about this method can be found in this + * class' introduction.

+ */ + void listGet() + { + transition(ScannerState.TRANSITION_LIST_GET); + + current.listGet(); + } + + /** Event method that denotes the null value. + */ + void nullObject() + { + transition(ScannerState.TRANSITION_NULL_OBJECT); + + current.nullObject(); + } + + /** Event method that denotes a string. + * + * @param string The string that should be written. + */ + void stringReference(String string) + { + transition(ScannerState.TRANSITION_STRING_REFERENCE); + + current.stringReference(string); + } + + /** Event method that denotes a reference to an existing object. + * + * @param id The ObjectId to be used. + */ + void objectReference(ObjectId id) + { + transition(ScannerState.TRANSITION_OBJECT_REFERENCE); + + current.objectReference(id); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/ScannerState.java b/libjava/classpath/gnu/java/beans/encoder/ScannerState.java new file mode 100644 index 000000000..14d63056e --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/ScannerState.java @@ -0,0 +1,236 @@ +/* ScannerState.java + 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.java.beans.encoder; + +import java.util.HashMap; + +/**

Provides the infrastructure for the state machine and the transition + * mechanism.

+ * + *

Each states knows a set of successor. There can be one successor for + * every transition variant. Furthermore a state knows about a default + * successor which is taken when there is no special setup for a + * transition.

+ * + * @author Robert Schuster (robertschuster@fsfe.org) + * + */ +public abstract class ScannerState +{ + + static final int TRANSITION_METHOD_INVOCATION = 0; + + static final int TRANSITION_STATIC_METHOD_INVOCATION = 1; + + static final int TRANSITION_STATIC_FIELD_ACCESS = 2; + + static final int TRANSITION_CLASS_RESOLUTION = 3; + + static final int TRANSITION_OBJECT_INSTANTIATION = 4; + + static final int TRANSITION_PRIMITIVE_INSTANTIATION = 5; + + static final int TRANSITION_OBJECT_ARRAY_INSTANTIATION = 6; + + static final int TRANSITION_PRIMITIVE_ARRAY_INSTANTIATION = 7; + + static final int TRANSITION_ARRAY_SET = 8; + + static final int TRANSITION_ARRAY_GET = 9; + + static final int TRANSITION_LIST_SET = 10; + + static final int TRANSITION_LIST_GET = 11; + + static final int TRANSITION_NULL_OBJECT = 12; + + static final int TRANSITION_STRING_REFERENCE = 13; + + static final int TRANSITION_OBJECT_REFERENCE = 14; + + static final int TRANSITION_FIRST = 0; + + static final int TRANSITION_LAST = 14; + + static final String DEFAULT_STATE_NAME = "default"; + + String defaultSuccessor = DEFAULT_STATE_NAME; + + static String[] transitionNames = { "METHOD_INVOCATION", "STATIC_METHOD_INVOCATION", + "STATIC_FIELD_ACCESS", "CLASS_RESOLUTION", + "OBJECT_INSTANTIATION", + "PRIMITIVE_INSTANTIATION", "OBJECT_ARRAY_INSTANTIATION", + "PRIMITIVE_ARRAY_INSTANTIATION", + "ARRAY_SET", "ARRAY_GET", "LIST_SET", "LIST_GET", + "NULL_OBJECT", "STRING_REFERENCE", "OBJECT_REFERENCE" }; + + /** + * Stores the transition setup as the relation + * transition->successor's state name. + */ + HashMap transitions = new HashMap(); + + int calls; + + Context context; + + String name; + + final void init(String newName) + { + assert (name == null); + + name = newName; + } + + final String getName() + { + return name; + } + + final void enter(Context ctx) + { + calls++; + context = ctx; + + enterImpl(ctx); + } + + protected void enterImpl(Context ctx) + { + } + + final Context context() + { + return context; + } + + final int getCalls() + { + return calls; + } + + /** + *

Stores a successor's state name for a certain transition.

+ * + *

This method is only used at the configuration time of the state + * machine.

+ * + * @param transition One of the transition constants. + * @param stateName The state name of the successor. + */ + final void putSuccessor(int transition, String stateName) + { + assert (transition >= TRANSITION_FIRST && transition <= TRANSITION_LAST) : + "Transition identifier '" + transition + "' is unknown."; + + transitions.put(new Integer(transition), stateName); + } + + /**

Retrieves a the state name of a successor for the given transition + * constant.

+ * + *

Returns the default successor's state name if no special setup was + * prepared.

+ * + * @param transition One of the transition constants. + * @return The state name of the successor. + */ + final String getSuccessor(int transition) + { + String state = (String) transitions.get(new Integer(transition)); + + return (state == null) ? defaultSuccessor : state; + } + + /** + * Sets the name for the default successor state. + * + * @param newDefaultSuccessor The default successor's state name. + */ + final void setDefaultSuccessor(String newDefaultSuccessor) + { + defaultSuccessor = newDefaultSuccessor; + } + + abstract void methodInvocation(String methodName); + + abstract void staticMethodInvocation(String className, String methodName); + + abstract void staticFieldAccess(String className, String fieldName); + + abstract void classResolution(String className); + + abstract void objectInstantiation(String className, ObjectId objectId); + + abstract void primitiveInstantiation(String primitiveName, + String valueAsString); + + abstract void objectArrayInstantiation(String arrayClassName, String lengthAsString, ObjectId objectId); + + abstract void primitiveArrayInstantiation(String arrayClassName, String lengthAsString, ObjectId objectId); + + abstract void arraySet(String indexAsString); + + abstract void arrayGet(String indexAsString); + + abstract void listGet(); + + abstract void listSet(); + + abstract void nullObject(); + + abstract void stringReference(String string); + + abstract void objectReference(ObjectId id); + + /** + *

A special event that does not provoke a direct transition.

+ * + *

Instead the transition is done by the ScanEngine: It goes + * back to the previous state and just uses this method to inform the state + * about this happening.

+ */ + abstract void end(); + + void enter() + { + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/StAXWriter.java b/libjava/classpath/gnu/java/beans/encoder/StAXWriter.java new file mode 100644 index 000000000..da88c5361 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/StAXWriter.java @@ -0,0 +1,233 @@ +/* StAXWriter.java + 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.java.beans.encoder; + +import java.io.OutputStream; + +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +/** A {@link Writer} implementation based on the StAX API. + * + * @author Robert Schuster (robertschuster@fsfe.org) + * + */ +public class StAXWriter implements Writer +{ + XMLStreamWriter writer; + + int indent = 0; + + public StAXWriter(OutputStream os) + { + try + { + XMLOutputFactory factory = XMLOutputFactory.newInstance(); + writer = factory.createXMLStreamWriter(os); + } + catch (XMLStreamException se) + { + throw (InternalError) + new InternalError( + "Could not instantiate a streaming XML writer.") + .initCause(se); + } + + } + + public void flush() + { + if (writer != null) + { + try + { + writer.flush(); + } + catch (XMLStreamException xse) + { + // TODO: find out + } + } + + } + + public void close() + { + if (writer != null) + { + try + { + writer.close(); + } + catch (XMLStreamException xse) + { + // TODO: find out + } + writer = null; + } + + } + + public void writePreamble() + { + try + { + writer.writeStartDocument("UTF-8", "1.0"); + } + catch (XMLStreamException xmlse) + { + + } + } + + public void writeEnd(boolean wasEmpty) + { + try + { + indent -= 2; + + if (wasEmpty) + return; + + for (int i = 0; i < indent; i++) + writer.writeCharacters(" "); + + writer.writeEndElement(); + + writer.writeCharacters("\n"); + } + catch (XMLStreamException xmlse) + { + + } + } + + public void writeEndNoChildren() + { + try + { + writer.writeEndElement(); + writer.writeCharacters("\n"); + } + catch (XMLStreamException xmlse) + { + + } + } + + public void write(String tagName, boolean empty) + { + write(tagName, null, null, null, empty); + } + + public void write(String tagName, String value) + { + write(tagName, value, null, null, value == null); + } + + public void writeNoChildren(String tagName, String value) + { + try + { + for (int i = 0; i < indent; i++) + writer.writeCharacters(" "); + + writer.writeStartElement(tagName); + + writer.writeCharacters(value); + } + catch (XMLStreamException xmlse) + { + + } + } + + public void write(String tagName, String attributeName, + String attributeValue, boolean empty) + { + write(tagName, null, new String[] { attributeName }, + new String[] { attributeValue }, empty); + } + + public void write(String tagName, String value, String[] attributeNames, + String[] attributeValues, boolean empty) + { + try + { + for (int i = 0; i < indent; i++) + + writer.writeCharacters(" "); + + if (empty) + writer.writeEmptyElement(tagName); + else + writer.writeStartElement(tagName); + + if (attributeNames != null) + for (int i = 0; i < attributeNames.length; i++) + writer.writeAttribute(attributeNames[i], attributeValues[i]); + + writer.writeCharacters("\n"); + + indent += 2; + + if (value != null) + { + for (int i = 0; i < indent; i++) + writer.writeCharacters(" "); + + writer.writeCharacters(value); + + writer.writeCharacters("\n"); + } + } + catch (XMLStreamException xmlse) + { + + } + } + + public void write(String tagName, String[] attributeNames, + String[] attributeValues, boolean empty) + { + write(tagName, null, attributeNames, attributeValues, empty); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/Writer.java b/libjava/classpath/gnu/java/beans/encoder/Writer.java new file mode 100644 index 000000000..e08c786d8 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/Writer.java @@ -0,0 +1,174 @@ +/* Writer.java -- Writing interface for XML persistence. + 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.java.beans.encoder; + +/** A Writer represents a simplified interface to an XML + * writer that is used for the XML persistence mechanism. + * + *

Its sole purpose is to allow multiple backends which may remove + * the need to have certain APIs in the classpath. Eg. it is possible + * to write a stripped down XML Writer that does not rely on SAX, StAX + * or DOM APIs.

+ * + *

The caller may assume that every action is done immediately. However + * it is possible that the underlying implementation uses buffering streams. + * To make sure the data is written call the {@link flush} method.

+ * + *

The Writer implementation should care about the formatting + * of the XML stream making it possible to generate three types of formats using + * a special method invocation chain.

+ * + *

Write + * + * <element/> + * + * by issuing write("element", true) (or any of the other + * write-variants that allows specifying the isEmpty argument) + * and writeEnd(true).

+ * + *

Write + * + * <element>body</element> + * + * by issuing writeNoChildren("element", "body") and writeNoChildrenEnd().

+ * + *

+ * Write + * + * <element> + * <child1/> + * <child2/> + * ... + * <element/> + * + * by issuing write("element", false) (or any of the other + * write-variants that allows specifying the isEmpty argument) + * and writeEnd(false).

+ * + *

Note: It is important that the values of isEmpty and + * wasEmpty match. Otherwise strange things might happen to + * the layout.

+ * + * @author Robert Schuster (robertschuster@fsfe.org) + * + */ +public interface Writer +{ + // TODO: This interface's design is not the best. Feel free to + // improve it as you like. + + /** Writes the XML preamble. */ + void writePreamble(); + + /** Writes the end of an XML tag. + * + *

If your tag has not generated any body text or child + * elements provide true as the argument to generate + * more space efficient variant of the tag.>/p> + * + * @param wasEmpty Whether the tag was empty or not. + */ + void writeEnd(boolean wasEmpty); + + /** Writes an XML tag without any attributes. + * + * @param tagName The name of the tag to write. + * @param empty Whether the element has child elements. + */ + void write(String tagName, boolean empty); + + /** Writes an XML tag with one attribute name and value. + * + * @param tagName The name of the tag to write. + * @param attributeName The name of attribute. + * @param attributeValue The attribute's value. + * @param empty Whether the element has child elements. + */ + void write(String tagName, String attributeName, String attributeValue, boolean empty); + + /** Writes an XML tag with multiple attributes and a body text. + * + * @param tagName The name of the tag to write. + * @param value The element's body content. + * @param attributeNames A set of attribute names. + * @param attributeValues A set of attribute values. + * @param empty Whether the element has child elements. + */ + void write(String tagName, String value, String[] attributeNames, + String[] attributeValues, boolean empty); + + /** Writes an XML tag with multiple attributes without a body text. + * + * @param tagName The name of the tag to write. + * @param attributeNames A set of attribute names. + * @param attributeValues A set of attribute values. + * @param empty Whether the element has child elements. + */ + void write(String tagName, String[] attributeNames, String[] attributeValues, boolean empty); + + /** Writes an XML tag with no attributes but with a body text + * that may have child elements. + * + * @param tagName The name of the tag to write. + * @param value The element's body content. + */ + void write(String tagName, String value); + + /** Writes an XML tag with no attributes but with a body text + * that does not have child elements. + * + * @param tagName The name of the tag to write. + * @param value The element's body content. + */ + void writeNoChildren(String tagName, String value); + + /** Writes the end of an XML tag that has no child elements. + * + *

Must be used in combination with {@link writeNoChildren} only.

+ */ + void writeEndNoChildren(); + + /** Forces the implementation to write some data. + */ + void flush(); + + /** Closes the writer. + */ + void close(); +} diff --git a/libjava/classpath/gnu/java/beans/encoder/elements/ArrayInstantiation.java b/libjava/classpath/gnu/java/beans/encoder/elements/ArrayInstantiation.java new file mode 100644 index 000000000..51e00c361 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/elements/ArrayInstantiation.java @@ -0,0 +1,74 @@ +/* ArrayInstantiation.java + 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.java.beans.encoder.elements; + +import gnu.java.beans.encoder.ObjectId; +import gnu.java.beans.encoder.Writer; + +/** Generates an XML element denoting the instantiation of an array. + * + * @author Robert Schuster (robertschuster@fsfe.org) + * + */ +public class ArrayInstantiation extends Element +{ + final String className; + + final String lengthAsString; + + public ArrayInstantiation(String newClassName, String newLengthAsString) + { + className = newClassName; + lengthAsString = newLengthAsString; + } + + public void writeStart(Writer writer) + { + ObjectId objectId = getId(); + if (objectId.isUnused()) + writer.write("array", new String[] { "class", "length" }, + new String[] { className, lengthAsString }, isEmpty()); + else + writer.write("array", new String[] { "id", "class", "length" }, + new String[] { objectId.toString(), className, + lengthAsString }, isEmpty()); + + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/elements/Array_Get.java b/libjava/classpath/gnu/java/beans/encoder/elements/Array_Get.java new file mode 100644 index 000000000..912ecebb5 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/elements/Array_Get.java @@ -0,0 +1,62 @@ +/* Array_Get.java + 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.java.beans.encoder.elements; + +import gnu.java.beans.encoder.Writer; + +/** + * Generates an XML element denoting the retrieval of an array value. + * + * @author Robert Schuster (robertschuster@fsfe.org) + */ +public class Array_Get extends Element +{ + final String indexAsString; + + public Array_Get(String newIndexAsString) + { + indexAsString = newIndexAsString; + } + + public void writeStart(Writer writer) + { + writer.write("void", "index", indexAsString, isEmpty()); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/elements/Array_Set.java b/libjava/classpath/gnu/java/beans/encoder/elements/Array_Set.java new file mode 100644 index 000000000..096232055 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/elements/Array_Set.java @@ -0,0 +1,57 @@ +/* Array_Set.java -- FIXME: briefly describe file purpose + 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.java.beans.encoder.elements; + +import gnu.java.beans.encoder.Writer; + +public class Array_Set extends Element +{ + final String indexAsString; + + public Array_Set(String newIndexAsString) + { + indexAsString = newIndexAsString; + } + + public void writeStart(Writer writer) + { + writer.write("void", "index", indexAsString, isEmpty()); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/elements/ClassResolution.java b/libjava/classpath/gnu/java/beans/encoder/elements/ClassResolution.java new file mode 100644 index 000000000..cb736d5c0 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/elements/ClassResolution.java @@ -0,0 +1,67 @@ +/* ClassResolution.java + 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.java.beans.encoder.elements; + +import gnu.java.beans.encoder.Writer; + +/** Generates an XML element denoting the resolution of a class. + * + * @author Robert Schuster (robertschuster@fsfe.org) + * + */ +public class ClassResolution extends Element +{ + final String className; + + public ClassResolution(String newClassName) + { + className = newClassName; + } + + public void writeStart(Writer writer) + { + writer.writeNoChildren("class", className); + } + + public void writeEnd(Writer writer) + { + writer.writeEndNoChildren(); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/elements/Element.java b/libjava/classpath/gnu/java/beans/encoder/elements/Element.java new file mode 100644 index 000000000..a8c0ecdf7 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/elements/Element.java @@ -0,0 +1,157 @@ +/* Element.java -- Base class for object tree elements. + 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.java.beans.encoder.elements; + +import java.util.Iterator; +import java.util.LinkedList; + +import gnu.java.beans.encoder.ObjectId; +import gnu.java.beans.encoder.Writer; + +/** Element is the base class for the object tree elements. + * + *

It provides the neccessary infrastructure every element subclass + * needs in order to interact with the {@link gnu.java.beans.encoder.Root} + * class.

+ * + * @author Robert Schuster (robertschuster@fsfe.org) + */ +public abstract class Element +{ + /** + * Stores the child elements. + */ + private LinkedList children = new LinkedList(); + + /** + * An optional ObjectId instance which is needed for certain subclasses + * only. + */ + private ObjectId objectId; + + /** Sets an {@link gnu.java.beans.encoder.ObjectId} instance in this + * Element. + * + *

This can only be done once.

+ * + * @param objectId An ObjectId instance. + */ + public final void initId(ObjectId objectId) + { + assert (this.objectId == null); + assert (objectId != null); + + this.objectId = objectId; + } + + /** Adds a child element to this Element. + * + * @param elem The new child. + */ + public final void addChild(Element elem) + { + children.add(elem); + } + + /** Removes the child element added last. + */ + public final void removeLast() + { + children.removeLast(); + } + + /** Provides access to the child elements via an iterator. + * + * @return An iterator for the child elements. + */ + public final Iterator iterator(){ + return children.iterator(); + } + + /** Clears all the stored child elements. + * + */ + public final void clear() + { + children.clear(); + } + + /** Returns whether this element contains child elements. + * + *

This method is useful to decide which formatting variant + * for the XML element can be chosen.

+ * + * @return Whether the element has child elements. + */ + public final boolean isEmpty() + { + return children.isEmpty(); + } + + /** Retrieves the element's {@link gnu.java.beans.encoder.ObjectId} instance + * if it has one. + * + * @return The ObjectId instance or null. + */ + public final ObjectId getId() + { + return objectId; + } + + /** Writes the opening XML tag. + * + * @param writer The writer to be used for XML writing. + */ + public abstract void writeStart(Writer writer); + + /** Writes the closing XML tag. + * + *

By default this does writer.writeEnd(children.isEmpty()). + * Override if neccessary, for example when using the + * {@link gnu.java.beans.encoder.Writer#writeNoChildren} method + * variants. + * + * @param writer The writer to be used for XML writing. + */ + public void writeEnd(Writer writer) + { + writer.writeEnd(children.isEmpty()); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/elements/List_Get.java b/libjava/classpath/gnu/java/beans/encoder/elements/List_Get.java new file mode 100644 index 000000000..c14ab91f9 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/elements/List_Get.java @@ -0,0 +1,56 @@ +/* List_Get.java + 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.java.beans.encoder.elements; + +import gnu.java.beans.encoder.Writer; + +/** Generates an XML element denoting the retrieval of a list's element. + * + * @author Robert Schuster (robertschuster@fsfe.org) + * + */ +public class List_Get extends Element +{ + + public void writeStart(Writer writer) + { + writer.write("object", "get"); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/elements/List_Set.java b/libjava/classpath/gnu/java/beans/encoder/elements/List_Set.java new file mode 100644 index 000000000..3e7cca628 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/elements/List_Set.java @@ -0,0 +1,56 @@ +/* List_Set.java + 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.java.beans.encoder.elements; + +import gnu.java.beans.encoder.Writer; + +/** Generates an XML element denoting the setting of a list's element. + * + * @author Robert Schuster (robertschuster@fsfe.org) + * + */ +public class List_Set extends Element +{ + + public void writeStart(Writer writer) + { + writer.write("object", "set"); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/elements/MethodInvocation.java b/libjava/classpath/gnu/java/beans/encoder/elements/MethodInvocation.java new file mode 100644 index 000000000..1de5bb62d --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/elements/MethodInvocation.java @@ -0,0 +1,62 @@ +/* MethodCall.java + 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.java.beans.encoder.elements; + +import gnu.java.beans.encoder.Writer; + +/** Generates an XML element denoting a non-static method call. + * + * @author Robert Schuster (robertschuster@fsfe.org) + * + */ +public class MethodInvocation extends Element +{ + final String methodName; + + public MethodInvocation(String newMethodName) + { + methodName = newMethodName; + } + + public void writeStart(Writer writer) + { + writer.write("void", "method", methodName, isEmpty()); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/elements/NullObject.java b/libjava/classpath/gnu/java/beans/encoder/elements/NullObject.java new file mode 100644 index 000000000..211e2a74b --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/elements/NullObject.java @@ -0,0 +1,61 @@ +/* NullObject.java + 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.java.beans.encoder.elements; + +import gnu.java.beans.encoder.Writer; + +/** Generates an XML element denoting the null value. + * + * @author Robert Schuster (robertschuster@fsfe.org) + * + */ +public class NullObject extends Element +{ + + public void writeStart(Writer writer) + { + writer.write("null", true); + } + + public void writeEnd(Writer writer) + { + writer.writeEnd(true); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/elements/ObjectInstantiation.java b/libjava/classpath/gnu/java/beans/encoder/elements/ObjectInstantiation.java new file mode 100644 index 000000000..98614809f --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/elements/ObjectInstantiation.java @@ -0,0 +1,68 @@ +/* ObjectInstantiation.java + 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.java.beans.encoder.elements; + +import gnu.java.beans.encoder.ObjectId; +import gnu.java.beans.encoder.Writer; + +/** Generates an XML element denoting the instantiation of an object. + * + * @author Robert Schuster (robertschuster@fsfe.org) + * + */ +public class ObjectInstantiation extends Element +{ + final String className; + + public ObjectInstantiation(String newClassName) + { + className = newClassName; + } + + public void writeStart(Writer writer) + { + ObjectId objectId = getId(); + if (objectId.isUnused()) + writer.write("object", "class", className, isEmpty()); + else + writer.write("object", new String[] { "id", "class" }, + new String[] { objectId.toString(), className }, isEmpty()); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/elements/ObjectReference.java b/libjava/classpath/gnu/java/beans/encoder/elements/ObjectReference.java new file mode 100644 index 000000000..13a597a58 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/elements/ObjectReference.java @@ -0,0 +1,68 @@ +/* StringInstantiation.java + 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.java.beans.encoder.elements; + +import gnu.java.beans.encoder.ObjectId; +import gnu.java.beans.encoder.Writer; + +/** Generates an XML element denoting referencing an existing object. + * + * @author Robert Schuster (robertschuster@fsfe.org) + * + */ +public class ObjectReference extends Element +{ + final ObjectId id; + + public ObjectReference(ObjectId newId) + { + id = newId; + + // Initializing the Id here is making sure it gets + // actually used. This step modifies the Id instance + // in other elements. + id.init(); + } + + public void writeStart(Writer writer) + { + writer.write("object", "idref", id.toString(), isEmpty()); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/elements/PrimitiveInstantiation.java b/libjava/classpath/gnu/java/beans/encoder/elements/PrimitiveInstantiation.java new file mode 100644 index 000000000..ae34b9dad --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/elements/PrimitiveInstantiation.java @@ -0,0 +1,69 @@ +/* PrimitiveInstantiation.java + 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.java.beans.encoder.elements; + +import gnu.java.beans.encoder.Writer; + +/** Generates an XML element denoting a primitive data value. + * + * @author Robert Schuster (robertschuster@fsfe.org) + * + */ +public class PrimitiveInstantiation extends Element +{ + final String primitiveName; + + final String valueAsString; + + public PrimitiveInstantiation(String newPrimitiveName, String newValueAsString) + { + primitiveName = newPrimitiveName; + valueAsString = newValueAsString; + } + + public void writeStart(Writer writer) + { + writer.writeNoChildren(primitiveName, valueAsString); + } + + public void writeEnd(Writer writer) + { + writer.writeEndNoChildren(); + } +} diff --git a/libjava/classpath/gnu/java/beans/encoder/elements/StaticFieldAccess.java b/libjava/classpath/gnu/java/beans/encoder/elements/StaticFieldAccess.java new file mode 100644 index 000000000..7fcbf5203 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/elements/StaticFieldAccess.java @@ -0,0 +1,66 @@ +/* StaticFieldAccess.java + 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.java.beans.encoder.elements; + +import gnu.java.beans.encoder.Writer; + +/** Generates an XML element denoting a static method call. + * + * @author Robert Schuster (robertschuster@fsfe.org) + * + */ +public class StaticFieldAccess extends Element +{ + final String className; + + final String fieldName; + + public StaticFieldAccess(String newClassName, String newFieldName) + { + className = newClassName; + fieldName = newFieldName; + } + + public void writeStart(Writer writer) + { + writer.write("object", new String[] { "class", "field" }, + new String[] { className, fieldName }, isEmpty()); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/elements/StaticMethodInvocation.java b/libjava/classpath/gnu/java/beans/encoder/elements/StaticMethodInvocation.java new file mode 100644 index 000000000..92d49dc41 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/elements/StaticMethodInvocation.java @@ -0,0 +1,67 @@ +/* StaticMethodCall.java + -- A class denoting an XML element which makes up a static method call. + 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.java.beans.encoder.elements; + +import gnu.java.beans.encoder.Writer; + +/** + * + * @author Robert Schuster (robertschuster@fsfe.org) + * + */ +public class StaticMethodInvocation extends Element +{ + final String className; + + final String methodName; + + public StaticMethodInvocation(String newClassName, String newMethodName) + { + className = newClassName; + methodName = newMethodName; + } + + public void writeStart(Writer writer) + { + writer.write("void", new String[] { "class", "method" }, + new String[] { className, methodName }, isEmpty()); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/elements/StringReference.java b/libjava/classpath/gnu/java/beans/encoder/elements/StringReference.java new file mode 100644 index 000000000..7e6787da3 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/elements/StringReference.java @@ -0,0 +1,63 @@ +/* StringInstantiation.java + -- A class denoting an XML element which retrieves an array element. + 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.java.beans.encoder.elements; + +import gnu.java.beans.encoder.Writer; + +public class StringReference extends Element +{ + final String string; + + public StringReference(String newString) + { + string = newString; + } + + public void writeStart(Writer writer) + { + writer.writeNoChildren("string", string); + } + + public void writeEnd(Writer writer) + { + writer.writeEndNoChildren(); + } + +} diff --git a/libjava/classpath/gnu/java/beans/package.html b/libjava/classpath/gnu/java/beans/package.html new file mode 100644 index 000000000..f3b052683 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.beans + + +

+ + + diff --git a/libjava/classpath/gnu/java/io/ASN1ParsingException.java b/libjava/classpath/gnu/java/io/ASN1ParsingException.java new file mode 100644 index 000000000..9cf98abd3 --- /dev/null +++ b/libjava/classpath/gnu/java/io/ASN1ParsingException.java @@ -0,0 +1,56 @@ +/* ASN1ParsingException.java -- ASN.1 parsing exception. + Copyright (C) 2003 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.io; + +/** + * Signals a malformed ASN.1 sequence. + */ +public class ASN1ParsingException extends java.io.IOException +{ + + public ASN1ParsingException() + { + super(); + } + + public ASN1ParsingException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/gnu/java/io/Base64InputStream.java b/libjava/classpath/gnu/java/io/Base64InputStream.java new file mode 100644 index 000000000..1105b6022 --- /dev/null +++ b/libjava/classpath/gnu/java/io/Base64InputStream.java @@ -0,0 +1,220 @@ +/* Base64InputStream.java -- base-64 input stream. + Copyright (C) 2003, 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.io; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * A filter input stream that decodes data encoded in the Base-64 + * encoding scheme. + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +public class Base64InputStream extends FilterInputStream +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + /** Base-64 digits. */ + private static final String BASE_64 = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + /** Base-64 padding character. */ + private static final char BASE_64_PAD = '='; + + /** Decoding state. */ + private int state; + + /** Intermediate decoded value. */ + private int temp; + + /** EOF flag. */ + private boolean eof; + + private final byte[] one = new byte[1]; + + // Constructors. + // ------------------------------------------------------------------------ + + /** + * Create a new Base-64 input stream. The input bytes must be the + * ASCII characters A-Z, a-z, 0-9, + and /, with optional whitespace, + * and will be decoded into a byte stream. + * + * @param in The source of Base-64 input. + */ + public Base64InputStream(InputStream in) + { + super(in); + state = 0; + temp = 0; + eof = false; + } + + // Class method. + // ------------------------------------------------------------------------ + + /** + * Decode a single Base-64 string to a byte array. + * + * @param base64 The Base-64 encoded data. + * @return The decoded bytes. + * @throws IOException If the given data do not compose a valid Base-64 + * sequence. + */ + public static byte[] decode(String base64) throws IOException + { + Base64InputStream in = + new Base64InputStream(new ByteArrayInputStream(base64.getBytes())); + ByteArrayOutputStream out = + new ByteArrayOutputStream((int) (base64.length() / 0.666)); + byte[] buf = new byte[1024]; + int len; + while ((len = in.read(buf)) != -1) + out.write(buf, 0, len); + return out.toByteArray(); + } + + // Instance methods. + // ------------------------------------------------------------------------ + + public int available() + { + return 0; + } + + public int read() throws IOException + { + if (read(one) == 1) + return one[0]; + return -1; + } + + public int read(byte[] buf, int off, int len) throws IOException + { + if (eof) + return -1; + int count = 0; + while (count < len) + { + int i; + while (Character.isWhitespace((char) (i = in.read()))) + ; + + int pos = BASE_64.indexOf((char) i); + if (pos >= 0) + { + switch (state) + { + case 0: + temp = pos << 2; + state = 1; + break; + case 1: + buf[count++] = (byte) (temp | (pos >>> 4)); + temp = (pos & 0x0F) << 4; + state = 2; + break; + case 2: + buf[count++] = (byte) (temp | (pos >>> 2)); + temp = (pos & 0x03) << 6; + state = 3; + break; + case 3: + buf[count++] = (byte) (temp | pos); + state = 0; + break; + } + } + else if (i == BASE_64_PAD) + { + switch (state) + { + case 0: + case 1: + throw new IOException("malformed Base-64 input"); + case 2: + while (Character.isWhitespace((char) (i = in.read()))) + ; + if (i != BASE_64_PAD) + throw new IOException("malformed Base-64 input"); + case 3: + while (Character.isWhitespace((char) (i = in.read()))) + ; + } + eof = true; + break; + } + else // First non-Base-64 character, consider it end-of-stream. + { + if (state != 0) + throw new IOException("malformed Base-64 input"); + eof = true; + break; + } + } + return count; + } + + public boolean markSupported() + { + return false; + } + + public void mark(int markLimit) { } + + public void reset() throws IOException + { + throw new IOException("reset not supported"); + } + + public long skip(long n) throws IOException + { + long skipped; + for (skipped = 0; skipped < n; skipped++) + if (read() == -1) + break; + return skipped; + } +} diff --git a/libjava/classpath/gnu/java/io/ClassLoaderObjectInputStream.java b/libjava/classpath/gnu/java/io/ClassLoaderObjectInputStream.java new file mode 100644 index 000000000..e3f3d4c42 --- /dev/null +++ b/libjava/classpath/gnu/java/io/ClassLoaderObjectInputStream.java @@ -0,0 +1,73 @@ +/* gnu.java.io.ClassLoaderObjectInputStream + Copyright (C) 1998 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.io; + +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.StreamCorruptedException; + +/** + * ClassLoaderObjectInputStream is ObjectInputStream, with + * the ability to use a specific ClassLoader. + * + * @author Geoff Berry + * @version 1.1.0, 29 Jul 1998 + */ + +public class ClassLoaderObjectInputStream extends ObjectInputStream { + ClassLoader myClassLoader; + + /** Create the new ClassLoaderObjectInputStream. + * @param in the InputStream to read the Objects from. + * @param myClassLoader the ClassLoader to load classes + * with. + */ + public ClassLoaderObjectInputStream(InputStream in, ClassLoader myClassLoader) throws IOException,StreamCorruptedException { + super(in); + this.myClassLoader = myClassLoader; + } + + /** Overriden method to use the loadClass() method from + * the ClassLoader. + */ + public Class resolveClass(String name) throws IOException, ClassNotFoundException { + return myClassLoader.loadClass(name); + } +} diff --git a/libjava/classpath/gnu/java/io/NullOutputStream.java b/libjava/classpath/gnu/java/io/NullOutputStream.java new file mode 100644 index 000000000..603a2d3dd --- /dev/null +++ b/libjava/classpath/gnu/java/io/NullOutputStream.java @@ -0,0 +1,56 @@ +/* NullOutputStream.java -- OutputStream that does absolutely nothing + Copyright (C) 1998 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.io; + +import java.io.OutputStream; + +/** + This is a placeholder OutputStream that does absolutley nothing + when written to. It is intended to be used in the same manner as + /dev/null. None of this class's methods do anything at all. +*/ +public class NullOutputStream extends OutputStream +{ + public NullOutputStream() {} + public void write( int b ) {} + public void write( byte b[] ) {} + public void write( byte b[], int off, int len ) {} + public void flush() {} + public void close() {} +} diff --git a/libjava/classpath/gnu/java/io/ObjectIdentityMap2Int.java b/libjava/classpath/gnu/java/io/ObjectIdentityMap2Int.java new file mode 100644 index 000000000..ed62e8381 --- /dev/null +++ b/libjava/classpath/gnu/java/io/ObjectIdentityMap2Int.java @@ -0,0 +1,292 @@ +/* ObjectIdentityMapToInt.java -- Helper class for faster serialization + 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.io; + +/** + * This class provides a map from Object to non-negative int values. + * Objects are considered equal only if their references are equal. + * + * This can be used to equip objects with an integer id. This class + * is implemented to use as little memory as possible, particularly + * not to create hashtable buckets and Integer instances for each + * mapping. + * + * @author Fridtjof Siebert (siebert@aicas.com) + */ +public class ObjectIdentityMap2Int +{ + + + /** + * Prime numbers used as size of array. We need the size to be a + * prime number since the delta used for conflict resulution must + * not have any common divisors with the length. + */ + private static final int[] PRIMES = { + 0x1f, + 0x3d, + 0x7f, + 0xfb, + 0x1fd, + 0x3fd, + 0x7f7, + 0xffd, + 0x1fff, + 0x3ffd, + 0x7fed, + 0xfff1, + 0x1ffff, + 0x3fffb, + 0x7ffff, + 0xffffd, + 0x1ffff7, + 0x3ffffd, + 0x7ffff1, + 0xfffffd, + 0x1ffffd9, + 0x3fffffb, + 0x7ffffd9, + 0xfffffc7, + 0x1ffffffd, + 0x3fffffdd, + 0x7fffffff}; + + + /** + * Object to be used instead of "null" + */ + private static final Object NIL = new Object(); + + + /** + * The objects in this map: + * + * invariant + * objectTable.size == PRIMES[cap] + */ + private Object[] objectTable; + + + /** + * The corresponding integer ids. + * + * invariant + * intTable.size == PRIMES[cap] + */ + private int[] intTable; + + + /** + * The number of entries in this map. + * + * invariant + * size < limit + */ + private int size = 0; + + + /** + * The index in primes of the size of the tables. + */ + private int cap = 0; + + + /** + * The limit for size at which the table size is increased. + * + * invariant + * limit = PRIMES[cap] / 4 * 3; + */ + private int limit = 0; + + + /** + * Constructs an empty ObjectIdentityMap2Int. + */ + public ObjectIdentityMap2Int() + { + alloc(0); + } + + + /** + * Helper function to alloc the object and int array for the given + * capacity. Set limit, reset size to 0. + * + * No elements will be stored in the newly allocated arrays. + * + * @param c the capacity: this is an index in PRIMES, PRIMES[c] + * gives the size of the arrays. + * + * @throws InternalError if c >= PRIMES.length (in this case, a + * normal Hashtable would throw an OutOfMemoryError or a + * NegativeArraySizeException since the array size exceeds the range + * of positive integers). + */ + private void alloc(int c) + { + if (c >= PRIMES.length) + throw new InternalError("Hash table size overflow"); + + cap = c; + int len = PRIMES[c]; + objectTable = new Object[len]; + intTable = new int[len]; + limit = len / 4 * 3; + + size = 0; + } + + + /** + * Add a mapping to this Map. + * + * ensures + * (get(o) == i); + * + * @param o object reference or null that is to be mapped. + * + * @param i the integer id to be associated with o + * + * @throws IllegalArgumentException if i<0 + * + * @throws InternalError if hash tables has grown to more then + * 0x7fffffff entries (ie., size >= 0x7fffffff*3/4). + */ + public void put(Object o, int i) + { + if (i < 0) + throw new IllegalArgumentException("int argument must be postive: "+i); + + o = (o == null) ? NIL : o; + int s = slot(o); + Object[] ot = objectTable; + intTable[s] = i; + if (objectTable[s] == null) + { + objectTable[s] = o; + size++; + if (size >= limit) + { + rehash(); + } + } + } + + + /** + * Helper function to find the index of a free or existing slot for + * object o + * + * ensure + * ((objectTable[result] != null) IMPLIES (objectTable[result] == o)); + * + * @param o an object, must not be null. + * + * @return an index of o + */ + private int slot(Object o) + { + Object[] ot = objectTable; + int hc = System.identityHashCode(o); + int len = ot.length; + int result = hc % len; + result = result < 0 ? -result : result; + int delta = 16 - (hc & 15); + Object existing = ot[result]; + while ((existing != null) && (existing != o)) + { + result += delta; + if (result >= len) + result -= len; + existing = ot[result]; + } + return result; + } + + + /** + * Helper function for put() to increaes the capacity of this table + * to the next size (approx. double the size). Keep the mapping and + * the size unchanged. + * + * ensure + * (cap == \old cap+1); + */ + private void rehash() + { + Object[] ot = objectTable; + int [] it = intTable; + alloc(cap + 1); + + for (int i = 0; i < ot.length; i++) + put(ot[i], it[i]); + } + + + /** + * Obtain an element from this map + * + * @param o an object or null + * + * @return the corresponding integer id for o or -1 if o has not + * been put into this map. + */ + public int get(Object o) + { + o = (o == null) ? NIL : o; + int s = slot(o); + return objectTable[s] == null ? -1 : intTable[s]; + } + + /** + * Clear this map + * + * ensures + * ((size == 0) && \forall Object o: get(o) == -1) + */ + public void clear() + { + Object[] ot = objectTable; + size = 0; + for (int i = 0; i < ot.length; i++) + ot[i] = null; + } + +} diff --git a/libjava/classpath/gnu/java/io/ObjectIdentityWrapper.java b/libjava/classpath/gnu/java/io/ObjectIdentityWrapper.java new file mode 100644 index 000000000..53c9943de --- /dev/null +++ b/libjava/classpath/gnu/java/io/ObjectIdentityWrapper.java @@ -0,0 +1,100 @@ +/* ObjectIdentityWrapper.java -- Wrapper class used to override equals() + and hashCode() to be as discriminating as possible + Copyright (C) 1998 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.io; + +/** + This class is a thin wrapper around Object that makes + the methods hashCode() and equals(Object) + as discriminating as possible. +*/ +public class ObjectIdentityWrapper +{ + + /** + Constructs a ObjectIdentityWrapper that is wrapped + around o. + */ + public ObjectIdentityWrapper( Object o ) + { + object = o; + } + + /** + Uses System.identityHashCode(Object) to compute a + hash code for the object wrapped by this + ObjectIdentityWrapper. + + @see java.lang.System#identityHashCode(java.lang.Object) + @see java.util.Hashtable + @see java.lang.Object#hashCode() + */ + public int hashCode() + { + return System.identityHashCode( object ); + } + + /** + Uses the == operator to test for equality between + the object wrapped by this ObjectIdentityWrapper and + the object wrapped by the ObjectIdentityWrapper o. + Returns false if o is not a ObjectIdentityWrapper. + + @see java.util.Hashtable + @see java.lang.Object#equals() + */ + public boolean equals( Object o ) + { + if( o instanceof ObjectIdentityWrapper ) + return object == ((ObjectIdentityWrapper)o).object; + else + return false; + } + + public String toString() + { + return "ObjectIdentityWrapper< " + object + ", " + hashCode() + " >"; + } + + /** + The Object wrapped by this + ObjectIdentityWrapper. + */ + public Object object; +} diff --git a/libjava/classpath/gnu/java/io/PlatformHelper.java b/libjava/classpath/gnu/java/io/PlatformHelper.java new file mode 100644 index 000000000..545241110 --- /dev/null +++ b/libjava/classpath/gnu/java/io/PlatformHelper.java @@ -0,0 +1,129 @@ +/* PlatformHelper.java -- Isolate OS-specific IO helper methods and variables + Copyright (C) 1998, 2002, 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.io; + +/** + * We had many changes in File.java, URLStreamHandler.java etc. to handle + * path representations on different platforms (Windows/Unix-family). + * Finally we'd like to collect all these ad hoc codes into this utility class. + * --Gansha + */ +public class PlatformHelper +{ + public static final boolean isWindows = System.getProperty("os.name").indexOf("Windows") >= 0; + public static final String separator = System.getProperty("file.separator"); + public static final char separatorChar = separator.charAt(0); + public static final String pathSeparator = System.getProperty("path.separator"); + public static final char pathSeparatorChar = pathSeparator.charAt(0); + + /** + * On most platforms 260 is equal or greater than a max path value, + * so we can set the initial buffer size of StringBuffer to half of this value + * to improve performance. + */ + public static final int INITIAL_MAX_PATH = 260/2; + + /** + * This routine checks the input param "path" whether it begins with root path + * prefix. + * if not, return 0; + * if yes, return the len of root path prefix; + * --for Unix-family platform, root path begins with "/" and len is 1 + * --for Windows platform, root path begins with "drive:\\" and len is 3 + */ + public static final int beginWithRootPathPrefix(String path) + { + if (path.startsWith("/") || path.startsWith("\\")) + return 1; + + if (!isWindows) + return 0; + + if (path.length() > 2 + && Character.isLetter(path.charAt(0)) + && path.charAt(1) == ':' + && (path.charAt(2) == '/' || path.charAt(2) == '\\')) + return 3; + + return 0; + } + + /** + * This routine checks the input param "path" whether it's root directory. + * --for Unix-family platform, root directory is "/" + * --for Windows platform, root directory is "\\" or "drive:\\". + */ + public static final boolean isRootDirectory(String path) + { + int len = path.length(); + return len > 0 && beginWithRootPathPrefix(path) == len; + } + + /** + * This routine checks whether input param "path" ends with separator + */ + public static final boolean endWithSeparator(String path) + { + if (path.endsWith("\\") || path.endsWith("/")) + return true; + + return false; + } + + /** + * This routine removes from input param "path" the tail separator if it exists, + * and return the remain part. + */ + public static final String removeTailSeparator(String path) + { + if (endWithSeparator(path) && !isRootDirectory(path)) + return path.substring(0, path.length() - 1); + + return path; + } + + /** + * This routine returns last index of separator in input param "path", + * and return it. + */ + public static final int lastIndexOfSeparator(String path) + { + return Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\")); + } + +} diff --git a/libjava/classpath/gnu/java/io/package.html b/libjava/classpath/gnu/java/io/package.html new file mode 100644 index 000000000..74da8277f --- /dev/null +++ b/libjava/classpath/gnu/java/io/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.io + + +

+ + + diff --git a/libjava/classpath/gnu/java/lang/ArrayHelper.java b/libjava/classpath/gnu/java/lang/ArrayHelper.java new file mode 100644 index 000000000..5f675831e --- /dev/null +++ b/libjava/classpath/gnu/java/lang/ArrayHelper.java @@ -0,0 +1,78 @@ +/* ArrayHelper.java -- Helper methods for handling array operations + Copyright (C) 1998, 2002 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.lang; + +/** + * ArrayHelper helps you do things with arrays. + * + * @author John Keiser + */ +public class ArrayHelper +{ + /** + * Counterpart to java.util.Collection.contains. + * + * @param array the array to search + * @param searchFor the object to locate + * @return true if some array element equals(searchFor) + */ + public static boolean contains(Object[] array, Object searchFor) + { + return indexOf(array, searchFor) != -1; + } + + /** + * Counterpart to java.util.Collection.indexOf. + * + * @param array the array to search + * @param searchFor the object to locate + * @return the index of the first equal object, or -1 + */ + public static int indexOf(Object[] array, Object searchFor) + { + for (int i = 0; i < array.length; i++) + { + if(array[i].equals(searchFor)) + { + return i; + } + } + return -1; + } +} diff --git a/libjava/classpath/gnu/java/lang/CPStringBuilder.java b/libjava/classpath/gnu/java/lang/CPStringBuilder.java new file mode 100644 index 000000000..f42629d46 --- /dev/null +++ b/libjava/classpath/gnu/java/lang/CPStringBuilder.java @@ -0,0 +1,1161 @@ +/* ClasspathStringBuffer.java -- Growable strings without locking or copying + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 + 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.lang; + +import gnu.classpath.SystemProperties; + +import java.io.Serializable; + +/** + * This class is based on java.lang.AbstractStringBuffer but + * without the copying of the string by toString. + * If you modify this, please consider also modifying that code. + * This code is not thread-safe; limit its use to internal use within + * methods. + */ +public final class CPStringBuilder + implements Serializable, CharSequence, Appendable +{ + + /** + * Index of next available character (and thus the size of the current + * string contents). Note that this has permissions set this way so that + * String can get the value. + * + * @serial the number of characters in the buffer + */ + private int count; + + /** + * The buffer. Note that this has permissions set this way so that String + * can get the value. + * + * @serial the buffer + */ + private char[] value; + + /** + * A flag to denote whether the string being created has been + * allocated to a {@link String} object. On construction, + * the character array, {@link #value} is referenced only + * by this class. Once {@link #toString()}, + * {@link #substring(int)} or {@link #substring(int,int)} + * are called, the array is also referenced by a {@link String} + * object and this flag is set. Subsequent modifications to + * this buffer cause a new array to be allocated and the flag + * to be reset. + */ + private boolean allocated = false; + + /** + * The default capacity of a buffer. + * This can be configured using gnu.classpath.cpstringbuilder.capacity + */ + private static final int DEFAULT_CAPACITY; + + static + { + String cap = + SystemProperties.getProperty("gnu.classpath.cpstringbuilder.capacity"); + if (cap == null) + DEFAULT_CAPACITY = 32; + else + DEFAULT_CAPACITY = Integer.parseInt(cap); + } + + /** + * Create a new CPStringBuilder with the default capacity. + */ + public CPStringBuilder() + { + this(DEFAULT_CAPACITY); + } + + /** + * Create an empty CPStringBuilder with the specified initial + * capacity. + * + * @param capacity the initial capacity + * @throws NegativeArraySizeException if capacity is negative + */ + public CPStringBuilder(int capacity) + { + value = new char[capacity]; + } + + /** + * Create a new CPStringBuilder with the characters in the + * specified String. Initial capacity will be the size of the + * String plus the default capacity. + * + * @param str the String to convert + * @throws NullPointerException if str is null + */ + public CPStringBuilder(String str) + { + count = str.length(); + value = new char[count + DEFAULT_CAPACITY]; + str.getChars(0, count, value, 0); + } + + /** + * Create a new CPStringBuilder with the characters in the + * specified StringBuffer. Initial capacity will be the size of the + * String plus the default capacity. + * + * @param str the String to convert + * @throws NullPointerException if str is null + */ + public CPStringBuilder(StringBuffer str) + { + count = str.length(); + value = new char[count + DEFAULT_CAPACITY]; + str.getChars(0, count, value, 0); + } + + /** + * Create a new CPStringBuilder with the characters in the + * specified StringBuilder. Initial capacity will be the size of the + * String plus the default capacity. + * + * @param str the String to convert + * @throws NullPointerException if str is null + */ + public CPStringBuilder(StringBuilder str) + { + count = str.length(); + value = new char[count + DEFAULT_CAPACITY]; + str.getChars(0, count, value, 0); + } + + /** + * Create a new CPStringBuilder with the characters in the + * specified CharSequence. Initial capacity will be the + * length of the sequence plus the default capacity; if the sequence + * reports a length less than or equal to 0, then the initial capacity + * will be the default. + * + * @param seq the initializing CharSequence + * @throws NullPointerException if str is null + * @since 1.5 + */ + public CPStringBuilder(CharSequence seq) + { + int len = seq.length(); + count = len <= 0 ? 0 : len; + value = new char[count + DEFAULT_CAPACITY]; + for (int i = 0; i < len; ++i) + value[i] = seq.charAt(i); + } + + /** + * Set the length of this StringBuffer. If the new length is greater than + * the current length, all the new characters are set to '\0'. If the new + * length is less than the current length, the first newLength + * characters of the old array will be preserved, and the remaining + * characters are truncated. + * + * @param newLength the new length + * @throws IndexOutOfBoundsException if the new length is negative + * (while unspecified, this is a StringIndexOutOfBoundsException) + * @see #length() + */ + public void setLength(int newLength) + { + if (newLength < 0) + throw new StringIndexOutOfBoundsException(newLength); + + int valueLength = value.length; + + /* Always call ensureCapacity in order to preserve + copy-on-write semantics, except when the position + is simply being reset + */ + if (newLength > 0) + ensureCapacity(newLength); + + if (newLength < valueLength) + { + /* If the StringBuffer's value just grew, then we know that + value is newly allocated and the region between count and + newLength is filled with '\0'. */ + count = newLength; + } + else + { + /* The StringBuffer's value doesn't need to grow. However, + we should clear out any cruft that may exist. */ + while (count < newLength) + value[count++] = '\0'; + } + } + + /** + * Get the character at the specified index. + * + * @param index the index of the character to get, starting at 0 + * @return the character at the specified index + * @throws IndexOutOfBoundsException if index is negative or >= length() + * (while unspecified, this is a StringIndexOutOfBoundsException) + */ + public char charAt(int index) + { + if (index < 0 || index >= count) + throw new StringIndexOutOfBoundsException(index); + return value[index]; + } + + /** + * Get the code point at the specified index. This is like #charAt(int), + * but if the character is the start of a surrogate pair, and the + * following character completes the pair, then the corresponding + * supplementary code point is returned. + * @param index the index of the codepoint to get, starting at 0 + * @return the codepoint at the specified index + * @throws IndexOutOfBoundsException if index is negative or >= length() + * @since 1.5 + */ + public int codePointAt(int index) + { + return Character.codePointAt(value, index, count); + } + + /** + * Get the code point before the specified index. This is like + * #codePointAt(int), but checks the characters at index-1 and + * index-2 to see if they form a supplementary code point. + * @param index the index just past the codepoint to get, starting at 0 + * @return the codepoint at the specified index + * @throws IndexOutOfBoundsException if index is negative or >= length() + * @since 1.5 + */ + public int codePointBefore(int index) + { + // Character.codePointBefore() doesn't perform this check. We + // could use the CharSequence overload, but this is just as easy. + if (index >= count) + throw new IndexOutOfBoundsException(); + return Character.codePointBefore(value, index, 1); + } + + /** + * Get the specified array of characters. srcOffset - srcEnd + * characters will be copied into the array you pass in. + * + * @param srcOffset the index to start copying from (inclusive) + * @param srcEnd the index to stop copying from (exclusive) + * @param dst the array to copy into + * @param dstOffset the index to start copying into + * @throws NullPointerException if dst is null + * @throws IndexOutOfBoundsException if any source or target indices are + * out of range (while unspecified, source problems cause a + * StringIndexOutOfBoundsException, and dest problems cause an + * ArrayIndexOutOfBoundsException) + * @see System#arraycopy(Object, int, Object, int, int) + */ + public void getChars(int srcOffset, int srcEnd, + char[] dst, int dstOffset) + { + if (srcOffset < 0 || srcEnd > count || srcEnd < srcOffset) + throw new StringIndexOutOfBoundsException(); + System.arraycopy(value, srcOffset, dst, dstOffset, srcEnd - srcOffset); + } + + /** + * Set the character at the specified index. + * + * @param index the index of the character to set starting at 0 + * @param ch the value to set that character to + * @throws IndexOutOfBoundsException if index is negative or >= length() + * (while unspecified, this is a StringIndexOutOfBoundsException) + */ + public void setCharAt(int index, char ch) + { + if (index < 0 || index >= count) + throw new StringIndexOutOfBoundsException(index); + // Call ensureCapacity to enforce copy-on-write. + ensureCapacity(count); + value[index] = ch; + } + + /** + * Append the String value of the argument to this + * StringBuffer. Uses String.valueOf() to convert + * to String. + * + * @param obj the Object to convert and append + * @return this StringBuffer + * @see String#valueOf(Object) + * @see #append(String) + */ + public CPStringBuilder append(Object obj) + { + return append(String.valueOf(obj)); + } + + /** + * Append the String to this StringBuffer. If + * str is null, the String "null" is appended. + * + * @param str the String to append + * @return this StringBuffer + */ + public CPStringBuilder append(String str) + { + if (str == null) + str = "null"; + int len = str.length(); + ensureCapacity(count + len); + str.getChars(0, len, value, count); + count += len; + return this; + } + + /** + * Append the StringBuilder value of the argument to this + * StringBuilder. This behaves the same as + * append((Object) stringBuffer), except it is more efficient. + * + * @param stringBuffer the StringBuilder to convert and append + * @return this StringBuilder + * @see #append(Object) + */ + public CPStringBuilder append(StringBuffer stringBuffer) + { + if (stringBuffer == null) + return append("null"); + synchronized (stringBuffer) + { + int len = stringBuffer.length(); + ensureCapacity(count + len); + stringBuffer.getChars(0, len, value, count); + count += len; + } + return this; + } + + /** + * Append the char array to this StringBuffer. + * This is similar (but more efficient) than + * append(new String(data)), except in the case of null. + * + * @param data the char[] to append + * @return this StringBuffer + * @throws NullPointerException if str is null + * @see #append(char[], int, int) + */ + public CPStringBuilder append(char[] data) + { + return append(data, 0, data.length); + } + + /** + * Append part of the char array to this + * StringBuffer. This is similar (but more efficient) than + * append(new String(data, offset, count)), except in the case + * of null. + * + * @param data the char[] to append + * @param offset the start location in str + * @param count the number of characters to get from str + * @return this StringBuffer + * @throws NullPointerException if str is null + * @throws IndexOutOfBoundsException if offset or count is out of range + * (while unspecified, this is a StringIndexOutOfBoundsException) + */ + public CPStringBuilder append(char[] data, int offset, int count) + { + if (offset < 0 || count < 0 || offset > data.length - count) + throw new StringIndexOutOfBoundsException(); + ensureCapacity(this.count + count); + System.arraycopy(data, offset, value, this.count, count); + this.count += count; + return this; + } + + /** + * Append the String value of the argument to this + * StringBuffer. Uses String.valueOf() to convert + * to String. + * + * @param bool the boolean to convert and append + * @return this StringBuffer + * @see String#valueOf(boolean) + */ + public CPStringBuilder append(boolean bool) + { + return append(bool ? "true" : "false"); + } + + /** + * Append the char to this StringBuffer. + * + * @param ch the char to append + * @return this StringBuffer + */ + public CPStringBuilder append(char ch) + { + ensureCapacity(count + 1); + value[count++] = ch; + return this; + } + + /** + * Append the characters in the CharSequence to this + * buffer. + * + * @param seq the CharSequence providing the characters + * @return this StringBuffer + * @since 1.5 + */ + public CPStringBuilder append(CharSequence seq) + { + return append(seq, 0, seq.length()); + } + + /** + * Append some characters from the CharSequence to this + * buffer. If the argument is null, the four characters "null" are + * appended. + * + * @param seq the CharSequence providing the characters + * @param start the starting index + * @param end one past the final index + * @return this StringBuffer + * @since 1.5 + */ + public CPStringBuilder append(CharSequence seq, int start, int end) + { + if (seq == null) + return append("null"); + if (end - start > 0) + { + ensureCapacity(count + end - start); + for (; start < end; ++start) + value[count++] = seq.charAt(start); + } + return this; + } + + /** + * Append the String value of the argument to this + * StringBuffer. Uses String.valueOf() to convert + * to String. + * + * @param inum the int to convert and append + * @return this StringBuffer + * @see String#valueOf(int) + */ + // This is native in libgcj, for efficiency. + public CPStringBuilder append(int inum) + { + return append(String.valueOf(inum)); + } + + /** + * Append the String value of the argument to this + * StringBuffer. Uses String.valueOf() to convert + * to String. + * + * @param lnum the long to convert and append + * @return this StringBuffer + * @see String#valueOf(long) + */ + public CPStringBuilder append(long lnum) + { + return append(Long.toString(lnum, 10)); + } + + /** + * Append the String value of the argument to this + * StringBuffer. Uses String.valueOf() to convert + * to String. + * + * @param fnum the float to convert and append + * @return this StringBuffer + * @see String#valueOf(float) + */ + public CPStringBuilder append(float fnum) + { + return append(Float.toString(fnum)); + } + + /** + * Append the String value of the argument to this + * StringBuffer. Uses String.valueOf() to convert + * to String. + * + * @param dnum the double to convert and append + * @return this StringBuffer + * @see String#valueOf(double) + */ + public CPStringBuilder append(double dnum) + { + return append(Double.toString(dnum)); + } + + /** + * Append the code point to this StringBuffer. + * This is like #append(char), but will append two characters + * if a supplementary code point is given. + * + * @param code the code point to append + * @return this StringBuffer + * @see Character#toChars(int, char[], int) + * @since 1.5 + */ + public CPStringBuilder appendCodePoint(int code) + { + int len = Character.charCount(code); + ensureCapacity(count + len); + Character.toChars(code, value, count); + count += len; + return this; + } + + /** + * Delete characters from this StringBuffer. + * delete(10, 12) will delete 10 and 11, but not 12. It is + * harmless for end to be larger than length(). + * + * @param start the first character to delete + * @param end the index after the last character to delete + * @return this StringBuffer + * @throws StringIndexOutOfBoundsException if start or end are out of bounds + * @since 1.2 + */ + public CPStringBuilder delete(int start, int end) + { + if (start < 0 || start > count || start > end) + throw new StringIndexOutOfBoundsException(start); + if (end > count) + end = count; + ensureCapacity(count); + if (count - end != 0) + System.arraycopy(value, end, value, start, count - end); + count -= end - start; + return this; + } + + /** + * Delete a character from this StringBuffer. + * + * @param index the index of the character to delete + * @return this StringBuffer + * @throws StringIndexOutOfBoundsException if index is out of bounds + * @since 1.2 + */ + public CPStringBuilder deleteCharAt(int index) + { + return delete(index, index + 1); + } + + /** + * Replace characters between index start (inclusive) and + * end (exclusive) with str. If end + * is larger than the size of this StringBuffer, all characters after + * start are replaced. + * + * @param start the beginning index of characters to delete (inclusive) + * @param end the ending index of characters to delete (exclusive) + * @param str the new String to insert + * @return this StringBuffer + * @throws StringIndexOutOfBoundsException if start or end are out of bounds + * @throws NullPointerException if str is null + * @since 1.2 + */ + public CPStringBuilder replace(int start, int end, String str) + { + if (start < 0 || start > count || start > end) + throw new StringIndexOutOfBoundsException(start); + + int len = str.length(); + // Calculate the difference in 'count' after the replace. + int delta = len - (end > count ? count : end) + start; + ensureCapacity(count + delta); + + if (delta != 0 && end < count) + System.arraycopy(value, end, value, end + delta, count - end); + + str.getChars(0, len, value, start); + count += delta; + return this; + } + + /** + * Insert a subarray of the char[] argument into this + * StringBuffer. + * + * @param offset the place to insert in this buffer + * @param str the char[] to insert + * @param str_offset the index in str to start inserting from + * @param len the number of characters to insert + * @return this StringBuffer + * @throws NullPointerException if str is null + * @throws StringIndexOutOfBoundsException if any index is out of bounds + * @since 1.2 + */ + public CPStringBuilder insert(int offset, char[] str, int str_offset, int len) + { + if (offset < 0 || offset > count || len < 0 + || str_offset < 0 || str_offset > str.length - len) + throw new StringIndexOutOfBoundsException(); + ensureCapacity(count + len); + System.arraycopy(value, offset, value, offset + len, count - offset); + System.arraycopy(str, str_offset, value, offset, len); + count += len; + return this; + } + + /** + * Insert the String value of the argument into this + * StringBuffer. Uses String.valueOf() to convert + * to String. + * + * @param offset the place to insert in this buffer + * @param obj the Object to convert and insert + * @return this StringBuffer + * @exception StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(Object) + */ + public CPStringBuilder insert(int offset, Object obj) + { + return insert(offset, obj == null ? "null" : obj.toString()); + } + + /** + * Insert the String argument into this + * StringBuffer. If str is null, the String "null" is used + * instead. + * + * @param offset the place to insert in this buffer + * @param str the String to insert + * @return this StringBuffer + * @throws StringIndexOutOfBoundsException if offset is out of bounds + */ + public CPStringBuilder insert(int offset, String str) + { + if (offset < 0 || offset > count) + throw new StringIndexOutOfBoundsException(offset); + if (str == null) + str = "null"; + int len = str.length(); + ensureCapacity(count + len); + System.arraycopy(value, offset, value, offset + len, count - offset); + str.getChars(0, len, value, offset); + count += len; + return this; + } + + /** + * Insert the CharSequence argument into this + * StringBuffer. If the sequence is null, the String + * "null" is used instead. + * + * @param offset the place to insert in this buffer + * @param sequence the CharSequence to insert + * @return this StringBuffer + * @throws IndexOutOfBoundsException if offset is out of bounds + * @since 1.5 + */ + public CPStringBuilder insert(int offset, CharSequence sequence) + { + if (sequence == null) + sequence = "null"; + return insert(offset, sequence, 0, sequence.length()); + } + + /** + * Insert a subsequence of the CharSequence argument into this + * StringBuffer. If the sequence is null, the String + * "null" is used instead. + * + * @param offset the place to insert in this buffer + * @param sequence the CharSequence to insert + * @param start the starting index of the subsequence + * @param end one past the ending index of the subsequence + * @return this StringBuffer + * @throws IndexOutOfBoundsException if offset, start, + * or end are out of bounds + * @since 1.5 + */ + public CPStringBuilder insert(int offset, CharSequence sequence, int start, int end) + { + if (sequence == null) + sequence = "null"; + if (start < 0 || end < 0 || start > end || end > sequence.length()) + throw new IndexOutOfBoundsException(); + int len = end - start; + ensureCapacity(count + len); + System.arraycopy(value, offset, value, offset + len, count - offset); + for (int i = start; i < end; ++i) + value[offset++] = sequence.charAt(i); + count += len; + return this; + } + + /** + * Insert the char[] argument into this + * StringBuffer. + * + * @param offset the place to insert in this buffer + * @param data the char[] to insert + * @return this StringBuffer + * @throws NullPointerException if data is null + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see #insert(int, char[], int, int) + */ + public CPStringBuilder insert(int offset, char[] data) + { + return insert(offset, data, 0, data.length); + } + + /** + * Insert the String value of the argument into this + * StringBuffer. Uses String.valueOf() to convert + * to String. + * + * @param offset the place to insert in this buffer + * @param bool the boolean to convert and insert + * @return this StringBuffer + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(boolean) + */ + public CPStringBuilder insert(int offset, boolean bool) + { + return insert(offset, bool ? "true" : "false"); + } + + /** + * Insert the char argument into this StringBuffer. + * + * @param offset the place to insert in this buffer + * @param ch the char to insert + * @return this StringBuffer + * @throws StringIndexOutOfBoundsException if offset is out of bounds + */ + public CPStringBuilder insert(int offset, char ch) + { + if (offset < 0 || offset > count) + throw new StringIndexOutOfBoundsException(offset); + ensureCapacity(count + 1); + System.arraycopy(value, offset, value, offset + 1, count - offset); + value[offset] = ch; + count++; + return this; + } + + /** + * Insert the String value of the argument into this + * StringBuffer. Uses String.valueOf() to convert + * to String. + * + * @param offset the place to insert in this buffer + * @param inum the int to convert and insert + * @return this StringBuffer + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(int) + */ + public CPStringBuilder insert(int offset, int inum) + { + return insert(offset, String.valueOf(inum)); + } + + /** + * Insert the String value of the argument into this + * StringBuffer. Uses String.valueOf() to convert + * to String. + * + * @param offset the place to insert in this buffer + * @param lnum the long to convert and insert + * @return this StringBuffer + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(long) + */ + public CPStringBuilder insert(int offset, long lnum) + { + return insert(offset, Long.toString(lnum, 10)); + } + + /** + * Insert the String value of the argument into this + * StringBuffer. Uses String.valueOf() to convert + * to String. + * + * @param offset the place to insert in this buffer + * @param fnum the float to convert and insert + * @return this StringBuffer + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(float) + */ + public CPStringBuilder insert(int offset, float fnum) + { + return insert(offset, Float.toString(fnum)); + } + + /** + * Insert the String value of the argument into this + * StringBuffer. Uses String.valueOf() to convert + * to String. + * + * @param offset the place to insert in this buffer + * @param dnum the double to convert and insert + * @return this StringBuffer + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(double) + */ + public CPStringBuilder insert(int offset, double dnum) + { + return insert(offset, Double.toString(dnum)); + } + + /** + * Finds the first instance of a substring in this StringBuilder. + * + * @param str String to find + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + * @see #indexOf(String, int) + */ + public int indexOf(String str) + { + return indexOf(str, 0); + } + + /** + * Finds the first instance of a String in this StringBuffer, starting at + * a given index. If starting index is less than 0, the search starts at + * the beginning of this String. If the starting index is greater than the + * length of this String, or the substring is not found, -1 is returned. + * + * @param str String to find + * @param fromIndex index to start the search + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + * @since 1.4 + */ + public int indexOf(String str, int fromIndex) + { + if (fromIndex < 0) + fromIndex = 0; + int olength = str.length(); + int limit = count - olength; + String s = VMCPStringBuilder.toString(value, 0, count); + for (; fromIndex <= limit; ++fromIndex) + if (s.regionMatches(fromIndex, str, 0, olength)) + return fromIndex; + return -1; + } + + /** + * Finds the last instance of a substring in this StringBuffer. + * + * @param str String to find + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + * @see #lastIndexOf(String, int) + * @since 1.4 + */ + public int lastIndexOf(String str) + { + return lastIndexOf(str, count - str.length()); + } + + /** + * Finds the last instance of a String in this StringBuffer, starting at a + * given index. If starting index is greater than the maximum valid index, + * then the search begins at the end of this String. If the starting index + * is less than zero, or the substring is not found, -1 is returned. + * + * @param str String to find + * @param fromIndex index to start the search + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + * @since 1.4 + */ + public int lastIndexOf(String str, int fromIndex) + { + fromIndex = Math.min(fromIndex, count - str.length()); + String s = VMCPStringBuilder.toString(value, 0, count); + int olength = str.length(); + for ( ; fromIndex >= 0; fromIndex--) + if (s.regionMatches(fromIndex, str, 0, olength)) + return fromIndex; + return -1; + } + + /** + * Reverse the characters in this StringBuffer. The same sequence of + * characters exists, but in the reverse index ordering. + * + * @return this StringBuffer + */ + public CPStringBuilder reverse() + { + // Call ensureCapacity to enforce copy-on-write. + ensureCapacity(count); + for (int i = count >> 1, j = count - i; --i >= 0; ++j) + { + char c = value[i]; + value[i] = value[j]; + value[j] = c; + } + return this; + } + + /** + * This may reduce the amount of memory used by the StringBuffer, + * by resizing the internal array to remove unused space. However, + * this method is not required to resize, so this behavior cannot + * be relied upon. + * @since 1.5 + */ + public void trimToSize() + { + int wouldSave = value.length - count; + // Some random heuristics: if we save less than 20 characters, who + // cares. + if (wouldSave < 20) + return; + // If we save more than 200 characters, shrink. + // If we save more than 1/4 of the buffer, shrink. + if (wouldSave > 200 || wouldSave * 4 > value.length) + allocateArray(count); + } + + /** + * Return the number of code points between two indices in the + * StringBuffer. An unpaired surrogate counts as a + * code point for this purpose. Characters outside the indicated + * range are not examined, even if the range ends in the middle of a + * surrogate pair. + * + * @param start the starting index + * @param end one past the ending index + * @return the number of code points + * @since 1.5 + */ + public int codePointCount(int start, int end) + { + if (start < 0 || end >= count || start > end) + throw new StringIndexOutOfBoundsException(); + + int count = 0; + while (start < end) + { + char base = value[start]; + if (base < Character.MIN_HIGH_SURROGATE + || base > Character.MAX_HIGH_SURROGATE + || start == end + || start == count + || value[start + 1] < Character.MIN_LOW_SURROGATE + || value[start + 1] > Character.MAX_LOW_SURROGATE) + { + // Nothing. + } + else + { + // Surrogate pair. + ++start; + } + ++start; + ++count; + } + return count; + } + + /** + * Starting at the given index, this counts forward by the indicated + * number of code points, and then returns the resulting index. An + * unpaired surrogate counts as a single code point for this + * purpose. + * + * @param start the starting index + * @param codePoints the number of code points + * @return the resulting index + * @since 1.5 + */ + public int offsetByCodePoints(int start, int codePoints) + { + while (codePoints > 0) + { + char base = value[start]; + if (base < Character.MIN_HIGH_SURROGATE + || base > Character.MAX_HIGH_SURROGATE + || start == count + || value[start + 1] < Character.MIN_LOW_SURROGATE + || value[start + 1] > Character.MAX_LOW_SURROGATE) + { + // Nothing. + } + else + { + // Surrogate pair. + ++start; + } + ++start; + --codePoints; + } + return start; + } + + /** + * Increase the capacity of this StringBuilder. This will + * ensure that an expensive growing operation will not occur until either + * minimumCapacity is reached or the array has been allocated. + * The buffer is grown to either minimumCapacity * 2, if + * the array has been allocated or the larger of minimumCapacity and + * capacity() * 2 + 2, if it is not already large enough. + * + * @param minimumCapacity the new capacity + * @see #length() + */ + public void ensureCapacity(int minimumCapacity) + { + if (allocated || minimumCapacity > value.length) + { + if (minimumCapacity > value.length) + { + int max = value.length * 2 + 2; + minimumCapacity = (minimumCapacity < max ? max : minimumCapacity); + } + else + minimumCapacity *= 2; + allocateArray(minimumCapacity); + } + } + + /** + * Allocates a new character array. This method is triggered when + * a write is attempted after the array has been passed to a + * {@link String} object, so that the builder does not modify + * the immutable {@link String}. + * + * @param capacity the size of the new array. + */ + private void allocateArray(int capacity) + { + char[] nb = new char[capacity]; + System.arraycopy(value, 0, nb, 0, count); + value = nb; + allocated = false; + } + + /** + * Get the length of the String this StringBuilder + * would create. Not to be confused with the capacity of the + * StringBuilder. + * + * @return the length of this StringBuilder + * @see #capacity() + * @see #setLength(int) + */ + public int length() + { + return count; + } + + /** + * Creates a substring of this StringBuilder, starting at a specified index + * and ending at one character before a specified index. This is implemented + * the same as substring(beginIndex, endIndex), to satisfy + * the CharSequence interface. + * + * @param beginIndex index to start at (inclusive, base 0) + * @param endIndex index to end at (exclusive) + * @return new String which is a substring of this StringBuilder + * @throws IndexOutOfBoundsException if beginIndex or endIndex is out of + * bounds + * @see #substring(int, int) + */ + public CharSequence subSequence(int beginIndex, int endIndex) + { + return substring(beginIndex, endIndex); + } + + /** + * Creates a substring of this CPStringBuilder, starting at a specified index + * and ending at the end of this StringBuilder. + * + * @param beginIndex index to start substring (base 0) + * @return new String which is a substring of this StringBuilder + * @throws StringIndexOutOfBoundsException if beginIndex is out of bounds + * @see #substring(int, int) + */ + public String substring(int beginIndex) + { + return substring(beginIndex, count); + } + + /** + * Creates a substring of this CPStringBuilder, starting at a specified index + * and ending at one character before a specified index. + * + * @param beginIndex index to start at (inclusive, base 0) + * @param endIndex index to end at (exclusive) + * @return new String which is a substring of this StringBuilder + * @throws StringIndexOutOfBoundsException if beginIndex or endIndex is out + * of bounds + */ + public String substring(int beginIndex, int endIndex) + { + if (beginIndex < 0 || endIndex > count || endIndex < beginIndex) + throw new StringIndexOutOfBoundsException(); + int len = endIndex - beginIndex; + if (len == 0) + return ""; + allocated = true; + return VMCPStringBuilder.toString(value, beginIndex, len); + } + + /** + * Convert this CPStringBuilder to a String. The + * String is composed of the characters currently in this StringBuilder. Note + * that the result is not a copy, so we flag this here and make sure to + * allocate a new array on the next write attempt (see {@link #ensureCapacity(int)}). + * + * @return the characters in this StringBuilder + */ + public String toString() + { + allocated = true; + return VMCPStringBuilder.toString(value, 0, count); + } + +} diff --git a/libjava/classpath/gnu/java/lang/CharData.java b/libjava/classpath/gnu/java/lang/CharData.java new file mode 100644 index 000000000..cb33035e6 --- /dev/null +++ b/libjava/classpath/gnu/java/lang/CharData.java @@ -0,0 +1,1705 @@ +/* gnu/java/lang/CharData -- Database for java.lang.Character Unicode info + Copyright (C) 2002 Free Software Foundation, Inc. + *** This file is generated by scripts/unicode-muncher.pl *** + +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.lang; + +/** + * This contains the info about the unicode characters, that + * java.lang.Character needs. It is generated automatically from + * ../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.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 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. 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 + * which lists the characters which are special cased, and + * UPPER_EXPAND, which lists their expansion. + * + * @author scripts/unicode-muncher.pl (written by Jochen Hoenicke, + * Eric Blake) + * @see Character + * @see String + */ +public interface CharData +{ + /** + * The Unicode definition file that was parsed to build this database. + */ + 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[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 + = 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 = 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 + * character type, the next bit is a flag for non-breaking spaces, and the + * 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 4.0.0, but may soon become one. + */ + 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" + + "\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" + + "\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\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\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\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 + * character. The value is -1 if Unicode does not define a value, -2 + * if the value is not a positive integer, otherwise it is the value. + * Note that this is a signed value, but stored as an unsigned char + * since this is a String literal. + */ + 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" + + "\034\035\036\037 !\"#\uffff\uffff\012" + + "\013\014\015\016\017\020\021\022\023\024\025" + + "\026\027\030\031\032\033\034\035\036\037 " + + "!\"#\uffff\uffff\uffff\uffff\uffff\uffff\002\003" + + "\uffff\001\uffff\ufffe\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\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\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\ufffe\uffff\uffff\024\036(" + + "2UPPER to determine their titlecase). The listing + * is a sorted sequence of character pairs; converting the first character + * of the pair to titlecase produces the second character. + */ + String TITLE + = "\u01c4\u01c5\u01c5\u01c5\u01c6\u01c5\u01c7\u01c8\u01c8\u01c8\u01c9" + + "\u01c8\u01ca\u01cb\u01cb\u01cb\u01cc\u01cb\u01f1\u01f2\u01f2\u01f2" + + "\u01f3\u01f2"; + + /** + * This is a listing of characters with multi-character uppercase sequences. + * A character appears in this list exactly when it has a non-zero entry + * in the low-order 2-bit field of DIRECTION. The listing is a sorted + * sequence of pairs (hence a binary search on the even elements is an + * efficient way to lookup a character). The first element of a pair is the + * character with the expansion, and the second is the index into + * UPPER_EXPAND where the expansion begins. Use the 2-bit field of + * DIRECTION to determine where the expansion ends. + */ + String UPPER_SPECIAL + = "\u00df\000\u0149\002\u01f0\004\u0390\006\u03b0\011" + + "\u0587\014\u1e96\016\u1e97\020\u1e98\022\u1e99\024" + + "\u1e9a\026\u1f50\030\u1f52\032\u1f54\035\u1f56 " + + "\u1f80#\u1f81%\u1f82'\u1f83)\u1f84+" + + "\u1f85-\u1f86/\u1f871\u1f883\u1f895" + + "\u1f8a7\u1f8b9\u1f8c;\u1f8d=\u1f8e?" + + "\u1f8fA\u1f90C\u1f91E\u1f92G\u1f93I" + + "\u1f94K\u1f95M\u1f96O\u1f97Q\u1f98S" + + "\u1f99U\u1f9aW\u1f9bY\u1f9c[\u1f9d]" + + "\u1f9e_\u1f9fa\u1fa0c\u1fa1e\u1fa2g" + + "\u1fa3i\u1fa4k\u1fa5m\u1fa6o\u1fa7q" + + "\u1fa8s\u1fa9u\u1faaw\u1faby\u1fac{" + + "\u1fad}\u1fae\u007f\u1faf\u0081\u1fb2\u0083\u1fb3\u0085" + + "\u1fb4\u0087\u1fb6\u0089\u1fb7\u008b\u1fbc\u008e\u1fc2\u0090" + + "\u1fc3\u0092\u1fc4\u0094\u1fc6\u0096\u1fc7\u0098\u1fcc\u009b" + + "\u1fd2\u009d\u1fd3\u00a0\u1fd6\u00a3\u1fd7\u00a5\u1fe2\u00a8" + + "\u1fe3\u00ab\u1fe4\u00ae\u1fe6\u00b0\u1fe7\u00b2\u1ff2\u00b5" + + "\u1ff3\u00b7\u1ff4\u00b9\u1ff6\u00bb\u1ff7\u00bd\u1ffc\u00c0" + + "\ufb00\u00c2\ufb01\u00c4\ufb02\u00c6\ufb03\u00c8\ufb04\u00cb" + + "\ufb05\u00ce\ufb06\u00d0\ufb13\u00d2\ufb14\u00d4\ufb15\u00d6" + + "\ufb16\u00d8\ufb17\u00da"; + + /** + * This is the listing of special case multi-character uppercase sequences. + * Characters listed in UPPER_SPECIAL index into this table to find their + * uppercase expansion. Remember that you must also perform special-casing + * on two single-character sequences in the Turkish locale, which are not + * covered here in CharData. + */ + String UPPER_EXPAND + = "SS\u02bcNJ\u030c\u0399\u0308\u0301\u03a5\u0308" + + "\u0301\u0535\u0552H\u0331T\u0308W\u030aY\u030a" + + "A\u02be\u03a5\u0313\u03a5\u0313\u0300\u03a5\u0313\u0301\u03a5" + + "\u0313\u0342\u1f08\u0399\u1f09\u0399\u1f0a\u0399\u1f0b\u0399\u1f0c" + + "\u0399\u1f0d\u0399\u1f0e\u0399\u1f0f\u0399\u1f08\u0399\u1f09\u0399" + + "\u1f0a\u0399\u1f0b\u0399\u1f0c\u0399\u1f0d\u0399\u1f0e\u0399\u1f0f" + + "\u0399\u1f28\u0399\u1f29\u0399\u1f2a\u0399\u1f2b\u0399\u1f2c\u0399" + + "\u1f2d\u0399\u1f2e\u0399\u1f2f\u0399\u1f28\u0399\u1f29\u0399\u1f2a" + + "\u0399\u1f2b\u0399\u1f2c\u0399\u1f2d\u0399\u1f2e\u0399\u1f2f\u0399" + + "\u1f68\u0399\u1f69\u0399\u1f6a\u0399\u1f6b\u0399\u1f6c\u0399\u1f6d" + + "\u0399\u1f6e\u0399\u1f6f\u0399\u1f68\u0399\u1f69\u0399\u1f6a\u0399" + + "\u1f6b\u0399\u1f6c\u0399\u1f6d\u0399\u1f6e\u0399\u1f6f\u0399\u1fba" + + "\u0399\u0391\u0399\u0386\u0399\u0391\u0342\u0391\u0342\u0399\u0391" + + "\u0399\u1fca\u0399\u0397\u0399\u0389\u0399\u0397\u0342\u0397\u0342" + + "\u0399\u0397\u0399\u0399\u0308\u0300\u0399\u0308\u0301\u0399\u0342" + + "\u0399\u0308\u0342\u03a5\u0308\u0300\u03a5\u0308\u0301\u03a1\u0313" + + "\u03a5\u0342\u03a5\u0308\u0342\u1ffa\u0399\u03a9\u0399\u038f\u0399" + + "\u03a9\u0342\u03a9\u0342\u0399\u03a9\u0399FFFI" + + "FLFFIFFLSTS" + + "T\u0544\u0546\u0544\u0535\u0544\u053b\u054e\u0546\u0544\u053d"; +} diff --git a/libjava/classpath/gnu/java/lang/ClassHelper.java b/libjava/classpath/gnu/java/lang/ClassHelper.java new file mode 100644 index 000000000..e190889de --- /dev/null +++ b/libjava/classpath/gnu/java/lang/ClassHelper.java @@ -0,0 +1,205 @@ +/* ClassHelper.java -- Utility methods to augment java.lang.Class + Copyright (C) 1998, 2002 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.lang; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +/** + * ClassHelper has various methods that ought to have been in Class. + * + * @author John Keiser + * @author Eric Blake (ebb9@email.byu.edu) + */ +public class ClassHelper +{ + /** + * Strip the package part from the class name. + * + * @param clazz the class to get the truncated name from + * @return the truncated class name + */ + public static String getTruncatedClassName(Class clazz) + { + return getTruncatedName(clazz.getName()); + } + + /** + * Strip the package part from the class name, or the class part from + * the method or field name. + * + * @param name the name to truncate + * @return the truncated name + */ + public static String getTruncatedName(String name) + { + int lastInd = name.lastIndexOf('.'); + if (lastInd == -1) + return name; + return name.substring(lastInd + 1); + } + + /** + * Return the name of the class as written by the user. + * This is used by the various reflection toString methods. + * It differs from {@link Class#getName()} in that it prints + * arrays with trailing "[]"s. Note that it does not treat + * member classes specially, so a dollar sign may still appear + * in the result. This is intentional. + * @param klass the class + * @return a pretty form of the class' name + */ + public static String getUserName(Class klass) + { + int arrayCount = 0; + while (klass.isArray()) + { + ++arrayCount; + klass = klass.getComponentType(); + } + String name = klass.getName(); + if (arrayCount == 0) + return name; + CPStringBuilder b = new CPStringBuilder(name.length() + 2 * arrayCount); + b.append(name); + for (int i = 0; i < arrayCount; ++i) + b.append("[]"); + return b.toString(); + } + + /** Cache of methods found in getAllMethods(). */ + private static Map allMethods = new HashMap(); + + /** + * Get all the methods, public, private and otherwise, from the class, + * getting them from the most recent class to find them. This may not + * be quite the correct approach, as this includes methods that are not + * inherited or accessible from clazz, so beware. + * + * @param clazz the class to start at + * @return all methods declared or inherited in clazz + */ + public static Method[] getAllMethods(Class clazz) + { + Method[] retval = (Method[]) allMethods.get(clazz); + if (retval == null) + { + Set methods = new HashSet(); + Class c = clazz; + while (c != null) + { + Method[] currentMethods = c.getDeclaredMethods(); + loop: + for (int i = 0; i < currentMethods.length; i++) + { + Method current = currentMethods[i]; + int size = methods.size(); + Iterator iter = methods.iterator(); + while (--size >= 0) + { + Method override = (Method) iter.next(); + if (current.getName().equals(override.getName()) + && Arrays.equals(current.getParameterTypes(), + override.getParameterTypes()) + && current.getReturnType() == override.getReturnType()) + continue loop; + } + methods.add(current); + } + c = c.getSuperclass(); + } + retval = new Method[methods.size()]; + methods.toArray(retval); + allMethods.put(clazz, retval); + } + return retval; + } + + /** Cache of fields found in getAllFields(). */ + private static Map allFields = new HashMap(); + + /** + * Get all the fields, public, private and otherwise, from the class, + * getting them from the most recent class to find them. This may not + * be quite the correct approach, as this includes fields that are not + * inherited or accessible from clazz, so beware. + * + * @param clazz the class to start at + * @return all fields declared or inherited in clazz + */ + public static Field[] getAllFields(Class clazz) + { + Field[] retval = (Field[]) allFields.get(clazz); + if (retval == null) + { + Set fields = new HashSet(); + Class c = clazz; + while (c != null) + { + Field[] currentFields = c.getDeclaredFields(); + loop: + for (int i = 0; i < currentFields.length; i++) + { + Field current = currentFields[i]; + int size = fields.size(); + Iterator iter = fields.iterator(); + while (--size >= 0) + { + Field override = (Field) iter.next(); + if (current.getName().equals(override.getName()) + && current.getType() == override.getType()) + continue loop; + } + fields.add(current); + } + c = c.getSuperclass(); + } + retval = new Field[fields.size()]; + fields.toArray(retval); + allFields.put(clazz, retval); + } + return retval; + } +} diff --git a/libjava/classpath/gnu/java/lang/InstrumentationImpl.java b/libjava/classpath/gnu/java/lang/InstrumentationImpl.java new file mode 100644 index 000000000..a601baf55 --- /dev/null +++ b/libjava/classpath/gnu/java/lang/InstrumentationImpl.java @@ -0,0 +1,241 @@ +/* InstrumentationImpl.java -- GNU implementation of + java.lang.instrument.Instrumentation + 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.java.lang; + +import java.lang.instrument.Instrumentation; +import java.lang.instrument.ClassFileTransformer; +import java.lang.instrument.ClassDefinition; +import java.lang.instrument.UnmodifiableClassException; +import java.lang.instrument.IllegalClassFormatException; + +import java.security.ProtectionDomain; + +import java.util.ArrayList; +import java.util.Iterator; + +/** + * An Instrumentation object has transformers that will + * be called each time a class is defined or redefined. + * The object is given to a premain function + * that is called before the main function. + * + * @author Nicolas Geoffray (nicolas.geoffray@menlina.com) + * @since 1.5 + */ +public final class InstrumentationImpl implements Instrumentation +{ + + /* List of transformers */ + private ArrayList transformers = + new ArrayList(); + + + InstrumentationImpl() + { + } + + /** + * Adds a ClassFileTransformer object + * to the instrumentation. Each time a class is defined + * or redefined, the transform method of the + * transformer object is called. + * + * @param transformer the transformer to add + * @throws NullPointerException if transformer is null + */ + public void addTransformer(ClassFileTransformer transformer) + { + if (transformer == null) + throw new NullPointerException(); + synchronized(transformers) + { + transformers.add(transformer); + } + } + + /** + * Removes the given transformer from the set of transformers + * this Instrumentation object has. + * + * @param transformer the transformer to remove + * @return true if the transformer was found and removed, false if + * the transformer was not found + * @throws NullPointerException if transformer is null + */ + public boolean removeTransformer(ClassFileTransformer transformer) + { + if (transformer == null) + throw new NullPointerException(); + + boolean result; + synchronized (transformers) + { + result = transformers.remove(transformer); + } + return result; + } + + /** + * Returns if the current JVM supports class redefinition + * + * @return true if the current JVM supports class redefinition + */ + public boolean isRedefineClassesSupported() + { + return VMInstrumentationImpl.isRedefineClassesSupported(); + } + + /** + * Redefine classes present in the definitions array, with + * the corresponding class files. + * + * @param definitions an array of classes to redefine + * + * @throws ClassNotFoundException if a class cannot be found + * @throws UnmodifiableClassException if a class cannot be modified + * @throws UnsupportedOperationException if the JVM does not support + * redefinition or the redefinition made unsupported changes + * @throws ClassFormatError if a class file is not valid + * @throws NoClassDefFoundError if a class name is not equal to the name + * in the class file specified + * @throws UnsupportedClassVersionError if the class file version numbers + * are unsupported + * @throws ClassCircularityError if circularity occured with the new + * classes + * @throws LinkageError if a linkage error occurs + * @throws NullPointerException if the definitions array is null, or any + * of its element + * + * @see isRedefineClassesSupported() + * @see addTransformer(java.lang.instrument.ClassFileTransformer) + * @see ClassFileTransformer + */ + public void redefineClasses(ClassDefinition[] definitions) + throws ClassNotFoundException, + UnmodifiableClassException + { + if (!isRedefineClassesSupported()) + throw new UnsupportedOperationException(); + + VMInstrumentationImpl.redefineClasses(this, definitions); + } + + + /** + * Get all the classes loaded by the JVM. + * + * @return an array containing all the classes loaded by the JVM. The array + * is empty if no class is loaded. + */ + public Class[] getAllLoadedClasses() + { + return VMInstrumentationImpl.getAllLoadedClasses(); + } + + /** + * Get all the classes loaded by a given class loader + * + * @param loader the loader + * + * @return an array containing all the classes loaded by the given loader. + * The array is empty if no class was loaded by the loader. + */ + public Class[] getInitiatedClasses(ClassLoader loader) + { + return VMInstrumentationImpl.getInitiatedClasses(loader); + } + + /** + * Get the size of an object. + * + * @param objectToSize the object + * @return the size of the object + * @throws NullPointerException if objectToSize is null. + */ + public long getObjectSize(Object objectToSize) + { + // We alleviate the VM work + if (objectToSize == null) + throw new NullPointerException(); + return VMInstrumentationImpl.getObjectSize(objectToSize); + } + + /** + * Called by the VM or redefineClasses to call each transformer + * + * @param loader the loader of the class + * @param className the name of the class with packages separated with "/" + * @param classBeingRedefined the class being redefined if it's the case, + * null otherwise + * @param protectionDomain the protection domain of the class being defined + * or redefined + * @param classfileBuffer the input byte buffer in class file format + * + * @return the new class file + */ + public byte[] callTransformers(ClassLoader loader, String className, + Class classBeingRedefined, ProtectionDomain protectionDomain, + byte[] classfileBuffer) + { + byte[] newBuffer = null; + byte[] oldBuffer = classfileBuffer; + ClassFileTransformer current; + synchronized (transformers) + { + Iterator i = transformers.iterator(); + while (i.hasNext()) + { + current = i.next(); + try + { + newBuffer = current.transform(loader, className, + classBeingRedefined, protectionDomain, oldBuffer); + } + catch (IllegalClassFormatException ignored) + { + //IGNORED + } + if (newBuffer != null) + oldBuffer = newBuffer; + } + } + return oldBuffer; + } +} diff --git a/libjava/classpath/gnu/java/lang/MainThread.java b/libjava/classpath/gnu/java/lang/MainThread.java new file mode 100644 index 000000000..a72956421 --- /dev/null +++ b/libjava/classpath/gnu/java/lang/MainThread.java @@ -0,0 +1,83 @@ +/* MainThread.java -- + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 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.java.lang; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * MainThread is a Thread which uses the main() method of some class. + * + * @author John Keiser + * @author Tom Tromey (tromey@redhat.com) + */ +public class MainThread +{ + // Private data. + String[] args; + Method mainMethod; + + public MainThread(String classname, String[] args) + throws ClassNotFoundException, NoSuchMethodException + { + Class found = Class.forName(classname, true, + ClassLoader.getSystemClassLoader()); + Class[] argTypes = new Class[1]; + argTypes[0] = args.getClass(); + mainMethod = found.getMethod("main", argTypes); + this.args = args; + } + + public void run() + { + try + { + mainMethod.invoke(null,(Object) args); + } + catch(IllegalAccessException e) + { + // Ignore. + } + catch(InvocationTargetException e) + { + // Ignore. + } + } +} diff --git a/libjava/classpath/gnu/java/lang/management/BeanImpl.java b/libjava/classpath/gnu/java/lang/management/BeanImpl.java new file mode 100644 index 000000000..a7c2357b6 --- /dev/null +++ b/libjava/classpath/gnu/java/lang/management/BeanImpl.java @@ -0,0 +1,447 @@ +/* BeanImpl.java - A common superclass for bean implementations. + Copyright (C) 2006 Free Software Foundation + +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.lang.management; + +import gnu.javax.management.Translator; + +import java.lang.management.ManagementPermission; + +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.management.AttributeNotFoundException; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanConstructorInfo; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.MBeanOperationInfo; +import javax.management.MBeanParameterInfo; +import javax.management.NotCompliantMBeanException; +import javax.management.ReflectionException; +import javax.management.StandardMBean; + +import javax.management.openmbean.ArrayType; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenMBeanAttributeInfo; +import javax.management.openmbean.OpenMBeanAttributeInfoSupport; +import javax.management.openmbean.OpenMBeanConstructorInfo; +import javax.management.openmbean.OpenMBeanConstructorInfoSupport; +import javax.management.openmbean.OpenMBeanInfo; +import javax.management.openmbean.OpenMBeanInfoSupport; +import javax.management.openmbean.OpenMBeanOperationInfo; +import javax.management.openmbean.OpenMBeanOperationInfoSupport; +import javax.management.openmbean.OpenMBeanParameterInfo; +import javax.management.openmbean.OpenMBeanParameterInfoSupport; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; + +/** + * A common superclass for bean implementations. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public class BeanImpl + extends StandardMBean +{ + + /** + * Cached open bean information. + */ + private OpenMBeanInfo openInfo; + + /** + * Constructs a new BeanImpl. + * + * @param iface the bean interface being implemented. + * @throws NotCompliantMBeanException if this class doesn't implement + * the interface or a method appears + * in the interface that doesn't comply + * with the naming conventions. + */ + protected BeanImpl(Class iface) + throws NotCompliantMBeanException + { + super(iface); + } + + protected void cacheMBeanInfo(MBeanInfo info) + { + if (info == null) + return; + try + { + MBeanAttributeInfo[] oldA = info.getAttributes(); + OpenMBeanAttributeInfo[] attribs = + new OpenMBeanAttributeInfoSupport[oldA.length]; + for (int a = 0; a < oldA.length; ++a) + { + OpenMBeanParameterInfo param = Translator.translate(oldA[a].getType()); + if (param.getMinValue() == null) + { + Object[] lv; + if (param.getLegalValues() == null) + lv = null; + else + lv = param.getLegalValues().toArray(); + attribs[a] = new OpenMBeanAttributeInfoSupport(oldA[a].getName(), + oldA[a].getDescription(), + ((OpenType) + param.getOpenType()), + oldA[a].isReadable(), + oldA[a].isWritable(), + oldA[a].isIs(), + param.getDefaultValue(), + lv); + } + else + attribs[a] = new OpenMBeanAttributeInfoSupport(oldA[a].getName(), + oldA[a].getDescription(), + ((OpenType) + param.getOpenType()), + oldA[a].isReadable(), + oldA[a].isWritable(), + oldA[a].isIs(), + param.getDefaultValue(), + ((Comparable) + param.getMinValue()), + ((Comparable) + param.getMaxValue())); + } + MBeanConstructorInfo[] oldC = info.getConstructors(); + OpenMBeanConstructorInfo[] cons = new OpenMBeanConstructorInfoSupport[oldC.length]; + for (int a = 0; a < oldC.length; ++a) + cons[a] = + new OpenMBeanConstructorInfoSupport(oldC[a].getName(), + oldC[a].getDescription(), + translateSignature(oldC[a].getSignature())); + MBeanOperationInfo[] oldO = info.getOperations(); + OpenMBeanOperationInfo[] ops = new OpenMBeanOperationInfoSupport[oldO.length]; + for (int a = 0; a < oldO.length; ++a) + ops[a] = + new OpenMBeanOperationInfoSupport(oldO[a].getName(), + oldO[a].getDescription(), + translateSignature(oldO[a].getSignature()), + Translator.translate(oldO[a].getReturnType()).getOpenType(), + oldO[a].getImpact()); + openInfo = new OpenMBeanInfoSupport(info.getClassName(), info.getDescription(), + attribs, cons, ops, info.getNotifications()); + } + catch (OpenDataException e) + { + throw (InternalError) (new InternalError("A problem occurred creating the open type " + + "descriptors.").initCause(e)); + } + } + + protected void checkMonitorPermissions() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new ManagementPermission("monitor")); + } + + protected void checkControlPermissions() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new ManagementPermission("control")); + } + + public Object getAttribute(String attribute) + throws AttributeNotFoundException, MBeanException, + ReflectionException + { + Object value = super.getAttribute(attribute); + if (value instanceof Enum) + return ((Enum) value).name(); + Class vClass = value.getClass(); + if (vClass.isArray()) + vClass = vClass.getComponentType(); + String cName = vClass.getName(); + String[] allowedTypes = OpenType.ALLOWED_CLASSNAMES; + for (int a = 0; a < allowedTypes.length; ++a) + if (cName.equals(allowedTypes[a])) + return value; + OpenMBeanInfo info = (OpenMBeanInfo) getMBeanInfo(); + MBeanAttributeInfo[] attribs = + (MBeanAttributeInfo[]) info.getAttributes(); + OpenType type = null; + for (int a = 0; a < attribs.length; ++a) + if (attribs[a].getName().equals(attribute)) + type = ((OpenMBeanAttributeInfo) attribs[a]).getOpenType(); + if (value instanceof List) + { + try + { + Class e = + Class.forName(((ArrayType) type).getElementOpenType().getClassName()); + List l = (List) value; + Object[] array = (Object[]) Array.newInstance(e, l.size()); + return l.toArray(array); + } + catch (ClassNotFoundException e) + { + throw (InternalError) (new InternalError("The class of the list " + + "element type could not " + + "be created").initCause(e)); + } + } + if (value instanceof Map) + { + TabularType ttype = (TabularType) type; + TabularData data = new TabularDataSupport(ttype); + Iterator it = ((Map) value).entrySet().iterator(); + while (it.hasNext()) + { + Map.Entry entry = (Map.Entry) it.next(); + try + { + data.put(new CompositeDataSupport(ttype.getRowType(), + new String[] { + "key", + "value" + }, + new Object[] { + entry.getKey(), + entry.getValue() + })); + } + catch (OpenDataException e) + { + throw (InternalError) (new InternalError("A problem occurred " + + "converting the map " + + "to a composite data " + + "structure.").initCause(e)); + } + } + return data; + } + CompositeType cType = (CompositeType) type; + Set names = cType.keySet(); + Iterator it = names.iterator(); + List values = new ArrayList(names.size()); + while (it.hasNext()) + { + String field = (String) it.next(); + Method getter = null; + try + { + getter = vClass.getMethod("get" + field); + } + catch (NoSuchMethodException e) + { + /* Ignored; the type tells us it's there. */ + } + try + { + values.add(getter.invoke(value)); + } + catch (IllegalAccessException e) + { + throw new ReflectionException(e, "Failed to retrieve " + field); + } + catch (IllegalArgumentException e) + { + throw new ReflectionException(e, "Failed to retrieve " + field); + } + catch (InvocationTargetException e) + { + throw new MBeanException((Exception) e.getCause(), + "The getter of " + field + + " threw an exception"); + } + } + try + { + return new CompositeDataSupport(cType, + (String[]) + names.toArray(new String[names.size()]), + values.toArray()); + } + catch (OpenDataException e) + { + throw (InternalError) (new InternalError("A problem occurred " + + "converting the value " + + "to a composite data " + + "structure.").initCause(e)); + } + } + + protected MBeanInfo getCachedMBeanInfo() + { + return (MBeanInfo) openInfo; + } + + /** + * Override this method so as to prevent the description of a constructor's + * parameter being @code{null}. Open MBeans can not have @code{null} descriptions, + * but one will occur as the names of parameters aren't stored for reflection. + * + * @param constructor the constructor whose parameter needs describing. + * @param parameter the parameter to be described. + * @param sequenceNo the number of the parameter to describe. + * @return a description of the constructor's parameter. + */ + protected String getDescription(MBeanConstructorInfo constructor, + MBeanParameterInfo parameter, + int sequenceNo) + { + String desc = parameter.getDescription(); + if (desc == null) + return "param" + sequenceNo; + else + return desc; + } + + /** + * Override this method so as to prevent the description of an operation's + * parameter being @code{null}. Open MBeans can not have @code{null} descriptions, + * but one will occur as the names of parameters aren't stored for reflection. + * + * @param operation the operation whose parameter needs describing. + * @param parameter the parameter to be described. + * @param sequenceNo the number of the parameter to describe. + * @return a description of the operation's parameter. + */ + protected String getDescription(MBeanOperationInfo operation, + MBeanParameterInfo parameter, + int sequenceNo) + { + String desc = parameter.getDescription(); + if (desc == null) + return "param" + sequenceNo; + else + return desc; + } + + /** + * Override this method so as to prevent the name of a constructor's + * parameter being @code{null}. Open MBeans can not have @code{null} names, + * but one will occur as the names of parameters aren't stored for reflection. + * + * @param constructor the constructor whose parameter needs a name. + * @param parameter the parameter to be named. + * @param sequenceNo the number of the parameter to name. + * @return a description of the constructor's parameter. + */ + protected String getParameterName(MBeanConstructorInfo constructor, + MBeanParameterInfo parameter, + int sequenceNo) + { + String name = parameter.getName(); + if (name == null) + return "param" + sequenceNo; + else + return name; + } + + /** + * Override this method so as to prevent the name of an operation's + * parameter being @code{null}. Open MBeans can not have @code{null} names, + * but one will occur as the names of parameters aren't stored for reflection. + * + * @param operation the operation whose parameter needs a name. + * @param parameter the parameter to be named. + * @param sequenceNo the number of the parameter to name. + * @return a description of the operation's parameter. + */ + protected String getParameterName(MBeanOperationInfo operation, + MBeanParameterInfo parameter, + int sequenceNo) + { + String name = parameter.getName(); + if (name == null) + return "param" + sequenceNo; + else + return name; + } + + public MBeanInfo getMBeanInfo() + { + super.getMBeanInfo(); + return getCachedMBeanInfo(); + } + + private OpenMBeanParameterInfo[] translateSignature(MBeanParameterInfo[] oldS) + throws OpenDataException + { + OpenMBeanParameterInfo[] sig = new OpenMBeanParameterInfoSupport[oldS.length]; + for (int a = 0; a < oldS.length; ++a) + { + OpenMBeanParameterInfo param = Translator.translate(oldS[a].getType()); + if (param.getMinValue() == null) + { + Object[] lv; + if (param.getLegalValues() == null) + lv = null; + else + lv = param.getLegalValues().toArray(); + sig[a] = new OpenMBeanParameterInfoSupport(oldS[a].getName(), + oldS[a].getDescription(), + ((OpenType) + param.getOpenType()), + param.getDefaultValue(), + lv); + } + else + sig[a] = new OpenMBeanParameterInfoSupport(oldS[a].getName(), + oldS[a].getDescription(), + ((OpenType) + param.getOpenType()), + param.getDefaultValue(), + ((Comparable) + param.getMinValue()), + ((Comparable) + param.getMaxValue())); + } + return sig; + } + + +} diff --git a/libjava/classpath/gnu/java/lang/management/ClassLoadingMXBeanImpl.java b/libjava/classpath/gnu/java/lang/management/ClassLoadingMXBeanImpl.java new file mode 100644 index 000000000..d98a39633 --- /dev/null +++ b/libjava/classpath/gnu/java/lang/management/ClassLoadingMXBeanImpl.java @@ -0,0 +1,98 @@ +/* ClassLoadingMXBeanImpl.java - Implementation of a class loading bean + Copyright (C) 2006 Free Software Foundation + +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.lang.management; + +import java.lang.management.ClassLoadingMXBean; + +import javax.management.NotCompliantMBeanException; + +/** + * Provides access to information about the class loading + * behaviour of the current invocation of the virtual + * machine. Instances of this bean are obtained by calling + * {@link ManagementFactory#getClassLoadingMXBean()}. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public final class ClassLoadingMXBeanImpl + extends BeanImpl + implements ClassLoadingMXBean +{ + + /** + * Constructs a new ClassLoadingMXBeanImpl. + * + * @throws NotCompliantMBeanException if this class doesn't implement + * the interface or a method appears + * in the interface that doesn't comply + * with the naming conventions. + */ + public ClassLoadingMXBeanImpl() + throws NotCompliantMBeanException + { + super(ClassLoadingMXBean.class); + } + + public int getLoadedClassCount() + { + return VMClassLoadingMXBeanImpl.getLoadedClassCount(); + } + + public long getTotalLoadedClassCount() + { + return getLoadedClassCount() + getUnloadedClassCount(); + } + + public long getUnloadedClassCount() + { + return VMClassLoadingMXBeanImpl.getUnloadedClassCount(); + } + + public boolean isVerbose() + { + return VMClassLoadingMXBeanImpl.isVerbose(); + } + + public void setVerbose(boolean verbose) + { + checkControlPermissions(); + VMClassLoadingMXBeanImpl.setVerbose(verbose); + } + +} diff --git a/libjava/classpath/gnu/java/lang/management/CompilationMXBeanImpl.java b/libjava/classpath/gnu/java/lang/management/CompilationMXBeanImpl.java new file mode 100644 index 000000000..1b77edf5a --- /dev/null +++ b/libjava/classpath/gnu/java/lang/management/CompilationMXBeanImpl.java @@ -0,0 +1,105 @@ +/* CompilationMXBeanImpl.java - Implementation of a compilation bean + Copyright (C) 2006 Free Software Foundation + +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.lang.management; + +import gnu.classpath.SystemProperties; + +import java.lang.management.CompilationMXBean; + +import javax.management.NotCompliantMBeanException; + +/** + * Provides access to information about the JIT + * compiler of the virtual machine, if one exists. + * Instances of this bean are obtained by calling + * {@link ManagementFactory#getCompilationMXBean()}, + * if this is the case. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public final class CompilationMXBeanImpl + extends BeanImpl + implements CompilationMXBean +{ + + /** + * Constant for compiler name. + */ + private static final String COMPILER_NAME = "gnu.java.compiler.name"; + + /** + * Constant for compilation time support. + */ + private static final String COMPILATION_TIME_SUPPORT = + "gnu.java.lang.management.CompilationTimeSupport"; + + /** + * Constructs a new CompilationMXBeanImpl. + * + * @throws NotCompliantMBeanException if this class doesn't implement + * the interface or a method appears + * in the interface that doesn't comply + * with the naming conventions. + */ + public CompilationMXBeanImpl() + throws NotCompliantMBeanException + { + super(CompilationMXBean.class); + } + + public String getName() + { + return SystemProperties.getProperty(COMPILER_NAME); + } + + public boolean isCompilationTimeMonitoringSupported() + { + return SystemProperties.getProperty(COMPILATION_TIME_SUPPORT) != null; + } + + public long getTotalCompilationTime() + { + if (isCompilationTimeMonitoringSupported()) + return VMCompilationMXBeanImpl.getTotalCompilationTime(); + else + throw new UnsupportedOperationException("Compilation time monitoring " + + "is not supported"); + } + +} diff --git a/libjava/classpath/gnu/java/lang/management/GarbageCollectorMXBeanImpl.java b/libjava/classpath/gnu/java/lang/management/GarbageCollectorMXBeanImpl.java new file mode 100644 index 000000000..7a2d762fa --- /dev/null +++ b/libjava/classpath/gnu/java/lang/management/GarbageCollectorMXBeanImpl.java @@ -0,0 +1,84 @@ +/* GarbageCollectorMXBeanImpl.java - Implementation of a GC bean + Copyright (C) 2006 Free Software Foundation + +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.lang.management; + +import java.lang.management.GarbageCollectorMXBean; + +import javax.management.NotCompliantMBeanException; + +/** + * Provides access to information about one of the garbage + * collectors used by the current invocation of the + * virtual machine. An instance of this bean for each garbage + * collector is obtained by calling + * {@link ManagementFactory#getGarbageCollectorMXBeans()}. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public final class GarbageCollectorMXBeanImpl + extends MemoryManagerMXBeanImpl + implements GarbageCollectorMXBean +{ + + /** + * Constructs a new GarbageCollectorMXBeanImpl. + * + * @param name the name of the garbage collector this bean represents. + * @throws NotCompliantMBeanException if this class doesn't implement + * the interface or a method appears + * in the interface that doesn't comply + * with the naming conventions. + */ + public GarbageCollectorMXBeanImpl(String name) + throws NotCompliantMBeanException + { + super(name, GarbageCollectorMXBean.class); + } + + public long getCollectionCount() + { + return VMGarbageCollectorMXBeanImpl.getCollectionCount(name); + } + + public long getCollectionTime() + { + return VMGarbageCollectorMXBeanImpl.getCollectionTime(name); + } + +} diff --git a/libjava/classpath/gnu/java/lang/management/MemoryMXBeanImpl.java b/libjava/classpath/gnu/java/lang/management/MemoryMXBeanImpl.java new file mode 100644 index 000000000..10e6522f1 --- /dev/null +++ b/libjava/classpath/gnu/java/lang/management/MemoryMXBeanImpl.java @@ -0,0 +1,281 @@ +/* MemoryMXBeanImpl.java - Implementation of a memory bean + Copyright (C) 2006 Free Software Foundation + +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.lang.management; + +import gnu.javax.management.ListenerData; + +import java.lang.management.MemoryMXBean; +import java.lang.management.MemoryNotificationInfo; +import java.lang.management.MemoryUsage; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import javax.management.ListenerNotFoundException; +import javax.management.MBeanNotificationInfo; +import javax.management.NotCompliantMBeanException; +import javax.management.Notification; +import javax.management.NotificationEmitter; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; + +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; + +/** + * Provides access to information about the memory + * management of the current invocation of the virtual + * machine. Instances of this bean are obtained by calling + * {@link ManagementFactory#getMemoryMXBean()}. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public final class MemoryMXBeanImpl + extends BeanImpl + implements MemoryMXBean, NotificationEmitter +{ + + private List listeners; + + private long notificationCount; + + public static CompositeType notifType; + + public static CompositeType usageType; + + static + { + try + { + CompositeType usageType = + new CompositeType(MemoryUsage.class.getName(), + "Describes the usage levels of a pool", + new String[] { "init", "used", + "committed", "max" + }, + new String[] { "Initial level", + "Used level", + "Committed level", + "Maximum level" + }, + new OpenType[] { + SimpleType.LONG, SimpleType.LONG, + SimpleType.LONG, SimpleType.LONG + }); + CompositeType notifType = + new CompositeType(MemoryNotificationInfo.class.getName(), + "Provides the notification info on memory usage", + new String[] { "poolName", "usage", "count" }, + new String[] { "Name of the memory pool", + "Usage level of the memory pool", + "Number of times the threshold " + + "has been crossed" + }, + new OpenType[] { + SimpleType.STRING, usageType, SimpleType.LONG + }); + } + catch (OpenDataException e) + { + throw new IllegalStateException("Something went wrong in creating " + + "the composite data types.", e); + } + } + + /** + * Constructs a new MemoryMXBeanImpl. + * + * @throws NotCompliantMBeanException if this class doesn't implement + * the interface or a method appears + * in the interface that doesn't comply + * with the naming conventions. + */ + public MemoryMXBeanImpl() + throws NotCompliantMBeanException + { + super(MemoryMXBean.class); + listeners = new ArrayList(); + notificationCount = 0; + } + + public void gc() + { + System.gc(); + } + + public MemoryUsage getHeapMemoryUsage() + { + return VMMemoryMXBeanImpl.getHeapMemoryUsage(); + } + + public MemoryUsage getNonHeapMemoryUsage() + { + return VMMemoryMXBeanImpl.getNonHeapMemoryUsage(); + } + + public int getObjectPendingFinalizationCount() + { + return VMMemoryMXBeanImpl.getObjectPendingFinalizationCount(); + } + + public boolean isVerbose() + { + return VMMemoryMXBeanImpl.isVerbose(); + } + + public void setVerbose(boolean verbose) + { + checkControlPermissions(); + VMMemoryMXBeanImpl.setVerbose(verbose); + } + + public void addNotificationListener(NotificationListener listener, + NotificationFilter filter, + Object passback) + { + if (listener == null) + throw new IllegalArgumentException("Null listener added to bean."); + listeners.add(new ListenerData(listener, filter, passback)); + } + + public MBeanNotificationInfo[] getNotificationInfo() + { + return new MBeanNotificationInfo[] + { + new MBeanNotificationInfo(new String[] + { + MemoryNotificationInfo.MEMORY_COLLECTION_THRESHOLD_EXCEEDED, + MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED + }, + Notification.class.getName(), + "Memory Usage Notifications") + }; + } + + public void removeNotificationListener(NotificationListener listener) + throws ListenerNotFoundException + { + Iterator it = listeners.iterator(); + boolean foundOne = false; + while (it.hasNext()) + { + ListenerData data = (ListenerData) it.next(); + if (data.getListener() == listener) + { + it.remove(); + foundOne = true; + } + } + if (!foundOne) + throw new ListenerNotFoundException("The specified listener, " + listener + + "is not registered with this bean."); + } + + public void removeNotificationListener(NotificationListener listener, + NotificationFilter filter, + Object passback) + throws ListenerNotFoundException + { + if (!(listeners.remove(new ListenerData(listener, filter, passback)))) + { + throw new ListenerNotFoundException("The specified listener, " + listener + + " with filter " + filter + + "and passback " + passback + + ", is not registered with this bean."); + } + } + + void fireNotification(String type, String poolName, long init, long used, + long committed, long max, long count) + { + Notification notif = new Notification(type, this, notificationCount); + MemoryUsage usage = new MemoryUsage(init, used, committed, max); + CompositeData data; + try + { + data = new CompositeDataSupport(notifType, + new String[] { + "poolName", "usage", "count" + }, + new Object[] { + poolName, usage, Long.valueOf(count) + }); + } + catch (OpenDataException e) + { + throw new IllegalStateException("Something went wrong in creating " + + "the composite data instance.", e); + } + notif.setUserData(data); + Iterator it = listeners.iterator(); + while (it.hasNext()) + { + ListenerData ldata = (ListenerData) it.next(); + NotificationFilter filter = ldata.getFilter(); + if (filter == null || filter.isNotificationEnabled(notif)) + ldata.getListener().handleNotification(notif, ldata.getPassback()); + } + ++notificationCount; + } + + void fireThresholdExceededNotification(String poolName, long init, + long used, long committed, + long max, long count) + { + fireNotification(MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED, + poolName, init, used, committed, max, count); + } + + void fireCollectionThresholdExceededNotification(String poolName, + long init, + long used, + long committed, + long max, + long count) + { + fireNotification(MemoryNotificationInfo.MEMORY_COLLECTION_THRESHOLD_EXCEEDED, + poolName, init, used, committed, max, count); + } + +} diff --git a/libjava/classpath/gnu/java/lang/management/MemoryManagerMXBeanImpl.java b/libjava/classpath/gnu/java/lang/management/MemoryManagerMXBeanImpl.java new file mode 100644 index 000000000..51d0ed972 --- /dev/null +++ b/libjava/classpath/gnu/java/lang/management/MemoryManagerMXBeanImpl.java @@ -0,0 +1,112 @@ +/* MemoryManagerMXBeanImpl.java - Implementation of a memory manager bean + Copyright (C) 2006 Free Software Foundation + +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.lang.management; + +import java.lang.management.MemoryManagerMXBean; + +import javax.management.NotCompliantMBeanException; + +/** + * Provides access to information about one of the memory + * managers used by the current invocation of the + * virtual machine. An instance of this bean for each memory + * manager is obtained by calling + * {@link ManagementFactory#getMemoryPoolMXBeans()}. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public class MemoryManagerMXBeanImpl + extends BeanImpl + implements MemoryManagerMXBean +{ + + /** + * The name of the memory manager. + */ + protected String name; + + /** + * Constructs a new MemoryManagerMXBeanImpl. + * + * @param name the name of the manager this bean represents. + * @throws NotCompliantMBeanException if this class doesn't implement + * the interface or a method appears + * in the interface that doesn't comply + * with the naming conventions. + */ + public MemoryManagerMXBeanImpl(String name) + throws NotCompliantMBeanException + { + this(name, MemoryManagerMXBean.class); + } + + /** + * Constructs a new MemoryManagerMXBeanImpl + * implementing the specified bean interface. + * + * @param name the name of the manager this bean represents. + * @param iface the bean interface being implemented. + * @throws NotCompliantMBeanException if this class doesn't implement + * the interface or a method appears + * in the interface that doesn't comply + * with the naming conventions. + */ + protected MemoryManagerMXBeanImpl(String name, Class iface) + throws NotCompliantMBeanException + { + super(iface); + this.name = name; + } + + public String[] getMemoryPoolNames() + { + return VMMemoryManagerMXBeanImpl.getMemoryPoolNames(name); + } + + public String getName() + { + return name; + } + + public boolean isValid() + { + return VMMemoryManagerMXBeanImpl.isValid(name); + } + +} diff --git a/libjava/classpath/gnu/java/lang/management/MemoryPoolMXBeanImpl.java b/libjava/classpath/gnu/java/lang/management/MemoryPoolMXBeanImpl.java new file mode 100644 index 000000000..d92e6703f --- /dev/null +++ b/libjava/classpath/gnu/java/lang/management/MemoryPoolMXBeanImpl.java @@ -0,0 +1,226 @@ +/* MemoryPoolMXBeanImpl.java - Implementation of a memory pool bean + Copyright (C) 2006 Free Software Foundation + +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.lang.management; + +import gnu.classpath.SystemProperties; + +import java.lang.management.MemoryPoolMXBean; +import java.lang.management.MemoryType; +import java.lang.management.MemoryUsage; + +import javax.management.NotCompliantMBeanException; + +/** + * Provides access to information about one of the memory + * resources or pools used by the current invocation of the + * virtual machine. An instance of this bean for each memory + * pool is obtained by calling + * {@link ManagementFactory#getMemoryPoolMXBeans()}. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public final class MemoryPoolMXBeanImpl + extends BeanImpl + implements MemoryPoolMXBean +{ + + /** + * The name of the pool. + */ + private String name; + + /** + * Constant for collection usage threshold. + */ + private static final String COLLECTION_USAGE_THRESHOLD = + "gnu.java.lang.management.CollectionUsageThresholdSupport"; + + /** + * Constant for thread time support. + */ + private static final String USAGE_THRESHOLD = + "gnu.java.lang.management.UsageThresholdSupport"; + + /** + * Constructs a new MemoryPoolMXBeanImpl. + * + * @param name the name of the pool this bean represents. + * @throws NotCompliantMBeanException if this class doesn't implement + * the interface or a method appears + * in the interface that doesn't comply + * with the naming conventions. + */ + public MemoryPoolMXBeanImpl(String name) + throws NotCompliantMBeanException + { + super(MemoryPoolMXBean.class); + this.name = name; + } + + public MemoryUsage getCollectionUsage() + { + return VMMemoryPoolMXBeanImpl.getCollectionUsage(name); + } + + public long getCollectionUsageThreshold() + { + if (isCollectionUsageThresholdSupported()) + return VMMemoryPoolMXBeanImpl.getCollectionUsageThreshold(name); + else + throw new UnsupportedOperationException("A collection usage "+ + "threshold is not supported."); + } + + public long getCollectionUsageThresholdCount() + { + if (isCollectionUsageThresholdSupported()) + return VMMemoryPoolMXBeanImpl.getCollectionUsageThresholdCount(name); + else + throw new UnsupportedOperationException("A collection usage "+ + "threshold is not supported."); + } + + public String[] getMemoryManagerNames() + { + return VMMemoryPoolMXBeanImpl.getMemoryManagerNames(name); + } + + public String getName() + { + return name; + } + + public MemoryUsage getPeakUsage() + { + if (isValid()) + return VMMemoryPoolMXBeanImpl.getPeakUsage(name); + else + return null; + } + + public MemoryType getType() + { + return + MemoryType.valueOf(VMMemoryPoolMXBeanImpl.getType(name)); + } + + public MemoryUsage getUsage() + { + if (isValid()) + return VMMemoryPoolMXBeanImpl.getUsage(name); + else + return null; + } + + public long getUsageThreshold() + { + if (isUsageThresholdSupported()) + return VMMemoryPoolMXBeanImpl.getUsageThreshold(name); + else + throw new UnsupportedOperationException("A usage threshold " + + "is not supported."); + } + + public long getUsageThresholdCount() + { + if (isUsageThresholdSupported()) + return VMMemoryPoolMXBeanImpl.getUsageThresholdCount(name); + else + throw new UnsupportedOperationException("A usage threshold " + + "is not supported."); + } + + public boolean isCollectionUsageThresholdExceeded() + { + return getCollectionUsage().getUsed() >= getCollectionUsageThreshold(); + } + + public boolean isCollectionUsageThresholdSupported() + { + return SystemProperties.getProperty(COLLECTION_USAGE_THRESHOLD) != null; + } + + public boolean isUsageThresholdExceeded() + { + return getUsage().getUsed() >= getUsageThreshold(); + } + + public boolean isUsageThresholdSupported() + { + return SystemProperties.getProperty(USAGE_THRESHOLD) != null; + } + + public boolean isValid() + { + return VMMemoryPoolMXBeanImpl.isValid(name); + } + + public void resetPeakUsage() + { + checkControlPermissions(); + VMMemoryPoolMXBeanImpl.resetPeakUsage(name); + } + + public void setCollectionUsageThreshold(long threshold) + { + checkControlPermissions(); + if (threshold < 0) + throw new IllegalArgumentException("Threshold of " + threshold + + "is less than zero."); + if (isCollectionUsageThresholdSupported()) + VMMemoryPoolMXBeanImpl.setCollectionUsageThreshold(name, threshold); + else + throw new UnsupportedOperationException("A collection usage "+ + "threshold is not supported."); + } + + public void setUsageThreshold(long threshold) + { + checkControlPermissions(); + if (threshold < 0) + throw new IllegalArgumentException("Threshold of " + threshold + + "is less than zero."); + if (isUsageThresholdSupported()) + VMMemoryPoolMXBeanImpl.setUsageThreshold(name, threshold); + else + throw new UnsupportedOperationException("A usage threshold " + + "is not supported."); + } + +} diff --git a/libjava/classpath/gnu/java/lang/management/OperatingSystemMXBeanImpl.java b/libjava/classpath/gnu/java/lang/management/OperatingSystemMXBeanImpl.java new file mode 100644 index 000000000..7f5a9586c --- /dev/null +++ b/libjava/classpath/gnu/java/lang/management/OperatingSystemMXBeanImpl.java @@ -0,0 +1,95 @@ +/* OperatingSystemMXBeanImpl.java - Implementation of an operating system bean + Copyright (C) 2006 Free Software Foundation + +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.lang.management; + +import java.lang.management.OperatingSystemMXBean; + +import javax.management.NotCompliantMBeanException; + +/** + * Provides access to information about the underlying operating + * system. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public final class OperatingSystemMXBeanImpl + extends BeanImpl + implements OperatingSystemMXBean +{ + + /** + * Constructs a new OperatingSystemMXBeanImpl. + * + * @throws NotCompliantMBeanException if this class doesn't implement + * the interface or a method appears + * in the interface that doesn't comply + * with the naming conventions. + */ + public OperatingSystemMXBeanImpl() + throws NotCompliantMBeanException + { + super(OperatingSystemMXBean.class); + } + + public String getArch() + { + return System.getProperty("os.arch"); + } + + public int getAvailableProcessors() + { + return Runtime.getRuntime().availableProcessors(); + } + + public String getName() + { + return System.getProperty("os.name"); + } + + public double getSystemLoadAverage() + { + return VMOperatingSystemMXBeanImpl.getSystemLoadAverage(); + } + + public String getVersion() + { + return System.getProperty("os.version"); + } + +} diff --git a/libjava/classpath/gnu/java/lang/management/RuntimeMXBeanImpl.java b/libjava/classpath/gnu/java/lang/management/RuntimeMXBeanImpl.java new file mode 100644 index 000000000..8db943bb6 --- /dev/null +++ b/libjava/classpath/gnu/java/lang/management/RuntimeMXBeanImpl.java @@ -0,0 +1,197 @@ +/* RuntimeMXBeanImpl.java - Implementation of an runtime bean + Copyright (C) 2006 Free Software Foundation + +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.lang.management; + +import gnu.classpath.SystemProperties; + +import java.lang.management.RuntimeMXBean; + +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import javax.management.NotCompliantMBeanException; + +/** + * Provides access to information about the virtual machine. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public final class RuntimeMXBeanImpl + extends BeanImpl + implements RuntimeMXBean +{ + + private static final String SUN_BOOT_CLASS_PATH = "sun.boot.class.path"; + private static final String JAVA_BOOT_CLASS_PATH = "java.boot.class.path"; + + private long startTime = -1; + + private String bootClassPath = null; + + private boolean bootClassPathSupported = true; + + /** + * Constructs a new RuntimeMXBeanImpl. + * + * @throws NotCompliantMBeanException if this class doesn't implement + * the interface or a method appears + * in the interface that doesn't comply + * with the naming conventions. + */ + public RuntimeMXBeanImpl() + throws NotCompliantMBeanException + { + super(RuntimeMXBean.class); + } + + public String getBootClassPath() + { + checkMonitorPermissions(); + if (isBootClassPathSupported()) + return bootClassPath; + else + throw + new UnsupportedOperationException("Retrieving the boot " + + "classpath is not supported."); + } + + public String getClassPath() + { + return System.getProperty("java.class.path"); + } + + public List getInputArguments() + { + checkMonitorPermissions(); + return Arrays.asList(VMRuntimeMXBeanImpl.getInputArguments()); + } + + public String getLibraryPath() + { + return System.getProperty("java.library.path"); + } + + public String getManagementSpecVersion() + { + return "1.0"; + } + + public String getName() + { + return VMRuntimeMXBeanImpl.getName(); + } + + public String getSpecName() + { + return System.getProperty("java.vm.specification.name"); + } + + public String getSpecVendor() + { + return System.getProperty("java.vm.specification.vendor"); + } + + public String getSpecVersion() + { + return System.getProperty("java.vm.specification.version"); + } + + public long getStartTime() + { + if (startTime == -1) + startTime = VMRuntimeMXBeanImpl.getStartTime(); + return startTime; + } + + public Map getSystemProperties() + { + Map map = new HashMap(); + Properties props = System.getProperties(); + Iterator entries = props.entrySet().iterator(); + while (entries.hasNext()) + { + Map.Entry next = (Map.Entry) entries.next(); + Object key = next.getKey(); + Object value = next.getValue(); + if (key instanceof String && + value instanceof String) + map.put(key, value); + } + return map; + } + + public long getUptime() + { + return new Date().getTime() - getStartTime(); + } + + public String getVmName() + { + return System.getProperty("java.vm.name"); + } + + public String getVmVendor() + { + return System.getProperty("java.vm.vendor"); + } + + public String getVmVersion() + { + return System.getProperty("java.vm.version"); + } + + public boolean isBootClassPathSupported() + { + if (bootClassPath == null) + { + bootClassPath = SystemProperties.getProperty(JAVA_BOOT_CLASS_PATH); + if (bootClassPath == null) + bootClassPath = SystemProperties.getProperty(SUN_BOOT_CLASS_PATH); + if (bootClassPath == null) + bootClassPathSupported = false; + } + return bootClassPathSupported; + } + +} diff --git a/libjava/classpath/gnu/java/lang/management/ThreadMXBeanImpl.java b/libjava/classpath/gnu/java/lang/management/ThreadMXBeanImpl.java new file mode 100644 index 000000000..97040997b --- /dev/null +++ b/libjava/classpath/gnu/java/lang/management/ThreadMXBeanImpl.java @@ -0,0 +1,350 @@ +/* ThreadMXBeanImpl.java - Implementation of a thread bean + Copyright (C) 2006 Free Software Foundation + +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.lang.management; + +import gnu.classpath.SystemProperties; + +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; + +import javax.management.NotCompliantMBeanException; + +/** + * Provides access to information about the threads + * of the virtual machine. An instance of this bean is + * obtained by calling + * {@link ManagementFactory#getThreadMXBean()}. + * See {@link java.lang.management.ThreadMXBean} for + * full documentation. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public final class ThreadMXBeanImpl + extends BeanImpl + implements ThreadMXBean +{ + + /** + * Constant for current thread time support. + */ + private static final String CURRENT_THREAD_TIME_SUPPORT = + "gnu.java.lang.management.CurrentThreadTimeSupport"; + + /** + * Constant for thread time support. + */ + private static final String THREAD_TIME_SUPPORT = + "gnu.java.lang.management.ThreadTimeSupport"; + + /** + * Constant for thread contention support. + */ + private static final String CONTENTION_SUPPORT = + "gnu.java.lang.management.ThreadContentionSupport"; + + /** + * Constant for initial value of thread time support. + */ + private static final String TIME_ENABLED = + "gnu.java.lang.management.ThreadTimeInitallyEnabled"; + + /** + * Constant for monitor usage monitoring support. + */ + private static final String MONITOR_SUPPORT = + "gnu.java.lang.management.MonitorUsageMonitoringSupport"; + + /** + * Constant for ownable synchronizer usage monitoring support. + */ + private static final String SYNCHRONIZER_SUPPORT = + "gnu.java.lang.management.OwnableSynchronizerUsageMonitoringSupport"; + + /** + * Flag to indicate whether time monitoring is enabled or not. + */ + private boolean timeEnabled; + + /** + * Flag to indicate whether contention monitoring is enabled or not. + */ + private boolean contentionEnabled; + + /** + * Default constructor to set up flag states. The + * VM has to specify whether time monitoring is initially + * enabled or not. + * + * @throws NotCompliantMBeanException if this class doesn't implement + * the interface or a method appears + * in the interface that doesn't comply + * with the naming conventions. + */ + public ThreadMXBeanImpl() + throws NotCompliantMBeanException + { + super(ThreadMXBean.class); + timeEnabled = Boolean.parseBoolean(SystemProperties.getProperty(TIME_ENABLED)); + contentionEnabled = false; + } + + public ThreadInfo[] dumpAllThreads(boolean lockedMonitors, + boolean lockedSynchronizers) + { + return getThreadInfo(getAllThreadIds(), lockedMonitors, + lockedSynchronizers); + } + + public long[] findDeadlockedThreads() + { + checkMonitorPermissions(); + if (!isSynchronizerUsageSupported()) + throw new UnsupportedOperationException("Ownable synchronizer usage " + + "monitoring is not provided " + + "by this VM."); + return VMThreadMXBeanImpl.findDeadlockedThreads(); + } + + public long[] findMonitorDeadlockedThreads() + { + checkMonitorPermissions(); + return VMThreadMXBeanImpl.findMonitorDeadlockedThreads(); + } + + public long[] getAllThreadIds() + { + checkMonitorPermissions(); + return VMThreadMXBeanImpl.getAllThreadIds(); + } + + public long getCurrentThreadCpuTime() + { + if (!isCurrentThreadCpuTimeSupported()) + throw new UnsupportedOperationException("Current thread CPU " + + "time not supported."); + if (!timeEnabled) + return -1; + return VMThreadMXBeanImpl.getCurrentThreadCpuTime(); + } + + public long getCurrentThreadUserTime() + { + if (!isCurrentThreadCpuTimeSupported()) + throw new UnsupportedOperationException("Current thread user " + + "time not supported."); + if (!timeEnabled) + return -1; + return VMThreadMXBeanImpl.getCurrentThreadUserTime(); + } + + public int getDaemonThreadCount() + { + return VMThreadMXBeanImpl.getDaemonThreadCount(); + } + + public int getPeakThreadCount() + { + return VMThreadMXBeanImpl.getPeakThreadCount(); + } + + public int getThreadCount() + { + return VMThreadMXBeanImpl.getThreadCount(); + } + + public long getThreadCpuTime(long id) + { + if (!isThreadCpuTimeSupported()) + throw new UnsupportedOperationException("Thread CPU time not " + + "supported."); + if (id <= 0) + throw new IllegalArgumentException("Invalid thread id: " + id); + if (!timeEnabled) + return -1; + return VMThreadMXBeanImpl.getThreadCpuTime(id); + } + + public ThreadInfo getThreadInfo(long id) + { + return getThreadInfo(id, 0); + } + + public ThreadInfo[] getThreadInfo(long[] ids) + { + return getThreadInfo(ids, 0); + } + + public ThreadInfo getThreadInfo(long id, int maxDepth) + { + checkMonitorPermissions(); + if (id <= 0) + throw new IllegalArgumentException("Invalid thread id: " + id); + if (maxDepth < 0) + throw new IllegalArgumentException("Invalid depth: " + maxDepth); + return VMThreadMXBeanImpl.getThreadInfoForId(id, maxDepth); + } + + public ThreadInfo[] getThreadInfo(long[] ids, int maxDepth) + { + checkMonitorPermissions(); + if (maxDepth < 0) + throw new IllegalArgumentException("Invalid depth: " + maxDepth); + ThreadInfo[] infos = new ThreadInfo[ids.length]; + for (int a = 0; a < ids.length; ++a) + { + if (ids[a] <= 0) + throw new IllegalArgumentException("Invalid thread id " + a + + ": " + ids[a]); + infos[a] = VMThreadMXBeanImpl.getThreadInfoForId(ids[a], maxDepth); + } + return infos; + } + + public ThreadInfo[] getThreadInfo(long[] ids, boolean lockedMonitors, + boolean lockedSynchronizers) + { + checkMonitorPermissions(); + if (lockedMonitors && !isObjectMonitorUsageSupported()) + throw new UnsupportedOperationException("Monitor usage monitoring is " + + "not provided by this VM."); + if (lockedSynchronizers && !isSynchronizerUsageSupported()) + throw new UnsupportedOperationException("Ownable synchronizer usage " + + "monitoring is not provided " + + "by this VM."); + ThreadInfo[] infos = getThreadInfo(ids, Integer.MAX_VALUE); + if (lockedMonitors) + for (ThreadInfo info : infos) + VMThreadMXBeanImpl.getMonitorInfo(info); + if (lockedSynchronizers) + for (ThreadInfo info : infos) + VMThreadMXBeanImpl.getLockInfo(info); + return infos; + } + + public long getThreadUserTime(long id) + { + if (!isThreadCpuTimeSupported()) + throw new UnsupportedOperationException("Thread user time not " + + "supported."); + if (id <= 0) + throw new IllegalArgumentException("Invalid thread id: " + id); + if (!timeEnabled) + return -1; + return VMThreadMXBeanImpl.getThreadUserTime(id); + } + + public long getTotalStartedThreadCount() + { + return VMThreadMXBeanImpl.getTotalStartedThreadCount(); + } + + public boolean isCurrentThreadCpuTimeSupported() + { + if (isThreadCpuTimeSupported()) + return true; + return SystemProperties.getProperty(CURRENT_THREAD_TIME_SUPPORT) != null; + } + + public boolean isObjectMonitorUsageSupported() + { + return SystemProperties.getProperty(MONITOR_SUPPORT) != null; + } + + public boolean isSynchronizerUsageSupported() + { + return SystemProperties.getProperty(SYNCHRONIZER_SUPPORT) != null; + } + + public boolean isThreadContentionMonitoringEnabled() + { + if (isThreadContentionMonitoringSupported()) + return contentionEnabled; + else + throw new UnsupportedOperationException("Contention monitoring " + + "not supported."); + } + + public boolean isThreadContentionMonitoringSupported() + { + return SystemProperties.getProperty(CONTENTION_SUPPORT) != null; + } + + public boolean isThreadCpuTimeEnabled() + { + if (isThreadCpuTimeSupported() || + isCurrentThreadCpuTimeSupported()) + return timeEnabled; + else + throw new UnsupportedOperationException("Thread time not " + + "supported."); + } + + public boolean isThreadCpuTimeSupported() + { + return SystemProperties.getProperty(THREAD_TIME_SUPPORT) != null; + } + + public void resetPeakThreadCount() + { + checkControlPermissions(); + VMThreadMXBeanImpl.resetPeakThreadCount(); + } + + public void setThreadContentionMonitoringEnabled(boolean enable) + { + checkControlPermissions(); + if (isThreadContentionMonitoringSupported()) + contentionEnabled = enable; + else + throw new UnsupportedOperationException("Contention monitoring " + + "not supported."); + } + + public void setThreadCpuTimeEnabled(boolean enable) + { + checkControlPermissions(); + if (isThreadCpuTimeSupported() || + isCurrentThreadCpuTimeSupported()) + timeEnabled = enable; + else + throw new UnsupportedOperationException("Thread time not " + + "supported."); + } + +} diff --git a/libjava/classpath/gnu/java/lang/management/package.html b/libjava/classpath/gnu/java/lang/management/package.html new file mode 100644 index 000000000..fc1bafc0c --- /dev/null +++ b/libjava/classpath/gnu/java/lang/management/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.lang.management + + +

GNU implementations of the Java system management beans.

+ + + diff --git a/libjava/classpath/gnu/java/lang/package.html b/libjava/classpath/gnu/java/lang/package.html new file mode 100644 index 000000000..1f16776b6 --- /dev/null +++ b/libjava/classpath/gnu/java/lang/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.lang + + +

+ + + diff --git a/libjava/classpath/gnu/java/lang/reflect/ClassSignatureParser.java b/libjava/classpath/gnu/java/lang/reflect/ClassSignatureParser.java new file mode 100644 index 000000000..31f28385f --- /dev/null +++ b/libjava/classpath/gnu/java/lang/reflect/ClassSignatureParser.java @@ -0,0 +1,92 @@ +/* ClassSignatureParser.java + Copyright (C) 2005 + Free Software Foundation + +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.lang.reflect; + +import java.lang.reflect.*; +import java.util.ArrayList; + +public class ClassSignatureParser extends GenericSignatureParser +{ + private TypeVariable[] typeParameters; + private Type superclassType; + private Type[] interfaceTypes; + + public ClassSignatureParser(Class c, String signature) + { + super(c, c.getClassLoader(), signature); + + if (peekChar() == '<') + { + typeParameters = readFormalTypeParameters(); + } + else + { + typeParameters = new TypeVariable[0]; + } + // SuperclassSignature + superclassType = readClassTypeSignature(); + ArrayList interfaces = new ArrayList(); + while (peekChar() == 'L') + { + // SuperinterfaceSignature + interfaces.add(readClassTypeSignature()); + } + interfaceTypes = new Type[interfaces.size()]; + interfaces.toArray(interfaceTypes); + end(); + } + + public TypeVariable[] getTypeParameters() + { + TypeImpl.resolve(typeParameters); + return typeParameters; + } + + public Type getSuperclassType() + { + superclassType = TypeImpl.resolve(superclassType); + return superclassType; + } + + public Type[] getInterfaceTypes() + { + TypeImpl.resolve(interfaceTypes); + return interfaceTypes; + } +} diff --git a/libjava/classpath/gnu/java/lang/reflect/FieldSignatureParser.java b/libjava/classpath/gnu/java/lang/reflect/FieldSignatureParser.java new file mode 100644 index 000000000..16622d33f --- /dev/null +++ b/libjava/classpath/gnu/java/lang/reflect/FieldSignatureParser.java @@ -0,0 +1,103 @@ +/* FieldSignatureParser.java + Copyright (C) 2005 + Free Software Foundation + +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.lang.reflect; + +import java.lang.reflect.GenericSignatureFormatError; +import java.lang.reflect.Type; + +public final class FieldSignatureParser extends GenericSignatureParser +{ + private Type type; + + public FieldSignatureParser(Class container, String signature) + { + super(container, container.getClassLoader(), signature); + + switch (peekChar()) + { + case 'L': + case '[': + case 'T': + type = readFieldTypeSignature(); + break; + case 'Z': + consume('Z'); + type = boolean.class; + break; + case 'B': + consume('B'); + type = byte.class; + break; + case 'S': + consume('S'); + type = short.class; + break; + case 'C': + consume('C'); + type = char.class; + break; + case 'I': + consume('I'); + type = int.class; + break; + case 'F': + consume('F'); + type = float.class; + break; + case 'J': + consume('J'); + type = long.class; + break; + case 'D': + consume('D'); + type = double.class; + break; + default: + throw new GenericSignatureFormatError(); + } + + end(); + } + + public Type getFieldType() + { + type = TypeImpl.resolve(type); + return type; + } +} diff --git a/libjava/classpath/gnu/java/lang/reflect/GenericSignatureParser.java b/libjava/classpath/gnu/java/lang/reflect/GenericSignatureParser.java new file mode 100644 index 000000000..e413c76c7 --- /dev/null +++ b/libjava/classpath/gnu/java/lang/reflect/GenericSignatureParser.java @@ -0,0 +1,631 @@ +/* GenericSignatureParser.java + Copyright (C) 2005 + Free Software Foundation + +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.lang.reflect; + +import gnu.java.lang.CPStringBuilder; + +import java.lang.reflect.Constructor; +import java.lang.reflect.GenericArrayType; +import java.lang.reflect.GenericDeclaration; +import java.lang.reflect.GenericSignatureFormatError; +import java.lang.reflect.MalformedParameterizedTypeException; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.lang.reflect.WildcardType; + +import java.util.ArrayList; +import java.util.Arrays; + +final class TypeVariableImpl extends TypeImpl implements TypeVariable +{ + private GenericDeclaration decl; + private Type[] bounds; + private String name; + + TypeVariableImpl(GenericDeclaration decl, Type[] bounds, String name) + { + this.decl = decl; + this.bounds = bounds; + this.name = name; + } + + Type resolve() + { + return this; + } + + public Type[] getBounds() + { + resolve(bounds); + return (Type[]) bounds.clone(); + } + + public GenericDeclaration getGenericDeclaration() + { + return decl; + } + + public String getName() + { + return name; + } + + public boolean equals(Object obj) + { + if (obj instanceof TypeVariableImpl) + { + TypeVariableImpl other = (TypeVariableImpl)obj; + return decl.equals(other.decl) && name.equals(other.name); + } + return false; + } + + public int hashCode() + { + return 0x5f4d5156 ^ decl.hashCode() ^ name.hashCode(); + } + + public String toString() + { + return name; + } +} + +final class ParameterizedTypeImpl extends TypeImpl implements ParameterizedType +{ + private String rawTypeName; + private ClassLoader loader; + private Class rawType; + private Type owner; + private Type[] typeArgs; + + ParameterizedTypeImpl(String rawTypeName, ClassLoader loader, Type owner, + Type[] typeArgs) + { + this.rawTypeName = rawTypeName; + this.loader = loader; + this.owner = owner; + this.typeArgs = typeArgs; + } + + Type resolve() + { + if (rawType == null) + { + try + { + rawType = Class.forName(rawTypeName, false, loader); + } + catch (ClassNotFoundException x) + { + throw new TypeNotPresentException(rawTypeName, x); + } + } + if (typeArgs == null) + { + if (owner == null) + { + return rawType; + } + typeArgs = new Type[0]; + } + resolve(typeArgs); + owner = resolve(owner); + return this; + } + + public Type[] getActualTypeArguments() + { + return (Type[]) typeArgs.clone(); + } + + public Type getRawType() + { + return rawType; + } + + public Type getOwnerType() + { + return owner; + } + + public boolean equals(Object obj) + { + if (obj instanceof ParameterizedTypeImpl) + { + ParameterizedTypeImpl other = (ParameterizedTypeImpl)obj; + return rawType.equals(other.rawType) + && ((owner == null && other.owner == null) + || owner.equals(other.owner)) + && Arrays.deepEquals(typeArgs, other.typeArgs); + } + return false; + } + + public int hashCode() + { + int h = 0x58158970 ^ rawType.hashCode(); + if (owner != null) + { + h ^= Integer.reverse(owner.hashCode()); + } + for (int i = 0; i < typeArgs.length; i++) + { + h ^= Integer.rotateLeft(typeArgs[i].hashCode(), i); + } + return h; + } + + public String toString() + { + CPStringBuilder sb = new CPStringBuilder(); + if (owner != null) + { + sb.append(owner); + sb.append('.'); + sb.append(rawType.getSimpleName()); + } + else + { + sb.append(rawTypeName); + } + if (typeArgs.length > 0) + { + sb.append('<'); + for (int i = 0; i < typeArgs.length; i++) + { + if (i > 0) + sb.append(", "); + if (typeArgs[i] instanceof Class) + { + sb.append(((Class)typeArgs[i]).getName()); + } + else + { + sb.append(typeArgs[i]); + } + } + sb.append('>'); + } + return sb.toString(); + } +} + +final class GenericArrayTypeImpl extends TypeImpl implements GenericArrayType +{ + private Type componentType; + + GenericArrayTypeImpl(Type componentType) + { + this.componentType = componentType; + } + + Type resolve() + { + componentType = resolve(componentType); + return this; + } + + public Type getGenericComponentType() + { + return componentType; + } + + public boolean equals(Object obj) + { + if (obj instanceof GenericArrayTypeImpl) + { + GenericArrayTypeImpl other = (GenericArrayTypeImpl)obj; + return componentType.equals(other.componentType); + } + return false; + } + + public int hashCode() + { + return 0x4be37a7f ^ componentType.hashCode(); + } + + public String toString() + { + return componentType + "[]"; + } +} + +final class UnresolvedTypeVariable extends TypeImpl implements Type +{ + private GenericDeclaration decl; + private String name; + + UnresolvedTypeVariable(GenericDeclaration decl, String name) + { + this.decl = decl; + this.name = name; + } + + Type resolve() + { + GenericDeclaration d = decl; + while (d != null) + { + for (TypeVariable t : d.getTypeParameters()) + { + if (t.getName().equals(name)) + { + return t; + } + } + d = getParent(d); + } + throw new MalformedParameterizedTypeException(); + } + + private static GenericDeclaration getParent(GenericDeclaration d) + { + if (d instanceof Class) + { + Method m = ((Class)d).getEnclosingMethod(); + if (m != null) + { + return m; + } + Constructor c = ((Class)d).getEnclosingConstructor(); + if (c != null) + { + return c; + } + return ((Class)d).getEnclosingClass(); + } + else if (d instanceof Method) + { + return ((Method)d).getDeclaringClass(); + } + else if (d instanceof Constructor) + { + return ((Constructor)d).getDeclaringClass(); + } + else + { + // TODO figure out what this represents + throw new Error(); + } + } +} + +final class WildcardTypeImpl extends TypeImpl implements WildcardType +{ + private Type lower; + private Type upper; + + WildcardTypeImpl(Type lower, Type upper) + { + this.lower = lower; + this.upper = upper; + } + + Type resolve() + { + upper = resolve(upper); + lower = resolve(lower); + return this; + } + + public Type[] getUpperBounds() + { + if (upper == null) + { + return new Type[0]; + } + return new Type[] { upper }; + } + + public Type[] getLowerBounds() + { + if (lower == null) + { + return new Type[0]; + } + return new Type[] { lower }; + } + + public boolean equals(Object obj) + { + if (obj instanceof WildcardTypeImpl) + { + WildcardTypeImpl other = (WildcardTypeImpl)obj; + return Arrays.deepEquals(getUpperBounds(), other.getUpperBounds()) + && Arrays.deepEquals(getLowerBounds(), other.getLowerBounds()); + } + return false; + } + + public int hashCode() + { + int h = 0x75d074fd; + if (upper != null) + { + h ^= upper.hashCode(); + } + if (lower != null) + { + h ^= lower.hashCode(); + } + return h; + } + + public String toString() + { + if (lower != null) + { + return "? super " + lower; + } + if (upper == java.lang.Object.class) + { + return "?"; + } + return "? extends " + upper; + } +} + +class GenericSignatureParser +{ + private ClassLoader loader; + private GenericDeclaration container; + private String signature; + private int pos; + + GenericSignatureParser(GenericDeclaration container, ClassLoader loader, + String signature) + { + this.container = container; + this.loader = loader; + this.signature = signature; + } + + TypeVariable[] readFormalTypeParameters() + { + consume('<'); + ArrayList params = new ArrayList(); + do + { + // TODO should we handle name clashes? + params.add(readFormalTypeParameter()); + } while (peekChar() != '>'); + consume('>'); + TypeVariable[] list = new TypeVariable[params.size()]; + params.toArray(list); + return list; + } + + private TypeVariable readFormalTypeParameter() + { + String identifier = readIdentifier(); + consume(':'); + ArrayList bounds = new ArrayList(); + if (peekChar() != ':') + { + bounds.add(readFieldTypeSignature()); + } + while (peekChar() == ':') + { + consume(':'); + bounds.add(readFieldTypeSignature()); + } + Type[] b = new Type[bounds.size()]; + bounds.toArray(b); + return new TypeVariableImpl(container, b, identifier); + } + + Type readFieldTypeSignature() + { + switch (peekChar()) + { + case 'L': + return readClassTypeSignature(); + case '[': + return readArrayTypeSignature(); + case 'T': + return readTypeVariableSignature(); + default: + throw new GenericSignatureFormatError(); + } + } + + Type readClassTypeSignature() + { + consume('L'); + String className = ""; + for (;;) + { + String part = readIdentifier(); + if (peekChar() != '/') + { + className += part; + break; + } + consume('/'); + className += part + "."; + } + Type[] typeArguments = null; + if (peekChar() == '<') + { + typeArguments = readTypeArguments(); + } + Type type = new ParameterizedTypeImpl(className, loader, null, + typeArguments); + while (peekChar() == '.') + { + consume('.'); + className += "$" + readIdentifier(); + typeArguments = null; + if (peekChar() == '<') + { + typeArguments = readTypeArguments(); + } + type = new ParameterizedTypeImpl(className, loader, type, + typeArguments); + } + consume(';'); + return type; + } + + private Type[] readTypeArguments() + { + consume('<'); + ArrayList list = new ArrayList(); + do + { + list.add(readTypeArgument()); + } while ((peekChar() != '>')); + consume('>'); + Type[] arr = new Type[list.size()]; + list.toArray(arr); + return arr; + } + + private Type readTypeArgument() + { + char c = peekChar(); + if (c == '+') + { + consume('+'); + return new WildcardTypeImpl(null, readFieldTypeSignature()); + } + else if (c == '-') + { + consume('-'); + return new WildcardTypeImpl(readFieldTypeSignature(), + java.lang.Object.class); + } + else if (c == '*') + { + consume('*'); + return new WildcardTypeImpl(null, java.lang.Object.class); + } + else + { + return readFieldTypeSignature(); + } + } + + Type readArrayTypeSignature() + { + consume('['); + switch (peekChar()) + { + case 'L': + case '[': + case 'T': + return new GenericArrayTypeImpl(readFieldTypeSignature()); + case 'Z': + consume('Z'); + return boolean[].class; + case 'B': + consume('B'); + return byte[].class; + case 'S': + consume('S'); + return short[].class; + case 'C': + consume('C'); + return char[].class; + case 'I': + consume('I'); + return int[].class; + case 'F': + consume('F'); + return float[].class; + case 'J': + consume('J'); + return long[].class; + case 'D': + consume('D'); + return double[].class; + default: + throw new GenericSignatureFormatError(); + } + } + + Type readTypeVariableSignature() + { + consume('T'); + String identifier = readIdentifier(); + consume(';'); + return new UnresolvedTypeVariable(container, identifier); + } + + private String readIdentifier() + { + int start = pos; + char c; + do + { + readChar(); + c = peekChar(); + } while (";:./<>-+*".indexOf(c) == -1); + return signature.substring(start, pos); + } + + final char peekChar() + { + if (pos == signature.length()) + return '\u0000'; + else + return signature.charAt(pos); + } + + final char readChar() + { + return signature.charAt(pos++); + } + + final void consume(char c) + { + if (readChar() != c) + throw new GenericSignatureFormatError(); + } + + final void end() + { + if (pos != signature.length()) + throw new GenericSignatureFormatError(); + } +} diff --git a/libjava/classpath/gnu/java/lang/reflect/MethodSignatureParser.java b/libjava/classpath/gnu/java/lang/reflect/MethodSignatureParser.java new file mode 100644 index 000000000..50f98e299 --- /dev/null +++ b/libjava/classpath/gnu/java/lang/reflect/MethodSignatureParser.java @@ -0,0 +1,167 @@ +/* MethodSignatureParser.java + Copyright (C) 2005 + Free Software Foundation + +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.lang.reflect; + +import java.lang.reflect.*; +import java.util.ArrayList; + +public class MethodSignatureParser extends GenericSignatureParser +{ + private TypeVariable[] typeParameters; + private Type[] argTypes; + private Type retType; + private Type[] throwsSigs; + + public MethodSignatureParser(Method method, String signature) + { + this(method, method.getDeclaringClass().getClassLoader(), signature); + } + + public MethodSignatureParser(Constructor method, String signature) + { + this(method, method.getDeclaringClass().getClassLoader(), signature); + } + + private MethodSignatureParser(GenericDeclaration wrapper, + ClassLoader loader, String signature) + { + super(wrapper, loader, signature); + + if (peekChar() == '<') + { + typeParameters = readFormalTypeParameters(); + } + else + { + typeParameters = new TypeVariable[0]; + } + consume('('); + ArrayList args = new ArrayList(); + while (peekChar() != ')') + { + args.add(readTypeSignature()); + } + argTypes = new Type[args.size()]; + args.toArray(argTypes); + consume(')'); + retType = readTypeSignature(); + ArrayList throwsSigs = new ArrayList(); + while (peekChar() == '^') + { + consume('^'); + if(peekChar() == 'T') + { + throwsSigs.add(readTypeVariableSignature()); + } + else + { + throwsSigs.add(readClassTypeSignature()); + } + } + this.throwsSigs = new Type[throwsSigs.size()]; + throwsSigs.toArray(this.throwsSigs); + end(); + } + + public TypeVariable[] getTypeParameters() + { + TypeImpl.resolve(typeParameters); + return typeParameters; + } + + public Type[] getGenericParameterTypes() + { + TypeImpl.resolve(argTypes); + return argTypes; + } + + public Type getGenericReturnType() + { + retType = TypeImpl.resolve(retType); + return retType; + } + + public Type[] getGenericExceptionTypes() + { + TypeImpl.resolve(throwsSigs); + return throwsSigs; + } + + private Type readTypeSignature() + { + switch (peekChar()) + { + case 'T': + return readTypeVariableSignature(); + case 'L': + return readClassTypeSignature(); + case '[': + return readArrayTypeSignature(); + case 'Z': + consume('Z'); + return boolean.class; + case 'B': + consume('B'); + return byte.class; + case 'S': + consume('S'); + return short.class; + case 'C': + consume('C'); + return char.class; + case 'I': + consume('I'); + return int.class; + case 'F': + consume('F'); + return float.class; + case 'J': + consume('J'); + return long.class; + case 'D': + consume('D'); + return double.class; + case 'V': + consume('V'); + return void.class; + default: + throw new GenericSignatureFormatError(); + } + } +} diff --git a/libjava/classpath/gnu/java/lang/reflect/TypeImpl.java b/libjava/classpath/gnu/java/lang/reflect/TypeImpl.java new file mode 100644 index 000000000..30906f629 --- /dev/null +++ b/libjava/classpath/gnu/java/lang/reflect/TypeImpl.java @@ -0,0 +1,63 @@ +/* TypeImpl.java + Copyright (C) 2005 + Free Software Foundation + +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.lang.reflect; + +import java.lang.reflect.Type; + +abstract class TypeImpl implements Type +{ + abstract Type resolve(); + + static void resolve(Type[] types) + { + for (int i = 0; i < types.length; i++) + { + types[i] = resolve(types[i]); + } + } + + static Type resolve(Type type) + { + if (type instanceof TypeImpl) + { + type = ((TypeImpl) type).resolve(); + } + return type; + } +} diff --git a/libjava/classpath/gnu/java/lang/reflect/TypeSignature.java b/libjava/classpath/gnu/java/lang/reflect/TypeSignature.java new file mode 100644 index 000000000..c0a3ab0a5 --- /dev/null +++ b/libjava/classpath/gnu/java/lang/reflect/TypeSignature.java @@ -0,0 +1,290 @@ +/* TypeSignature.java -- Class used to compute type signatures + Copyright (C) 1998, 2000, 2002 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.lang.reflect; + +import gnu.java.lang.CPStringBuilder; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.lang.reflect.Method; + +/** + * This class provides static methods that can be used to compute + * type-signatures of Classs or Members. + * More specific methods are also provided for computing the + * type-signature of Constructors and + * Methods. Methods are also provided to go in the + * reverse direction. + * + * @author Eric Blake (ebb9@email.byu.edu) + */ +public class TypeSignature +{ + /** + * Returns a String representing the type-encoding of a class. + * The .class file format has different encodings for classes, depending + * on whether it must be disambiguated from primitive types or not; hence + * the descriptor parameter to choose between them. If you are planning + * on decoding primitive types along with classes, then descriptor should + * be true for correct results. Type-encodings are computed as follows: + * + *
+   * boolean -> "Z"
+   * byte    -> "B"
+   * char    -> "C"
+   * double  -> "D"
+   * float   -> "F"
+   * int     -> "I"
+   * long    -> "J"
+   * short   -> "S"
+   * void    -> "V"
+   * arrays  -> "[" + descriptor format of component type
+   * object  -> class format: fully qualified name with '.' replaced by '/'
+   *            descriptor format: "L" + class format + ";"
+   * 
+ * + * @param type the class name to encode + * @param descriptor true to return objects in descriptor format + * @return the class name, as it appears in bytecode constant pools + * @see #getClassForEncoding(String) + */ + public static String getEncodingOfClass(String type, boolean descriptor) + { + if (! descriptor || type.charAt(0) == '[') + return type.replace('.', '/'); + if (type.equals("boolean")) + return "Z"; + if (type.equals("byte")) + return "B"; + if (type.equals("short")) + return "S"; + if (type.equals("char")) + return "C"; + if (type.equals("int")) + return "I"; + if (type.equals("long")) + return "J"; + if (type.equals("float")) + return "F"; + if (type.equals("double")) + return "D"; + if (type.equals("void")) + return "V"; + return 'L' + type.replace('.', '/') + ';'; + } + + /** + * Gets the descriptor encoding for a class. + * + * @param clazz the class to encode + * @param descriptor true to return objects in descriptor format + * @return the class name, as it appears in bytecode constant pools + * @see #getEncodingOfClass(String, boolean) + */ + public static String getEncodingOfClass(Class clazz, boolean descriptor) + { + return getEncodingOfClass(clazz.getName(), descriptor); + } + + /** + * Gets the descriptor encoding for a class. + * + * @param clazz the class to encode + * @return the class name, as it appears in bytecode constant pools + * @see #getEncodingOfClass(String, boolean) + */ + public static String getEncodingOfClass(Class clazz) + { + return getEncodingOfClass(clazz.getName(), true); + } + + + /** + * This function is the inverse of getEncodingOfClass. This + * accepts both object and descriptor formats, but must know which style + * of string is being passed in (usually, descriptor should be true). In + * descriptor format, "I" is treated as int.class, in object format, it + * is treated as a class named I in the unnamed package. This method is + * strictly equivalent to {@link #getClassForEncoding(java.lang.String, boolean, java.lang.ClassLoader)} + * with a class loader equal to null. In that case, it + * uses the default class loader on the calling stack. + * + * @param type_code the class name to decode + * @param descriptor if the string is in descriptor format + * @return the corresponding Class object + * @throws ClassNotFoundException if the class cannot be located + * @see #getEncodingOfClass(Class, boolean) + */ + public static Class getClassForEncoding(String type_code, boolean descriptor) + throws ClassNotFoundException + { + return getClassForEncoding(type_code, descriptor, null); + } + + /** + * This function is the inverse of getEncodingOfClass. This + * accepts both object and descriptor formats, but must know which style + * of string is being passed in (usually, descriptor should be true). In + * descriptor format, "I" is treated as int.class, in object format, it + * is treated as a class named I in the unnamed package. + * + * @param type_code The class name to decode. + * @param descriptor If the string is in descriptor format. + * @param loader The class loader when resolving generic object name. If + * loader is null then it uses the default class loader on the + * calling stack. + * @return the corresponding Class object. + * @throws ClassNotFoundException if the class cannot be located. + * @see #getEncodingOfClass(Class, boolean) + * @see #getClassForEncoding(String, boolean) + */ + public static Class getClassForEncoding(String type_code, boolean descriptor, + ClassLoader loader) + throws ClassNotFoundException + { + if (descriptor) + { + switch (type_code.charAt(0)) + { + case 'B': + return byte.class; + case 'C': + return char.class; + case 'D': + return double.class; + case 'F': + return float.class; + case 'I': + return int.class; + case 'J': + return long.class; + case 'S': + return short.class; + case 'V': + return void.class; + case 'Z': + return boolean.class; + default: + throw new ClassNotFoundException("Invalid class name: " + + type_code); + case 'L': + type_code = type_code.substring(1, type_code.length() - 1); + // Fallthrough. + case '[': + } + } + return Class.forName(type_code.replace('/', '.'), true, loader); + } + + /** + * Gets the Class object for a type name. + * + * @param type_code the class name to decode + * @return the corresponding Class object + * @throws ClassNotFoundException if the class cannot be located + * @see #getClassForEncoding(String, boolean) + */ + public static Class getClassForEncoding(String type_code) + throws ClassNotFoundException + { + return getClassForEncoding(type_code, true); + } + + /** + * Returns a String representing the type-encoding of a + * method. The type-encoding of a method is: + * + * "(" + parameter type descriptors + ")" + return type descriptor + * + * XXX This could be faster if it were implemented natively. + * + * @param m the method to encode + * @return the encoding + */ + public static String getEncodingOfMethod(Method m) + { + Class[] paramTypes = m.getParameterTypes(); + CPStringBuilder buf = new CPStringBuilder("("); + for (int i = 0; i < paramTypes.length; i++) + buf.append(getEncodingOfClass(paramTypes[i].getName(), true)); + buf.append(')').append(getEncodingOfClass(m.getReturnType().getName(), + true)); + return buf.toString(); + } + + /** + * Returns a String representing the type-encoding of a + * constructor. The type-encoding of a method is: + * + * "(" + parameter type descriptors + ")V" + * + * XXX This could be faster if it were implemented natively. + * + * @param c the constructor to encode + * @return the encoding + */ + public static String getEncodingOfConstructor(Constructor c) + { + Class[] paramTypes = c.getParameterTypes(); + CPStringBuilder buf = new CPStringBuilder("("); + for (int i = 0; i < paramTypes.length; i++) + buf.append(getEncodingOfClass(paramTypes[i].getName(), true)); + buf.append(")V"); + return buf.toString(); + } + + /** + * Returns a String representing the type-encoding of a + * class member. This appropriately handles Constructors, Methods, and + * Fields. + * + * @param mem the member to encode + * @return the encoding + */ + public static String getEncodingOfMember(Member mem) + { + if (mem instanceof Constructor) + return getEncodingOfConstructor((Constructor) mem); + if (mem instanceof Method) + return getEncodingOfMethod((Method) mem); + else // Field + return getEncodingOfClass(((Field) mem).getType().getName(), true); + } +} // class TypeSignature diff --git a/libjava/classpath/gnu/java/lang/reflect/package.html b/libjava/classpath/gnu/java/lang/reflect/package.html new file mode 100644 index 000000000..a837d37d2 --- /dev/null +++ b/libjava/classpath/gnu/java/lang/reflect/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.lang.reflect + + +

+ + + diff --git a/libjava/classpath/gnu/java/locale/.cvsignore b/libjava/classpath/gnu/java/locale/.cvsignore new file mode 100644 index 000000000..d41ae8d81 --- /dev/null +++ b/libjava/classpath/gnu/java/locale/.cvsignore @@ -0,0 +1 @@ +LocaleData.java diff --git a/libjava/classpath/gnu/java/locale/LocaleHelper.java b/libjava/classpath/gnu/java/locale/LocaleHelper.java new file mode 100644 index 000000000..8b108768d --- /dev/null +++ b/libjava/classpath/gnu/java/locale/LocaleHelper.java @@ -0,0 +1,147 @@ +/* LocaleHelper.java -- helper routines for localization + Copyright (C) 2004, 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.java.locale; + +import java.text.Collator; +import java.util.Locale; + +/** + * This class provides common helper methods + * for handling localized data. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * + * @see java.util.Locale + * @see java.util.ResourceBundle + */ +public class LocaleHelper +{ + /** + *

+ * This method is used by the localized name lookup methods to + * retrieve the next locale to try. The next locale is derived + * from the supplied locale by applying the first applicable + * rule from the following: + *

+ *
    + *
  1. If the variant contains a '_', then + * this and everything following it is trimmed.
  2. + *
  3. If the variant is non-empty, it is converted to + * an empty string.
  4. + *
  5. If the country is non-empty, it is converted to + * an empty string.
  6. + *
  7. If the language is non-empty, it is converted to + * an empty string (forming {@link java.util.Locale#ROOT})
  8. + *
+ *

+ * The base fallback locale is {@link java.util.Locale#ROOT}. + *

+ * + * @param locale the locale for which a localized piece of + * data could not be obtained. + * @return the next fallback locale to try. + */ + public static Locale getFallbackLocale(Locale locale) + { + String language = locale.getLanguage(); + String country = locale.getCountry(); + String variant = locale.getVariant(); + int uscore = variant.indexOf('_'); + if (uscore != -1) + return new Locale(language, country, + variant.substring(0, uscore)); + if (!variant.isEmpty()) + return new Locale(language, country, ""); + if (!country.isEmpty()) + return new Locale(language, "", ""); + return Locale.ROOT; + } + + /** + * Return an array of all the locales for which there is a + * {@link Collator} instance. A new array is returned each time. + */ + public static Locale[] getCollatorLocales() + { + // For now we don't bother caching. This is probably + // not called very frequently. And, we would have to + // clone the array anyway. + if (LocaleData.collatorLocaleNames.length == 0) + return new Locale[] { Locale.US }; + Locale[] result = new Locale[LocaleData.collatorLocaleNames.length]; + for (int i = 0; i < result.length; ++i) + { + String language; + String region = ""; + String variant = ""; + String name = LocaleData.collatorLocaleNames[i]; + + language = name.substring(0, 2); + + if (name.length() > 2) + region = name.substring(3); + + int index = region.indexOf("_"); + if (index > 0) + { + variant = region.substring(index + 1); + region = region.substring(0, index - 1); + } + + result[i] = new Locale(language, region, variant); + } + return result; + } + + /** + * Return the number of locales we know of. + */ + public static int getLocaleCount() + { + return LocaleData.localeNames.length; + } + + /** + * Return the Nth locale name. + */ + public static String getLocaleName(int n) + { + return LocaleData.localeNames[n]; + } +} diff --git a/libjava/classpath/gnu/java/locale/package.html b/libjava/classpath/gnu/java/locale/package.html new file mode 100644 index 000000000..c4bc7c3e8 --- /dev/null +++ b/libjava/classpath/gnu/java/locale/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.locale + + +

+ + + diff --git a/libjava/classpath/gnu/java/math/Fixed.java b/libjava/classpath/gnu/java/math/Fixed.java new file mode 100644 index 000000000..6b210deda --- /dev/null +++ b/libjava/classpath/gnu/java/math/Fixed.java @@ -0,0 +1,220 @@ +/* Fixed.java -- Utility methods for fixed point arithmetics + 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.math; + +/** + * Utility methods for fixed point arithmetics. + */ +public final class Fixed +{ + + /** + * Private constructor to avoid instantiation. + */ + private Fixed() + { + // Forbidden constructor. + } + + /** + * Divides two fixed point values with n digits. + * + * @param n the number of digits + * @param a the first operand as fixed point value + * @param b the second operand as fixed point value + * + * @return a / b as fixed point value + */ + public static int div(int n, int a, int b) + { + return (int) ((((long) a) << n) / b); + } + + /** + * Multiplies two fixed point values with n digits. + * + * @param n the number of digits + * @param a the first operand as fixed point value + * @param b the second operand as fixed point value + * + * @return a * b as fixed point value + */ + public static int mul(int n, int a, int b) + { + return (int) ((((long) a) * b) >> n); + } + + /** + * Returns the ceiling value of a fixed point value a with + * the n digits. + * + * @param n the number of digits + * @param a the fixed point value + * + * @return ceil(a) as fixed point value + */ + public static int ceil(int n, int a) + { + return (a + (1 << n - 1)) & -(1 << n); + } + + /** + * Returns the floor value of a fixed point value a with + * n digits. + * + * @param n the number of digits + * @param a the fixed point value + * + * @return floor(a) as fixed point value + */ + public static int floor(int n, int a) + { + return a & -(1 << n); + } + + /** + * Truncates the number so that only the digits after the point are left. + * + * @param n the number of digits + * @param a the fixed point value + * + * @return the truncated value + */ + public static int trunc(int n, int a) + { + return a & (0xFFFFFFFF >>> 32 - n); + } + + /** + * Returns the round value of a fixed point value a with + * the n digits. + * + * @param n the number of digits + * @param a the fixed point value + * + * @return round(a) as fixed point value + */ + public static int round(int n, int a) + { + return (a + (1 << (n - 1))) & -(1 << n); + } + + /** + * Returns the fixed point value a with n digits + * as float. + * + * @param n the number of digits + * @param a the fixed point value + * + * @return the float value of a + */ + public static float floatValue(int n, int a) + { + return ((float) a) / (1 << n); + } + + /** + * Returns the fixed point value a with n digits + * as double. + * + * @param n the number of digits + * @param a the fixed point value + * + * @return the double value of a + */ + public static double doubleValue(int n, int a) + { + return ((double) a) / (1 << n); + } + + /** + * Returns the fixed point value that corresponds to the specified float + * value a with n digits. + * + * @param n the number of digits + * @param a the float value + * + * @return the fixed point value + */ + public static int fixedValue(int n, float a) + { + return (int) (a * (1 << n)); + } + + /** + * Returns the fixed point value that corresponds to the specified double + * value a with n digits. + * + * @param n the number of digits + * @param a the double value + * + * @return the fixed point value + */ + public static int fixedValue(int n, double a) + { + return (int) (a * (1 << n)); + } + + /** + * Returns the integer value of the specified fixed point value + * a. This simply cuts of the digits (== floor(a)). + * + * @param n the number of digits + * @param a the fixed point value + * + * @return the integer value + */ + public static int intValue(int n, int a) + { + return a >> n; + } + + /** + * Returns a fixed point decimal as rounded integer value. + * + * @param n the number of digits + * @param a the fixed point number + * + * @return the fixed point decimal as rounded integer value + */ + public static int roundIntValue(int n, int a) + { + return (a + (1 << (n - 1))) >> n; + } +} diff --git a/libjava/classpath/gnu/java/math/GMP.java b/libjava/classpath/gnu/java/math/GMP.java new file mode 100644 index 000000000..4df790a40 --- /dev/null +++ b/libjava/classpath/gnu/java/math/GMP.java @@ -0,0 +1,474 @@ +/* gnu.java.math.GMP -- Arbitary precision integers using GMP + 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.math; + +import gnu.classpath.Pointer; + +/** + * Implement BigInteger using GMP + */ +public final class GMP +{ + private Pointer native_ptr; + private int refCount = 1; + + public GMP() + { + super(); + + natInitialize(); + } + + private synchronized void acquireRef() + { + refCount++; + } + + private synchronized void releaseRef() + { + refCount--; + if (refCount == 0) + { + natFinalize(); + native_ptr = null; + } + } + + protected void finalize() + { + releaseRef(); + } + + + public void fromByteArray(byte[] v) + { + acquireRef(); + natFromByteArray(v); + releaseRef(); + } + + public void fromBI(GMP x) + { + acquireRef(); + x.acquireRef(); + natFromBI(x.native_ptr); + x.releaseRef(); + releaseRef(); + } + + public void fromLong(long n) + { + acquireRef(); + natFromLong(n); + releaseRef(); + } + + public int fromString(String s, int rdx) + { + acquireRef(); + int result = natFromString(s, rdx); + releaseRef(); + return result; + } + + public void fromSignedMagnitude(byte[] m, boolean isNegative) + { + acquireRef(); + natFromSignedMagnitude(m, isNegative); + releaseRef(); + } + + public String toString(int b) + { + acquireRef(); + String result = natToString(b); + releaseRef(); + return result; + } + + public void toByteArray(byte[] r) + { + acquireRef(); + natToByteArray(r); + releaseRef(); + } + + public double doubleValue() + { + acquireRef(); + double result = natDoubleValue(); + releaseRef(); + return result; + } + + public int absIntValue() + { + acquireRef(); + int result = natAbsIntValue(); + releaseRef(); + return result; + } + + public int compare(GMP x) + { + acquireRef(); + x.acquireRef(); + int result = natCompare(x.native_ptr); + x.releaseRef(); + releaseRef(); + return result; + } + + public void add(GMP x, GMP r) + { + acquireRef(); + x.acquireRef(); + r.acquireRef(); + natAdd(x.native_ptr, r.native_ptr); + r.releaseRef(); + x.releaseRef(); + releaseRef(); + } + + public void subtract(GMP x, GMP r) + { + acquireRef(); + x.acquireRef(); + r.acquireRef(); + natSubtract(x.native_ptr, r.native_ptr); + r.releaseRef(); + x.releaseRef(); + releaseRef(); + } + + public void multiply(GMP x, GMP r) + { + acquireRef(); + x.acquireRef(); + r.acquireRef(); + natMultiply(x.native_ptr, r.native_ptr); + r.releaseRef(); + x.releaseRef(); + releaseRef(); + } + + public void quotient(GMP x, GMP r) + { + acquireRef(); + x.acquireRef(); + r.acquireRef(); + natQuotient(x.native_ptr, r.native_ptr); + r.releaseRef(); + x.releaseRef(); + releaseRef(); + } + + public void remainder(GMP x, GMP r) + { + acquireRef(); + x.acquireRef(); + r.acquireRef(); + natRemainder(x.native_ptr, r.native_ptr); + r.releaseRef(); + x.releaseRef(); + releaseRef(); + } + + public void quotientAndRemainder(GMP x, GMP q, GMP r) + { + acquireRef(); + x.acquireRef(); + q.acquireRef(); + r.acquireRef(); + natQuotientAndRemainder(x.native_ptr, q.native_ptr, r.native_ptr); + r.releaseRef(); + q.releaseRef(); + x.releaseRef(); + releaseRef(); + } + + public void modulo(GMP x, GMP r) + { + acquireRef(); + x.acquireRef(); + r.acquireRef(); + natModulo(x.native_ptr, r.native_ptr); + r.releaseRef(); + x.releaseRef(); + releaseRef(); + } + + public void pow(int n, GMP r) + { + acquireRef(); + r.acquireRef(); + natPow(n, r.native_ptr); + r.releaseRef(); + releaseRef(); + } + + public void modPow(GMP e, GMP m, GMP r) + { + acquireRef(); + e.acquireRef(); + m.acquireRef(); + r.acquireRef(); + natModPow(e.native_ptr, m.native_ptr, r.native_ptr); + r.releaseRef(); + m.releaseRef(); + e.releaseRef(); + releaseRef(); + } + + public void modInverse(GMP m, GMP r) + { + acquireRef(); + m.acquireRef(); + r.acquireRef(); + natModInverse(m.native_ptr, r.native_ptr); + r.releaseRef(); + m.releaseRef(); + releaseRef(); + } + + public void gcd(GMP x, GMP r) + { + acquireRef(); + x.acquireRef(); + r.acquireRef(); + natGCD(x.native_ptr, r.native_ptr); + r.releaseRef(); + x.releaseRef(); + releaseRef(); + } + + public void shiftLeft(int n, GMP r) + { + acquireRef(); + r.acquireRef(); + natShiftLeft(n, r.native_ptr); + r.releaseRef(); + releaseRef(); + } + + public void shiftRight(int n, GMP r) + { + acquireRef(); + r.acquireRef(); + natShiftRight(n, r.native_ptr); + r.releaseRef(); + releaseRef(); + } + + public void abs(GMP r) + { + acquireRef(); + r.acquireRef(); + natAbs(r.native_ptr); + r.releaseRef(); + releaseRef(); + } + + public void negate(GMP r) + { + acquireRef(); + r.acquireRef(); + natNegate(r.native_ptr); + r.releaseRef(); + releaseRef(); + } + + public int bitLength() + { + acquireRef(); + int result = natBitLength(); + releaseRef(); + return result; + } + + public int bitCount() + { + acquireRef(); + int result = natSetBitCount(); + releaseRef(); + return result; + } + + public void and(GMP x, GMP r) + { + acquireRef(); + x.acquireRef(); + r.acquireRef(); + natAnd(x.native_ptr, r.native_ptr); + r.releaseRef(); + x.releaseRef(); + releaseRef(); + } + + public void or(GMP x, GMP r) + { + acquireRef(); + x.acquireRef(); + r.acquireRef(); + natOr(x.native_ptr, r.native_ptr); + r.releaseRef(); + x.releaseRef(); + releaseRef(); + } + + public void xor(GMP x, GMP r) + { + acquireRef(); + x.acquireRef(); + r.acquireRef(); + natXor(x.native_ptr, r.native_ptr); + r.releaseRef(); + x.releaseRef(); + releaseRef(); + } + + public void andNot(GMP x, GMP r) + { + acquireRef(); + x.acquireRef(); + r.acquireRef(); + natAndNot(x.native_ptr, r.native_ptr); + r.releaseRef(); + x.releaseRef(); + releaseRef(); + } + + public void not(GMP r) + { + acquireRef(); + r.acquireRef(); + natNot(r.native_ptr); + r.releaseRef(); + releaseRef(); + } + + public void flipBit(int n, GMP r) + { + acquireRef(); + r.acquireRef(); + natFlipBit(n, r.native_ptr); + r.releaseRef(); + releaseRef(); + } + + public int testBit(int n) + { + acquireRef(); + int result = natTestBit(n); + releaseRef(); + return result; + } + + public void setBit(int n, boolean setIt, GMP r) + { + acquireRef(); + r.acquireRef(); + natSetBit(n, setIt, r.native_ptr); + r.releaseRef(); + releaseRef(); + } + + public int testPrimality(int certainty) + { + acquireRef(); + int result = natTestPrimality(certainty); + releaseRef(); + return result; + } + + public int lowestSetBit() + { + acquireRef(); + int result = natLowestSetBit(); + releaseRef(); + return result; + } + + // Native methods ......................................................... + + public static native void natInitializeLibrary(); + + private native void natInitialize(); + private native void natFinalize(); + + private native void natFromLong(long n); + private native void natFromBI(Pointer x); + private native void natFromByteArray(byte[] v); + private native int natFromString(String s, int rdx); + private native void natFromSignedMagnitude(byte[] m, boolean isNegative); + + private native String natToString(int base); + private native void natToByteArray(byte[] r); + private native int natAbsIntValue(); + private native double natDoubleValue(); + + private native int natCompare(Pointer y); + private native void natAdd(Pointer x, Pointer r); + private native void natSubtract(Pointer x, Pointer r); + private native void natMultiply(Pointer x, Pointer r); + private native void natQuotient(Pointer x, Pointer r); + private native void natRemainder(Pointer x, Pointer r); + private native void natQuotientAndRemainder(Pointer x, Pointer q, Pointer r); + private native void natModulo(Pointer m, Pointer r); + private native void natPow(int n, Pointer r); + private native void natModPow(Pointer e, Pointer m, Pointer r); + private native void natModInverse(Pointer x, Pointer r); + private native void natGCD(Pointer x, Pointer r); + private native int natTestPrimality(int c); + private native void natShiftLeft(int n, Pointer r); + private native void natShiftRight(int n, Pointer r); + private native int natLowestSetBit(); + private native void natAbs(Pointer r); + private native void natNegate(Pointer r); + private native int natBitLength(); + private native int natSetBitCount(); + private native void natXor(Pointer x, Pointer r); + private native void natOr(Pointer x, Pointer r); + private native void natAnd(Pointer x, Pointer r); + private native void natAndNot(Pointer x, Pointer r); + private native void natFlipBit(int n, Pointer r); + private native int natTestBit(int n); + private native void natSetBit(int n, boolean setIt, Pointer r); + private native void natNot(Pointer r); +} diff --git a/libjava/classpath/gnu/java/math/MPN.java b/libjava/classpath/gnu/java/math/MPN.java new file mode 100644 index 000000000..9143ef03b --- /dev/null +++ b/libjava/classpath/gnu/java/math/MPN.java @@ -0,0 +1,771 @@ +/* gnu.java.math.MPN + Copyright (C) 1999, 2000, 2001, 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. */ + +// Included from Kawa 1.6.62 with permission of the author, +// Per Bothner . + +package gnu.java.math; + +/** This contains various low-level routines for unsigned bigints. + * The interfaces match the mpn interfaces in gmp, + * so it should be easy to replace them with fast native functions + * that are trivial wrappers around the mpn_ functions in gmp + * (at least on platforms that use 32-bit "limbs"). + */ + +public class MPN +{ + /** Add x[0:size-1] and y, and write the size least + * significant words of the result to dest. + * Return carry, either 0 or 1. + * All values are unsigned. + * This is basically the same as gmp's mpn_add_1. */ + public static int add_1 (int[] dest, int[] x, int size, int y) + { + long carry = (long) y & 0xffffffffL; + for (int i = 0; i < size; i++) + { + carry += ((long) x[i] & 0xffffffffL); + dest[i] = (int) carry; + carry >>= 32; + } + return (int) carry; + } + + /** Add x[0:len-1] and y[0:len-1] and write the len least + * significant words of the result to dest[0:len-1]. + * All words are treated as unsigned. + * @return the carry, either 0 or 1 + * This function is basically the same as gmp's mpn_add_n. + */ + public static int add_n (int dest[], int[] x, int[] y, int len) + { + long carry = 0; + for (int i = 0; i < len; i++) + { + carry += ((long) x[i] & 0xffffffffL) + + ((long) y[i] & 0xffffffffL); + dest[i] = (int) carry; + carry >>>= 32; + } + return (int) carry; + } + + /** Subtract Y[0:size-1] from X[0:size-1], and write + * the size least significant words of the result to dest[0:size-1]. + * Return borrow, either 0 or 1. + * This is basically the same as gmp's mpn_sub_n function. + */ + + public static int sub_n (int[] dest, int[] X, int[] Y, int size) + { + int cy = 0; + for (int i = 0; i < size; i++) + { + int y = Y[i]; + int x = X[i]; + y += cy; /* add previous carry to subtrahend */ + // Invert the high-order bit, because: (unsigned) X > (unsigned) Y + // iff: (int) (X^0x80000000) > (int) (Y^0x80000000). + cy = (y^0x80000000) < (cy^0x80000000) ? 1 : 0; + y = x - y; + cy += (y^0x80000000) > (x ^ 0x80000000) ? 1 : 0; + dest[i] = y; + } + return cy; + } + + /** Multiply x[0:len-1] by y, and write the len least + * significant words of the product to dest[0:len-1]. + * Return the most significant word of the product. + * All values are treated as if they were unsigned + * (i.e. masked with 0xffffffffL). + * OK if dest==x (not sure if this is guaranteed for mpn_mul_1). + * This function is basically the same as gmp's mpn_mul_1. + */ + + public static int mul_1 (int[] dest, int[] x, int len, int y) + { + long yword = (long) y & 0xffffffffL; + long carry = 0; + for (int j = 0; j < len; j++) + { + carry += ((long) x[j] & 0xffffffffL) * yword; + dest[j] = (int) carry; + carry >>>= 32; + } + return (int) carry; + } + + /** + * Multiply x[0:xlen-1] and y[0:ylen-1], and + * write the result to dest[0:xlen+ylen-1]. + * The destination has to have space for xlen+ylen words, + * even if the result might be one limb smaller. + * This function requires that xlen >= ylen. + * The destination must be distinct from either input operands. + * All operands are unsigned. + * This function is basically the same gmp's mpn_mul. */ + + public static void mul (int[] dest, + int[] x, int xlen, + int[] y, int ylen) + { + dest[xlen] = MPN.mul_1 (dest, x, xlen, y[0]); + + for (int i = 1; i < ylen; i++) + { + long yword = (long) y[i] & 0xffffffffL; + long carry = 0; + for (int j = 0; j < xlen; j++) + { + carry += ((long) x[j] & 0xffffffffL) * yword + + ((long) dest[i+j] & 0xffffffffL); + dest[i+j] = (int) carry; + carry >>>= 32; + } + dest[i+xlen] = (int) carry; + } + } + + /* Divide (unsigned long) N by (unsigned int) D. + * Returns (remainder << 32)+(unsigned int)(quotient). + * Assumes (unsigned int)(N>>32) < (unsigned int)D. + * Code transcribed from gmp-2.0's mpn_udiv_w_sdiv function. + */ + public static long udiv_qrnnd (long N, int D) + { + long q, r; + long a1 = N >>> 32; + long a0 = N & 0xffffffffL; + if (D >= 0) + { + if (a1 < ((D - a1 - (a0 >>> 31)) & 0xffffffffL)) + { + /* dividend, divisor, and quotient are nonnegative */ + q = N / D; + r = N % D; + } + else + { + /* Compute c1*2^32 + c0 = a1*2^32 + a0 - 2^31*d */ + long c = N - ((long) D << 31); + /* Divide (c1*2^32 + c0) by d */ + q = c / D; + r = c % D; + /* Add 2^31 to quotient */ + q += 1 << 31; + } + } + else + { + long b1 = D >>> 1; /* d/2, between 2^30 and 2^31 - 1 */ + //long c1 = (a1 >> 1); /* A/2 */ + //int c0 = (a1 << 31) + (a0 >> 1); + long c = N >>> 1; + if (a1 < b1 || (a1 >> 1) < b1) + { + if (a1 < b1) + { + q = c / b1; + r = c % b1; + } + else /* c1 < b1, so 2^31 <= (A/2)/b1 < 2^32 */ + { + c = ~(c - (b1 << 32)); + q = c / b1; /* (A/2) / (d/2) */ + r = c % b1; + q = (~q) & 0xffffffffL; /* (A/2)/b1 */ + r = (b1 - 1) - r; /* r < b1 => new r >= 0 */ + } + r = 2 * r + (a0 & 1); + if ((D & 1) != 0) + { + if (r >= q) { + r = r - q; + } else if (q - r <= ((long) D & 0xffffffffL)) { + r = r - q + D; + q -= 1; + } else { + r = r - q + D + D; + q -= 2; + } + } + } + else /* Implies c1 = b1 */ + { /* Hence a1 = d - 1 = 2*b1 - 1 */ + if (a0 >= ((long)(-D) & 0xffffffffL)) + { + q = -1; + r = a0 + D; + } + else + { + q = -2; + r = a0 + D + D; + } + } + } + + return (r << 32) | (q & 0xFFFFFFFFl); + } + + /** Divide divident[0:len-1] by (unsigned int)divisor. + * Write result into quotient[0:len-1. + * Return the one-word (unsigned) remainder. + * OK for quotient==dividend. + */ + + public static int divmod_1 (int[] quotient, int[] dividend, + int len, int divisor) + { + int i = len - 1; + long r = dividend[i]; + if ((r & 0xffffffffL) >= ((long)divisor & 0xffffffffL)) + r = 0; + else + { + quotient[i--] = 0; + r <<= 32; + } + + for (; i >= 0; i--) + { + int n0 = dividend[i]; + r = (r & ~0xffffffffL) | (n0 & 0xffffffffL); + r = udiv_qrnnd (r, divisor); + quotient[i] = (int) r; + } + return (int)(r >> 32); + } + + /* Subtract x[0:len-1]*y from dest[offset:offset+len-1]. + * All values are treated as if unsigned. + * @return the most significant word of + * the product, minus borrow-out from the subtraction. + */ + public static int submul_1 (int[] dest, int offset, int[] x, int len, int y) + { + long yl = (long) y & 0xffffffffL; + int carry = 0; + int j = 0; + do + { + long prod = ((long) x[j] & 0xffffffffL) * yl; + int prod_low = (int) prod; + int prod_high = (int) (prod >> 32); + prod_low += carry; + // Invert the high-order bit, because: (unsigned) X > (unsigned) Y + // iff: (int) (X^0x80000000) > (int) (Y^0x80000000). + carry = ((prod_low ^ 0x80000000) < (carry ^ 0x80000000) ? 1 : 0) + + prod_high; + int x_j = dest[offset+j]; + prod_low = x_j - prod_low; + if ((prod_low ^ 0x80000000) > (x_j ^ 0x80000000)) + carry++; + dest[offset+j] = prod_low; + } + while (++j < len); + return carry; + } + + /** Divide zds[0:nx] by y[0:ny-1]. + * The remainder ends up in zds[0:ny-1]. + * The quotient ends up in zds[ny:nx]. + * Assumes: nx>ny. + * (int)y[ny-1] < 0 (i.e. most significant bit set) + */ + + public static void divide (int[] zds, int nx, int[] y, int ny) + { + // This is basically Knuth's formulation of the classical algorithm, + // but translated from in scm_divbigbig in Jaffar's SCM implementation. + + // Correspondance with Knuth's notation: + // Knuth's u[0:m+n] == zds[nx:0]. + // Knuth's v[1:n] == y[ny-1:0] + // Knuth's n == ny. + // Knuth's m == nx-ny. + // Our nx == Knuth's m+n. + + // Could be re-implemented using gmp's mpn_divrem: + // zds[nx] = mpn_divrem (&zds[ny], 0, zds, nx, y, ny). + + int j = nx; + do + { // loop over digits of quotient + // Knuth's j == our nx-j. + // Knuth's u[j:j+n] == our zds[j:j-ny]. + int qhat; // treated as unsigned + if (zds[j]==y[ny-1]) + qhat = -1; // 0xffffffff + else + { + long w = (((long)(zds[j])) << 32) + ((long)zds[j-1] & 0xffffffffL); + qhat = (int) udiv_qrnnd (w, y[ny-1]); + } + if (qhat != 0) + { + int borrow = submul_1 (zds, j - ny, y, ny, qhat); + int save = zds[j]; + long num = ((long)save&0xffffffffL) - ((long)borrow&0xffffffffL); + while (num != 0) + { + qhat--; + long carry = 0; + for (int i = 0; i < ny; i++) + { + carry += ((long) zds[j-ny+i] & 0xffffffffL) + + ((long) y[i] & 0xffffffffL); + zds[j-ny+i] = (int) carry; + carry >>>= 32; + } + zds[j] += carry; + num = carry - 1; + } + } + zds[j] = qhat; + } while (--j >= ny); + } + + /** Number of digits in the conversion base that always fits in a word. + * For example, for base 10 this is 9, since 10**9 is the + * largest number that fits into a words (assuming 32-bit words). + * This is the same as gmp's __mp_bases[radix].chars_per_limb. + * @param radix the base + * @return number of digits */ + public static int chars_per_word (int radix) + { + if (radix < 10) + { + if (radix < 8) + { + if (radix <= 2) + return 32; + else if (radix == 3) + return 20; + else if (radix == 4) + return 16; + else + return 18 - radix; + } + else + return 10; + } + else if (radix < 12) + return 9; + else if (radix <= 16) + return 8; + else if (radix <= 23) + return 7; + else if (radix <= 40) + return 6; + // The following are conservative, but we don't care. + else if (radix <= 256) + return 4; + else + return 1; + } + + /** Count the number of leading zero bits in an int. */ + public static int count_leading_zeros (int i) + { + if (i == 0) + return 32; + int count = 0; + for (int k = 16; k > 0; k = k >> 1) { + int j = i >>> k; + if (j == 0) + count += k; + else + i = j; + } + return count; + } + + public static int set_str (int dest[], byte[] str, int str_len, int base) + { + int size = 0; + if ((base & (base - 1)) == 0) + { + // The base is a power of 2. Read the input string from + // least to most significant character/digit. */ + + int next_bitpos = 0; + int bits_per_indigit = 0; + for (int i = base; (i >>= 1) != 0; ) bits_per_indigit++; + int res_digit = 0; + + for (int i = str_len; --i >= 0; ) + { + int inp_digit = str[i]; + res_digit |= inp_digit << next_bitpos; + next_bitpos += bits_per_indigit; + if (next_bitpos >= 32) + { + dest[size++] = res_digit; + next_bitpos -= 32; + res_digit = inp_digit >> (bits_per_indigit - next_bitpos); + } + } + + if (res_digit != 0) + dest[size++] = res_digit; + } + else + { + // General case. The base is not a power of 2. + int indigits_per_limb = MPN.chars_per_word (base); + int str_pos = 0; + + while (str_pos < str_len) + { + int chunk = str_len - str_pos; + if (chunk > indigits_per_limb) + chunk = indigits_per_limb; + int res_digit = str[str_pos++]; + int big_base = base; + + while (--chunk > 0) + { + res_digit = res_digit * base + str[str_pos++]; + big_base *= base; + } + + int cy_limb; + if (size == 0) + cy_limb = res_digit; + else + { + cy_limb = MPN.mul_1 (dest, dest, size, big_base); + cy_limb += MPN.add_1 (dest, dest, size, res_digit); + } + if (cy_limb != 0) + dest[size++] = cy_limb; + } + } + return size; + } + + /** Compare x[0:size-1] with y[0:size-1], treating them as unsigned integers. + * @result -1, 0, or 1 depending on if x<y, x==y, or x>y. + * This is basically the same as gmp's mpn_cmp function. + */ + public static int cmp (int[] x, int[] y, int size) + { + while (--size >= 0) + { + int x_word = x[size]; + int y_word = y[size]; + if (x_word != y_word) + { + // Invert the high-order bit, because: + // (unsigned) X > (unsigned) Y iff + // (int) (X^0x80000000) > (int) (Y^0x80000000). + return (x_word ^ 0x80000000) > (y_word ^0x80000000) ? 1 : -1; + } + } + return 0; + } + + /** + * Compare x[0:xlen-1] with y[0:ylen-1], treating them as unsigned integers. + * + * @return -1, 0, or 1 depending on if x<y, x==y, or x>y. + */ + public static int cmp (int[] x, int xlen, int[] y, int ylen) + { + return xlen > ylen ? 1 : xlen < ylen ? -1 : cmp (x, y, xlen); + } + + /** + * Shift x[x_start:x_start+len-1] count bits to the "right" + * (i.e. divide by 2**count). + * Store the len least significant words of the result at dest. + * The bits shifted out to the right are returned. + * OK if dest==x. + * Assumes: 0 < count < 32 + */ + public static int rshift (int[] dest, int[] x, int x_start, + int len, int count) + { + int count_2 = 32 - count; + int low_word = x[x_start]; + int retval = low_word << count_2; + int i = 1; + for (; i < len; i++) + { + int high_word = x[x_start+i]; + dest[i-1] = (low_word >>> count) | (high_word << count_2); + low_word = high_word; + } + dest[i-1] = low_word >>> count; + return retval; + } + + /** + * Shift x[x_start:x_start+len-1] count bits to the "right" + * (i.e. divide by 2**count). + * Store the len least significant words of the result at dest. + * OK if dest==x. + * Assumes: 0 <= count < 32 + * Same as rshift, but handles count==0 (and has no return value). + */ + public static void rshift0 (int[] dest, int[] x, int x_start, + int len, int count) + { + if (count > 0) + rshift(dest, x, x_start, len, count); + else + for (int i = 0; i < len; i++) + dest[i] = x[i + x_start]; + } + + /** Return the long-truncated value of right shifting. + * @param x a two's-complement "bignum" + * @param len the number of significant words in x + * @param count the shift count + * @return (long)(x[0..len-1] >> count). + */ + public static long rshift_long (int[] x, int len, int count) + { + int wordno = count >> 5; + count &= 31; + int sign = x[len-1] < 0 ? -1 : 0; + int w0 = wordno >= len ? sign : x[wordno]; + wordno++; + int w1 = wordno >= len ? sign : x[wordno]; + if (count != 0) + { + wordno++; + int w2 = wordno >= len ? sign : x[wordno]; + w0 = (w0 >>> count) | (w1 << (32-count)); + w1 = (w1 >>> count) | (w2 << (32-count)); + } + return ((long)w1 << 32) | ((long)w0 & 0xffffffffL); + } + + /* Shift x[0:len-1] left by count bits, and store the len least + * significant words of the result in dest[d_offset:d_offset+len-1]. + * Return the bits shifted out from the most significant digit. + * Assumes 0 < count < 32. + * OK if dest==x. + */ + + public static int lshift (int[] dest, int d_offset, + int[] x, int len, int count) + { + int count_2 = 32 - count; + int i = len - 1; + int high_word = x[i]; + int retval = high_word >>> count_2; + d_offset++; + while (--i >= 0) + { + int low_word = x[i]; + dest[d_offset+i] = (high_word << count) | (low_word >>> count_2); + high_word = low_word; + } + dest[d_offset+i] = high_word << count; + return retval; + } + + /** Return least i such that word & (1<<i). Assumes word!=0. */ + + public static int findLowestBit (int word) + { + int i = 0; + while ((word & 0xF) == 0) + { + word >>= 4; + i += 4; + } + if ((word & 3) == 0) + { + word >>= 2; + i += 2; + } + if ((word & 1) == 0) + i += 1; + return i; + } + + /** Return least i such that words & (1<<i). Assumes there is such an i. */ + + public static int findLowestBit (int[] words) + { + for (int i = 0; ; i++) + { + if (words[i] != 0) + return 32 * i + findLowestBit (words[i]); + } + } + + /** Calculate Greatest Common Divisior of x[0:len-1] and y[0:len-1]. + * Assumes both arguments are non-zero. + * Leaves result in x, and returns len of result. + * Also destroys y (actually sets it to a copy of the result). */ + + public static int gcd (int[] x, int[] y, int len) + { + int i, word; + // Find sh such that both x and y are divisible by 2**sh. + for (i = 0; ; i++) + { + word = x[i] | y[i]; + if (word != 0) + { + // Must terminate, since x and y are non-zero. + break; + } + } + int initShiftWords = i; + int initShiftBits = findLowestBit (word); + // Logically: sh = initShiftWords * 32 + initShiftBits + + // Temporarily devide both x and y by 2**sh. + len -= initShiftWords; + MPN.rshift0 (x, x, initShiftWords, len, initShiftBits); + MPN.rshift0 (y, y, initShiftWords, len, initShiftBits); + + int[] odd_arg; /* One of x or y which is odd. */ + int[] other_arg; /* The other one can be even or odd. */ + if ((x[0] & 1) != 0) + { + odd_arg = x; + other_arg = y; + } + else + { + odd_arg = y; + other_arg = x; + } + + for (;;) + { + // Shift other_arg until it is odd; this doesn't + // affect the gcd, since we divide by 2**k, which does not + // divide odd_arg. + for (i = 0; other_arg[i] == 0; ) i++; + if (i > 0) + { + int j; + for (j = 0; j < len-i; j++) + other_arg[j] = other_arg[j+i]; + for ( ; j < len; j++) + other_arg[j] = 0; + } + i = findLowestBit(other_arg[0]); + if (i > 0) + MPN.rshift (other_arg, other_arg, 0, len, i); + + // Now both odd_arg and other_arg are odd. + + // Subtract the smaller from the larger. + // This does not change the result, since gcd(a-b,b)==gcd(a,b). + i = MPN.cmp(odd_arg, other_arg, len); + if (i == 0) + break; + if (i > 0) + { // odd_arg > other_arg + MPN.sub_n (odd_arg, odd_arg, other_arg, len); + // Now odd_arg is even, so swap with other_arg; + int[] tmp = odd_arg; odd_arg = other_arg; other_arg = tmp; + } + else + { // other_arg > odd_arg + MPN.sub_n (other_arg, other_arg, odd_arg, len); + } + while (odd_arg[len-1] == 0 && other_arg[len-1] == 0) + len--; + } + if (initShiftWords + initShiftBits > 0) + { + if (initShiftBits > 0) + { + int sh_out = MPN.lshift (x, initShiftWords, x, len, initShiftBits); + if (sh_out != 0) + x[(len++)+initShiftWords] = sh_out; + } + else + { + for (i = len; --i >= 0;) + x[i+initShiftWords] = x[i]; + } + for (i = initShiftWords; --i >= 0; ) + x[i] = 0; + len += initShiftWords; + } + return len; + } + + public static int intLength (int i) + { + return 32 - count_leading_zeros (i < 0 ? ~i : i); + } + + /** Calcaulte the Common Lisp "integer-length" function. + * Assumes input is canonicalized: len==BigInteger.wordsNeeded(words,len) */ + public static int intLength (int[] words, int len) + { + len--; + return intLength (words[len]) + 32 * len; + } + + /* DEBUGGING: + public static void dprint (BigInteger x) + { + if (x.words == null) + System.err.print(Long.toString((long) x.ival & 0xffffffffL, 16)); + else + dprint (System.err, x.words, x.ival); + } + public static void dprint (int[] x) { dprint (System.err, x, x.length); } + public static void dprint (int[] x, int len) { dprint (System.err, x, len); } + public static void dprint (java.io.PrintStream ps, int[] x, int len) + { + ps.print('('); + for (int i = 0; i < len; i++) + { + if (i > 0) + ps.print (' '); + ps.print ("#x" + Long.toString ((long) x[i] & 0xffffffffL, 16)); + } + ps.print(')'); + } + */ +} diff --git a/libjava/classpath/gnu/java/math/package.html b/libjava/classpath/gnu/java/math/package.html new file mode 100644 index 000000000..97e101831 --- /dev/null +++ b/libjava/classpath/gnu/java/math/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.math + + +

+ + + diff --git a/libjava/classpath/gnu/java/net/CRLFInputStream.java b/libjava/classpath/gnu/java/net/CRLFInputStream.java new file mode 100644 index 000000000..5e394ae2c --- /dev/null +++ b/libjava/classpath/gnu/java/net/CRLFInputStream.java @@ -0,0 +1,178 @@ +/* CRLFInputStream.java -- + Copyright (C) 2002, 2003, 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.net; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * An input stream that filters out CR/LF pairs into LFs. + * + * @author Chris Burdess (dog@gnu.org) + */ +public class CRLFInputStream + extends InputStream +{ + /** + * The CR octet. + */ + public static final int CR = 13; + + /** + * The LF octet. + */ + public static final int LF = 10; + + /** + * The underlying input stream. + */ + protected InputStream in; + + private boolean doReset; + + /** + * Constructs a CR/LF input stream connected to the specified input + * stream. + */ + public CRLFInputStream(InputStream in) + { + this.in = in.markSupported() ? in : new BufferedInputStream(in); + } + + /** + * Reads the next byte of data from this input stream. + * Returns -1 if the end of the stream has been reached. + * @exception IOException if an I/O error occurs + */ + public int read() + throws IOException + { + int c = in.read(); + if (c == CR) + { + in.mark(1); + int d = in.read(); + if (d == LF) + { + c = d; + } + else + { + in.reset(); + } + } + return c; + } + + /** + * Reads up to b.length bytes of data from this input stream into + * an array of bytes. + * Returns -1 if the end of the stream has been reached. + * @exception IOException if an I/O error occurs + */ + public int read(byte[] b) + throws IOException + { + return read(b, 0, b.length); + } + + /** + * Reads up to len bytes of data from this input stream into an + * array of bytes, starting at the specified offset. + * Returns -1 if the end of the stream has been reached. + * @exception IOException if an I/O error occurs + */ + public int read(byte[] b, int off, int len) + throws IOException + { + in.mark(len + 1); + int l = in.read(b, off, len); + if (l > 0) + { + int i = indexOfCRLF(b, off, l); + if (doReset) + { + in.reset(); + if (i != -1) + { + l = in.read(b, off, (i + 1) - off); // read to CR + in.read(); // skip LF + b[i] = LF; // fix CR as LF + } + else + { + l = in.read(b, off, len); // CR(s) but no LF + } + } + } + return l; + } + + private int indexOfCRLF(byte[] b, int off, int len) + throws IOException + { + doReset = false; + int end = off + len; + int em1 = end - 1; + for (int i = off; i < end; i++) + { + if (b[i] == CR) + { + int d; + if (i == em1) + { + d = in.read(); + doReset = true; + } + else + { + d = b[i + 1]; + } + if (d == LF) + { + doReset = true; + return i; + } + } + } + return -1; + } + +} diff --git a/libjava/classpath/gnu/java/net/CRLFOutputStream.java b/libjava/classpath/gnu/java/net/CRLFOutputStream.java new file mode 100644 index 000000000..0e9428373 --- /dev/null +++ b/libjava/classpath/gnu/java/net/CRLFOutputStream.java @@ -0,0 +1,182 @@ +/* CRLFOutputStream.java -- + Copyright (C) 2002, 2003, 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.net; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; + +/** + * An output stream that filters LFs into CR/LF pairs. + * + * @author Chris Burdess (dog@gnu.org) + */ +public class CRLFOutputStream + extends FilterOutputStream +{ + static final String US_ASCII = "US-ASCII"; + + /** + * The CR octet. + */ + public static final int CR = 13; + + /** + * The LF octet. + */ + public static final int LF = 10; + + /** + * The CR/LF pair. + */ + public static final byte[] CRLF = { CR, LF }; + + /** + * The last byte read. + */ + protected int last; + + /** + * Constructs a CR/LF output stream connected to the specified output stream. + */ + public CRLFOutputStream(OutputStream out) + { + super(out); + last = -1; + } + + /** + * Writes a character to the underlying stream. + * @exception IOException if an I/O error occurred + */ + public void write(int ch) throws IOException + { + if (ch == CR) + { + out.write(CRLF); + } + else if (ch == LF) + { + if (last != CR) + { + out.write(CRLF); + } + } + else + { + out.write(ch); + } + last = ch; + } + + /** + * Writes a byte array to the underlying stream. + * @exception IOException if an I/O error occurred + */ + public void write(byte[] b) + throws IOException + { + write(b, 0, b.length); + } + + /** + * Writes a portion of a byte array to the underlying stream. + * @exception IOException if an I/O error occurred + */ + public void write(byte[] b, int off, int len) + throws IOException + { + int d = off; + len += off; + for (int i = off; i < len; i++) + { + switch (b[i]) + { + case CR: + out.write (b, d, i - d); + out.write (CRLF, 0, 2); + d = i + 1; + break; + case LF: + if (last != CR) + { + out.write (b, d, i - d); + out.write (CRLF, 0, 2); + } + d = i + 1; + break; + } + last = b[i]; + } + if (len - d > 0) + { + out.write (b, d, len - d); + } + } + + /** + * Writes the specified ASCII string to the underlying stream. + * @exception IOException if an I/O error occurred + */ + public void write(String text) + throws IOException + { + try + { + byte[] bytes = text.getBytes(US_ASCII); + write(bytes, 0, bytes.length); + } + catch (UnsupportedEncodingException e) + { + throw new IOException("The US-ASCII encoding is not supported " + + "on this system"); + } + } + + /** + * Writes a newline to the underlying stream. + * @exception IOException if an I/O error occurred + */ + public void writeln() + throws IOException + { + out.write(CRLF, 0, 2); + } +} diff --git a/libjava/classpath/gnu/java/net/DefaultContentHandlerFactory.java b/libjava/classpath/gnu/java/net/DefaultContentHandlerFactory.java new file mode 100644 index 000000000..1d113b935 --- /dev/null +++ b/libjava/classpath/gnu/java/net/DefaultContentHandlerFactory.java @@ -0,0 +1,94 @@ +/* DefaultContentHandlerFactory.java + 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.net; + +import java.io.IOException; +import java.net.ContentHandler; +import java.net.ContentHandlerFactory; +import java.net.URLConnection; +import java.util.Arrays; +import java.util.HashSet; + +/** Content Handler for Image types, using the AWT Toolkit's image decoder. */ +class ImageHandler extends ContentHandler +{ + static ImageHandler instance = new ImageHandler(); + + public Object getContent(URLConnection urlc) throws IOException + { + // FIXME: implement using ImageIO + // ClasspathToolkit tk = (ClasspathToolkit) Toolkit.getDefaultToolkit(); + // java.awt.image.ImageProducer ip = tk.createImageProducer(urlc.getURL()); + // return ip; + return null; + } +} + +/** + */ +public class DefaultContentHandlerFactory implements ContentHandlerFactory +{ + /** For now, hard code the list of types that we assume should + * be supported by the Toolkit. ClasspathToolkit should perhaps provide + * an API to express what Image MIME types the Toolkit understands. + */ + private static String[] known_image_types = + { + "image/bmp", + "image/gif", + "image/jpeg", + "image/png", + "image/tiff", + "image/x-portable-anymap", + "image/x-cmu-raster", + "image/x-xbitmap", + "image/x-xpixmap" + }; + + private static HashSet imageTypes + = new HashSet(Arrays.asList(known_image_types)); + + public ContentHandler createContentHandler(String mimeType) + { + if (imageTypes.contains(mimeType)) + return ImageHandler.instance; + // Currently, only image types are handled. + return null; + } +} diff --git a/libjava/classpath/gnu/java/net/DefaultProxySelector.java b/libjava/classpath/gnu/java/net/DefaultProxySelector.java new file mode 100644 index 000000000..f0215a054 --- /dev/null +++ b/libjava/classpath/gnu/java/net/DefaultProxySelector.java @@ -0,0 +1,80 @@ +/* DefaultProxySelector.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.java.net; + +import java.io.IOException; +import java.net.Proxy; +import java.net.ProxySelector; +import java.net.SocketAddress; +import java.net.URI; +import java.util.ArrayList; +import java.util.List; + +public final class DefaultProxySelector + extends ProxySelector +{ + private static final List proxies = new ArrayList(); + + static + { + // The default proxy selector supports only direct connections. + proxies.add(Proxy.NO_PROXY); + } + + public DefaultProxySelector() + { + // Do nothing by default. + } + + public void connectFailed(URI uri, SocketAddress sa, IOException ioe) + { + if (uri == null || sa == null || ioe == null) + throw new IllegalArgumentException(); + + // Do nothing by default. + } + + public List select(URI uri) + { + if (uri == null) + throw new IllegalArgumentException(); + + return proxies; + } +} diff --git a/libjava/classpath/gnu/java/net/EmptyX509TrustManager.java b/libjava/classpath/gnu/java/net/EmptyX509TrustManager.java new file mode 100644 index 000000000..466b49ef8 --- /dev/null +++ b/libjava/classpath/gnu/java/net/EmptyX509TrustManager.java @@ -0,0 +1,69 @@ +/* EmptyX509TrustManager.java -- + 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.net; + +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import javax.net.ssl.X509TrustManager; + +/** + * Empty implementation of an X509 trust manager. + * This implementation does not check any certificates in the chain. + * + * @author Chris Burdess (dog@gnu.org) + */ +public class EmptyX509TrustManager + implements X509TrustManager +{ + public void checkClientTrusted(X509Certificate[] chain, String authType) + throws CertificateException + { + } + + public void checkServerTrusted(X509Certificate[] chain, String authType) + throws CertificateException + { + } + + public X509Certificate[] getAcceptedIssuers() + { + return new X509Certificate[0]; + } +} diff --git a/libjava/classpath/gnu/java/net/GetLocalHostAction.java b/libjava/classpath/gnu/java/net/GetLocalHostAction.java new file mode 100644 index 000000000..1e18877de --- /dev/null +++ b/libjava/classpath/gnu/java/net/GetLocalHostAction.java @@ -0,0 +1,64 @@ +/* GetLocalHostAction.java -- + Copyright (C) 2003, 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.net; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.security.PrivilegedAction; + +/** + * Privileged action to retrieve the local host InetAddress. + * + * @author Chris Burdess (dog@gnu.org) + */ +public class GetLocalHostAction + implements PrivilegedAction +{ + public InetAddress run() + { + try + { + return InetAddress.getLocalHost(); + } + catch (UnknownHostException e) + { + return null; + } + } +} diff --git a/libjava/classpath/gnu/java/net/HeaderFieldHelper.java b/libjava/classpath/gnu/java/net/HeaderFieldHelper.java new file mode 100644 index 000000000..ca3b9d2dd --- /dev/null +++ b/libjava/classpath/gnu/java/net/HeaderFieldHelper.java @@ -0,0 +1,136 @@ +/* HeaderFieldHelper.java -- Helps manage headers fields + Copyright (C) 1998, 2003 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.net; + +import java.util.HashMap; +import java.util.Map; +import java.util.Vector; + +/** + * This class manages header field keys and values. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class HeaderFieldHelper +{ + private Vector headerFieldKeys; + private Vector headerFieldValues; + + public HeaderFieldHelper() + { + this (10); + } + + public HeaderFieldHelper (int size) + { + headerFieldKeys = new Vector (size); + headerFieldValues = new Vector (size); + } + + public void addHeaderField (String key, String value) + { + headerFieldKeys.addElement (key); + headerFieldValues.addElement (value); + } + + public String getHeaderFieldKeyByIndex (int index) + { + String key = null; + + try + { + key = headerFieldKeys.elementAt (index); + } + catch (ArrayIndexOutOfBoundsException e) + { + } + + return key; + } + + public String getHeaderFieldValueByIndex(int index) + { + String value = null; + + try + { + value = headerFieldValues.elementAt (index); + } + catch (ArrayIndexOutOfBoundsException e) + { + } + + return value; + } + + public String getHeaderFieldValueByKey(String key) + { + String value = null; + + try + { + value = headerFieldValues.elementAt(headerFieldKeys.indexOf(key)); + } + catch (ArrayIndexOutOfBoundsException e) + { + } + + return value; + } + + public Map getHeaderFields() + { + HashMap headers = new HashMap(); + int max = headerFieldKeys.size(); + + for (int index = 0; index < max; index++) + { + headers.put(headerFieldKeys.elementAt(index), + headerFieldValues.elementAt(index)); + } + + return headers; + } + + public int getNumberOfEntries() + { + return headerFieldKeys.size(); + } + +} // class HeaderFieldHelper diff --git a/libjava/classpath/gnu/java/net/IndexListParser.java b/libjava/classpath/gnu/java/net/IndexListParser.java new file mode 100644 index 000000000..bf274b172 --- /dev/null +++ b/libjava/classpath/gnu/java/net/IndexListParser.java @@ -0,0 +1,183 @@ +/* IndexListParser.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.java.net; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.URL; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.Set; +import java.util.jar.JarFile; + +/** + * The INDEX.LIST file contains sections each separated by a blank line. + * Each section defines the content of a jar, with a + * header defining the jar file path name, followed by a list of paths. + * The jar file paths are relative to the codebase of the root jar. + * + Specification + index file : version-info blankline section* + version-info : JarIndex-Version: version-number + version-number : digit+{.digit+}* + section : body blankline + body : header name* + header : char+.jar newline + name : char+ newline + + * @author langel at redhat dot com + */ +public class IndexListParser +{ + public static final String JAR_INDEX_FILE = "META-INF/INDEX.LIST"; + public static final String JAR_INDEX_VERSION_KEY = "JarIndex-Version: "; + + double versionNumber; + // Map each jar to the prefixes defined for the jar. + // This is intentionally kept in insertion order. + LinkedHashMap> prefixes + = new LinkedHashMap>(); + + /** + * Parses the given jarfile's INDEX.LIST file if it exists. + * + * @param jarfile - the given jar file + * @param baseJarURL - the codebase of the jar file + * @param baseURL - the base url for the headers + */ + public IndexListParser(JarFile jarfile, URL baseJarURL, URL baseURL) + { + try + { + // Parse INDEX.LIST if it exists + if (jarfile.getEntry(JAR_INDEX_FILE) != null) + { + BufferedReader br = new BufferedReader(new InputStreamReader(new URL(baseJarURL, + JAR_INDEX_FILE).openStream())); + + // Must start with version info + String line = br.readLine(); + if (!line.startsWith(JAR_INDEX_VERSION_KEY)) + return; + versionNumber = Double.parseDouble(line.substring(JAR_INDEX_VERSION_KEY.length()).trim()); + + // Blank line must be next + line = br.readLine(); + if (! "".equals(line)) + { + clearAll(); + return; + } + + // May contain sections. + while ((line = br.readLine()) != null) + { + URL jarURL = new URL(baseURL, line); + HashSet values = new HashSet(); + + // Read the names in the section. + while ((line = br.readLine()) != null) + { + // Stop at section boundary. + if ("".equals(line)) + break; + values.add(line.trim()); + } + prefixes.put(jarURL, values); + // Might have seen an early EOF. + if (line == null) + break; + } + + br.close(); + } + else + { + // INDEX.LIST does not exist + clearAll(); + } + } + catch (Exception ex) + { + clearAll(); + } + } + + /** + * Clears all the variables. This is called when parsing fails. + */ + void clearAll() + { + versionNumber = 0; + prefixes = null; + } + + /** + * Gets the version info for the file. + * + * @return the version info. + */ + public String getVersionInfo() + { + return JAR_INDEX_VERSION_KEY + getVersionNumber(); + } + + /** + * Gets the version number of the file. + * + * @return the version number. + */ + public double getVersionNumber() + { + return versionNumber; + } + + /** + * Gets the map of all the headers found in the file. + * The keys in the map are URLs of jars. The values in the map + * are Sets of package prefixes (and top-level file names), as + * specifed in INDEX.LIST. + * + * @return an map of all the headers, or null if no INDEX.LIST was found + */ + public LinkedHashMap> getHeaders() + { + return prefixes; + } +} diff --git a/libjava/classpath/gnu/java/net/LineInputStream.java b/libjava/classpath/gnu/java/net/LineInputStream.java new file mode 100644 index 000000000..8bd4b69cd --- /dev/null +++ b/libjava/classpath/gnu/java/net/LineInputStream.java @@ -0,0 +1,223 @@ +/* LineInputStream.java -- + Copyright (C) 2002, 2003, 2004, 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.java.net; + +import java.io.BufferedInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * An input stream that can read lines of input. + * + * @author Chris Burdess (dog@gnu.org) + */ +public class LineInputStream + extends InputStream +{ + + /** + * The underlying input stream. + */ + protected InputStream in; + + /* + * Line buffer. + */ + private ByteArrayOutputStream buf; + + /* + * Encoding to use when translating bytes to characters. + */ + private String encoding; + + /* + * End-of-stream flag. + */ + private boolean eof; + + /** + * Whether we can use block reads. + */ + private final boolean blockReads; + + /** + * Constructor using the US-ASCII character encoding. + * @param in the underlying input stream + */ + public LineInputStream(InputStream in) + { + this(in, "US-ASCII"); + } + + /** + * Constructor. + * @param in the underlying input stream + * @param encoding the character encoding to use + */ + public LineInputStream(InputStream in, String encoding) + { + this.in = in; + buf = new ByteArrayOutputStream(); + this.encoding = encoding; + eof = false; + // If it is already buffered, additional buffering gains nothing. + blockReads = !(in instanceof BufferedInputStream) && in.markSupported(); + } + + public int read() + throws IOException + { + return in.read(); + } + + public int read(byte[] buf) + throws IOException + { + return in.read(buf); + } + + public int read(byte[] buf, int off, int len) + throws IOException + { + return in.read(buf, off, len); + } + + /** + * Read a line of input. + */ + public String readLine() + throws IOException + { + if (eof) + { + return null; + } + do + { + if (blockReads) + { + // Use mark and reset to read chunks of bytes + final int MAX_LENGTH = 1024; + int len, pos; + + len = in.available(); + if (len == 0 || len > MAX_LENGTH) + len = MAX_LENGTH; + byte[] b = new byte[len]; + in.mark(len); + // Read into buffer b + len = in.read(b, 0, len); + // Handle EOF + if (len == -1) + { + eof = true; + if (buf.size() == 0) + { + return null; + } + else + { + // We don't care about resetting buf + return buf.toString(encoding); + } + } + // Get index of LF in b + pos = indexOf(b, len, (byte) 0x0a); + if (pos != -1) + { + // Write pos bytes to buf + buf.write(b, 0, pos); + // Reset stream, and read pos + 1 bytes + in.reset(); + pos += 1; + while (pos > 0) + { + len = in.read(b, 0, pos); + pos = (len == -1) ? -1 : pos - len; + } + // Return line + String ret = buf.toString(encoding); + buf.reset(); + return ret; + } + else + { + // Append everything to buf and fall through to re-read. + buf.write(b, 0, len); + } + } + else + { + // We must use character reads in order not to read too much + // from the underlying stream. + int c = in.read(); + switch (c) + { + case -1: + eof = true; + if (buf.size() == 0) + { + return null; + } + // Fall through and return contents of buffer. + case 0x0a: // LF + String ret = buf.toString(encoding); + buf.reset(); + return ret; + default: + buf.write(c); + } + } + } + while (true); + } + + private int indexOf(byte[] b, int len, byte c) + { + for (int pos = 0; pos < len; pos++) + { + if (b[pos] == c) + { + return pos; + } + } + return -1; + } +} diff --git a/libjava/classpath/gnu/java/net/PlainDatagramSocketImpl.java b/libjava/classpath/gnu/java/net/PlainDatagramSocketImpl.java new file mode 100644 index 000000000..639c9ff55 --- /dev/null +++ b/libjava/classpath/gnu/java/net/PlainDatagramSocketImpl.java @@ -0,0 +1,486 @@ +/* PlainDatagramSocketImpl.java -- Default DatagramSocket implementation + Copyright (C) 1998, 1999, 2001, 2003, 2004, 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.java.net; + +import gnu.java.nio.VMChannel; + +import java.io.IOException; +import java.io.InterruptedIOException; +import java.net.DatagramPacket; +import java.net.DatagramSocketImpl; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.NetworkInterface; +import java.net.SocketAddress; +import java.net.SocketException; +import java.net.SocketTimeoutException; +import java.nio.ByteBuffer; + +/** + * Written using on-line Java Platform 1.2 API Specification, as well + * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998). + * Status: Believed complete and correct. + */ + +/** + * This is the default socket implementation for datagram sockets. + * It makes native calls to C routines that implement BSD style + * SOCK_DGRAM sockets in the AF_INET family. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + */ +public final class PlainDatagramSocketImpl extends DatagramSocketImpl +{ + private final VMChannel channel; + + /** + * The platform-specific socket implementation. + */ + private final VMPlainSocketImpl impl; + + /** + * Lock object to serialize threads wanting to receive + */ + private final Object RECEIVE_LOCK = new Object(); + + /** + * Lock object to serialize threads wanting to send + */ + private final Object SEND_LOCK = new Object(); + + /** + * Default do nothing constructor + */ + public PlainDatagramSocketImpl() throws IOException + { + channel = new VMChannel(); + impl = new VMPlainSocketImpl(channel); + } + + /*protected void finalize() throws Throwable + { + synchronized (this) + { + if (channel.getState().isValid()) + close(); + } + super.finalize(); + }*/ + + /*public int getNativeFD() + { + return native_fd; + }*/ + + /** + * Binds this socket to a particular port and interface + * + * @param port The port to bind to + * @param addr The address to bind to + * + * @exception SocketException If an error occurs + */ + protected synchronized void bind(int port, InetAddress addr) + throws SocketException + { + try + { + impl.bind(new InetSocketAddress(addr, port)); + } + catch (SocketException se) + { + throw se; + } + catch (IOException ioe) + { + SocketException se = new SocketException(); + se.initCause(ioe); + throw se; + } + } + + /** + * Creates a new datagram socket + * + * @exception SocketException If an error occurs + */ + protected synchronized void create() throws SocketException + { + try + { + channel.initSocket(false); + } + catch (SocketException se) + { + throw se; + } + catch (IOException ioe) + { + SocketException se = new SocketException(); + se.initCause(ioe); + throw se; + } + } + + /** + * Connects to the remote address and port specified as arguments. + * + * @param addr The remote address to connect to + * @param port The remote port to connect to + * + * @exception SocketException If an error occurs + */ + protected void connect(InetAddress addr, int port) throws SocketException + { + channel.connect(new InetSocketAddress(addr, port), 0); + } + + /** + * Disconnects the socket. + * + * @since 1.4 + */ + protected void disconnect() + { + synchronized (this) + { + try + { + if (channel.getState().isValid()) + channel.disconnect(); + } + catch (IOException ioe) + { + } + } + } + + /** + * Sets the Time to Live value for the socket + * + * @param ttl The new TTL value + * + * @exception IOException If an error occurs + */ + protected synchronized void setTimeToLive(int ttl) throws IOException + { + impl.setTimeToLive(ttl); + } + + /** + * Gets the Time to Live value for the socket + * + * @return The TTL value + * + * @exception IOException If an error occurs + */ + protected synchronized int getTimeToLive() throws IOException + { + return impl.getTimeToLive(); + } + + protected int getLocalPort() + { + if (channel == null) + return -1; + + try + { + InetSocketAddress local = channel.getLocalAddress(); + if (local == null) + return -1; + return local.getPort(); + } + catch (IOException ioe) + { + return -1; + } + } + + /** + * Sends a packet of data to a remote host + * + * @param packet The packet to send + * + * @exception IOException If an error occurs + */ + protected void send(DatagramPacket packet) throws IOException + { + synchronized (SEND_LOCK) + { + ByteBuffer buf = ByteBuffer.wrap(packet.getData(), + packet.getOffset(), + packet.getLength()); + InetAddress remote = packet.getAddress(); + int port = packet.getPort(); + if (remote == null) + throw new NullPointerException(); + if (port <= 0) + throw new SocketException("invalid port " + port); + while (true) + { + try + { + channel.send(buf, new InetSocketAddress(remote, port)); + break; + } + catch (InterruptedIOException ioe) + { + // Ignore; interrupted system call. + } + } + } + } + + /** + * Receives a UDP packet from the network + * + * @param packet The packet to fill in with the data received + * + * @exception IOException IOException If an error occurs + */ + protected void receive(DatagramPacket packet) + throws IOException + { + synchronized(RECEIVE_LOCK) + { + ByteBuffer buf = ByteBuffer.wrap(packet.getData(), + packet.getOffset(), + packet.getLength()); + SocketAddress addr = null; + while (true) + { + try + { + addr = channel.receive(buf); + break; + } + catch (SocketTimeoutException ste) + { + throw ste; + } + catch (InterruptedIOException iioe) + { + // Ignore. Loop. + } + } + if (addr != null) + packet.setSocketAddress(addr); + packet.setLength(buf.position() - packet.getOffset()); + } + } + + + /** + * Sets the value of an option on the socket + * + * @param optionId The identifier of the option to set + * @param value The value of the option to set + * + * @exception SocketException If an error occurs + */ + public synchronized void setOption(int optionId, Object value) + throws SocketException + { + switch (optionId) + { + case IP_MULTICAST_IF: + case IP_MULTICAST_IF2: + impl.setMulticastInterface(optionId, (InetAddress) value); + break; + + case IP_MULTICAST_LOOP: + case SO_BROADCAST: + case SO_KEEPALIVE: + case SO_OOBINLINE: + case TCP_NODELAY: + case IP_TOS: + case SO_LINGER: + case SO_RCVBUF: + case SO_SNDBUF: + case SO_TIMEOUT: + case SO_REUSEADDR: + impl.setOption(optionId, value); + return; + + default: + throw new SocketException("cannot set option " + optionId); + } + } + + /** + * Retrieves the value of an option on the socket + * + * @param optionId The identifier of the option to retrieve + * + * @return The value of the option + * + * @exception SocketException If an error occurs + */ + public synchronized Object getOption(int optionId) + throws SocketException + { + if (optionId == SO_BINDADDR) + { + try + { + InetSocketAddress local = channel.getLocalAddress(); + if (local == null) + return null; + return local.getAddress(); + } + catch (SocketException se) + { + throw se; + } + catch (IOException ioe) + { + SocketException se = new SocketException(); + se.initCause(ioe); + throw se; + } + } + if (optionId == IP_MULTICAST_IF || optionId == IP_MULTICAST_IF2) + return impl.getMulticastInterface(optionId); + + return impl.getOption(optionId); + } + + /** + * Closes the socket + */ + protected synchronized void close() + { + try + { + if (channel.getState().isValid()) + channel.close(); + } + catch (IOException ioe) + { + } + } + + /** + * Gets the Time to Live value for the socket + * + * @return The TTL value + * + * @exception IOException If an error occurs + * + * @deprecated 1.2 + */ + protected synchronized byte getTTL() throws IOException + { + return (byte) getTimeToLive(); + } + + /** + * Sets the Time to Live value for the socket + * + * @param ttl The new TTL value + * + * @exception IOException If an error occurs + * + * @deprecated 1.2 + */ + protected synchronized void setTTL(byte ttl) throws IOException + { + setTimeToLive(((int) ttl) & 0xFF); + } + + /** + * Joins a multicast group + * + * @param addr The group to join + * + * @exception IOException If an error occurs + */ + protected synchronized void join(InetAddress addr) throws IOException + { + impl.join(addr); + } + + /** + * Leaves a multicast group + * + * @param addr The group to leave + * + * @exception IOException If an error occurs + */ + protected synchronized void leave(InetAddress addr) throws IOException + { + impl.leave(addr); + } + + /** + * What does this method really do? + */ + protected synchronized int peek(InetAddress addr) throws IOException + { + throw new IOException("Not Implemented Yet"); + } + + public int peekData(DatagramPacket packet) + { + throw new InternalError + ("PlainDatagramSocketImpl::peekData is not implemented"); + } + + public void joinGroup(SocketAddress address, NetworkInterface netIf) + throws IOException + { + if (address == null) + throw new NullPointerException(); + if (!(address instanceof InetSocketAddress)) + throw new SocketException("unknown address type"); + impl.joinGroup((InetSocketAddress) address, netIf); + } + + public void leaveGroup(SocketAddress address, NetworkInterface netIf) + throws IOException + { + if (address == null) + throw new NullPointerException(); + if (!(address instanceof InetSocketAddress)) + throw new SocketException("unknown address type"); + impl.leaveGroup((InetSocketAddress) address, netIf); + } +} diff --git a/libjava/classpath/gnu/java/net/PlainSocketImpl.java b/libjava/classpath/gnu/java/net/PlainSocketImpl.java new file mode 100644 index 000000000..72db53186 --- /dev/null +++ b/libjava/classpath/gnu/java/net/PlainSocketImpl.java @@ -0,0 +1,678 @@ +/* PlainSocketImpl.java -- Default socket implementation + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 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.java.net; + +import gnu.java.nio.SocketChannelImpl; +import gnu.java.nio.VMChannel; + +import java.io.InputStream; +import java.io.IOException; +import java.io.InterruptedIOException; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.net.SocketException; +import java.net.SocketImpl; +import java.net.SocketTimeoutException; +import java.nio.ByteBuffer; + +/** + * Written using on-line Java Platform 1.2 API Specification, as well + * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998). + * Status: Believed complete and correct. + */ + +/** + * Unless the application installs its own SocketImplFactory, this is the + * default socket implemetation that will be used. It simply uses a + * combination of Java and native routines to implement standard BSD + * style sockets of family AF_INET and types SOCK_STREAM and SOCK_DGRAM + * + * @author Per Bothner (bothner@cygnus.com) + * @author Nic Ferrier (nferrier@tapsellferrier.co.uk) + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class PlainSocketImpl extends SocketImpl +{ + + /** + * The underlying plain socket VM implementation. + */ + protected VMPlainSocketImpl impl; + + /** + * A cached copy of the in stream for reading from the socket. + */ + private InputStream in; + + /** + * A cached copy of the out stream for writing to the socket. + */ + private OutputStream out; + + /** + * Indicates whether a channel initiated whatever operation + * is being invoked on this socket. + */ + private boolean inChannelOperation; + + /** + * The socket channel we use for IO operation. Package-private for + * use by inner classes. + */ + SocketChannelImpl channel; + + /** + * Indicates whether we should ignore whether any associated + * channel is set to non-blocking mode. Certain operations + * throw an IllegalBlockingModeException if the + * associated channel is in non-blocking mode, except + * if the operation is invoked by the channel itself. + */ + public final boolean isInChannelOperation() + { + return inChannelOperation; + } + + /** + * Sets our indicator of whether an I/O operation is being + * initiated by a channel. + */ + public final void setInChannelOperation(boolean b) + { + inChannelOperation = b; + } + + /** + * Default do nothing constructor. + */ + public PlainSocketImpl() + { + this.impl = new VMPlainSocketImpl(); + } + + /** + * Sets the specified option on a socket to the passed in object. For + * options that take an integer argument, the passed in object is an + * Integer. The option_id parameter is one of the defined constants in + * this interface. + * + * @param optionId The identifier of the option + * @param value The value to set the option to + * + * @throws SocketException if an error occurs + */ + public void setOption(int optionId, Object value) throws SocketException + { + switch (optionId) + { + case SO_LINGER: + case IP_MULTICAST_LOOP: + case SO_BROADCAST: + case SO_KEEPALIVE: + case SO_OOBINLINE: + case TCP_NODELAY: + case IP_TOS: + case SO_RCVBUF: + case SO_SNDBUF: + case SO_TIMEOUT: + case SO_REUSEADDR: + impl.setOption(optionId, value); + return; + default: + throw new SocketException("Unrecognized TCP option: " + optionId); + } + } + + /** + * Returns the current setting of the specified option. The Object returned + * will be an Integer for options that have integer values. The option_id + * is one of the defined constants in this interface. + * + * @param optionId the option identifier + * + * @return the current value of the option + * + * @throws SocketException if an error occurs + */ + public Object getOption(int optionId) throws SocketException + { + if (optionId == SO_BINDADDR) + { + try + { + return channel.getVMChannel().getLocalAddress().getAddress(); + } + catch (IOException ioe) + { + SocketException se = new SocketException(); + se.initCause(ioe); + throw se; + } + } + + // This filters options which are invalid for TCP. + switch (optionId) + { + case SO_LINGER: + case IP_MULTICAST_LOOP: + case SO_BROADCAST: + case SO_KEEPALIVE: + case SO_OOBINLINE: + case TCP_NODELAY: + case IP_TOS: + case SO_RCVBUF: + case SO_SNDBUF: + case SO_TIMEOUT: + case SO_REUSEADDR: + return impl.getOption(optionId); + default: + throw new SocketException("Unrecognized TCP option: " + optionId); + } + + } + + public void shutdownInput() throws IOException + { + impl.shutdownInput(); + } + + public void shutdownOutput() throws IOException + { + impl.shutdownOutput(); + } + + /** + * Creates a new socket that is not bound to any local address/port and + * is not connected to any remote address/port. The stream parameter will be + * ignored since PlainSocketImpl always is a stream socket. Datagram sockets + * are handled by PlainDatagramSocketImpl. + * + * @param stream true for stream sockets, false for + * datagram sockets + */ + protected synchronized void create(boolean stream) throws IOException + { + channel = new SocketChannelImpl(false); + VMChannel vmchannel = channel.getVMChannel(); + vmchannel.initSocket(stream); + channel.configureBlocking(true); + impl.getState().setChannelFD(vmchannel.getState()); + } + + /** + * Connects to the remote hostname and port specified as arguments. + * + * @param hostname the remote hostname to connect to + * @param port the remote port to connect to + * + * @throws IOException If an error occurs + */ + protected synchronized void connect(String hostname, int port) + throws IOException + { + connect(InetAddress.getByName(hostname), port); + } + + /** + * Connects to the remote address and port specified as arguments. + * + * @param addr the remote address to connect to + * @param port the remote port to connect to + * + * @throws IOException If an error occurs + */ + protected void connect(InetAddress addr, int port) throws IOException + { + connect(new InetSocketAddress(addr, port), 0); + } + + /** + * Connects to the remote socket address with a specified timeout. + * + * @param address the remote address to connect to + * @param timeout the timeout to use for this connect, 0 means infinite. + * + * @throws IOException If an error occurs + */ + protected synchronized void connect(SocketAddress address, int timeout) + throws IOException + { + if (channel == null) + create(true); + boolean connected = channel.connect(address, timeout); + if (!connected) + throw new SocketTimeoutException("connect timed out"); + + // Using the given SocketAddress is important to preserve + // hostnames given by the caller. + InetSocketAddress addr = (InetSocketAddress) address; + this.address = addr.getAddress(); + this.port = addr.getPort(); + } + + /** + * Binds to the specified port on the specified addr. Note that this addr + * must represent a local IP address. **** How bind to INADDR_ANY? **** + * + * @param addr the address to bind to + * @param port the port number to bind to + * + * @throws IOException if an error occurs + */ + protected synchronized void bind(InetAddress addr, int port) + throws IOException + { + if (channel == null) + create(true); + impl.bind(new InetSocketAddress(addr, port)); + localport = channel.getVMChannel().getLocalAddress().getPort(); + } + + /** + * Starts listening for connections on a socket. The queuelen parameter + * is how many pending connections will queue up waiting to be serviced + * before being accept'ed. If the queue of pending requests exceeds this + * number, additional connections will be refused. + * + * @param queuelen The length of the pending connection queue + * + * @throws IOException If an error occurs + */ + protected synchronized void listen(int queuelen) + throws IOException + { + impl.listen(queuelen); + } + + /** + * Accepts a new connection on this socket and returns in in the + * passed in SocketImpl. + * + * @param impl The SocketImpl object to accept this connection. + */ + protected synchronized void accept(SocketImpl impl) + throws IOException + { + if (channel == null) + create(true); + if (!(impl instanceof PlainSocketImpl)) + throw new IOException("incompatible SocketImpl: " + + impl.getClass().getName()); + PlainSocketImpl that = (PlainSocketImpl) impl; + VMChannel c = channel.getVMChannel().accept(); + that.impl.getState().setChannelFD(c.getState()); + that.channel = new SocketChannelImpl(c); + that.setOption(SO_REUSEADDR, Boolean.TRUE); + // Reset the inherited timeout. + that.setOption(SO_TIMEOUT, Integer.valueOf(0)); + + } + + /** + * Returns the number of bytes that the caller can read from this socket + * without blocking. + * + * @return the number of readable bytes before blocking + * + * @throws IOException if an error occurs + */ + protected int available() throws IOException + { + if (channel == null) + throw new SocketException("not connected"); + return channel.getVMChannel().available(); + } + + /** + * Closes the socket. This will cause any InputStream or OutputStream + * objects for this Socket to be closed as well. + * + *

+ * Note that if the SO_LINGER option is set on this socket, then the + * operation could block. + *

+ * + * @throws IOException if an error occurs + */ + protected void close() throws IOException + { + if (impl.getState().isValid()) + impl.close(); + + address = null; + port = -1; + } + + public void sendUrgentData(int data) throws IOException + { + impl.sendUrgentData(data); + } + + /** + * Returns an InputStream object for reading from this socket. This will + * be an instance of SocketInputStream. + * + * @return An input stream attached to the socket. + * + * @exception IOException If an error occurs + */ + protected synchronized InputStream getInputStream() throws IOException + { + if (in == null) + in = new SocketInputStream(); + + return in; + } + + /** + * Returns an OutputStream object for writing to this socket. This will + * be an instance of SocketOutputStream. + * + * @return An output stream attached to the socket. + * + * @exception IOException If an error occurs + */ + protected synchronized OutputStream getOutputStream() throws IOException + { + if (out == null) + out = new SocketOutputStream(); + + return out; + } + + public VMChannel getVMChannel() + { + if (channel == null) + return null; + return channel.getVMChannel(); + } + + /* (non-Javadoc) + * @see java.net.SocketImpl#getInetAddress() + */ + protected InetAddress getInetAddress() + { + if (channel == null) + return null; + + try + { + InetSocketAddress remote = channel.getVMChannel().getPeerAddress(); + if (remote == null) + return null; + // To mimic behavior of the RI the InetAddress instance which was + // used to establish the connection is returned instead of one that + // was created by the native layer (this preserves exact hostnames). + if (address != null) + return address; + + return remote.getAddress(); + } + catch (IOException ioe) + { + return null; + } + } + + /* (non-Javadoc) + * @see java.net.SocketImpl#getLocalPort() + */ + protected int getLocalPort() + { + if (channel == null) + return -1; + try + { + InetSocketAddress local = channel.getVMChannel().getLocalAddress(); + if (local == null) + return -1; + return local.getPort(); + } + catch (IOException ioe) + { + return -1; + } + } + + public InetSocketAddress getLocalAddress() + { + if (channel == null) + return null; + try + { + return channel.getVMChannel().getLocalAddress(); + } + catch (IOException ioe) + { + return null; + } + } + + /* (non-Javadoc) + * @see java.net.SocketImpl#getPort() + */ + protected int getPort() + { + if (channel == null) + return -1; + + try + { + InetSocketAddress remote = channel.getVMChannel().getPeerAddress(); + if (remote == null) + return -1; + return remote.getPort(); + } + catch (IOException ioe) + { + return -1; + } + } + + /** + * This class contains an implementation of InputStream for + * sockets. It in an internal only class used by PlainSocketImpl. + * + * @author Nic Ferrier + */ + final class SocketInputStream + extends InputStream + { + /** + * Returns the number of bytes available to be read before blocking + */ + public int available() throws IOException + { + return PlainSocketImpl.this.available(); + } + + /** + * This method not only closes the stream, it closes the underlying socket + * (and thus any connection) and invalidates any other Input/Output streams + * for the underlying impl object + */ + public void close() throws IOException + { + PlainSocketImpl.this.close(); + } + + /** + * Reads the next byte of data and returns it as an int. + * + * @return The byte read (as an int) or -1 if end of stream); + * + * @exception IOException If an error occurs. + */ + public int read() throws IOException + { + if (channel == null) + throw new SocketException("not connected"); + while (true) + { + try + { + return channel.getVMChannel().read(); + } + catch (SocketTimeoutException ste) + { + throw ste; + } + catch (InterruptedIOException iioe) + { + // Ignore; NIO may throw this; net io shouldn't + } + } + } + + /** + * Reads up to len bytes of data into the caller supplied buffer starting + * at offset bytes from the start of the buffer + * + * @param buf The buffer + * @param offset Offset into the buffer to start reading from + * @param len The number of bytes to read + * + * @return The number of bytes actually read or -1 if end of stream + * + * @exception IOException If an error occurs. + */ + public int read (byte[] buf, int offset, int len) throws IOException + { + if (channel == null) + throw new SocketException("not connected"); + ByteBuffer b = ByteBuffer.wrap(buf, offset, len); + while (true) + { + try + { + return channel.read(b); + } + catch (SocketTimeoutException ste) + { + throw ste; + } + catch (InterruptedIOException iioe) + { + // Ignored; NIO may throw this; net IO not. + } + } + } + } + + /** + * This class is used internally by PlainSocketImpl to be the + * OutputStream subclass returned by its + * getOutputStream method. It expects only to be used in that + * context. + * + * @author Nic Ferrier + */ + final class SocketOutputStream + extends OutputStream + { + /** + * This method closes the stream and the underlying socket connection. This + * action also effectively closes any other InputStream or OutputStream + * object associated with the connection. + * + * @exception IOException If an error occurs + */ + public void close() throws IOException + { + PlainSocketImpl.this.close(); + } + + /** + * Writes a byte (passed in as an int) to the given output stream + * + * @param b The byte to write + * + * @exception IOException If an error occurs + */ + public void write(int b) throws IOException + { + if (channel == null) + throw new SocketException("not connected"); + while (true) + { + try + { + channel.getVMChannel().write(b); + return; + } + catch (InterruptedIOException iioe) + { + // Ignored. + } + } + } + + /** + * Writes len number of bytes from the array buf to the stream starting + * at offset bytes into the buffer. + * + * @param buf The buffer + * @param offset Offset into the buffer to start writing from + * @param len The number of bytes to write + * + * @exception IOException If an error occurs. + */ + public void write (byte[] buf, int offset, int len) throws IOException + { + if (channel == null) + throw new SocketException("not connected"); + ByteBuffer b = ByteBuffer.wrap(buf, offset, len); + while (b.hasRemaining()) + { + try + { + if (channel.write(b) == -1) + throw new IOException("channel has been closed"); + } + catch (InterruptedIOException iioe) + { + // Ignored. + } + } + } + } +} diff --git a/libjava/classpath/gnu/java/net/URLParseError.java b/libjava/classpath/gnu/java/net/URLParseError.java new file mode 100644 index 000000000..90907480f --- /dev/null +++ b/libjava/classpath/gnu/java/net/URLParseError.java @@ -0,0 +1,57 @@ +/* URLParseError.java -- Helps bypassing the exception limitation for + URLStreamHandler.parseURL(). + Copyright (C) 2003 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.net; + +/** + * This class helps the people writing protocols to report URL parse + * errors in parseUrl as this method cannot report other exceptions + * than Errors. + * + * The main drawback is that it uses the Error mechanism which should not + * be used for that type of error reporting. + * + * @author Guilhem Lavaux (guilhem@kaffe.org) + */ +public class URLParseError extends Error +{ + public URLParseError(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/gnu/java/net/loader/FileResource.java b/libjava/classpath/gnu/java/net/loader/FileResource.java new file mode 100644 index 000000000..471584023 --- /dev/null +++ b/libjava/classpath/gnu/java/net/loader/FileResource.java @@ -0,0 +1,82 @@ +/* FileResource.java -- a Resource for file URLs + 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.net.loader; + + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; + +public final class FileResource extends Resource +{ + final File file; + + public FileResource(FileURLLoader loader, File file) + { + super(loader); + this.file = file; + } + + public InputStream getInputStream() throws IOException + { + return new FileInputStream(file); + } + + public int getLength() + { + return (int) file.length(); + } + + public URL getURL() + { + try + { + return file.toURL(); + } + catch (MalformedURLException e) + { + InternalError ie = new InternalError(); + ie.initCause(e); + throw ie; + } + } +} diff --git a/libjava/classpath/gnu/java/net/loader/FileURLLoader.java b/libjava/classpath/gnu/java/net/loader/FileURLLoader.java new file mode 100644 index 000000000..58b6dcf05 --- /dev/null +++ b/libjava/classpath/gnu/java/net/loader/FileURLLoader.java @@ -0,0 +1,145 @@ +/* FileURLLoader.java -- a URLLoader for file URLs + 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.net.loader; + + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.net.URLStreamHandlerFactory; +import java.util.StringTokenizer; + +/** + * A FileURLLoader is a type of URLLoader + * only loading from file url. + */ +public final class FileURLLoader extends URLLoader +{ + File dir; //the file for this file url + + public FileURLLoader(URLClassLoader classloader, + URLStreamHandlerCache cache, + URLStreamHandlerFactory factory, + URL url, URL absoluteUrl) + { + super(classloader, cache, factory, url, absoluteUrl); + dir = new File(absoluteUrl.getFile()); + } + + /** get resource with the name "name" in the file url */ + public Resource getResource(String name) + { + try + { + // Make sure that all components in name are valid by walking through + // them + File file = walkPathComponents(name); + + if (file == null) + return null; + + return new FileResource(this, file); + } + catch (IOException e) + { + // Fall through... + } + return null; + } + + /** + * Walk all path tokens and check them for validity. At no moment, we are + * allowed to reach a directory located "above" the root directory, stored + * in "dir" property. We are also not allowed to enter a non existing + * directory or a non directory component (plain file, symbolic link, ...). + * An empty or null path is valid. Pathnames components are separated by + * File.separatorChar + * + * @param resourceFileName the name to be checked for validity. + * @return the canonical file pointed by the resourceFileName or null if the + * walking failed + * @throws IOException in case of issue when creating the canonical + * resulting file + * @see File#separatorChar + */ + private File walkPathComponents(String resourceFileName) throws IOException + { + StringTokenizer stringTokenizer = new StringTokenizer(resourceFileName, File.separator); + File currentFile = dir; + int tokenCount = stringTokenizer.countTokens(); + + for (int i = 0; i < tokenCount - 1; i++) + { + String currentToken = stringTokenizer.nextToken(); + + // If we are at the root directory and trying to go up, the walking is + // finished with an error + if ("..".equals(currentToken) && currentFile.equals(dir)) + return null; + + currentFile = new File(currentFile, currentToken); + + // If the current file doesn't exist or is not a directory, the walking is + // finished with an error + if (! (currentFile.exists() && currentFile.isDirectory())) + return null; + + } + + // Treat the last token differently, if it exists, because it does not need + // to be a directory + if (tokenCount > 0) + { + String currentToken = stringTokenizer.nextToken(); + + if ("..".equals(currentToken) && currentFile.equals(dir)) + return null; + + currentFile = new File(currentFile, currentToken); + + // If the current file doesn't exist, the walking is + // finished with an error + if (! currentFile.exists()) + return null; + } + + return currentFile.getCanonicalFile(); + } +} diff --git a/libjava/classpath/gnu/java/net/loader/JarURLLoader.java b/libjava/classpath/gnu/java/net/loader/JarURLLoader.java new file mode 100644 index 000000000..6f06ad3b2 --- /dev/null +++ b/libjava/classpath/gnu/java/net/loader/JarURLLoader.java @@ -0,0 +1,215 @@ +package gnu.java.net.loader; + +import gnu.java.net.IndexListParser; + +import java.io.IOException; +import java.net.JarURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.net.URLStreamHandlerFactory; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.Manifest; + +/** + * A JarURLLoader is a type of URLLoader + * only loading from jar url. + */ +public final class JarURLLoader extends URLLoader +{ + // True if we've initialized -- i.e., tried open the jar file. + boolean initialized; + // The jar file for this url. + JarFile jarfile; + // Base jar: url for all resources loaded from jar. + final URL baseJarURL; + // The "Class-Path" attribute of this Jar's manifest. + ArrayList classPath; + // If not null, a mapping from INDEX.LIST for this jar only. + // This is a set of all prefixes and top-level files that + // ought to be available in this jar. + Set indexSet; + + // This constructor is used internally. It purposely does not open + // the jar file -- it defers this until later. This allows us to + // implement INDEX.LIST lazy-loading semantics. + private JarURLLoader(URLClassLoader classloader, URLStreamHandlerCache cache, + URLStreamHandlerFactory factory, + URL baseURL, URL absoluteUrl, + Set indexSet) + { + super(classloader, cache, factory, baseURL, absoluteUrl); + + URL newBaseURL = null; + try + { + // Cache url prefix for all resources in this jar url. + String base = baseURL.toExternalForm() + "!/"; + newBaseURL = new URL("jar", "", -1, base, cache.get(factory, "jar")); + } + catch (MalformedURLException ignore) + { + // Ignore. + } + this.baseJarURL = newBaseURL; + this.classPath = null; + this.indexSet = indexSet; + } + + // This constructor is used by URLClassLoader. It will immediately + // try to read the jar file, in case we've found an index or a class-path + // setting. FIXME: it would be nice to defer this as well, but URLClassLoader + // makes this hard. + public JarURLLoader(URLClassLoader classloader, URLStreamHandlerCache cache, + URLStreamHandlerFactory factory, + URL baseURL, URL absoluteUrl) + { + this(classloader, cache, factory, baseURL, absoluteUrl, null); + initialize(); + } + + private void initialize() + { + JarFile jarfile = null; + try + { + jarfile = + ((JarURLConnection) baseJarURL.openConnection()).getJarFile(); + + Manifest manifest; + Attributes attributes; + String classPathString; + + IndexListParser parser = new IndexListParser(jarfile, baseJarURL, + baseURL); + LinkedHashMap> indexMap = parser.getHeaders(); + if (indexMap != null) + { + // Note that the index also computes + // the resulting Class-Path -- there are jars out there + // where the index lists some required jars which do + // not appear in the Class-Path attribute in the manifest. + this.classPath = new ArrayList(); + Iterator>> it = indexMap.entrySet().iterator(); + while (it.hasNext()) + { + Map.Entry> entry = it.next(); + URL subURL = entry.getKey(); + Set prefixes = entry.getValue(); + if (subURL.equals(baseURL)) + this.indexSet = prefixes; + else + { + JarURLLoader subLoader = new JarURLLoader(classloader, + cache, + factory, subURL, + subURL, + prefixes); + // Note that we don't care if the sub-loader itself has an + // index or a class-path -- only the top-level jar + // file gets this treatment; its index should cover + // everything. + this.classPath.add(subLoader); + } + } + } + else if ((manifest = jarfile.getManifest()) != null + && (attributes = manifest.getMainAttributes()) != null + && ((classPathString + = attributes.getValue(Attributes.Name.CLASS_PATH)) + != null)) + { + this.classPath = new ArrayList(); + StringTokenizer st = new StringTokenizer(classPathString, " "); + while (st.hasMoreElements ()) + { + String e = st.nextToken (); + try + { + URL subURL = new URL(baseURL, e); + // We've seen at least one jar file whose Class-Path + // attribute includes the original jar. If we process + // that normally we end up with infinite recursion. + if (subURL.equals(baseURL)) + continue; + JarURLLoader subLoader = new JarURLLoader(classloader, + cache, factory, + subURL, subURL); + this.classPath.add(subLoader); + ArrayList extra = subLoader.getClassPath(); + if (extra != null) + this.classPath.addAll(extra); + } + catch (java.net.MalformedURLException xx) + { + // Give up + } + } + } + } + catch (IOException ioe) + { + /* ignored */ + } + + this.jarfile = jarfile; + this.initialized = true; + } + + /** get resource with the name "name" in the jar url */ + public Resource getResource(String name) + { + if (name.startsWith("/")) + name = name.substring(1); + if (indexSet != null) + { + // Trust the index. + String basename = name; + int offset = basename.lastIndexOf('/'); + if (offset != -1) + basename = basename.substring(0, offset); + if (! indexSet.contains(basename)) + return null; + // FIXME: if the index claim to hold the resource, and jar file + // doesn't have it, we're supposed to throw an exception. However, + // in our model this is tricky to implement, as another URLLoader from + // the same top-level jar may have an overlapping index entry. + } + + if (! initialized) + initialize(); + if (jarfile == null) + return null; + + JarEntry je = jarfile.getJarEntry(name); + if (je != null) + return new JarURLResource(this, name, je); + else + return null; + } + + public Manifest getManifest() + { + try + { + return (jarfile == null) ? null : jarfile.getManifest(); + } + catch (IOException ioe) + { + return null; + } + } + + public ArrayList getClassPath() + { + return classPath; + } +} diff --git a/libjava/classpath/gnu/java/net/loader/JarURLResource.java b/libjava/classpath/gnu/java/net/loader/JarURLResource.java new file mode 100644 index 000000000..1dec92fd3 --- /dev/null +++ b/libjava/classpath/gnu/java/net/loader/JarURLResource.java @@ -0,0 +1,94 @@ +/* JarURLResource.java -- a Resource for jar URLs + 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.net.loader; + + +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.security.cert.Certificate; +import java.util.jar.JarEntry; + +public final class JarURLResource extends Resource +{ + private final JarEntry entry; + private final String name; + + public JarURLResource(JarURLLoader loader, String name, JarEntry entry) + { + super(loader); + this.entry = entry; + this.name = name; + } + + public InputStream getInputStream() throws IOException + { + return ((JarURLLoader) loader).jarfile.getInputStream(entry); + } + + public int getLength() + { + return (int) entry.getSize(); + } + + public Certificate[] getCertificates() + { + // We have to get the entry from the jar file again, because the + // certificates will not be available until the entire entry has + // been read. + return ((JarEntry) ((JarURLLoader) loader).jarfile.getEntry(name)) + .getCertificates(); + } + + public URL getURL() + { + try + { + return new URL(((JarURLLoader) loader).baseJarURL, name, + loader.cache.get(loader.factory, "jar")); + } + catch (MalformedURLException e) + { + InternalError ie = new InternalError(); + ie.initCause(e); + throw ie; + } + } +} diff --git a/libjava/classpath/gnu/java/net/loader/RemoteResource.java b/libjava/classpath/gnu/java/net/loader/RemoteResource.java new file mode 100644 index 000000000..dc33b6636 --- /dev/null +++ b/libjava/classpath/gnu/java/net/loader/RemoteResource.java @@ -0,0 +1,78 @@ +/* Resource.java -- a Resource for "remote" URLs + 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.net.loader; + + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + +/** + * A resource from some remote location. + */ +public final class RemoteResource extends Resource +{ + private final URL url; + private final InputStream stream; + final int length; + + public RemoteResource(RemoteURLLoader loader, String name, URL url, + InputStream stream, int length) + { + super(loader); + this.url = url; + this.stream = stream; + this.length = length; + } + + public InputStream getInputStream() throws IOException + { + return stream; + } + + public int getLength() + { + return length; + } + + public URL getURL() + { + return url; + } +} diff --git a/libjava/classpath/gnu/java/net/loader/RemoteURLLoader.java b/libjava/classpath/gnu/java/net/loader/RemoteURLLoader.java new file mode 100644 index 000000000..81ef34f9e --- /dev/null +++ b/libjava/classpath/gnu/java/net/loader/RemoteURLLoader.java @@ -0,0 +1,101 @@ +/* RemoteURLLoader.java -- a URLLoader for "remote" objects + 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.net.loader; + + +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLClassLoader; +import java.net.URLConnection; +import java.net.URLStreamHandlerFactory; + +/** + * Loader for remote directories. + */ +public final class RemoteURLLoader extends URLLoader +{ + private final String protocol; + + public RemoteURLLoader(URLClassLoader classloader, + URLStreamHandlerCache cache, + URLStreamHandlerFactory factory, + URL url) + { + super(classloader, cache, factory, url); + protocol = url.getProtocol(); + } + + /** + * Get a remote resource. + * Returns null if no such resource exists. + */ + public Resource getResource(String name) + { + try + { + URL url = new URL(baseURL, name, cache.get(factory, protocol)); + URLConnection connection = url.openConnection(); + + // Open the connection and check the stream + // just to be sure it exists. + int length = connection.getContentLength(); + InputStream stream = connection.getInputStream(); + + // We can do some extra checking if it is a http request + if (connection instanceof HttpURLConnection) + { + int response = + ((HttpURLConnection) connection).getResponseCode(); + if (response / 100 != 2) + return null; + } + + if (stream != null) + return new RemoteResource(this, name, url, stream, length); + else + return null; + } + catch (IOException ioe) + { + return null; + } + } +} diff --git a/libjava/classpath/gnu/java/net/loader/Resource.java b/libjava/classpath/gnu/java/net/loader/Resource.java new file mode 100644 index 000000000..53720b039 --- /dev/null +++ b/libjava/classpath/gnu/java/net/loader/Resource.java @@ -0,0 +1,110 @@ +/* Resource.java -- a resource for URLLoader + 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.net.loader; + + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.security.CodeSource; +import java.security.cert.Certificate; + +/** + * A Resource represents a resource in some + * URLLoader. It also contains all information (e.g., + * URL, CodeSource, Manifest and + * InputStream) that is necessary for loading resources + * and creating classes from a URL. + */ +public abstract class Resource +{ + final URLLoader loader; + + public Resource(URLLoader loader) + { + this.loader = loader; + } + + /** + * Returns the non-null CodeSource associated with + * this resource. + */ + public CodeSource getCodeSource() + { + Certificate[] certs = getCertificates(); + if (certs == null) + return loader.noCertCodeSource; + else + return new CodeSource(loader.baseURL, certs); + } + + /** + * Returns Certificates associated with this + * resource, or null when there are none. + */ + public Certificate[] getCertificates() + { + return null; + } + + /** + * Return the URLLoader for this resource. + */ + public final URLLoader getLoader() + { + return loader; + } + + /** + * Return a URL that can be used to access this resource. + */ + public abstract URL getURL(); + + /** + * Returns the size of this Resource in bytes or + * -1 when unknown. + */ + public abstract int getLength(); + + /** + * Returns the non-null InputStream through which + * this resource can be loaded. + */ + public abstract InputStream getInputStream() throws IOException; +} diff --git a/libjava/classpath/gnu/java/net/loader/URLLoader.java b/libjava/classpath/gnu/java/net/loader/URLLoader.java new file mode 100644 index 000000000..337564f6a --- /dev/null +++ b/libjava/classpath/gnu/java/net/loader/URLLoader.java @@ -0,0 +1,148 @@ +/* URLLoader.java -- base helper class for URLClassLoader + 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.net.loader; + +import java.net.URL; +import java.net.URLClassLoader; +import java.net.URLStreamHandlerFactory; +import java.security.CodeSource; +import java.security.cert.Certificate; +import java.util.ArrayList; +import java.util.jar.Manifest; + +/** + * A URLLoader contains all logic to load resources from a + * given base URL. + */ +public abstract class URLLoader +{ + /** + * Our classloader to get info from if needed. + */ + final URLClassLoader classloader; + + /** + * The base URL from which all resources are loaded. + */ + final URL baseURL; + + /** + * The stream handler factory. + */ + final URLStreamHandlerFactory factory; + + /** + * The source for stream handlers. + */ + final URLStreamHandlerCache cache; + + /** + * A CodeSource without any associated certificates. + * It is common for classes to not have certificates associated + * with them. If they come from the same URLLoader + * then it is safe to share the associated CodeSource + * between them since CodeSource is immutable. + */ + final CodeSource noCertCodeSource; + + public URLLoader(URLClassLoader classloader, URLStreamHandlerCache cache, + URLStreamHandlerFactory factory, + URL baseURL) + { + this(classloader, cache, factory, baseURL, baseURL); + } + + public URLLoader(URLClassLoader classloader, URLStreamHandlerCache cache, + URLStreamHandlerFactory factory, + URL baseURL, URL overrideURL) + { + this.classloader = classloader; + this.baseURL = baseURL; + this.factory = factory; + this.cache = cache; + this.noCertCodeSource = new CodeSource(overrideURL, (Certificate[]) null); + } + + /** + * Return the base URL of this loader. + */ + public final URL getBaseURL() + { + return baseURL; + } + + /** + * Returns a Class loaded by this + * URLLoader, or null when this loader + * either can't load the class or doesn't know how to load classes + * at all. Most subclasses do not need to override this; it is only + * useful in situations where the subclass has a more direct way of + * making Class objects. + */ + public Class getClass(String className) + { + return null; + } + + /** + * Returns a Resource loaded by this + * URLLoader, or null when no + * Resource with the given name exists. + */ + public abstract Resource getResource(String s); + + /** + * Returns the Manifest associated with the + * Resources loaded by this URLLoader or + * null there is no such Manifest. + */ + public Manifest getManifest() + { + return null; + } + + /** + * Return a list of new URLLoader objects representing any + * class path entries added by this container. + */ + public ArrayList getClassPath() + { + return null; + } +} diff --git a/libjava/classpath/gnu/java/net/loader/URLStreamHandlerCache.java b/libjava/classpath/gnu/java/net/loader/URLStreamHandlerCache.java new file mode 100644 index 000000000..b7b8bf12b --- /dev/null +++ b/libjava/classpath/gnu/java/net/loader/URLStreamHandlerCache.java @@ -0,0 +1,85 @@ +/* URLStreamHandlerCache.java -- a cache for URLStreamHandlers + 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.net.loader; + +import java.net.URLStreamHandler; +import java.net.URLStreamHandlerFactory; +import java.util.HashMap; + +/** + */ +public class URLStreamHandlerCache +{ + /** + * A cache to store mappings between handler factory and its + * private protocol handler cache (also a HashMap), so we can avoid + * creating handlers each time the same protocol comes. + */ + private HashMap> factoryCache + = new HashMap>(5); + + public URLStreamHandlerCache() + { + } + + public synchronized void add(URLStreamHandlerFactory factory) + { + // Since we only support three protocols so far, 5 is enough + // for cache initial size. + if (factory != null && factoryCache.get(factory) == null) + factoryCache.put(factory, new HashMap(5)); + } + + public synchronized URLStreamHandler get(URLStreamHandlerFactory factory, + String protocol) + { + if (factory == null) + return null; + // Check if there're handler for the same protocol in cache. + HashMap cache = factoryCache.get(factory); + URLStreamHandler handler = cache.get(protocol); + if (handler == null) + { + // Add it to cache. + handler = factory.createURLStreamHandler(protocol); + cache.put(protocol, handler); + } + return handler; + } +} diff --git a/libjava/classpath/gnu/java/net/local/LocalServerSocket.java b/libjava/classpath/gnu/java/net/local/LocalServerSocket.java new file mode 100644 index 000000000..9d8a6ccdf --- /dev/null +++ b/libjava/classpath/gnu/java/net/local/LocalServerSocket.java @@ -0,0 +1,171 @@ +/* LocalServerSocket.java -- a unix domain 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.java.net.local; + +import java.io.IOException; + +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketAddress; + +public final class LocalServerSocket extends ServerSocket +{ + + // Fields. + // ------------------------------------------------------------------------- + + private LocalSocketImpl myImpl; + private boolean closed; + + // Constructors. + // ------------------------------------------------------------------------- + + public LocalServerSocket () throws IOException + { + myImpl = new LocalSocketImpl (); + } + + public LocalServerSocket (SocketAddress bindPoint) throws IOException + { + this (); + bind (bindPoint); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void bind (SocketAddress bindPoint) throws IOException + { + bind (bindPoint, 0); + } + + public void bind (SocketAddress bindPoint, int backlog) throws IOException + { + myImpl.doCreate (); + myImpl.bind (bindPoint); + myImpl.listen (backlog); + } + + public InetAddress getInetAddress () + { + return null; + } + + public int getLocalPort () + { + return -1; + } + + public SocketAddress getLocalSocketAddress () + { + return myImpl.getLocalAddress (); + } + + public Socket accept () throws IOException + { + LocalSocket s = new LocalSocket (true); + myImpl.accept (s.getLocalImpl()); + s.localConnected = true; + return s; + } + + public void close () throws IOException + { + myImpl.close (); + myImpl.unlink (); + closed = true; + } + + public boolean isBound () + { + return myImpl.getLocalAddress () != null; + } + + public boolean isClosed () + { + return closed; + } + + public void setSoTimeout (int timeout) + { + throw new UnsupportedOperationException ("local sockets do not support timeouts"); + } + + public int getSoTimeout () + { + throw new UnsupportedOperationException ("local sockets do not support timeouts"); + } + + public void setReuseAddress (boolean b) + { + throw new UnsupportedOperationException ("local sockets do not support reuse address"); + } + + public boolean getReuseAddress () + { + throw new UnsupportedOperationException ("local sockets do not support reuse address"); + } + + public String toString () + { + return LocalServerSocket.class.getName() + " [ address=" + + myImpl.getLocalAddress() + " ]"; + } + + public void setReceiveBufferSize (int size) + { + throw new UnsupportedOperationException ("local sockets do not support buffer size"); + } + + public int getReceiveBufferSize () + { + throw new UnsupportedOperationException ("local sockets do not support buffer size"); + } + + public void setSendBufferSize (int size) + { + throw new UnsupportedOperationException ("local sockets do not support buffer size"); + } + + public int getSendBufferSize () + { + throw new UnsupportedOperationException ("local sockets do not support buffer size"); + } +} diff --git a/libjava/classpath/gnu/java/net/local/LocalSocket.java b/libjava/classpath/gnu/java/net/local/LocalSocket.java new file mode 100644 index 000000000..92acc65bb --- /dev/null +++ b/libjava/classpath/gnu/java/net/local/LocalSocket.java @@ -0,0 +1,312 @@ +/* LocalSocket.java -- a unix domain client 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.java.net.local; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import java.net.InetAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketException; + +import java.nio.channels.IllegalBlockingModeException; +import java.nio.channels.SocketChannel; + +/** + * A local, or unix-domain socket. Unix domain sockets are connected on the + * local filesystem itself, rather than a remote address. + */ +public final class LocalSocket extends Socket +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final LocalSocketImpl localimpl; + boolean localClosed; + boolean localConnected; + + // Constructors. + // ------------------------------------------------------------------------- + + public LocalSocket () throws SocketException + { + super (); + localimpl = new LocalSocketImpl (); + } + + public LocalSocket (LocalSocketAddress addr) throws SocketException + { + this (); + try + { + connect (addr); + } + catch (IOException ioe) + { + SocketException se = new SocketException (); + se.initCause (ioe); + throw se; + } + } + + LocalSocket (boolean nocreate) throws IOException + { + super (); + localimpl = new LocalSocketImpl (nocreate); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void bind (SocketAddress bindpoint) throws IOException + { + throw new SocketException ("binding local client sockets is nonsensical"); + } + + public void connect (SocketAddress endpoint, int timeout) throws IOException + { + if (isClosed ()) + { + throw new SocketException ("socket is closed"); + } + if (! (endpoint instanceof LocalSocketAddress)) + { + throw new IllegalArgumentException ("socket address is not a local address"); + } + if (getChannel() != null && !getChannel().isBlocking()) + { + throw new IllegalBlockingModeException (); + } + + try + { + localimpl.doCreate (); + localimpl.localConnect ((LocalSocketAddress) endpoint); + } + catch (IOException ioe) + { + close (); + throw ioe; + } + localConnected = true; + } + + public InetAddress getInetAddress () + { + return null; + } + + public InetAddress getLocalAddress () + { + return null; + } + + public int getPort () + { + return -1; + } + + public int getLocalPort () + { + return -1; + } + + public SocketChannel getChannel () + { + return null; + } + + public SocketAddress getLocalSocketAddress () + { + return localimpl.getLocalAddress (); + } + + public SocketAddress getRemoteSocketAddress () + { + return localimpl.getRemoteAddress (); + } + + public InputStream getInputStream () throws IOException + { + return localimpl.getInputStream (); + } + + public OutputStream getOutputStream () throws IOException + { + return localimpl.getOutputStream (); + } + + public void sendUrgentData (int b) throws IOException + { + localimpl.sendUrgentData (b); + } + + public synchronized void close () throws IOException + { + localimpl.close (); + localClosed = true; + } + + public void shutdownInput () throws IOException + { + localimpl.shutdownInput (); + } + + public void shutdownOutput () throws IOException + { + localimpl.shutdownOutput (); + } + + public boolean isClosed () + { + return localClosed; + } + + public boolean isBound () + { + return false; + } + + public boolean isConnected () + { + return localConnected; + } + + // Unsupported methods. + // ------------------------------------------------------------------------- + + public void setTcpNoDelay (boolean b) throws SocketException + { + throw new SocketException ("local sockets do not support this option"); + } + + public boolean getTcpNoDelay() throws SocketException + { + throw new SocketException ("local sockets do not support this option"); + } + + public void setSoLinger (boolean b, int i) throws SocketException + { + throw new SocketException ("local sockets do not support this option"); + } + + public int getSoLinger () throws SocketException + { + throw new SocketException ("local sockets do not support this option"); + } + + public void setOOBInline (boolean b) throws SocketException + { + throw new SocketException ("local sockets do not support this option"); + } + + public boolean getOOBInline () throws SocketException + { + throw new SocketException ("local sockets do not support this option"); + } + + public void setSoTimeout (int i) throws SocketException + { + // Ignore. + } + + public int getSoTimeout () throws SocketException + { + // We don't support timeout, so we return 0. + return 0; + } + + public void setSendBufferSize (int i) throws SocketException + { + throw new SocketException ("local sockets do not support this option"); + } + + public int getSendBufferSize() throws SocketException + { + throw new SocketException ("local sockets do not support this option"); + } + + public void setReceiveBufferSize (int i) throws SocketException + { + throw new SocketException ("local sockets do not support this option"); + } + + public int getReceiveBufferSize () throws SocketException + { + throw new SocketException ("local sockets do not support this option"); + } + + public void setKeepAlive (boolean b) throws SocketException + { + throw new SocketException ("local sockets do not support this option"); + } + + public boolean getKeepAlive () throws SocketException + { + throw new SocketException ("local sockets do not support this option"); + } + + public void setTrafficClass (int i) throws SocketException + { + throw new SocketException ("local sockets do not support this option"); + } + + public int getTrafficClass () throws SocketException + { + throw new SocketException ("local sockets do not support this option"); + } + + public void setReuseAddress (boolean b) throws SocketException + { + throw new SocketException ("local sockets do not support this option"); + } + + public boolean getReuseAddress () throws SocketException + { + throw new SocketException ("local sockets do not support this option"); + } + + LocalSocketImpl getLocalImpl () + { + return localimpl; + } +} diff --git a/libjava/classpath/gnu/java/net/local/LocalSocketAddress.java b/libjava/classpath/gnu/java/net/local/LocalSocketAddress.java new file mode 100644 index 000000000..ac5c53db2 --- /dev/null +++ b/libjava/classpath/gnu/java/net/local/LocalSocketAddress.java @@ -0,0 +1,100 @@ +/* LocalSocketAddress.java -- unix-domain socket address. + 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.java.net.local; + +import java.net.SocketAddress; + +public final class LocalSocketAddress extends SocketAddress +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final String path; + + // Constructor. + // ------------------------------------------------------------------------- + + /** + * Creates a new unix domain socket address. + * + * @param path The path to the socket. + * @throws NullPointerException If path is null. + */ + public LocalSocketAddress (String path) + { + if (path == null) + { + throw new NullPointerException (); + } + this.path = path; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + /** + * Returns the path of the socket. + * + * @return The path. + */ + public String getPath () + { + return path; + } + + public boolean equals (Object o) + { + if (!(o instanceof LocalSocketAddress)) + { + return false; + } + return getPath ().equals (((LocalSocketAddress) o).getPath ()); + } + + public int hashCode () + { + return path.hashCode(); + } + + public String toString () + { + return super.toString() + " [ " + path + " ]"; + } +} diff --git a/libjava/classpath/gnu/java/net/local/LocalSocketImpl.java b/libjava/classpath/gnu/java/net/local/LocalSocketImpl.java new file mode 100644 index 000000000..f49b79947 --- /dev/null +++ b/libjava/classpath/gnu/java/net/local/LocalSocketImpl.java @@ -0,0 +1,334 @@ +/* LocalSocketImpl.java -- a unix domain client socket 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.java.net.local; + +import gnu.classpath.Configuration; + +import java.io.FileDescriptor; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; + +import java.net.InetAddress; +import java.net.SocketAddress; +import java.net.SocketException; +import java.net.SocketImpl; + +final class LocalSocketImpl extends SocketImpl +{ + + // Fields. + // ------------------------------------------------------------------------- + + private boolean created; + private InputStream in; + private OutputStream out; + // Package private to avoid synthetic accessor method. + int socket_fd; + private LocalSocketAddress local; + private LocalSocketAddress remote; + + static + { + try + { + if (Configuration.INIT_LOAD_LIBRARY) + { + System.loadLibrary ("javanet"); + } + } + catch (Exception x) + { + x.printStackTrace (); + } + } + + // Constructor. + // ------------------------------------------------------------------------- + + LocalSocketImpl () + { + this (false); + } + + LocalSocketImpl (boolean nocreate) + { + created = nocreate; + socket_fd = -1; + fd = new FileDescriptor (); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void setOption (int opt, Object value) throws SocketException + { + throw new SocketException ("local sockets do not support options"); + } + + public Object getOption (int opt) throws SocketException + { + throw new SocketException ("local sockets do not support options"); + } + + protected native void create (boolean stream) throws IOException; + protected native void listen (int timeout) throws IOException; + protected native void accept (LocalSocketImpl socket) throws IOException; + protected native int available (int fd) throws IOException; + protected native void close () throws IOException; + protected native void sendUrgentData (int data) throws IOException; + protected native void shutdownInput () throws IOException; + protected native void shutdownOutput () throws IOException; + + native void unlink () throws IOException; + native void localBind (LocalSocketAddress addr) throws IOException; + native void localConnect (LocalSocketAddress addr) throws IOException; + native int read (int fd, byte[] buf, int off, int len) throws IOException; + native void write (int fd, byte[] buf, int off, int len) throws IOException; + + protected int available() + throws IOException + { + return available(socket_fd); + } + + void doCreate () throws IOException + { + if (!created) + { + create (true); + } + } + + LocalSocketAddress getLocalAddress () + { + return local; + } + + LocalSocketAddress getRemoteAddress () + { + return remote; + } + + protected InputStream getInputStream() + { + if (in == null) + { + in = new LocalInputStream (this); + } + + return in; + } + + protected OutputStream getOutputStream() + { + if (out == null) + { + out = new LocalOutputStream (this); + } + + return out; + } + + protected void accept (SocketImpl impl) throws IOException + { + if (! (impl instanceof LocalSocketImpl)) + { + throw new IllegalArgumentException ("not a local socket"); + } + accept ((LocalSocketImpl) impl); + } + + protected void connect (String host, int port) throws IOException + { + throw new SocketException ("this is a local socket"); + } + + protected void connect (InetAddress addr, int port) throws IOException + { + throw new SocketException ("this is a local socket"); + } + + protected void connect(SocketAddress addr, int timeout) throws IOException + { + if (! (addr instanceof LocalSocketAddress)) + { + throw new SocketException ("address is not local"); + } + localConnect ((LocalSocketAddress) addr); + } + + protected void bind (InetAddress addr, int port) throws IOException + { + throw new SocketException ("this is a local socket"); + } + + protected void bind (SocketAddress addr) throws IOException + { + if (! (addr instanceof LocalSocketAddress)) + { + throw new SocketException ("address is not local"); + } + localBind ((LocalSocketAddress) addr); + } + + // Inner classes. + // ------------------------------------------------------------------------- + + class LocalInputStream extends InputStream + { + + // Field. + // ----------------------------------------------------------------------- + + private final LocalSocketImpl impl; + + // Constructor. + // ----------------------------------------------------------------------- + + LocalInputStream (LocalSocketImpl impl) + { + this.impl = impl; + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public int available () throws IOException + { + return impl.available(); + } + + public boolean markSupported () + { + return false; + } + + public void mark (int readLimit) + { + } + + public void reset () throws IOException + { + throw new IOException ("mark/reset not supported"); + } + + public void close () throws IOException + { + impl.close(); + } + + public int read () throws IOException + { + byte[] buf = new byte[1]; + int ret = read (buf); + if (ret != -1) + { + return buf[0] & 0xFF; + } + else + { + return -1; + } + } + + 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 = impl.read (socket_fd, buf, off, len); + + if (ret == 0) + { + return -1; + } + + return ret; + } + } + + class LocalOutputStream extends OutputStream + { + + // Field. + // ----------------------------------------------------------------------- + + private final LocalSocketImpl impl; + + // Constructor. + // ----------------------------------------------------------------------- + + LocalOutputStream (LocalSocketImpl impl) + { + this.impl = impl; + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public void close () throws IOException + { + impl.close (); + } + + public void flush () throws IOException + { + } + + public void write (int b) throws IOException + { + byte[] buf = new byte [1]; + buf[0] = (byte) b; + write (buf); + } + + public void write (byte[] buf) throws IOException + { + write (buf, 0, buf.length); + } + + public void write (byte[] buf, int off, int len) throws IOException + { + impl.write (socket_fd, buf, off, len); + } + } +} diff --git a/libjava/classpath/gnu/java/net/package.html b/libjava/classpath/gnu/java/net/package.html new file mode 100644 index 000000000..5641fbd92 --- /dev/null +++ b/libjava/classpath/gnu/java/net/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.net + + +

+ + + diff --git a/libjava/classpath/gnu/java/net/protocol/file/Connection.java b/libjava/classpath/gnu/java/net/protocol/file/Connection.java new file mode 100644 index 000000000..80155af0d --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/file/Connection.java @@ -0,0 +1,376 @@ +/* FileURLConnection.java -- URLConnection class for "file" protocol + Copyright (C) 1998, 1999, 2003 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.net.protocol.file; + +import gnu.classpath.SystemProperties; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FilePermission; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.net.ProtocolException; +import java.net.URL; +import java.net.URLConnection; +import java.security.Permission; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; +import java.net.MalformedURLException; + +/** + * This subclass of java.net.URLConnection models a URLConnection via + * the "file" protocol. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Nic Ferrier (nferrier@tapsellferrier.co.uk) + * @author Warren Levy (warrenl@cygnus.com) + */ +public class Connection extends URLConnection +{ + /** + * Default permission for a file + */ + private static final String DEFAULT_PERMISSION = "read"; + + private static class StaticData + { + /** + * HTTP-style DateFormat, used to format the last-modified header. + */ + static SimpleDateFormat dateFormat + = new SimpleDateFormat("EEE, dd MMM yyyy hh:mm:ss 'GMT'", + new Locale ("En", "Us", "Unix")); + + static String lineSeparator = + SystemProperties.getProperty("line.separator"); + } + + + /** + * This is a File object for this connection + */ + private File file; + + /** + * If a directory, contains a list of files in the directory. + */ + private byte[] directoryListing; + + /** + * InputStream if we are reading from the file + */ + private InputStream inputStream; + + /** + * OutputStream if we are writing to the file + */ + private OutputStream outputStream; + + /** + * FilePermission to read the file + */ + private FilePermission permission; + + /** + * Calls superclass constructor to initialize. + */ + public Connection(URL url) + { + super (url); + + permission = new FilePermission(getURL().getFile(), DEFAULT_PERMISSION); + } + + /** + * Unquote "%" + hex quotes characters + * + * @param str The string to unquote or null. + * + * @return The unquoted string or null if str was null. + * + * @exception MalformedURLException If the given string contains invalid + * escape sequences. + * + */ + public static String unquote(String str) throws MalformedURLException + { + if (str == null) + return null; + + final int MAX_BYTES_PER_UTF_8_CHAR = 3; + byte[] buf = new byte[str.length()*MAX_BYTES_PER_UTF_8_CHAR]; + int pos = 0; + for (int i = 0; i < str.length(); i++) + { + char c = str.charAt(i); + if (c == '%') + { + if (i + 2 >= str.length()) + throw new MalformedURLException(str + " : Invalid quoted character"); + int hi = Character.digit(str.charAt(++i), 16); + int lo = Character.digit(str.charAt(++i), 16); + if (lo < 0 || hi < 0) + 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"); + final int c_length = c_as_bytes.length; + System.arraycopy(c_as_bytes, 0, buf, pos, c_length); + pos += c_length; + } + catch (java.io.UnsupportedEncodingException x2) { + throw (Error) new InternalError().initCause(x2); + } + } + else + buf[pos++] = (byte) c; + } + try + { + return new String(buf, 0, pos, "utf-8"); + } + catch (java.io.UnsupportedEncodingException x2) + { + throw (Error) new InternalError().initCause(x2); + } + } + + /** + * "Connects" to the file by opening it. + */ + public void connect() throws IOException + { + // Call is ignored if already connected. + if (connected) + return; + + // If not connected, then file needs to be openned. + file = new File (unquote(getURL().getFile())); + + if (! file.isDirectory()) + { + if (doInput) + inputStream = new BufferedInputStream(new FileInputStream(file)); + + if (doOutput) + outputStream = new BufferedOutputStream(new FileOutputStream(file)); + } + else + { + if (doInput) + { + inputStream = new ByteArrayInputStream(getDirectoryListing()); + } + + if (doOutput) + throw new ProtocolException + ("file: protocol does not support output on directories"); + } + + connected = true; + } + + /** + * Populates the directoryListing field with a byte array + * containing a representation of the directory listing. + */ + byte[] getDirectoryListing() + throws IOException + { + if (directoryListing == null) + { + ByteArrayOutputStream sink = new ByteArrayOutputStream(); + // NB uses default character encoding for this system + Writer writer = new OutputStreamWriter(sink); + + String[] files = file.list(); + + for (int i = 0; i < files.length; i++) + { + writer.write(files[i]); + writer.write(StaticData.lineSeparator); + } + + directoryListing = sink.toByteArray(); + } + return directoryListing; + } + + /** + * Opens the file for reading and returns a stream for it. + * + * @return An InputStream for this connection. + * + * @exception IOException If an error occurs + */ + public InputStream getInputStream() + throws IOException + { + if (!doInput) + throw new ProtocolException("Can't open InputStream if doInput is false"); + + if (!connected) + connect(); + + return inputStream; + } + + /** + * Opens the file for writing and returns a stream for it. + * + * @return An OutputStream for this connection. + * + * @exception IOException If an error occurs. + */ + public OutputStream getOutputStream() + throws IOException + { + if (!doOutput) + throw new + ProtocolException("Can't open OutputStream if doOutput is false"); + + if (!connected) + connect(); + + return outputStream; + } + + /** + * Get the last modified time of the resource. + * + * @return the time since epoch that the resource was modified. + */ + public long getLastModified() + { + try + { + if (!connected) + connect(); + + return file.lastModified(); + } + catch (IOException e) + { + return -1; + } + } + + /** + * Get an http-style header field. Just handle a few common ones. + */ + public String getHeaderField(String field) + { + try + { + if (!connected) + connect(); + + if (field.equals("content-type")) + return guessContentTypeFromName(file.getName()); + else if (field.equals("content-length")) + { + if (file.isDirectory()) + { + return Integer.toString(getContentLength()); + } + return Long.toString(file.length()); + } + else if (field.equals("last-modified")) + { + synchronized (StaticData.dateFormat) + { + return StaticData.dateFormat.format( + new Date(file.lastModified())); + } + } + } + catch (IOException e) + { + // Fall through. + } + return null; + } + + /** + * Get the length of content. + * + * @return the length of the content. + */ + public int getContentLength() + { + try + { + if (!connected) + connect(); + + if (file.isDirectory()) + { + return getDirectoryListing().length; + } + return (int) file.length(); + } + catch (IOException e) + { + return -1; + } + } + + /** + * This method returns a Permission object representing the + * permissions required to access this URL. This method returns a + * java.io.FilePermission for the file's path with a read + * permission. + * + * @return A Permission object + */ + public Permission getPermission() throws IOException + { + return permission; + } +} diff --git a/libjava/classpath/gnu/java/net/protocol/file/Handler.java b/libjava/classpath/gnu/java/net/protocol/file/Handler.java new file mode 100644 index 000000000..58ebe4c46 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/file/Handler.java @@ -0,0 +1,91 @@ +/* Handler.java -- "file" protocol handler for java.net + Copyright (C) 1998, 1999, 2000, 2002, 2003, 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.net.protocol.file; + +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; + +/** + * This is the protocol handler for the "file" protocol. + * It implements the abstract openConnection() method from + * URLStreamHandler by returning a new FileURLConnection object (from + * this package). All other methods are inherited + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + */ +public class Handler extends URLStreamHandler +{ + /** + * A do nothing constructor + */ + public Handler() + { + } + + /** + * This method returs a new FileURLConnection for the specified URL + * + * @param url The URL to return a connection for + * + * @return The URLConnection + * + * @exception IOException If an error occurs + */ + protected URLConnection openConnection(URL url) throws IOException + { + // If a hostname is set, then we need to switch protocols to ftp + // in order to transfer this from the remote host. + String host = url.getHost(); + if ((host != null) && (! host.equals(""))) + { + // Reset the protocol (and implicitly the handler) for this URL. + // Then have the URL attempt the connection again, as it will + // get the changed handler the next time around. + // If the ftp protocol handler is not installed, an + // exception will be thrown from the new openConnection() call. + setURL (url, "ftp", url.getHost(), url.getPort(), url.getFile(), + url.getRef()); + return url.openConnection(); + } + + return new Connection(url); + } +} // class Handler diff --git a/libjava/classpath/gnu/java/net/protocol/file/package.html b/libjava/classpath/gnu/java/net/protocol/file/package.html new file mode 100644 index 000000000..cbce7413f --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/file/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.net.protocol.file + + +

+ + + diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/ActiveModeDTP.java b/libjava/classpath/gnu/java/net/protocol/ftp/ActiveModeDTP.java new file mode 100644 index 000000000..1ed31b830 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/ActiveModeDTP.java @@ -0,0 +1,251 @@ +/* ActiveModeDTP.java -- + Copyright (C) 2003, 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.net.protocol.ftp; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; + +/** + * An active mode FTP data transfer process. + * This starts a server on the specified port listening for a data + * connection. It converts the socket input into a file stream for reading. + * + * @author Chris Burdess (dog@gnu.org) + */ +final class ActiveModeDTP + implements DTP, Runnable +{ + + ServerSocket server; + Socket socket; + DTPInputStream in; + DTPOutputStream out; + boolean completed; + boolean inProgress; + int transferMode; + IOException exception; + Thread acceptThread; + int connectionTimeout; + + ActiveModeDTP(InetAddress localhost, int port, + int connectionTimeout, int timeout) + throws IOException + { + completed = false; + inProgress = false; + server = new ServerSocket(port, 1, localhost); + if (timeout > 0) + { + server.setSoTimeout(timeout); + } + if (connectionTimeout <= 0) + { + connectionTimeout = 20000; + } + this.connectionTimeout = connectionTimeout; + acceptThread = new Thread(this, "ActiveModeDTP"); + acceptThread.setDaemon(true); + acceptThread.start(); + } + + /** + * Start listening. + */ + public void run() + { + try + { + socket = server.accept(); + //System.err.println("Accepted connection from "+socket.getInetAddress()+":"+socket.getPort()); + } + catch (IOException e) + { + exception = e; + } + } + + /** + * Waits until a client has connected. + */ + public void waitFor() + throws IOException + { + try + { + acceptThread.join(connectionTimeout); + } + catch (InterruptedException e) + { + } + if (exception != null) + { + throw exception; + } + if (socket == null) + { + server.close(); + throw new IOException("client did not connect before timeout"); + } + acceptThread = null; + } + + /** + * Returns an input stream from which a remote file can be read. + */ + public InputStream getInputStream() + throws IOException + { + if (inProgress) + { + throw new IOException("Transfer in progress"); + } + if (acceptThread != null) + { + waitFor(); + } + switch (transferMode) + { + case FTPConnection.MODE_STREAM: + in = new StreamInputStream(this, socket.getInputStream()); + break; + case FTPConnection.MODE_BLOCK: + in = new BlockInputStream(this, socket.getInputStream()); + break; + case FTPConnection.MODE_COMPRESSED: + in = new CompressedInputStream(this, socket.getInputStream()); + break; + default: + throw new IllegalStateException("invalid transfer mode"); + } + in.setTransferComplete(false); + return in; + } + + /** + * Returns an output stream to which a local file can be written for + * upload. + */ + public OutputStream getOutputStream() throws IOException + { + if (inProgress) + { + throw new IOException("Transfer in progress"); + } + if (acceptThread != null) + { + waitFor(); + } + switch (transferMode) + { + case FTPConnection.MODE_STREAM: + out = new StreamOutputStream(this, socket.getOutputStream()); + break; + case FTPConnection.MODE_BLOCK: + out = new BlockOutputStream(this, socket.getOutputStream()); + break; + case FTPConnection.MODE_COMPRESSED: + out = new CompressedOutputStream(this, socket.getOutputStream()); + break; + default: + throw new IllegalStateException("invalid transfer mode"); + } + out.setTransferComplete(false); + return out; + } + + public void setTransferMode(int mode) + { + transferMode = mode; + } + + public void complete() + { + completed = true; + if (!inProgress) + { + transferComplete(); + } + } + + public boolean abort() + { + completed = true; + transferComplete(); + return inProgress; + } + + public void transferComplete() + { + if (socket == null) + { + return; + } + if (in != null) + { + in.setTransferComplete(true); + } + if (out != null) + { + out.setTransferComplete(true); + } + completed = completed || (transferMode == FTPConnection.MODE_STREAM); + if (completed && socket != null) + { + try + { + socket.close(); + } + catch (IOException e) + { + } + try + { + server.close(); + } + catch (IOException e) + { + } + } + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/BlockInputStream.java b/libjava/classpath/gnu/java/net/protocol/ftp/BlockInputStream.java new file mode 100644 index 000000000..09915e7ff --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/BlockInputStream.java @@ -0,0 +1,149 @@ +/* BlockInputStream.java -- + Copyright (C) 2003, 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.net.protocol.ftp; + +import java.io.IOException; +import java.io.InputStream; + +/** + * A DTP input stream that implements the FTP block transfer mode. + * + * @author Chris Burdess (dog@gnu.org) + */ +class BlockInputStream + extends DTPInputStream +{ + + static final int EOF = 64; + + int descriptor; + int max = -1; + int count = -1; + + BlockInputStream(DTP dtp, InputStream in) + { + super(dtp, in); + } + + public int read() + throws IOException + { + if (transferComplete) + { + return -1; + } + if (count == -1) + { + readHeader(); + } + if (max < 1) + { + close(); + return -1; + } + int c = in.read(); + if (c == -1) + { + dtp.transferComplete(); + } + count++; + if (count >= max) + { + count = -1; + if (descriptor == EOF) + { + close(); + } + } + return c; + } + + 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 (transferComplete) + { + return -1; + } + if (count == -1) + { + readHeader(); + } + if (max < 1) + { + close(); + return -1; + } + int l = in.read(buf, off, len); + if (l == -1) + { + dtp.transferComplete(); + } + count += l; + if (count >= max) + { + count = -1; + if (descriptor == EOF) + { + close(); + } + } + return l; + } + + /** + * Reads the block header. + */ + void readHeader() + throws IOException + { + descriptor = in.read(); + int max_hi = in.read(); + int max_lo = in.read(); + max = (max_hi << 8) | max_lo; + count = 0; + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/BlockOutputStream.java b/libjava/classpath/gnu/java/net/protocol/ftp/BlockOutputStream.java new file mode 100644 index 000000000..d181f9dec --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/BlockOutputStream.java @@ -0,0 +1,110 @@ +/* BlockOutputStream.java -- + Copyright (C) 2003, 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.net.protocol.ftp; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * A DTP output stream that implements the FTP block transfer mode. + * + * @author Chris Burdess (dog@gnu.org) + */ +class BlockOutputStream + extends DTPOutputStream +{ + + static final byte RECORD = -128; // 0x80 + static final byte EOF = 64; // 0x40 + + BlockOutputStream(DTP dtp, OutputStream out) + { + super(dtp, out); + } + + public void write(int c) + throws IOException + { + if (transferComplete) + { + return; + } + byte[] buf = new byte[] + { + RECORD, /* record descriptor */ + 0x00, 0x01, /* one byte */ + (byte) c /* the byte */ + }; + out.write(buf, 0, 4); + } + + public void write(byte[] b) + throws IOException + { + write(b, 0, b.length); + } + + public void write(byte[] b, int off, int len) + throws IOException + { + if (transferComplete) + { + return; + } + byte[] buf = new byte[len + 3]; + buf[0] = RECORD; /* record descriptor */ + buf[1] = (byte) ((len & 0x00ff) >> 8); /* high byte of bytecount */ + buf[2] = (byte) (len & 0xff00); /* low byte of bytecount */ + System.arraycopy(b, off, buf, 3, len); + out.write(buf, 0, len); + } + + public void close() + throws IOException + { + byte[] buf = new byte[] + { + EOF, /* eof descriptor */ + 0x00, 0x00 /* no bytes */ + }; + out.write(buf, 0, 3); + super.close(); + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/CompressedInputStream.java b/libjava/classpath/gnu/java/net/protocol/ftp/CompressedInputStream.java new file mode 100644 index 000000000..638d780e6 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/CompressedInputStream.java @@ -0,0 +1,214 @@ +/* CompressedInputStream.java -- + Copyright (C) 2003, 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.net.protocol.ftp; + +import java.io.IOException; +import java.io.InputStream; +import java.net.ProtocolException; + +/** + * A DTP input stream that implements the FTP compressed transfer mode. + * + * @author Chris Burdess (dog@gnu.org) + */ +class CompressedInputStream + extends DTPInputStream +{ + + static final int EOF = 64; + + static final int RAW = 0x00; + static final int COMPRESSED = 0x80; + static final int FILLER = 0xc0; + + int descriptor; + int max = -1; + int count = -1; + + int state = RAW; // RAW | STATE | FILLER + int rep; // the compressed byte + int n = 0; // the number of compressed or raw bytes + + CompressedInputStream(DTP dtp, InputStream in) + { + super(dtp, in); + } + + public int read() + throws IOException + { + if (transferComplete) + { + return -1; + } + if (count == -1) + { + readHeader(); + } + if (max < 1) + { + close(); + return -1; + } + if (n > 0 && (state == COMPRESSED || state == FILLER)) + { + n--; + return rep; + } + int c = in.read(); + if (c == -1) + { + close(); + } + count++; + if (count >= max) + { + count = -1; + if (descriptor == EOF) + { + close(); + } + } + if (c == -1) + { + return c; + } + while (n == 0) // read code header + { + state = (c & 0xc0); + n = (c & 0x3f); + c = in.read(); + if (c == -1) + { + return -1; + } + } + switch (state) + { + case RAW: + break; + case COMPRESSED: + case FILLER: + rep = c; + break; + default: + throw new ProtocolException("Illegal state: " + state); + } + n--; + return c; + } + + 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 (transferComplete) + { + return -1; + } + if (count == -1) + { + readHeader(); + } + if (max < 1) + { + close(); + return -1; + } + // TODO improve performance + for (int i = off; i < len; i++) + { + int c = read(); + if (c == -1) + { + close(); + return i; + } + buf[i] = (byte) c; + } + return len; + /* + int l = in.read (buf, off, len); + if (l==-1) + { + close (); + } + count += l; + if (count>=max) + { + count = -1; + if (descriptor==EOF) + { + close (); + } + } + return l; + */ + } + + /** + * Reads the block header. + */ + void readHeader() + throws IOException + { + descriptor = in.read(); + int max_hi = in.read(); + int max_lo = in.read(); + max = (max_hi << 8) | max_lo; + count = 0; + } + + /** + * Reads the code header. + */ + void readCodeHeader() + throws IOException + { + int code = in.read(); + state = (code & 0xc0); + n = (code & 0x3f); + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/CompressedOutputStream.java b/libjava/classpath/gnu/java/net/protocol/ftp/CompressedOutputStream.java new file mode 100644 index 000000000..ec3aef930 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/CompressedOutputStream.java @@ -0,0 +1,227 @@ +/* CompressedOutputStream.java -- + Copyright (C) 2003, 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.net.protocol.ftp; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * A DTP output stream that implements the FTP compressed transfer mode. + * + * @author Chris Burdess (dog@gnu.org) + */ +class CompressedOutputStream + extends DTPOutputStream +{ + + static final byte RECORD = -128; // 0x80 + static final byte EOF = 64; // 0x40 + + CompressedOutputStream(DTP dtp, OutputStream out) + { + super(dtp, out); + } + + /** + * Just one byte cannot be compressed. + * It takes 5 bytes to transmit - hardly very compressed! + */ + public void write(int c) + throws IOException + { + if (transferComplete) + { + return; + } + byte[] buf = new byte[] + { + RECORD, /* record descriptor */ + 0x00, 0x01, /* one byte */ + 0x01, /* one uncompressed byte */ + (byte) c /* the byte */ + }; + out.write(buf, 0, 5); + } + + public void write(byte[] b) + throws IOException + { + write(b, 0, b.length); + } + + /** + * The larger len is, the better. + */ + public void write(byte[] b, int off, int len) + throws IOException + { + if (transferComplete) + { + return; + } + byte[] buf = compress(b, off, len); + len = buf.length; + buf[0] = RECORD; /* record descriptor */ + buf[1] = (byte) ((len & 0x00ff) >> 8); /* high byte of bytecount */ + buf[2] = (byte) (len & 0xff00); /* low byte of bytecount */ + out.write(buf, 0, len); + } + + /** + * Returns the compressed form of the given byte array. + * The first 3 bytes are left free for header information. + */ + byte[] compress(byte[] b, int off, int len) + { + byte[] buf = new byte[len]; + byte last = 0; + int pos = 0, raw_count = 0, rep_count = 1; + for (int i = off; i < len; i++) + { + byte c = b[i]; + if (i > off && c == last) // compress + { + if (raw_count > 0) // flush raw bytes to buf + { + // need to add raw_count+1 bytes + if (pos + (raw_count + 1) > buf.length) + { + buf = realloc(buf, len); + } + pos = flush_raw(buf, pos, b, (i - raw_count) - 1, + raw_count); + raw_count = 0; + } + rep_count++; // keep looking for same byte + } + else + { + if (rep_count > 1) // flush compressed bytes to buf + { + // need to add 2 bytes + if (pos + 2 > buf.length) + { + buf = realloc(buf, len); + } + pos = flush_compressed(buf, pos, rep_count, last); + rep_count = 1; + } + raw_count++; // keep looking for raw bytes + } + if (rep_count == 127) // flush compressed bytes + { + // need to add 2 bytes + if (pos + 2 > buf.length) + { + buf = realloc(buf, len); + } + pos = flush_compressed(buf, pos, rep_count, last); + rep_count = 1; + } + if (raw_count == 127) // flush raw bytes + { + // need to add raw_count+1 bytes + if (pos + (raw_count + 1) > buf.length) + { + buf = realloc(buf, len); + } + pos = flush_raw(buf, pos, b, (i - raw_count), raw_count); + raw_count = 0; + } + last = c; + } + if (rep_count > 1) // flush compressed bytes + { + // need to add 2 bytes + if (pos + 2 > buf.length) + { + buf = realloc(buf, len); + } + pos = flush_compressed(buf, pos, rep_count, last); + rep_count = 1; + } + if (raw_count > 0) // flush raw bytes + { + // need to add raw_count+1 bytes + if (pos + (raw_count + 1) > buf.length) + { + buf = realloc(buf, len); + } + pos = flush_raw(buf, pos, b, (len - raw_count), raw_count); + raw_count = 0; + } + byte[] ret = new byte[pos + 3]; + System.arraycopy(buf, 0, ret, 3, pos); + return ret; + } + + int flush_compressed(byte[] buf, int pos, int count, byte c) + { + buf[pos++] = (byte) (0x80 | count); + buf[pos++] = c; + return pos; + } + + int flush_raw(byte[] buf, int pos, byte[] src, int off, int len) + { + buf[pos++] = (byte) len; + System.arraycopy(src, off, buf, pos, len); + return pos + len; + } + + byte[] realloc(byte[] buf, int len) + { + byte[] ret = new byte[buf.length + len]; + System.arraycopy(buf, 0, ret, 0, buf.length); + return ret; + } + + public void close() + throws IOException + { + byte[] buf = new byte[] + { + EOF, /* eof descriptor */ + 0x00, 0x00 /* no bytes */ + }; + out.write(buf, 0, 3); + out.close(); + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/DTP.java b/libjava/classpath/gnu/java/net/protocol/ftp/DTP.java new file mode 100644 index 000000000..9ba4b7c6c --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/DTP.java @@ -0,0 +1,91 @@ +/* DTP.java -- + Copyright (C) 2003, 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.net.protocol.ftp; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * An FTP data transfer process. + * + * @author Chris Burdess (dog@gnu.org) + */ +interface DTP +{ + + /** + * Returns an input stream from which a remote file can be read. + */ + InputStream getInputStream() + throws IOException; + + /** + * Returns an output stream to which a local file can be written for + * upload. + */ + OutputStream getOutputStream() + throws IOException; + + /** + * Sets the transfer mode to be used with this DTP. + */ + void setTransferMode(int mode); + + /** + * Marks this DTP completed. + * When the current transfer has finished, any resources will be released. + */ + void complete(); + + /** + * Aborts any current transfer and releases all resources held by this + * DTP. + * @return true if a transfer was interrupted, false otherwise + */ + boolean abort(); + + /** + * Used to notify the DTP that its current transfer is complete. + * This occurs either when end-of-stream is reached or a 226 response is + * received. + */ + void transferComplete(); + +} diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/DTPInputStream.java b/libjava/classpath/gnu/java/net/protocol/ftp/DTPInputStream.java new file mode 100644 index 000000000..7280b0133 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/DTPInputStream.java @@ -0,0 +1,87 @@ +/* DTPInputStream.java -- + Copyright (C) 2003, 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.net.protocol.ftp; + +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * An input stream that notifies a DTP on completion. + * + * @author Chris Burdess (dog@gnu.org) + */ +abstract class DTPInputStream + extends FilterInputStream +{ + + DTP dtp; + boolean transferComplete; + + /** + * Constructor. + * @param dtp the controlling data transfer process + * @param in the underlying socket stream + */ + DTPInputStream (DTP dtp, InputStream in) + { + super(in); + this.dtp = dtp; + transferComplete = false; + } + + /** + * Marks this input stream complete. + * This is called by the DTP. + */ + void setTransferComplete(boolean flag) + { + transferComplete = flag; + } + + /** + * Notifies the controlling DTP that this stream has completed transfer. + */ + public void close() + throws IOException + { + dtp.transferComplete(); + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/DTPOutputStream.java b/libjava/classpath/gnu/java/net/protocol/ftp/DTPOutputStream.java new file mode 100644 index 000000000..105c6f095 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/DTPOutputStream.java @@ -0,0 +1,85 @@ +/* DTPOutputStream.java -- + Copyright (C) 2003, 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.net.protocol.ftp; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * An output stream that notifies a DTP on end of stream. + * + * @author Chris Burdess (dog@gnu.org) + */ +abstract class DTPOutputStream extends FilterOutputStream +{ + + DTP dtp; + boolean transferComplete; + + /** + * Constructor. + * @param dtp the controlling data transfer process + * @param out the socket output stream + */ + DTPOutputStream (DTP dtp, OutputStream out) + { + super (out); + this.dtp = dtp; + transferComplete = false; + } + + /** + * Tells this stream whether transfer has completed or not. + * @param flag true if the process has completed, false otherwise + */ + void setTransferComplete (boolean flag) + { + transferComplete = flag; + } + + /** + * Notifies the controlling DTP that this stream has been terminated. + */ + public void close () throws IOException + { + dtp.transferComplete (); + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/FTPConnection.java b/libjava/classpath/gnu/java/net/protocol/ftp/FTPConnection.java new file mode 100644 index 000000000..4e253fcb9 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/FTPConnection.java @@ -0,0 +1,1352 @@ +/* FTPConnection.java -- + Copyright (C) 2003, 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.net.protocol.ftp; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.net.CRLFInputStream; +import gnu.java.net.CRLFOutputStream; +import gnu.java.net.EmptyX509TrustManager; +import gnu.java.net.LineInputStream; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.BindException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ProtocolException; +import java.net.Socket; +import java.net.UnknownHostException; +import java.security.GeneralSecurityException; +import java.util.ArrayList; +import java.util.List; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; + +/** + * An FTP client connection, or PI. + * This implements RFC 959, with the following exceptions: + *
    + *
  • STAT, HELP, SITE, SMNT, and ACCT commands are not supported.
  • + *
  • the TYPE command does not allow alternatives to the default bytesize + * (Non-print), and local bytesize is not supported.
  • + *
+ * + * @author Chris Burdess (dog@gnu.org) + */ +public class FTPConnection +{ + + /** + * The default FTP transmission control port. + */ + public static final int FTP_PORT = 21; + + /** + * The FTP data port. + */ + public static final int FTP_DATA_PORT = 20; + + // -- FTP vocabulary -- + protected static final String USER = "USER"; + protected static final String PASS = "PASS"; + protected static final String ACCT = "ACCT"; + protected static final String CWD = "CWD"; + protected static final String CDUP = "CDUP"; + protected static final String SMNT = "SMNT"; + protected static final String REIN = "REIN"; + protected static final String QUIT = "QUIT"; + + protected static final String PORT = "PORT"; + protected static final String PASV = "PASV"; + protected static final String TYPE = "TYPE"; + protected static final String STRU = "STRU"; + protected static final String MODE = "MODE"; + + protected static final String RETR = "RETR"; + protected static final String STOR = "STOR"; + protected static final String STOU = "STOU"; + protected static final String APPE = "APPE"; + protected static final String ALLO = "ALLO"; + protected static final String REST = "REST"; + protected static final String RNFR = "RNFR"; + protected static final String RNTO = "RNTO"; + protected static final String ABOR = "ABOR"; + protected static final String DELE = "DELE"; + protected static final String RMD = "RMD"; + protected static final String MKD = "MKD"; + protected static final String PWD = "PWD"; + protected static final String LIST = "LIST"; + protected static final String NLST = "NLST"; + protected static final String SITE = "SITE"; + protected static final String SYST = "SYST"; + protected static final String STAT = "STAT"; + protected static final String HELP = "HELP"; + protected static final String NOOP = "NOOP"; + + protected static final String AUTH = "AUTH"; + protected static final String PBSZ = "PBSZ"; + protected static final String PROT = "PROT"; + protected static final String CCC = "CCC"; + protected static final String TLS = "TLS"; + + public static final int TYPE_ASCII = 1; + public static final int TYPE_EBCDIC = 2; + public static final int TYPE_BINARY = 3; + + public static final int STRUCTURE_FILE = 1; + public static final int STRUCTURE_RECORD = 2; + public static final int STRUCTURE_PAGE = 3; + + public static final int MODE_STREAM = 1; + public static final int MODE_BLOCK = 2; + public static final int MODE_COMPRESSED = 3; + + // -- Telnet constants -- + private static final String US_ASCII = "US-ASCII"; + + /** + * The socket used to communicate with the server. + */ + protected Socket socket; + + /** + * The socket input stream. + */ + protected LineInputStream in; + + /** + * The socket output stream. + */ + protected CRLFOutputStream out; + + /** + * The timeout when attempting to connect a socket. + */ + protected int connectionTimeout; + + /** + * The read timeout on sockets. + */ + protected int timeout; + + /** + * If true, print debugging information. + */ + protected boolean debug; + + /** + * The current data transfer process in use by this connection. + */ + protected DTP dtp; + + /** + * The current representation type. + */ + protected int representationType = TYPE_ASCII; + + /** + * The current file structure type. + */ + protected int fileStructure = STRUCTURE_FILE; + + /** + * The current transfer mode. + */ + protected int transferMode = MODE_STREAM; + + /** + * If true, use passive mode. + */ + protected boolean passive = false; + + /** + * Creates a new connection to the server using the default port. + * @param hostname the hostname of the server to connect to + */ + public FTPConnection(String hostname) + throws UnknownHostException, IOException + { + this(hostname, -1, 0, 0, false); + } + + /** + * Creates a new connection to the server. + * @param hostname the hostname of the server to connect to + * @param port the port to connect to(if <=0, use default port) + */ + public FTPConnection(String hostname, int port) + throws UnknownHostException, IOException + { + this(hostname, port, 0, 0, false); + } + + /** + * Creates a new connection to the server. + * @param hostname the hostname of the server to connect to + * @param port the port to connect to(if <=0, use default port) + * @param connectionTimeout the connection timeout, in milliseconds + * @param timeout the I/O timeout, in milliseconds + * @param debug print debugging information + */ + public FTPConnection(String hostname, int port, + int connectionTimeout, int timeout, boolean debug) + throws UnknownHostException, IOException + { + this.connectionTimeout = connectionTimeout; + this.timeout = timeout; + this.debug = debug; + if (port <= 0) + { + port = FTP_PORT; + } + + // Set up socket + socket = new Socket(); + InetSocketAddress address = new InetSocketAddress(hostname, port); + if (connectionTimeout > 0) + { + socket.connect(address, connectionTimeout); + } + else + { + socket.connect(address); + } + if (timeout > 0) + { + socket.setSoTimeout(timeout); + } + + InputStream in = socket.getInputStream(); + in = new BufferedInputStream(in); + in = new CRLFInputStream(in); + this.in = new LineInputStream(in); + OutputStream out = socket.getOutputStream(); + out = new BufferedOutputStream(out); + this.out = new CRLFOutputStream(out); + + // Read greeting + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 220: // hello + break; + default: + throw new FTPException(response); + } + } + + /** + * Authenticate using the specified username and password. + * If the username suffices for the server, the password will not be used + * and may be null. + * @param username the username + * @param password the optional password + * @return true on success, false otherwise + */ + public boolean authenticate(String username, String password) + throws IOException + { + String cmd = USER + ' ' + username; + send(cmd); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 230: // User logged in + return true; + case 331: // User name okay, need password + break; + case 332: // Need account for login + case 530: // No such user + return false; + default: + throw new FTPException(response); + } + cmd = PASS + ' ' + password; + send(cmd); + response = getResponse(); + switch (response.getCode()) + { + case 230: // User logged in + case 202: // Superfluous + return true; + case 332: // Need account for login + case 530: // Bad password + return false; + default: + throw new FTPException(response); + } + } + + /** + * Negotiates TLS over the current connection. + * See IETF draft-murray-auth-ftp-ssl-15.txt for details. + * @param confidential whether to provide confidentiality for the + * connection + */ + public boolean starttls(boolean confidential) + throws IOException + { + return starttls(confidential, new EmptyX509TrustManager()); + } + + /** + * Negotiates TLS over the current connection. + * See IETF draft-murray-auth-ftp-ssl-15.txt for details. + * @param confidential whether to provide confidentiality for the + * connection + * @param tm the trust manager used to validate the server certificate. + */ + public boolean starttls(boolean confidential, TrustManager tm) + throws IOException + { + try + { + // Use SSLSocketFactory to negotiate a TLS session and wrap the + // current socket. + SSLContext context = SSLContext.getInstance("TLS"); + // We don't require strong validation of the server certificate + TrustManager[] trust = new TrustManager[] { tm }; + context.init(null, trust, null); + SSLSocketFactory factory = context.getSocketFactory(); + + send(AUTH + ' ' + TLS); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 500: + case 502: + case 504: + case 534: + case 431: + return false; + case 234: + break; + default: + throw new FTPException(response); + } + + String hostname = socket.getInetAddress().getHostName(); + int port = socket.getPort(); + SSLSocket ss = + (SSLSocket) factory.createSocket(socket, hostname, port, true); + String[] protocols = { "TLSv1", "SSLv3" }; + ss.setEnabledProtocols(protocols); + ss.setUseClientMode(true); + ss.startHandshake(); + + // PBSZ:PROT sequence + send(PBSZ + ' ' + Integer.MAX_VALUE); + response = getResponse(); + switch (response.getCode()) + { + case 501: // syntax error + case 503: // not authenticated + return false; + case 200: + break; + default: + throw new FTPException(response); + } + send(PROT + ' ' +(confidential ? 'P' : 'C')); + response = getResponse(); + switch (response.getCode()) + { + case 503: // not authenticated + case 504: // invalid level + case 536: // level not supported + return false; + case 200: + break; + default: + throw new FTPException(response); + } + + if (confidential) + { + // Set up streams + InputStream in = ss.getInputStream(); + in = new BufferedInputStream(in); + in = new CRLFInputStream(in); + this.in = new LineInputStream(in); + OutputStream out = ss.getOutputStream(); + out = new BufferedOutputStream(out); + this.out = new CRLFOutputStream(out); + } + return true; + } + catch (GeneralSecurityException e) + { + return false; + } + } + + /** + * Changes directory to the specified path. + * @param path an absolute or relative pathname + * @return true on success, false if the specified path does not exist + */ + public boolean changeWorkingDirectory(String path) + throws IOException + { + // Do nothing if the path is empty. + if (path.length() == 0) + return true; + String cmd = CWD + ' ' + path; + send(cmd); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 250: + return true; + case 550: + return false; + default: + throw new FTPException(response); + } + } + + /** + * Changes directory to the parent of the current working directory. + * @return true on success, false otherwise + */ + public boolean changeToParentDirectory() + throws IOException + { + send(CDUP); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 250: + return true; + case 550: + return false; + default: + throw new FTPException(response); + } + } + + /** + * Terminates an authenticated login. + * If file transfer is in progress, it remains active for result response + * only. + */ + public void reinitialize() + throws IOException + { + send(REIN); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 220: + if (dtp != null) + { + dtp.complete(); + dtp = null; + } + break; + default: + throw new FTPException(response); + } + } + + /** + * Terminates the control connection. + * The file transfer connection remains open for result response only. + * This connection is invalid and no further commands may be issued. + */ + public void logout() + throws IOException + { + send(QUIT); + try + { + getResponse(); // not required + } + catch (IOException e) + { + } + if (dtp != null) + { + dtp.complete(); + dtp = null; + } + try + { + socket.close(); + } + catch (IOException e) + { + } + } + + /** + * Initialise the data transfer process. + */ + protected void initialiseDTP() + throws IOException + { + if (dtp != null) + { + dtp.complete(); + dtp = null; + } + + InetAddress localhost = socket.getLocalAddress(); + if (passive) + { + send(PASV); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 227: + String message = response.getMessage(); + try + { + int start = message.indexOf(','); + char c = message.charAt(start - 1); + while (c >= 0x30 && c <= 0x39) + { + c = message.charAt((--start) - 1); + } + int mid1 = start; + for (int i = 0; i < 4; i++) + { + mid1 = message.indexOf(',', mid1 + 1); + } + int mid2 = message.indexOf(',', mid1 + 1); + if (mid1 == -1 || mid2 < mid1) + { + throw new ProtocolException("Malformed 227: " + + message); + } + int end = mid2; + c = message.charAt(end + 1); + while (c >= 0x30 && c <= 0x39) + { + c = message.charAt((++end) + 1); + } + + String address = + message.substring(start, mid1).replace(',', '.'); + int port_hi = + Integer.parseInt(message.substring(mid1 + 1, mid2)); + int port_lo = + Integer.parseInt(message.substring(mid2 + 1, end + 1)); + int port = (port_hi << 8) | port_lo; + + /*System.out.println("Entering passive mode: " + address + + ":" + port);*/ + dtp = new PassiveModeDTP(address, port, localhost, + connectionTimeout, timeout); + break; + } + catch (ArrayIndexOutOfBoundsException e) + { + throw new ProtocolException(e.getMessage() + ": " + + message); + } + catch (NumberFormatException e) + { + throw new ProtocolException(e.getMessage() + ": " + + message); + } + default: + throw new FTPException(response); + } + } + else + { + // Get the local port + int port = socket.getLocalPort() + 1; + int tries = 0; + // Bind the active mode DTP + while (dtp == null) + { + try + { + dtp = new ActiveModeDTP(localhost, port, + connectionTimeout, timeout); + /*System.out.println("Listening on: " + port);*/ + } + catch (BindException e) + { + port++; + tries++; + if (tries > 9) + { + throw e; + } + } + } + + // Send PORT command + CPStringBuilder buf = new CPStringBuilder(PORT); + buf.append(' '); + // Construct the address/port string form + byte[] address = localhost.getAddress(); + for (int i = 0; i < address.length; i++) + { + int a =(int) address[i]; + if (a < 0) + { + a += 0x100; + } + buf.append(a); + buf.append(','); + } + int port_hi =(port & 0xff00) >> 8; + int port_lo =(port & 0x00ff); + buf.append(port_hi); + buf.append(','); + buf.append(port_lo); + send(buf.toString()); + // Get response + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 200: // OK + break; + default: + dtp.abort(); + dtp = null; + throw new FTPException(response); + } + } + dtp.setTransferMode(transferMode); + } + + /** + * Set passive mode. + * @param flag true if we should use passive mode, false otherwise + */ + public void setPassive(boolean flag) + throws IOException + { + if (passive != flag) + { + passive = flag; + initialiseDTP(); + } + } + + /** + * Returns the current representation type of the transfer data. + * @return TYPE_ASCII, TYPE_EBCDIC, or TYPE_BINARY + */ + public int getRepresentationType() + { + return representationType; + } + + /** + * Sets the desired representation type of the transfer data. + * @param type TYPE_ASCII, TYPE_EBCDIC, or TYPE_BINARY + */ + public void setRepresentationType(int type) + throws IOException + { + CPStringBuilder buf = new CPStringBuilder(TYPE); + buf.append(' '); + switch (type) + { + case TYPE_ASCII: + buf.append('A'); + break; + case TYPE_EBCDIC: + buf.append('E'); + break; + case TYPE_BINARY: + buf.append('I'); + break; + default: + throw new IllegalArgumentException(Integer.toString(type)); + } + //buf.append(' '); + //buf.append('N'); + send(buf.toString()); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 200: + representationType = type; + break; + default: + throw new FTPException(response); + } + } + + /** + * Returns the current file structure type. + * @return STRUCTURE_FILE, STRUCTURE_RECORD, or STRUCTURE_PAGE + */ + public int getFileStructure() + { + return fileStructure; + } + + /** + * Sets the desired file structure type. + * @param structure STRUCTURE_FILE, STRUCTURE_RECORD, or STRUCTURE_PAGE + */ + public void setFileStructure(int structure) + throws IOException + { + CPStringBuilder buf = new CPStringBuilder(STRU); + buf.append(' '); + switch (structure) + { + case STRUCTURE_FILE: + buf.append('F'); + break; + case STRUCTURE_RECORD: + buf.append('R'); + break; + case STRUCTURE_PAGE: + buf.append('P'); + break; + default: + throw new IllegalArgumentException(Integer.toString(structure)); + } + send(buf.toString()); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 200: + fileStructure = structure; + break; + default: + throw new FTPException(response); + } + } + + /** + * Returns the current transfer mode. + * @return MODE_STREAM, MODE_BLOCK, or MODE_COMPRESSED + */ + public int getTransferMode() + { + return transferMode; + } + + /** + * Sets the desired transfer mode. + * @param mode MODE_STREAM, MODE_BLOCK, or MODE_COMPRESSED + */ + public void setTransferMode(int mode) + throws IOException + { + CPStringBuilder buf = new CPStringBuilder(MODE); + buf.append(' '); + switch (mode) + { + case MODE_STREAM: + buf.append('S'); + break; + case MODE_BLOCK: + buf.append('B'); + break; + case MODE_COMPRESSED: + buf.append('C'); + break; + default: + throw new IllegalArgumentException(Integer.toString(mode)); + } + send(buf.toString()); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 200: + transferMode = mode; + if (dtp != null) + { + dtp.setTransferMode(mode); + } + break; + default: + throw new FTPException(response); + } + } + + /** + * Retrieves the specified file. + * @param filename the filename of the file to retrieve + * @return an InputStream containing the file content + */ + public InputStream retrieve(String filename) + throws IOException + { + if (dtp == null || transferMode == MODE_STREAM) + { + initialiseDTP(); + } + /* + int size = -1; + String cmd = SIZE + ' ' + filename; + send(cmd); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 213: + size = Integer.parseInt(response.getMessage()); + break; + case 550: // File not found + default: + throw new FTPException(response); + } + */ + String cmd = RETR + ' ' + filename; + send(cmd); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 125: // Data connection already open; transfer starting + case 150: // File status okay; about to open data connection + return dtp.getInputStream(); + default: + throw new FTPException(response); + } + } + + /** + * Returns a stream for uploading a file. + * If a file with the same filename already exists on the server, it will + * be overwritten. + * @param filename the name of the file to save the content as + * @return an OutputStream to write the file data to + */ + public OutputStream store(String filename) + throws IOException + { + if (dtp == null || transferMode == MODE_STREAM) + { + initialiseDTP(); + } + String cmd = STOR + ' ' + filename; + send(cmd); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 125: // Data connection already open; transfer starting + case 150: // File status okay; about to open data connection + return dtp.getOutputStream(); + default: + throw new FTPException(response); + } + } + + /** + * Returns a stream for uploading a file. + * If a file with the same filename already exists on the server, the + * content specified will be appended to the existing file. + * @param filename the name of the file to save the content as + * @return an OutputStream to write the file data to + */ + public OutputStream append(String filename) + throws IOException + { + if (dtp == null || transferMode == MODE_STREAM) + { + initialiseDTP(); + } + String cmd = APPE + ' ' + filename; + send(cmd); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 125: // Data connection already open; transfer starting + case 150: // File status okay; about to open data connection + return dtp.getOutputStream(); + default: + throw new FTPException(response); + } + } + + /** + * This command may be required by some servers to reserve sufficient + * storage to accommodate the new file to be transferred. + * It should be immediately followed by a store or + * append. + * @param size the number of bytes of storage to allocate + */ + public void allocate(long size) + throws IOException + { + String cmd = ALLO + ' ' + size; + send(cmd); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 200: // OK + case 202: // Superfluous + break; + default: + throw new FTPException(response); + } + } + + /** + * Renames a file. + * @param oldName the current name of the file + * @param newName the new name + * @return true if successful, false otherwise + */ + public boolean rename(String oldName, String newName) + throws IOException + { + String cmd = RNFR + ' ' + oldName; + send(cmd); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 450: // File unavailable + case 550: // File not found + return false; + case 350: // Pending + break; + default: + throw new FTPException(response); + } + cmd = RNTO + ' ' + newName; + send(cmd); + response = getResponse(); + switch (response.getCode()) + { + case 250: // OK + return true; + case 450: + case 550: + return false; + default: + throw new FTPException(response); + } + } + + /** + * Aborts the transfer in progress. + * @return true if a transfer was in progress, false otherwise + */ + public boolean abort() + throws IOException + { + send(ABOR); + FTPResponse response = getResponse(); + // Abort client DTP + if (dtp != null) + { + dtp.abort(); + } + switch (response.getCode()) + { + case 226: // successful abort + return false; + case 426: // interrupted + response = getResponse(); + if (response.getCode() == 226) + { + return true; + } + // Otherwise fall through to throw exception + default: + throw new FTPException(response); + } + } + + /** + * Causes the file specified to be deleted at the server site. + * @param filename the file to delete + */ + public boolean delete(String filename) + throws IOException + { + String cmd = DELE + ' ' + filename; + send(cmd); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 250: // OK + return true; + case 450: // File unavailable + case 550: // File not found + return false; + default: + throw new FTPException(response); + } + } + + /** + * Causes the directory specified to be deleted. + * This may be an absolute or relative pathname. + * @param pathname the directory to delete + */ + public boolean removeDirectory(String pathname) + throws IOException + { + String cmd = RMD + ' ' + pathname; + send(cmd); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 250: // OK + return true; + case 550: // File not found + return false; + default: + throw new FTPException(response); + } + } + + /** + * Causes the directory specified to be created at the server site. + * This may be an absolute or relative pathname. + * @param pathname the directory to create + */ + public boolean makeDirectory(String pathname) + throws IOException + { + String cmd = MKD + ' ' + pathname; + send(cmd); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 257: // Directory created + return true; + case 550: // File not found + return false; + default: + throw new FTPException(response); + } + } + + /** + * Returns the current working directory. + */ + public String getWorkingDirectory() + throws IOException + { + send(PWD); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 257: + String message = response.getMessage(); + if (message.charAt(0) == '"') + { + int end = message.indexOf('"', 1); + if (end == -1) + { + throw new ProtocolException(message); + } + return message.substring(1, end); + } + else + { + int end = message.indexOf(' '); + if (end == -1) + { + return message; + } + else + { + return message.substring(0, end); + } + } + default: + throw new FTPException(response); + } + } + + /** + * Returns a listing of information about the specified pathname. + * If the pathname specifies a directory or other group of files, the + * server should transfer a list of files in the specified directory. + * If the pathname specifies a file then the server should send current + * information on the file. A null argument implies the user's + * current working or default directory. + * @param pathname the context pathname, or null + */ + public InputStream list(String pathname) + throws IOException + { + if (dtp == null || transferMode == MODE_STREAM) + { + initialiseDTP(); + } + if (pathname == null) + { + send(LIST); + } + else + { + String cmd = LIST + ' ' + pathname; + send(cmd); + } + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 125: // Data connection already open; transfer starting + case 150: // File status okay; about to open data connection + return dtp.getInputStream(); + default: + throw new FTPException(response); + } + } + + /** + * Returns a directory listing. The pathname should specify a + * directory or other system-specific file group descriptor; a null + * argument implies the user's current working or default directory. + * @param pathname the directory pathname, or null + * @return a list of filenames(strings) + */ + public List nameList(String pathname) + throws IOException + { + if (dtp == null || transferMode == MODE_STREAM) + { + initialiseDTP(); + } + if (pathname == null) + { + send(NLST); + } + else + { + String cmd = NLST + ' ' + pathname; + send(cmd); + } + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 125: // Data connection already open; transfer starting + case 150: // File status okay; about to open data connection + InputStream in = dtp.getInputStream(); + in = new BufferedInputStream(in); + in = new CRLFInputStream(in); // TODO ensure that TYPE is correct + LineInputStream li = new LineInputStream(in); + ArrayList ret = new ArrayList(); + for (String line = li.readLine(); + line != null; + line = li.readLine()) + { + ret.add(line); + } + li.close(); + return ret; + default: + throw new FTPException(response); + } + } + + /** + * Returns the type of operating system at the server. + */ + public String system() + throws IOException + { + send(SYST); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 215: + String message = response.getMessage(); + int end = message.indexOf(' '); + if (end == -1) + { + return message; + } + else + { + return message.substring(0, end); + } + default: + throw new FTPException(response); + } + } + + /** + * Does nothing. + * This method can be used to ensure that the connection does not time + * out. + */ + public void noop() + throws IOException + { + send(NOOP); + FTPResponse response = getResponse(); + switch (response.getCode()) + { + case 200: + break; + default: + throw new FTPException(response); + } + } + + // -- I/O -- + + /** + * Sends the specified command line to the server. + * The CRLF sequence is automatically appended. + * @param cmd the command line to send + */ + protected void send(String cmd) + throws IOException + { + byte[] data = cmd.getBytes(US_ASCII); + out.write(data); + out.writeln(); + out.flush(); + } + + /** + * Reads the next response from the server. + * If the server sends the "transfer complete" code, this is handled here, + * and the next response is passed to the caller. + */ + protected FTPResponse getResponse() + throws IOException + { + FTPResponse response = readResponse(); + if (response.getCode() == 226) + { + if (dtp != null) + { + dtp.transferComplete(); + } + response = readResponse(); + } + return response; + } + + /** + * Reads and parses the next response from the server. + */ + protected FTPResponse readResponse() + throws IOException + { + String line = in.readLine(); + if (line == null) + { + throw new ProtocolException( "EOF"); + } + if (line.length() < 4) + { + throw new ProtocolException(line); + } + int code = parseCode(line); + if (code == -1) + { + throw new ProtocolException(line); + } + char c = line.charAt(3); + if (c == ' ') + { + return new FTPResponse(code, line.substring(4)); + } + else if (c == '-') + { + CPStringBuilder buf = new CPStringBuilder(line.substring(4)); + buf.append('\n'); + while(true) + { + line = in.readLine(); + if (line == null) + { + throw new ProtocolException("EOF"); + } + if (line.length() >= 4 && + line.charAt(3) == ' ' && + parseCode(line) == code) + { + return new FTPResponse(code, line.substring(4), + buf.toString()); + } + else + { + buf.append(line); + buf.append('\n'); + } + } + } + else + { + throw new ProtocolException(line); + } + } + + /* + * Parses the 3-digit numeric code at the beginning of the given line. + * Returns -1 on failure. + */ + static final int parseCode(String line) + { + char[] c = { line.charAt(0), line.charAt(1), line.charAt(2) }; + int ret = 0; + for (int i = 0; i < 3; i++) + { + int digit =((int) c[i]) - 0x30; + if (digit < 0 || digit > 9) + { + return -1; + } + // Computing integer powers is way too expensive in Java! + switch (i) + { + case 0: + ret +=(100 * digit); + break; + case 1: + ret +=(10 * digit); + break; + case 2: + ret += digit; + break; + } + } + return ret; + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/FTPException.java b/libjava/classpath/gnu/java/net/protocol/ftp/FTPException.java new file mode 100644 index 000000000..1a7fcb85d --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/FTPException.java @@ -0,0 +1,75 @@ +/* FTPException.java -- + Copyright (C) 2003. 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.net.protocol.ftp; + +import java.io.IOException; + +/** + * An FTP control exception. + * + * @author Chris Burdess (dog@gnu.org) + */ +public class FTPException + extends IOException +{ + + /** + * The response that provoked this exception. + */ + protected final FTPResponse response; + + /** + * Constructs a new FTP exception. + * @param response the response that provoked this exception + */ + public FTPException(FTPResponse response) + { + super(response.getMessage()); + this.response = response; + } + + /** + * Returns the response that provoked this exception. + */ + public FTPResponse getResponse() + { + return response; + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/FTPResponse.java b/libjava/classpath/gnu/java/net/protocol/ftp/FTPResponse.java new file mode 100644 index 000000000..2620f0d70 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/FTPResponse.java @@ -0,0 +1,111 @@ +/* FTPResponse.java -- + Copyright (C) 2003, 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.net.protocol.ftp; + +/** + * An FTP control response. + * + * @author Chris Burdess (dog@gnu.org) + */ +public final class FTPResponse +{ + + /** + * The 3-digit status code. + */ + protected final int code; + + /** + * The human-readable message. + */ + protected final String message; + + /** + * Multiline data, if present. + */ + protected final String data; + + /** + * Constructs a new FTP response. + * @param code the status code + * @param message the message + */ + public FTPResponse(int code, String message) + { + this(code, message, null); + } + + /** + * Constructs a new multiline FTP response. + * @param code the status code + * @param message the message + * @param data multiline data + */ + public FTPResponse(int code, String message, String data) + { + this.code = code; + this.message = message; + this.data = data; + } + + /** + * Returns the 3-digit status code. + */ + public int getCode() + { + return code; + } + + /** + * Returns the human-readable message. + */ + public String getMessage() + { + return message; + } + + /** + * Returns the multiline data, or null if there was no such data. + */ + public String getData() + { + return data; + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/FTPURLConnection.java b/libjava/classpath/gnu/java/net/protocol/ftp/FTPURLConnection.java new file mode 100644 index 000000000..8cc1fafd1 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/FTPURLConnection.java @@ -0,0 +1,375 @@ +/* FTPURLConnection.java -- + Copyright (C) 2003, 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.net.protocol.ftp; + +import gnu.classpath.SystemProperties; +import gnu.java.net.GetLocalHostAction; + +import java.io.FilterInputStream; +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.URL; +import java.net.URLConnection; +import java.security.AccessController; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * An FTP URL connection. + * + * @author Chris Burdess (dog@gnu.org) + */ +public class FTPURLConnection + extends URLConnection +{ + + /** + * The connection managing the protocol exchange. + */ + protected FTPConnection connection; + + protected boolean passive; + protected int representationType; + protected int fileStructure; + protected int transferMode; + + /** + * Constructs an FTP connection to the specified URL. + * @param url the URL + */ + public FTPURLConnection(URL url) + { + super(url); + passive = true; + representationType = FTPConnection.TYPE_BINARY; + fileStructure = -1; + transferMode = -1; + } + + /** + * Establishes the connection. + */ + public void connect() + throws IOException + { + if (connected) + { + return; + } + String host = url.getHost(); + int port = url.getPort(); + String username = url.getUserInfo(); + String password = null; + if (username != null) + { + int ci = username.indexOf(':'); + if (ci != -1) + { + password = username.substring(ci + 1); + username = username.substring(0, ci); + } + } + else + { + username = "anonymous"; + GetLocalHostAction a = new GetLocalHostAction(); + InetAddress localhost = AccessController.doPrivileged(a); + password = SystemProperties.getProperty("user.name") + "@" + + ((localhost == null) ? "localhost" : localhost.getHostName()); + } + connection = new FTPConnection(host, port); + if (!connection.authenticate(username, password)) + { + throw new SecurityException("Authentication failed"); + } + connection.setPassive(passive); + if (representationType != -1) + { + connection.setRepresentationType(representationType); + } + if (fileStructure != -1) + { + connection.setFileStructure(fileStructure); + } + if (transferMode != -1) + { + connection.setTransferMode(transferMode); + } + } + + /** + * This connection supports doInput. + */ + public void setDoInput(boolean doinput) + { + doInput = doinput; + } + + /** + * This connection supports doOutput. + */ + public void setDoOutput(boolean dooutput) + { + doOutput = dooutput; + } + + /** + * Returns an input stream that reads from this open connection. + */ + public InputStream getInputStream() + throws IOException + { + if (!connected) + { + connect(); + } + String path = url.getPath(); + if (connection.changeWorkingDirectory(path)) + { + return this.new ClosingInputStream(connection.list(null)); + } + else + { + return this.new ClosingInputStream(connection.retrieve(path)); + } + } + + /** + * Returns an output stream that writes to this connection. + */ + public OutputStream getOutputStream() + throws IOException + { + if (!connected) + { + connect(); + } + String path = url.getPath(); + return this.new ClosingOutputStream(connection.store(path)); + } + + public String getRequestProperty(String key) + { + if ("passive".equals(key)) + { + return Boolean.toString(passive); + } + else if ("representationType".equals(key)) + { + switch (representationType) + { + case FTPConnection.TYPE_ASCII: + return "ASCII"; + case FTPConnection.TYPE_EBCDIC: + return "EBCDIC"; + case FTPConnection.TYPE_BINARY: + return "BINARY"; + } + } + else if ("fileStructure".equals(key)) + { + switch (fileStructure) + { + case FTPConnection.STRUCTURE_FILE: + return "FILE"; + case FTPConnection.STRUCTURE_RECORD: + return "RECORD"; + case FTPConnection.STRUCTURE_PAGE: + return "PAGE"; + } + } + else if ("transferMode".equals(key)) + { + switch (transferMode) + { + case FTPConnection.MODE_STREAM: + return "STREAM"; + case FTPConnection.MODE_BLOCK: + return "BLOCK"; + case FTPConnection.MODE_COMPRESSED: + return "COMPRESSED"; + } + } + return null; + } + + public Map> getRequestProperties() + { + Map> map = new HashMap>(); + addRequestPropertyValue(map, "passive"); + addRequestPropertyValue(map, "representationType"); + addRequestPropertyValue(map, "fileStructure"); + addRequestPropertyValue(map, "transferMode"); + return map; + } + + private void addRequestPropertyValue(Map> map, + String key) + { + String value = getRequestProperty(key); + ArrayList l = new ArrayList(); + l.add(value); + map.put(key, l); + } + + public void setRequestProperty(String key, String value) + { + if (connected) + { + throw new IllegalStateException(); + } + if ("passive".equals(key)) + { + passive = Boolean.valueOf(value).booleanValue(); + } + else if ("representationType".equals(key)) + { + if ("A".equalsIgnoreCase(value) || + "ASCII".equalsIgnoreCase(value)) + { + representationType = FTPConnection.TYPE_ASCII; + } + else if ("E".equalsIgnoreCase(value) || + "EBCDIC".equalsIgnoreCase(value)) + { + representationType = FTPConnection.TYPE_EBCDIC; + } + else if ("I".equalsIgnoreCase(value) || + "BINARY".equalsIgnoreCase(value)) + { + representationType = FTPConnection.TYPE_BINARY; + } + else + { + throw new IllegalArgumentException(value); + } + } + else if ("fileStructure".equals(key)) + { + if ("F".equalsIgnoreCase(value) || + "FILE".equalsIgnoreCase(value)) + { + fileStructure = FTPConnection.STRUCTURE_FILE; + } + else if ("R".equalsIgnoreCase(value) || + "RECORD".equalsIgnoreCase(value)) + { + fileStructure = FTPConnection.STRUCTURE_RECORD; + } + else if ("P".equalsIgnoreCase(value) || + "PAGE".equalsIgnoreCase(value)) + { + fileStructure = FTPConnection.STRUCTURE_PAGE; + } + else + { + throw new IllegalArgumentException(value); + } + } + else if ("transferMode".equals(key)) + { + if ("S".equalsIgnoreCase(value) || + "STREAM".equalsIgnoreCase(value)) + { + transferMode = FTPConnection.MODE_STREAM; + } + else if ("B".equalsIgnoreCase(value) || + "BLOCK".equalsIgnoreCase(value)) + { + transferMode = FTPConnection.MODE_BLOCK; + } + else if ("C".equalsIgnoreCase(value) || + "COMPRESSED".equalsIgnoreCase(value)) + { + transferMode = FTPConnection.MODE_COMPRESSED; + } + else + { + throw new IllegalArgumentException(value); + } + } + } + + public void addRequestProperty(String key, String value) + { + setRequestProperty(key, value); + } + + class ClosingInputStream + extends FilterInputStream + { + + ClosingInputStream(InputStream in) + { + super(in); + } + + public void close() + throws IOException + { + super.close(); + connection.logout(); + } + + } + + class ClosingOutputStream + extends FilterOutputStream + { + + ClosingOutputStream(OutputStream out) + { + super(out); + } + + public void close() + throws IOException + { + super.close(); + connection.logout(); + } + + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/Handler.java b/libjava/classpath/gnu/java/net/protocol/ftp/Handler.java new file mode 100644 index 000000000..7638b6664 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/Handler.java @@ -0,0 +1,69 @@ +/* Handler.java -- + Copyright (C) 2003, 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.net.protocol.ftp; + +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; + +/** + * An FTP URL stream handler. + * + * @author Chris Burdess (dog@gnu.org) + */ +public class Handler + extends URLStreamHandler +{ + + protected int getDefaultPort() + { + return FTPConnection.FTP_PORT; + } + + /** + * Returns an FTPURLConnection for the given URL. + */ + public URLConnection openConnection(URL url) + throws IOException + { + return new FTPURLConnection(url); + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/PassiveModeDTP.java b/libjava/classpath/gnu/java/net/protocol/ftp/PassiveModeDTP.java new file mode 100644 index 000000000..a74346c74 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/PassiveModeDTP.java @@ -0,0 +1,200 @@ +/* PassiveModeDTP.java -- + Copyright (C) 2003, 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.net.protocol.ftp; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; + +/** + * A passive mode FTP data transfer process. + * This connects to the host specified and proxies the resulting socket's + * input and output streams. + * + * @author Chris Burdess (dog@gnu.org) + */ +final class PassiveModeDTP + implements DTP +{ + + final String address; + final int port; + Socket socket; + DTPInputStream in; + DTPOutputStream out; + boolean completed; + boolean inProgress; + int transferMode; + + PassiveModeDTP(String address, int port, InetAddress localhost, + int connectionTimeout, int timeout) + throws IOException + { + this.address = address; + this.port = port; + completed = false; + inProgress = false; + socket = new Socket(); + InetSocketAddress remote = new InetSocketAddress(address, port); + InetSocketAddress local = new InetSocketAddress(localhost, port + 1); + socket.bind(local); + if (connectionTimeout > 0) + { + socket.connect(remote, connectionTimeout); + } + else + { + socket.connect(remote); + } + if (timeout > 0) + { + socket.setSoTimeout(timeout); + } + } + + /** + * Returns an input stream from which a remote file can be read. + */ + public InputStream getInputStream() + throws IOException + { + if (inProgress) + { + throw new IOException("Transfer in progress"); + } + switch (transferMode) + { + case FTPConnection.MODE_STREAM: + in = new StreamInputStream(this, socket.getInputStream()); + break; + case FTPConnection.MODE_BLOCK: + in = new BlockInputStream(this, socket.getInputStream()); + break; + case FTPConnection.MODE_COMPRESSED: + in = new CompressedInputStream(this, socket.getInputStream()); + break; + default: + throw new IllegalStateException("Invalid transfer mode"); + } + in.setTransferComplete(false); + return in; + } + + /** + * Returns an output stream to which a local file can be written for + * upload. + */ + public OutputStream getOutputStream() + throws IOException + { + if (inProgress) + { + throw new IOException("Transfer in progress"); + } + switch (transferMode) + { + case FTPConnection.MODE_STREAM: + out = new StreamOutputStream(this, socket.getOutputStream()); + break; + case FTPConnection.MODE_BLOCK: + out = new BlockOutputStream(this, socket.getOutputStream()); + break; + case FTPConnection.MODE_COMPRESSED: + out = new CompressedOutputStream(this, socket.getOutputStream()); + break; + default: + throw new IllegalStateException("Invalid transfer mode"); + } + out.setTransferComplete(false); + return out; + } + + public void setTransferMode(int mode) + { + transferMode = mode; + } + + public void complete() + { + completed = true; + if (!inProgress) + { + transferComplete(); + } + } + + public boolean abort() + { + completed = true; + transferComplete(); + return inProgress; + } + + /* + * Called by DTPInputStream or DTPOutputStream when end of + * stream is reached. + */ + public void transferComplete() + { + if (in != null) + { + in.setTransferComplete(true); + } + if (out != null) + { + out.setTransferComplete(true); + } + inProgress = false; + completed = completed ||(transferMode == FTPConnection.MODE_STREAM); + if (completed && socket != null) + { + try + { + socket.close(); + } + catch (IOException e) + { + } + } + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/StreamInputStream.java b/libjava/classpath/gnu/java/net/protocol/ftp/StreamInputStream.java new file mode 100644 index 000000000..beee14bcb --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/StreamInputStream.java @@ -0,0 +1,94 @@ +/* StreamInputStream.java -- + Copyright (C) 2003, 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.net.protocol.ftp; + +import java.io.IOException; +import java.io.InputStream; + +/** + * A DTP input stream that implements the FTP stream data transfer mode. + * + * @author Chris Burdess (dog@gnu.org) + */ +class StreamInputStream + extends DTPInputStream +{ + + StreamInputStream(DTP dtp, InputStream in) + { + super(dtp, in); + } + + public int read() + throws IOException + { + if (transferComplete) + { + return -1; + } + int c = in.read(); + if (c == -1) + { + close(); + } + return c; + } + + 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 (transferComplete) + { + return -1; + } + int l = in.read(buf, off, len); + if (l == -1) + { + close(); + } + return l; + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/StreamOutputStream.java b/libjava/classpath/gnu/java/net/protocol/ftp/StreamOutputStream.java new file mode 100644 index 000000000..2df1a87d8 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/StreamOutputStream.java @@ -0,0 +1,84 @@ +/* StreamOutputStream.java -- + Copyright (C) 2003, 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.net.protocol.ftp; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * A DTP output stream that implements the FTP stream transfer mode. + * + * @author Chris Burdess (dog@gnu.org) + */ +class StreamOutputStream + extends DTPOutputStream +{ + + StreamOutputStream(DTP dtp, OutputStream out) + { + super(dtp, out); + } + + public void write(int c) + throws IOException + { + if (transferComplete) + { + return; + } + out.write(c); + } + + public void write(byte[] b) + throws IOException + { + write(b, 0, b.length); + } + + public void write(byte[] b, int off, int len) + throws IOException + { + if (transferComplete) + { + return; + } + out.write(b, off, len); + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/ftp/package.html b/libjava/classpath/gnu/java/net/protocol/ftp/package.html new file mode 100644 index 000000000..fa3e34d74 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/ftp/package.html @@ -0,0 +1,60 @@ + + + + +GNU Classpath - gnu.java.net.protocol.ftp + + + +

+This package contains an FTP client. It can handle both active and passive +mode connections and the various transfer modes and representation types. +

+ +

+Interaction with the server is via a simple stream interface. Only one +concurrent stream (input or output) is supported. +

+ +

+The control connection to the server can be protected using TLS +(the starttls method). +

+ + + diff --git a/libjava/classpath/gnu/java/net/protocol/http/Authenticator.java b/libjava/classpath/gnu/java/net/protocol/http/Authenticator.java new file mode 100644 index 000000000..b4ee41e11 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/http/Authenticator.java @@ -0,0 +1,58 @@ +/* Authenticator.java -- + 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.net.protocol.http; + +/** + * Callback interface for managing authentication. + * @see Request#setAuthenticator + * + * @author Chris Burdess (dog@gnu.org) + */ +public interface Authenticator +{ + + /** + * Returns the credentials to supply for the given realm. + * @param realm the authentication realm + * @param attempt zero on first authentication attempt, increments on each + * unsuccessful attempt + */ + Credentials getCredentials(String realm, int attempt); + +} diff --git a/libjava/classpath/gnu/java/net/protocol/http/ByteArrayRequestBodyWriter.java b/libjava/classpath/gnu/java/net/protocol/http/ByteArrayRequestBodyWriter.java new file mode 100644 index 000000000..22a33ccd3 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/http/ByteArrayRequestBodyWriter.java @@ -0,0 +1,106 @@ +/* ByteArrayRequestBodyWriter.java -- + 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.net.protocol.http; + +/** + * A simple request body writer using a byte array. + * + * @author Chris Burdess (dog@gnu.org) + */ +public class ByteArrayRequestBodyWriter + implements RequestBodyWriter +{ + + /** + * The content. + */ + protected byte[] content; + + /** + * The position within the content at which the next read will occur. + */ + protected int pos; + + /** + * Constructs a new byte array request body writer with the specified + * content. + * @param content the content buffer + */ + public ByteArrayRequestBodyWriter(byte[] content) + { + this.content = content; + pos = 0; + } + + /** + * Returns the total number of bytes that will be written in a single pass + * by this writer. + */ + public int getContentLength() + { + return content.length; + } + + /** + * Initialises the writer. + * This will be called before each pass. + */ + public void reset() + { + pos = 0; + } + + /** + * Writes body content to the supplied buffer. + * @param buffer the content buffer + * @return the number of bytes written + */ + public int write(byte[] buffer) + { + int len = content.length - pos; + len = (buffer.length < len) ? buffer.length : len; + if (len > -1) + { + System.arraycopy(content, pos, buffer, 0, len); + pos += len; + } + return len; + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/http/ChunkedInputStream.java b/libjava/classpath/gnu/java/net/protocol/http/ChunkedInputStream.java new file mode 100644 index 000000000..33df0df95 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/http/ChunkedInputStream.java @@ -0,0 +1,223 @@ +/* ChunkedInputStream.java -- + 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.net.protocol.http; + +import gnu.java.lang.CPStringBuilder; + +import java.io.IOException; +import java.io.InputStream; +import java.net.ProtocolException; + + +// +// Note that we rely on the implemtation of skip() in the super class +// (InputStream) calling our read methods to account for chunk headers +// while skipping. +// + + +/** + * Input stream wrapper for the "chunked" transfer-coding. + * + * @author Chris Burdess (dog@gnu.org) + */ +public class ChunkedInputStream + extends InputStream +{ + Headers headers; + + /** The underlying stream. */ + private InputStream in; + + /** 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; + + /** + * Constructor. + * @param in the response socket input stream + * @param headers the headers to receive additional header lines + */ + public ChunkedInputStream(InputStream in, Headers headers) + { + this.in = in; + this.headers = headers; + size = -1; + count = 0; + meta = true; + } + + public int read() + throws IOException + { + byte[] buf = new byte[1]; + int len = read(buf, 0, 1); + if (len == -1) + { + return -1; + } + return 0xff & buf[0]; + } + + public synchronized int read(byte[] buffer, int offset, int length) + throws IOException + { + if (eof) + { + return -1; + } + if (meta) + { + // Read chunk header + int c, last = 0; + boolean seenSemi = false; + CPStringBuilder buf = new CPStringBuilder(); + do + { + c = in.read(); + if (c == 0x3b) // ; + { + seenSemi = true; + } + else if (c == 0x0a && last == 0x0d) // CRLF + { + try + { + size = Integer.parseInt(buf.toString(), 16); + } + catch (NumberFormatException nfe) + { + IOException ioe = new IOException("Bad chunk header"); + ioe.initCause(nfe); + // Unrecoverable. Don't try to read more. + in.close(); + throw ioe; + } + break; + } + else if (!seenSemi && c >= 0x30) + { + buf.append ((char) c); + } + last = c; + } + while(c != -1); + count = 0; + meta = false; + } + if (size == 0) + { + // Read trailer + headers.parse(in); + eof = true; + return -1; + } + else + { + 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) + { + // EOF before CRLF: bad, but ignore + eof = true; + return -1; + } + if (c1 != 0x0d || c2 != 0x0a) + { + throw new ProtocolException("expecting CRLF: " + c1 + "," + c2); + } + meta = true; + } + return len; + } + } + + /** + * This method returns the number of bytes that can be read from + * this stream before a read might block. Even if the underlying + * InputStream has data available past the end of the current chunk, + * we have no way of knowing how large the next chunk header will + * be. So we cannot report available data past the current chunk. + * + * @return The number of bytes that can be read before a read might + * block + * + * @exception IOException If an error occurs + */ + public int available() throws IOException + { + if (meta) + return 0; + + return Math.min(in.available(), size - count); + } + + /** + * This method closes the ChunkedInputStream by closing the underlying + * InputStream. + * + * @exception IOException If an error occurs + */ + public void close() throws IOException + { + in.close(); + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/http/Cookie.java b/libjava/classpath/gnu/java/net/protocol/http/Cookie.java new file mode 100644 index 000000000..122a23f79 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/http/Cookie.java @@ -0,0 +1,161 @@ +/* Cookie.java -- + 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.net.protocol.http; + +import gnu.java.lang.CPStringBuilder; + +import java.util.Date; + +/** + * An HTTP cookie, as specified in RFC 2109. + * + * @author Chris Burdess (dog@gnu.org) + */ +public class Cookie +{ + + /** + * The name of the cookie. + */ + protected final String name; + + /** + * The value of the cookie. + */ + protected final String value; + + /** + * Optional documentation of the intended use of the cookie. + */ + protected final String comment; + + /** + * The domain for which the cookie is valid. + */ + protected final String domain; + + /** + * Optional subset of URL paths within the domain for which the cookie is + * valid. + */ + protected final String path; + + /** + * Indicates that the user-agent should only use secure means to transmit + * this cookie to the server. + */ + protected final boolean secure; + + /** + * The date at which this cookie expires. + */ + protected final Date expires; + + public Cookie(String name, String value, String comment, String domain, + String path, boolean secure, Date expires) + { + this.name = name; + this.value = value; + this.comment = comment; + this.domain = domain; + this.path = path; + this.secure = secure; + this.expires = expires; + } + + public String getName() + { + return name; + } + + public String getValue() + { + return value; + } + + public String getComment() + { + return comment; + } + + public String getDomain() + { + return domain; + } + + public String getPath() + { + return path; + } + + public boolean isSecure() + { + return secure; + } + + public Date getExpiryDate() + { + return expires; + } + + public String toString() + { + return toString(true, true); + } + + public String toString(boolean showPath, boolean showDomain) + { + CPStringBuilder buf = new CPStringBuilder(); + buf.append(name); + buf.append('='); + buf.append(value); + if (showPath) + { + buf.append("; $Path="); + buf.append(path); + } + if (showDomain) + { + buf.append("; $Domain="); + buf.append(domain); + } + return buf.toString(); + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/http/CookieManager.java b/libjava/classpath/gnu/java/net/protocol/http/CookieManager.java new file mode 100644 index 000000000..da3686689 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/http/CookieManager.java @@ -0,0 +1,65 @@ +/* CookieManager.java -- + 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.net.protocol.http; + +/** + * Cookie manager interface. + * If an application wants to handle cookies, they should implement this + * interface and register the instance with each HTTPConnection they use. + * + * @author Chris Burdess (dog@gnu.org) + */ +public interface CookieManager +{ + + /** + * Stores a cookie in the cookie manager. + * @param cookie the cookie to store + */ + void setCookie(Cookie cookie); + + /** + * Retrieves the cookies matching the specified criteria. + * @param host the host name + * @param secure whether the connection is secure + * @param path the path to access + */ + Cookie[] getCookies(String host, boolean secure, String path); + +} diff --git a/libjava/classpath/gnu/java/net/protocol/http/Credentials.java b/libjava/classpath/gnu/java/net/protocol/http/Credentials.java new file mode 100644 index 000000000..f95b4b53c --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/http/Credentials.java @@ -0,0 +1,87 @@ +/* Credentials.java -- + 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.net.protocol.http; + +/** + * Represents a username/password combination that can be used to + * authenticate to an HTTP server. + * + * @author Chris Burdess (dog@gnu.org) + */ +public class Credentials +{ + + /** + * The username. + */ + private String username; + + /** + * The password. + */ + private String password; + + /** + * Constructor. + * @param username the username + * @param password the password + */ + public Credentials(String username, String password) + { + this.username = username; + this.password = password; + } + + /** + * Returns the username. + */ + public String getUsername() + { + return username; + } + + /** + * Returns the password. + */ + public String getPassword() + { + return password; + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/http/HTTPConnection.java b/libjava/classpath/gnu/java/net/protocol/http/HTTPConnection.java new file mode 100644 index 000000000..b96bf4c54 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/http/HTTPConnection.java @@ -0,0 +1,897 @@ +/* HTTPConnection.java -- + Copyright (C) 2004, 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.java.net.protocol.http; + +import gnu.classpath.SystemProperties; + +import gnu.java.lang.CPStringBuilder; +import gnu.java.net.EmptyX509TrustManager; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketException; +import java.security.GeneralSecurityException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; + +import javax.net.ssl.HandshakeCompletedListener; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; + +/** + * A connection to an HTTP server. + * + * @author Chris Burdess (dog@gnu.org) + */ +public class HTTPConnection +{ + + /** + * The default HTTP port. + */ + public static final int HTTP_PORT = 80; + + /** + * The default HTTPS port. + */ + public static final int HTTPS_PORT = 443; + + private static final String userAgent = SystemProperties.getProperty("http.agent"); + + /** + * The host name of the server to connect to. + */ + protected final String hostname; + + /** + * The port to connect to. + */ + protected final int port; + + /** + * Whether the connection should use transport level security (HTTPS). + */ + protected final boolean secure; + + /** + * The connection timeout for connecting the underlying socket. + */ + protected final int connectionTimeout; + + /** + * The read timeout for reads on the underlying socket. + */ + protected final int timeout; + + /** + * The host name of the proxy to connect to. + */ + protected String proxyHostname; + + /** + * The port on the proxy to connect to. + */ + protected int proxyPort; + + /** + * The major version of HTTP supported by this client. + */ + protected int majorVersion; + + /** + * The minor version of HTTP supported by this client. + */ + protected int minorVersion; + + private final List handshakeCompletedListeners; + + /** + * The socket this connection communicates on. + */ + protected Socket socket; + + /** + * The SSL socket factory to use. + */ + private SSLSocketFactory sslSocketFactory; + + /** + * The socket input stream. + */ + protected InputStream in; + + /** + * The socket output stream. + */ + protected OutputStream out; + + /** + * Nonce values seen by this connection. + */ + private Map nonceCounts; + + /** + * The cookie manager for this connection. + */ + protected CookieManager cookieManager; + + + /** + * The pool that this connection is a member of (if any). + */ + private Pool pool; + + /** + * Creates a new HTTP connection. + * @param hostname the name of the host to connect to + */ + public HTTPConnection(String hostname) + { + this(hostname, HTTP_PORT, false, 0, 0); + } + + /** + * Creates a new HTTP or HTTPS connection. + * @param hostname the name of the host to connect to + * @param secure whether to use a secure connection + */ + public HTTPConnection(String hostname, boolean secure) + { + this(hostname, secure ? HTTPS_PORT : HTTP_PORT, secure, 0, 0); + } + + /** + * Creates a new HTTP or HTTPS connection on the specified port. + * @param hostname the name of the host to connect to + * @param secure whether to use a secure connection + * @param connectionTimeout the connection timeout + * @param timeout the socket read timeout + */ + public HTTPConnection(String hostname, boolean secure, + int connectionTimeout, int timeout) + { + this(hostname, secure ? HTTPS_PORT : HTTP_PORT, secure, + connectionTimeout, timeout); + } + + /** + * Creates a new HTTP connection on the specified port. + * @param hostname the name of the host to connect to + * @param port the port on the host to connect to + */ + public HTTPConnection(String hostname, int port) + { + this(hostname, port, false, 0, 0); + } + + /** + * Creates a new HTTP or HTTPS connection on the specified port. + * @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 + */ + public HTTPConnection(String hostname, int port, boolean secure) + { + this(hostname, port, secure, 0, 0); + } + + /** + * Creates a new HTTP or HTTPS connection on the specified port. + * @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 + * @param connectionTimeout the connection timeout + * @param timeout the socket read timeout + * + * @throws IllegalArgumentException if either connectionTimeout or + * timeout less than zero. + */ + public HTTPConnection(String hostname, int port, boolean secure, + int connectionTimeout, int timeout) + { + if (connectionTimeout < 0 || timeout < 0) + throw new IllegalArgumentException(); + + this.hostname = hostname; + this.port = port; + this.secure = secure; + this.connectionTimeout = connectionTimeout; + this.timeout = timeout; + majorVersion = minorVersion = 1; + handshakeCompletedListeners + = new ArrayList(2); + } + + /** + * Returns the name of the host to connect to. + */ + public String getHostName() + { + return hostname; + } + + /** + * Returns the port on the host to connect to. + */ + public int getPort() + { + return port; + } + + /** + * Indicates whether to use a secure connection or not. + */ + public boolean isSecure() + { + return secure; + } + + /** + * Returns the HTTP version string supported by this connection. + * @see #majorVersion + * @see #minorVersion + */ + public String getVersion() + { + return "HTTP/" + majorVersion + '.' + minorVersion; + } + + /** + * Sets the HTTP version supported by this connection. + * @param majorVersion the major version + * @param minorVersion the minor version + */ + public void setVersion(int majorVersion, int minorVersion) + { + if (majorVersion != 1) + { + throw new IllegalArgumentException("major version not supported: " + + majorVersion); + } + if (minorVersion < 0 || minorVersion > 1) + { + throw new IllegalArgumentException("minor version not supported: " + + minorVersion); + } + this.majorVersion = majorVersion; + this.minorVersion = minorVersion; + } + + /** + * Directs this connection to use the specified proxy. + * @param hostname the proxy host name + * @param port the port on the proxy to connect to + */ + public void setProxy(String hostname, int port) + { + proxyHostname = hostname; + proxyPort = port; + } + + /** + * Indicates whether this connection is using an HTTP proxy. + */ + public boolean isUsingProxy() + { + return (proxyHostname != null && proxyPort > 0); + } + + /** + * Sets the cookie manager to use for this connection. + * @param cookieManager the cookie manager + */ + public void setCookieManager(CookieManager cookieManager) + { + this.cookieManager = cookieManager; + } + + /** + * Returns the cookie manager in use for this connection. + */ + public CookieManager getCookieManager() + { + 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 host 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, + int connectionTimeout, int timeout) + { + String ttl = + SystemProperties.getProperty("classpath.net.http.keepAliveTTL"); + connectionTTL = 10000; + if (ttl != null && ttl.length() > 0) + try + { + int v = 1000 * Integer.parseInt(ttl); + if (v >= 0) + connectionTTL = v; + } + catch (NumberFormatException _) + { + // Ignore. + } + + String mc = SystemProperties.getProperty("http.maxConnections"); + maxConnections = 5; + if (mc != null && mc.length() > 0) + try + { + int v = Integer.parseInt(mc); + if (v > 0) + maxConnections = v; + } + catch (NumberFormatException _) + { + // Ignore. + } + + HTTPConnection c = null; + + ListIterator it = connectionPool.listIterator(0); + while (it.hasNext()) + { + HTTPConnection cc = (HTTPConnection)it.next(); + if (matches(cc, host, port, secure)) + { + c = cc; + it.remove(); + // Update the timeout. + if (c.socket != null) + try + { + c.socket.setSoTimeout(timeout); + } + catch (SocketException _) + { + // Ignore. + } + break; + } + } + if (c == null) + { + c = new HTTPConnection(host, port, secure, + connectionTimeout, timeout); + 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; + + /** + * If this HTTPConnection is in the pool, the time it was put there. + */ + long timeLastUsed; + + /** + * Set the connection pool that this HTTPConnection is a member of. + * If left unset or set to null, it will not be a member of any pool + * and will not be a candidate for reuse. + * + * @param p the pool. + */ + void setPool(Pool p) + { + pool = p; + } + + /** + * Signal that this HTTPConnection is no longer needed and can be + * returned to the connection pool. + * + */ + void release() + { + if (pool != null) + { + useCount++; + pool.put(this); + + } + else + { + // If there is no pool, just close. + try + { + closeConnection(); + } + catch (IOException ioe) + { + // Ignore it. We are just cleaning up. + } + } + } + + /** + * Creates a new request using this connection. + * @param method the HTTP method to invoke + * @param path the URI-escaped RFC2396 abs_path with + * optional query part + */ + public Request newRequest(String method, String path) + { + if (method == null || method.length() == 0) + { + throw new IllegalArgumentException("method must have non-zero length"); + } + if (path == null || path.length() == 0) + { + path = "/"; + } + Request ret = new Request(this, method, path); + if ((secure && port != HTTPS_PORT) || + (!secure && port != HTTP_PORT)) + { + ret.setHeader("Host", hostname + ":" + port); + } + else + { + ret.setHeader("Host", hostname); + } + ret.setHeader("User-Agent", userAgent); + ret.setHeader("Connection", "keep-alive"); + ret.setHeader("Accept-Encoding", + "chunked;q=1.0, gzip;q=0.9, deflate;q=0.8, " + + "identity;q=0.6, *;q=0"); + if (cookieManager != null) + { + Cookie[] cookies = cookieManager.getCookies(hostname, secure, path); + if (cookies != null && cookies.length > 0) + { + CPStringBuilder buf = new CPStringBuilder(); + buf.append("$Version=1"); + for (int i = 0; i < cookies.length; i++) + { + buf.append(','); + buf.append(' '); + buf.append(cookies[i].toString()); + } + ret.setHeader("Cookie", buf.toString()); + } + } + return ret; + } + + /** + * Closes this connection. + */ + public void close() + throws IOException + { + closeConnection(); + } + + /** + * Retrieves the socket associated with this connection. + * This creates the socket if necessary. + */ + protected synchronized Socket getSocket() + throws IOException + { + if (socket == null) + { + String connectHostname = hostname; + int connectPort = port; + if (isUsingProxy()) + { + connectHostname = proxyHostname; + connectPort = proxyPort; + } + socket = new Socket(); + InetSocketAddress address = + new InetSocketAddress(connectHostname, connectPort); + if (connectionTimeout > 0) + { + socket.connect(address, connectionTimeout); + } + else + { + socket.connect(address); + } + if (timeout > 0) + { + socket.setSoTimeout(timeout); + } + if (secure) + { + try + { + SSLSocketFactory factory = getSSLSocketFactory(); + SSLSocket ss = + (SSLSocket) factory.createSocket(socket, connectHostname, + connectPort, true); + String[] protocols = { "TLSv1", "SSLv3" }; + ss.setEnabledProtocols(protocols); + ss.setUseClientMode(true); + synchronized (handshakeCompletedListeners) + { + if (!handshakeCompletedListeners.isEmpty()) + { + for (Iterator i = + handshakeCompletedListeners.iterator(); + i.hasNext(); ) + { + HandshakeCompletedListener l = + (HandshakeCompletedListener) i.next(); + ss.addHandshakeCompletedListener(l); + } + } + } + ss.startHandshake(); + socket = ss; + } + catch (GeneralSecurityException e) + { + throw new IOException(e.getMessage()); + } + } + in = socket.getInputStream(); + in = new BufferedInputStream(in); + out = socket.getOutputStream(); + out = new BufferedOutputStream(out); + } + return socket; + } + + SSLSocketFactory getSSLSocketFactory() + throws GeneralSecurityException + { + if (sslSocketFactory == null) + { + TrustManager tm = new EmptyX509TrustManager(); + SSLContext context = SSLContext.getInstance("SSL"); + TrustManager[] trust = new TrustManager[] { tm }; + context.init(null, trust, null); + sslSocketFactory = context.getSocketFactory(); + } + return sslSocketFactory; + } + + void setSSLSocketFactory(SSLSocketFactory factory) + { + sslSocketFactory = factory; + } + + protected synchronized InputStream getInputStream() + throws IOException + { + if (socket == null) + { + getSocket(); + } + return in; + } + + protected synchronized OutputStream getOutputStream() + throws IOException + { + if (socket == null) + { + getSocket(); + } + return out; + } + + /** + * Closes the underlying socket, if any. + */ + protected synchronized void closeConnection() + throws IOException + { + if (socket != null) + { + try + { + socket.close(); + } + finally + { + socket = null; + } + } + } + + /** + * Returns a URI representing the connection. + * This does not include any request path component. + */ + protected String getURI() + { + CPStringBuilder buf = new CPStringBuilder(); + buf.append(secure ? "https://" : "http://"); + buf.append(hostname); + if (secure) + { + if (port != HTTPConnection.HTTPS_PORT) + { + buf.append(':'); + buf.append(port); + } + } + else + { + if (port != HTTPConnection.HTTP_PORT) + { + buf.append(':'); + buf.append(port); + } + } + return buf.toString(); + } + + /** + * Get the number of times the specified nonce has been seen by this + * connection. + */ + int getNonceCount(String nonce) + { + if (nonceCounts == null) + { + return 0; + } + return nonceCounts.get(nonce).intValue(); + } + + /** + * Increment the number of times the specified nonce has been seen. + */ + void incrementNonce(String nonce) + { + int current = getNonceCount(nonce); + if (nonceCounts == null) + { + nonceCounts = new HashMap(); + } + nonceCounts.put(nonce, new Integer(current + 1)); + } + + // -- Events -- + + void addHandshakeCompletedListener(HandshakeCompletedListener l) + { + synchronized (handshakeCompletedListeners) + { + handshakeCompletedListeners.add(l); + } + } + void removeHandshakeCompletedListener(HandshakeCompletedListener l) + { + synchronized (handshakeCompletedListeners) + { + handshakeCompletedListeners.remove(l); + } + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/http/HTTPDateFormat.java b/libjava/classpath/gnu/java/net/protocol/http/HTTPDateFormat.java new file mode 100644 index 000000000..743f8e8e2 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/http/HTTPDateFormat.java @@ -0,0 +1,440 @@ +/* HTTPDateFormat.java -- + 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.net.protocol.http; + +import java.text.DateFormat; +import java.text.DecimalFormat; +import java.text.FieldPosition; +import java.text.NumberFormat; +import java.text.ParsePosition; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.TimeZone; + +/** + * HTTP date formatter and parser. + * Formats dates according to RFC 822 (updated by RFC 1123). + * Parses dates according to the above, or RFC 1036, or the + * ANSI C asctime() format. + * + * @author Chris Burdess (dog@gnu.org) + */ +public class HTTPDateFormat + extends DateFormat +{ + + static final String[] DAYS_OF_WEEK = { + null, "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" + }; + + static final String[] MONTHS = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; + + public HTTPDateFormat() + { + calendar = new GregorianCalendar(TimeZone.getTimeZone ("GMT")); + numberFormat = new DecimalFormat(); + } + + /** + * Appends the textual value for the specified field to the given string + * buffer. This method should be avoided, use format(Date) + * instead. + * @param date the Date object + * @param buf the buffer to append to + * @param field the current field position + * @return the modified buffer + */ + public StringBuffer format(Date date, StringBuffer buf, + FieldPosition field) + { + calendar.clear(); + calendar.setTime(date); + buf.setLength(0); + + // Day of week + buf.append(DAYS_OF_WEEK[calendar.get(Calendar.DAY_OF_WEEK)]); + buf.append(','); + buf.append(' '); + + // Day of month + int day = calendar.get(Calendar.DAY_OF_MONTH); + buf.append(Character.forDigit(day / 10, 10)); + buf.append(Character.forDigit(day % 10, 10)); + buf.append(' '); + + // Month + buf.append(MONTHS[calendar.get(Calendar.MONTH)]); + buf.append(' '); + + // Year + int year = calendar.get(Calendar.YEAR); + if (year < 1000) + { + buf.append('0'); + if (year < 100) + { + buf.append('0'); + if (year < 10) + { + buf.append('0'); + } + } + } + buf.append(Integer.toString(year)); + buf.append(' '); + + // Hour + int hour = calendar.get(Calendar.HOUR_OF_DAY); + buf.append(Character.forDigit(hour / 10, 10)); + buf.append(Character.forDigit(hour % 10, 10)); + buf.append(':'); + + // Minute + int minute = calendar.get(Calendar.MINUTE); + buf.append(Character.forDigit(minute / 10, 10)); + buf.append(Character.forDigit(minute % 10, 10)); + buf.append(':'); + + // Second + int second = calendar.get(Calendar.SECOND); + buf.append(Character.forDigit(second / 10, 10)); + buf.append(Character.forDigit(second % 10, 10)); + buf.append(' '); + + // Timezone + // Get time offset in minutes + int zoneOffset =(calendar.get(Calendar.ZONE_OFFSET) + + calendar.get(Calendar.DST_OFFSET)) / 60000; + + // Apply + or - appropriately + if (zoneOffset < 0) + { + zoneOffset = -zoneOffset; + buf.append('-'); + } + else + { + buf.append('+'); + } + + // Set the 2 2-char fields as specified above + int tzhours = zoneOffset / 60; + buf.append(Character.forDigit(tzhours / 10, 10)); + buf.append(Character.forDigit(tzhours % 10, 10)); + int tzminutes = zoneOffset % 60; + buf.append(Character.forDigit(tzminutes / 10, 10)); + buf.append(Character.forDigit(tzminutes % 10, 10)); + + field.setBeginIndex(0); + field.setEndIndex(buf.length()); + return buf; + } + + /** + * Parses the given date in the current TimeZone. + * @param text the formatted date to be parsed + * @param pos the current parse position + */ + public Date parse(String text, ParsePosition pos) + { + int date, month, year, hour, minute, second; + String monthText; + int start = 0, end = -1; + int len = text.length(); + calendar.clear(); + pos.setIndex(start); + try + { + // Advance to date + if (Character.isLetter(text.charAt(start))) + { + start = skipNonWhitespace(text, start); + } + // Determine mode + switch(start) + { + case 3: + // asctime + start = skipWhitespace(text, start); + pos.setIndex(start); + end = skipNonWhitespace(text, start + 1); + monthText = text.substring(start, end); + month = -1; + for (int i = 0; i < 12; i++) + { + if (MONTHS[i].equals(monthText)) + { + month = i; + break; + } + } + if (month == -1) + { + pos.setErrorIndex(end); + return null; + } + // Advance to date + start = skipWhitespace(text, end + 1); + pos.setIndex(start); + end = skipNonWhitespace(text, start + 1); + date = Integer.parseInt(text.substring(start, end)); + // Advance to hour + start = skipWhitespace(text, end + 1); + pos.setIndex(start); + end = skipTo(text, start + 1, ':'); + hour = Integer.parseInt(text.substring(start, end)); + // Advance to minute + start = end + 1; + pos.setIndex(start); + end = skipTo(text, start + 1, ':'); + minute = Integer.parseInt(text.substring(start, end)); + // Advance to second + start = end + 1; + pos.setIndex(start); + end = skipNonWhitespace(text, start + 1); + second = Integer.parseInt(text.substring(start, end)); + // Advance to year + start = skipWhitespace(text, end + 1); + pos.setIndex(start); + end = skipNonWhitespace(text, start + 1); + year = Integer.parseInt(text.substring(start, end)); + break; + case 0: + case 4: + // rfc822 + start = skipWhitespace(text, start); + pos.setIndex(start); + end = skipNonWhitespace(text, start + 1); + date = Integer.parseInt(text.substring(start, end)); + // Advance to month + start = skipWhitespace(text, end + 1); + pos.setIndex(start); + end = skipNonWhitespace(text, start + 1); + monthText = text.substring(start, end); + month = -1; + for (int i = 0; i < 12; i++) + { + if (MONTHS[i].equals(monthText)) + { + month = i; + break; + } + } + if (month == -1) + { + pos.setErrorIndex(end); + return null; + } + // Advance to year + start = skipWhitespace(text, end + 1); + pos.setIndex(start); + end = skipNonWhitespace(text, start + 1); + year = Integer.parseInt(text.substring(start, end)); + // Advance to hour + start = skipWhitespace(text, end + 1); + pos.setIndex(start); + end = skipTo(text, start + 1, ':'); + hour = Integer.parseInt(text.substring(start, end)); + // Advance to minute + start = end + 1; + pos.setIndex(start); + end = skipTo(text, start + 1, ':'); + minute = Integer.parseInt(text.substring(start, end)); + // Advance to second + start = end + 1; + pos.setIndex(start); + end = start + 1; + while (end < len && !Character.isWhitespace(text.charAt(end))) + { + end++; + } + second = Integer.parseInt(text.substring(start, end)); + break; + default: + // rfc850(obsolete) + start = skipWhitespace(text, start); + pos.setIndex(start); + end = skipTo(text, start + 1, '-'); + date = Integer.parseInt(text.substring(start, end)); + // Advance to month + start = end + 1; + pos.setIndex(start); + end = skipTo(text, start + 1, '-'); + monthText = text.substring(start, end); + month = -1; + for (int i = 0; i < 12; i++) + { + if (MONTHS[i].equals(monthText)) + { + month = i; + break; + } + } + if (month == -1) + { + pos.setErrorIndex(end); + return null; + } + // Advance to year + start = end + 1; + pos.setIndex(start); + end = skipNonWhitespace(text, start + 1); + year = 1900 + Integer.parseInt(text.substring(start, end)); + // Advance to hour + start = skipWhitespace(text, end + 1); + pos.setIndex(start); + end = skipTo(text, start + 1, ':'); + hour = Integer.parseInt(text.substring(start, end)); + // Advance to minute + start = end + 1; + pos.setIndex(start); + end = skipTo(text, start + 1, ':'); + minute = Integer.parseInt(text.substring(start, end)); + // Advance to second + start = end + 1; + pos.setIndex(start); + end = start + 1; + while (end < len && !Character.isWhitespace(text.charAt(end))) + { + end++; + } + second = Integer.parseInt(text.substring(start, end)); + } + + calendar.set(Calendar.YEAR, year); + calendar.set(Calendar.MONTH, month); + calendar.set(Calendar.DAY_OF_MONTH, date); + calendar.set(Calendar.HOUR, hour); + calendar.set(Calendar.MINUTE, minute); + calendar.set(Calendar.SECOND, second); + + if (end != len) + { + // Timezone + start = skipWhitespace(text, end + 1); + end = start + 1; + while (end < len && !Character.isWhitespace(text.charAt(end))) + { + end++; + } + char pm = text.charAt(start); + if (Character.isLetter(pm)) + { + TimeZone tz = + TimeZone.getTimeZone(text.substring(start, end)); + calendar.set(Calendar.ZONE_OFFSET, tz.getRawOffset()); + } + else + { + int zoneOffset = 0; + zoneOffset += 600 * Character.digit(text.charAt(++start), 10); + zoneOffset += 60 * Character.digit(text.charAt(++start), 10); + zoneOffset += 10 * Character.digit(text.charAt(++start), 10); + zoneOffset += Character.digit(text.charAt(++start), 10); + zoneOffset *= 60000; // minutes -> ms + if ('-' == pm) + { + zoneOffset = -zoneOffset; + } + calendar.set(Calendar.ZONE_OFFSET, zoneOffset); + } + } + pos.setIndex(end); + + return calendar.getTime(); + } + catch (NumberFormatException e) + { + pos.setErrorIndex(Math.max(start, end)); + } + catch (StringIndexOutOfBoundsException e) + { + pos.setErrorIndex(Math.max(start, end)); + } + return null; + } + + private int skipWhitespace(String text, int pos) + { + while(Character.isWhitespace(text.charAt(pos))) + { + pos++; + } + return pos; + } + + private int skipNonWhitespace(String text, int pos) + { + while(!Character.isWhitespace(text.charAt(pos))) + { + pos++; + } + return pos; + } + + private int skipTo(String text, int pos, char c) + { + while(text.charAt(pos) != c) + { + pos++; + } + return pos; + } + + /** + * Don't allow setting the calendar. + */ + public void setCalendar(Calendar newCalendar) + { + throw new UnsupportedOperationException(); + } + + /** + * Don't allow setting the NumberFormat. + */ + public void setNumberFormat(NumberFormat newNumberFormat) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/http/HTTPURLConnection.java b/libjava/classpath/gnu/java/net/protocol/http/HTTPURLConnection.java new file mode 100644 index 000000000..9ba5c4793 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/http/HTTPURLConnection.java @@ -0,0 +1,693 @@ +/* HTTPURLConnection.java -- + Copyright (C) 2004, 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.java.net.protocol.http; + +import gnu.classpath.SystemProperties; + +import java.io.ByteArrayOutputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.ProtocolException; +import java.net.URL; +import java.security.cert.Certificate; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Map; + +import javax.net.ssl.HandshakeCompletedEvent; +import javax.net.ssl.HandshakeCompletedListener; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.SSLSocketFactory; + +/** + * A URLConnection that uses the HTTPConnection class. + * + * @author Chris Burdess (dog@gnu.org) + */ +public class HTTPURLConnection + extends HttpsURLConnection + implements HandshakeCompletedListener +{ + /* + * The underlying connection. + */ + private HTTPConnection connection; + + // These are package private for use in anonymous inner classes. + String proxyHostname; + int proxyPort = -1; + String agent; + boolean keepAlive; + + private Request request; + private Headers requestHeaders; + private ByteArrayOutputStream requestSink; + private boolean requestMethodSetExplicitly; + + private Response response; + private InputStream responseSink; + private InputStream errorSink; + + private HandshakeCompletedEvent handshakeEvent; + + /** + * Constructor. + * @param url the URL + */ + public HTTPURLConnection(URL url) + throws IOException + { + super(url); + requestHeaders = new Headers(); + String proxy = SystemProperties.getProperty("http.proxyHost"); + if (proxy != null && proxy.length() > 0) + { + String port = SystemProperties.getProperty("http.proxyPort"); + if (port != null && port.length() > 0) + { + try + { + proxyPort = Integer.parseInt(port); + proxyHostname = proxy; + } + catch (NumberFormatException _) + { + // Ignore. + } + } + } + agent = SystemProperties.getProperty("http.agent"); + String ka = SystemProperties.getProperty("http.keepAlive"); + keepAlive = !(ka != null && "false".equals(ka)); + } + + public void connect() + throws IOException + { + if (connected) + { + return; + } + String protocol = url.getProtocol(); + boolean secure = "https".equals(protocol); + String host = url.getHost(); + int port = url.getPort(); + if (port < 0) + { + port = secure ? HTTPConnection.HTTPS_PORT : + HTTPConnection.HTTP_PORT; + } + String file = url.getFile(); + String username = url.getUserInfo(); + String password = null; + if (username != null) + { + int ci = username.indexOf(':'); + if (ci != -1) + { + password = username.substring(ci + 1); + username = username.substring(0, ci); + } + } + final Credentials creds = (username == null) ? null : + new Credentials (username, password); + + if ("POST".equals(method)) + { + String contentType = requestHeaders.getValue("Content-Type"); + if (null == contentType) + requestHeaders.addValue("Content-Type", + "application/x-www-form-urlencoded"); + } + + boolean retry; + do + { + retry = false; + if (connection == null) + { + connection = getConnection(host, port, secure); + if (secure) + { + SSLSocketFactory factory = getSSLSocketFactory(); + // FIXME: use the verifier + // HostnameVerifier verifier = getHostnameVerifier(); + if (factory != null) + { + connection.setSSLSocketFactory(factory); + } + connection.addHandshakeCompletedListener(this); + // TODO verifier + } + } + if (proxyHostname != null) + { + if (proxyPort < 0) + { + proxyPort = secure ? HTTPConnection.HTTPS_PORT : + HTTPConnection.HTTP_PORT; + } + connection.setProxy(proxyHostname, proxyPort); + } + try + { + request = connection.newRequest(method, file); + if (!keepAlive) + { + request.setHeader("Connection", "close"); + } + if (agent != null) + { + request.setHeader("User-Agent", agent); + } + request.getHeaders().putAll(requestHeaders); + if (requestSink != null) + { + byte[] content = requestSink.toByteArray(); + RequestBodyWriter writer = new ByteArrayRequestBodyWriter(content); + request.setRequestBodyWriter(writer); + } + if (creds != null) + { + request.setAuthenticator(new Authenticator() { + public Credentials getCredentials(String realm, int attempts) + { + return (attempts < 2) ? creds : null; + } + }); + } + response = request.dispatch(); + } + catch (IOException ioe) + { + if (connection.useCount > 0) + { + // Connection re-use failed: Try a new connection. + try + { + connection.close(); + } + catch (IOException _) + { + // Ignore. + } + connection = null; + retry = true; + continue; + } + else + { + // First time the connection was used: Hard failure. + throw ioe; + } + } + + 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) + { + String connectionUri = connection.getURI(); + int start = connectionUri.length(); + if (location.startsWith(connectionUri) && + location.charAt(start) == '/') + { + file = location.substring(start); + retry = true; + } + else if (location.startsWith("http:")) + { + connection.close(); + connection = null; + secure = false; + start = 7; + int end = location.indexOf('/', start); + if (end == -1) + end = location.length(); + host = location.substring(start, end); + int ci = host.lastIndexOf(':'); + if (ci != -1) + { + port = Integer.parseInt(host.substring (ci + 1)); + host = host.substring(0, ci); + } + else + { + port = HTTPConnection.HTTP_PORT; + } + file = location.substring(end); + retry = true; + } + else if (location.startsWith("https:")) + { + connection.close(); + connection = null; + secure = true; + start = 8; + int end = location.indexOf('/', start); + if (end == -1) + end = location.length(); + host = location.substring(start, end); + int ci = host.lastIndexOf(':'); + if (ci != -1) + { + port = Integer.parseInt(host.substring (ci + 1)); + host = host.substring(0, ci); + } + else + { + port = HTTPConnection.HTTPS_PORT; + } + file = location.substring(end); + retry = true; + } + else if (location.length() > 0) + { + // Malformed absolute URI, treat as file part of URI + if (location.charAt(0) == '/') + { + // Absolute path + file = location; + } + else + { + // Relative path + int lsi = file.lastIndexOf('/'); + file = (lsi == -1) ? "/" : file.substring(0, lsi + 1); + file += location; + } + retry = true; + } + } + } + else + { + responseSink = response.getBody(); + + if (response.isError()) + errorSink = responseSink; + } + } + while (retry); + connected = true; + } + + /** + * Returns a connection, from the pool if necessary. + */ + HTTPConnection getConnection(String host, int port, boolean secure) + throws IOException + { + HTTPConnection connection; + if (keepAlive) + { + connection = HTTPConnection.Pool.instance.get(host, port, secure, + getConnectTimeout(), + getReadTimeout()); + } + else + { + connection = new HTTPConnection(host, port, secure, + getConnectTimeout(), getReadTimeout()); + } + return connection; + } + + public void disconnect() + { + if (connection != null) + { + try + { + connection.close(); + } + catch (IOException e) + { + } + } + } + + public boolean usingProxy() + { + return (proxyHostname != null); + } + + /** + * Overrides the corresponding method in HttpURLConnection to permit + * arbitrary methods, as long as they're valid ASCII alphabetic + * characters. This is to permit WebDAV and other HTTP extensions to + * function. + * @param method the method + */ + public void setRequestMethod(String method) + throws ProtocolException + { + if (connected) + { + throw new ProtocolException("Already connected"); + } + // Validate + method = method.toUpperCase(); + int len = method.length(); + if (len == 0) + { + throw new ProtocolException("Empty method name"); + } + for (int i = 0; i < len; i++) + { + char c = method.charAt(i); + if (c < 0x41 || c > 0x5a) + { + throw new ProtocolException("Illegal character '" + c + + "' at index " + i); + } + } + // OK + this.method = method; + requestMethodSetExplicitly = true; + } + + public String getRequestProperty(String key) + { + return requestHeaders.getValue(key); + } + + public Map> getRequestProperties() + { + if (connected) + throw new IllegalStateException("Already connected"); + + Map> m = requestHeaders.getAsMap(); + return Collections.unmodifiableMap(m); + } + + 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); + requestHeaders.addValue(key, value); + } + + public OutputStream getOutputStream() + throws IOException + { + if (connected) + { + throw new ProtocolException("Already connected"); + } + if (!doOutput) + { + throw new ProtocolException("doOutput is false"); + } + else if (!requestMethodSetExplicitly) + { + /* + * Silently change the method to POST if no method was set + * explicitly. This is due to broken applications depending on this + * behaviour (Apache XMLRPC for one). + */ + method = "POST"; + } + if (requestSink == null) + { + requestSink = new ByteArrayOutputStream(); + } + return requestSink; + } + + // -- Response -- + + public InputStream getInputStream() + throws IOException + { + if (!connected) + { + connect(); + } + if (!doInput) + { + 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; + } + + public InputStream getErrorStream() + { + return errorSink; + } + + public Map> getHeaderFields() + { + if (!connected) + { + try + { + connect(); + } + catch (IOException e) + { + return null; + } + } + Map> m = response.getHeaders().getAsMap(); + m.put(null, Collections.singletonList(getStatusLine(response))); + return Collections.unmodifiableMap(m); + } + + String getStatusLine(Response response) + { + return "HTTP/" + response.getMajorVersion() + + "." + response.getMinorVersion() + + " " + response.getCode() + + " " + response.getMessage(); + } + + public String getHeaderField(int index) + { + if (!connected) + { + try + { + connect(); + } + catch (IOException e) + { + return null; + } + } + if (index == 0) + { + return getStatusLine(response); + } + return response.getHeaders().getHeaderValue(index - 1); + } + + public String getHeaderFieldKey(int index) + { + if (!connected) + { + try + { + connect(); + } + catch (IOException e) + { + return null; + } + } + // index of zero is the status line. + return response.getHeaders().getHeaderName(index - 1); + } + + public String getHeaderField(String name) + { + if (!connected) + { + try + { + connect(); + } + catch (IOException e) + { + return null; + } + } + return response.getHeader(name); + } + + public long getHeaderFieldDate(String name, long def) + { + if (!connected) + { + try + { + connect(); + } + catch (IOException e) + { + return def; + } + } + Date date = response.getDateHeader(name); + return (date == null) ? def : date.getTime(); + } + + public String getContentType() + { + return getHeaderField("Content-Type"); + } + + public int getResponseCode() + throws IOException + { + if (!connected) + { + connect(); + } + return response.getCode(); + } + + public String getResponseMessage() + throws IOException + { + if (!connected) + { + connect(); + } + return response.getMessage(); + } + + // -- HTTPS specific -- + + public String getCipherSuite() + { + if (!connected) + { + throw new IllegalStateException("not connected"); + } + return handshakeEvent.getCipherSuite(); + } + + public Certificate[] getLocalCertificates() + { + if (!connected) + { + throw new IllegalStateException("not connected"); + } + return handshakeEvent.getLocalCertificates(); + } + + public Certificate[] getServerCertificates() + throws SSLPeerUnverifiedException + { + if (!connected) + { + throw new IllegalStateException("not connected"); + } + return handshakeEvent.getPeerCertificates(); + } + + // HandshakeCompletedListener + + public void handshakeCompleted(HandshakeCompletedEvent event) + { + handshakeEvent = event; + } + + /** + * Set the read timeout, in milliseconds, or zero if the timeout + * is to be considered infinite. + * + * Overloaded. + * + */ + public void setReadTimeout(int timeout) + throws IllegalArgumentException + { + super.setReadTimeout(timeout); + if (connection == null) + return; + try + { + connection.getSocket().setSoTimeout(timeout); + } + catch (IOException se) + { + // Ignore socket exceptions. + } + } +} diff --git a/libjava/classpath/gnu/java/net/protocol/http/Handler.java b/libjava/classpath/gnu/java/net/protocol/http/Handler.java new file mode 100644 index 000000000..30810321d --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/http/Handler.java @@ -0,0 +1,72 @@ +/* Handler.java -- + 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.net.protocol.http; + +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; + +/** + * An HTTP URL stream handler. + * + * @author Chris Burdess (dog@gnu.org) + */ +public class Handler + extends URLStreamHandler +{ + + /** + * Returns the default HTTP port (80). + */ + protected int getDefaultPort() + { + return HTTPConnection.HTTP_PORT; + } + + /** + * Returns an HTTPURLConnection for the given URL. + */ + public URLConnection openConnection(URL url) + throws IOException + { + return new HTTPURLConnection(url); + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/http/Headers.java b/libjava/classpath/gnu/java/net/protocol/http/Headers.java new file mode 100644 index 000000000..faf5eb195 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/http/Headers.java @@ -0,0 +1,424 @@ +/* Headers.java -- + 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.net.protocol.http; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.net.LineInputStream; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.Iterable; +import java.text.DateFormat; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * A collection of HTTP header names and associated values. The + * values are {@link ArrayList ArrayLists} of Strings. Retrieval of + * values is case insensitive. An iteration over the collection + * returns the header names in the order they were received. + * + * @author Chris Burdess (dog@gnu.org) + * @author David Daney (ddaney@avtrex.com) + */ +class Headers implements Iterable +{ + /** + * A list of HeaderElements + */ + private final ArrayList headers + = new ArrayList(); + + /** + * The HTTP dateformat used to parse date header fields. + */ + private static final DateFormat dateFormat = new HTTPDateFormat(); + + /** + * Class for a Header element consisting of + * a name and value String. + */ + static class HeaderElement + { + String name; + String value; + + HeaderElement(String name, String value) + { + this.name = name; + this.value = value; + } + } + + /** + * Default constructor. + */ + public Headers() + { + // nothing to do + } + + /** + * Return an Iterator over this collection of headers. + * Iterator.getNext() returns objects of type {@link HeaderElement}. + * + * @return the Iterator. + */ + public Iterator iterator() + { + return headers.iterator(); + } + + /** + * Returns the value of the specified header as a string. If + * multiple values are present, the last one is returned. + * + * @param header the header name (case insensitive search) + * @return The header value or null if not found. + */ + public String getValue(String header) + { + for (int i = headers.size() - 1; i >= 0; i--) + { + HeaderElement e = headers.get(i); + if (e.name.equalsIgnoreCase(header)) + { + return e.value; + } + } + return null; + } + + /** + * Returns the value of the specified header as an integer. If + * multiple values are present, the last one is returned. + * + * @param header the header name (case insensitive search) + * @return The header value or -1 if not present or + * not an integer value. + */ + public int getIntValue(String header) + { + String val = getValue(header); + if (val == null) + { + return -1; + } + try + { + return Integer.parseInt(val); + } + catch (NumberFormatException e) + { + // fall through + } + return -1; + } + + /** + * Returns the value of the specified header as a long. If + * multiple values are present, the last one is returned. + * + * @param header the header name (case insensitive search) + * @return The header value or -1 if not present or + * not a long value. + */ + public long getLongValue(String header) + { + String val = getValue(header); + if (val == null) + { + return -1; + } + try + { + return Long.parseLong(val); + } + catch (NumberFormatException e) + { + // fall through + } + return -1; + } + + /** + * Returns the value of the specified header as a date. If + * multiple values are present, the last one is returned. + * + * @param header the header name (case insensitive search) + * @return The header value or null if not present or + * not a date value. + */ + public Date getDateValue(String header) + { + String val = getValue(header); + if (val == null) + { + return null; + } + try + { + return dateFormat.parse(val); + } + catch (ParseException e) + { + return null; + } + } + + /** + * Add a header to this set of headers. If there is an existing + * header with the same name it's value is replaced with the new value. + * If multiple headers of the same name exist only the last one's value + * is replaced. + * + * @param name the header name + * @param value the header value + * + * @see #addValue(String, String) + */ + public void put(String name, String value) + { + for (int i = headers.size() - 1; i >= 0; i--) + { + HeaderElement e = headers.get(i); + if (e.name.equalsIgnoreCase(name)) + { + e.value = value; + return; + } + } + + // nothing was replaced so add it as new HeaderElement + addValue(name, value); + } + + /** + * Add all headers from a set of headers to this set. Any existing header + * with the same (case insensitive) name as one of the new headers will + * be overridden. + * + * @param o the headers to be added + */ + public void putAll(Headers o) + { + for (Iterator it = o.iterator(); it.hasNext(); ) + { + HeaderElement e = it.next(); + remove(e.name); + addValue(e.name, e.value); + } + } + + /** + * Remove a header from this set of headers. If there is more than + * one instance of a header of the given name, they are all removed. + * + * @param name the header name + */ + public void remove(String name) + { + for (Iterator it = headers.iterator(); it.hasNext(); ) + { + HeaderElement e = it.next(); + if (e.name.equalsIgnoreCase(name)) + it.remove(); + } + } + + /** + * Parse the specified InputStream, adding headers to this collection. + * + * @param in the InputStream. + * @throws IOException if I/O error occured. + */ + public void parse(InputStream in) + throws IOException + { + LineInputStream lin = (in instanceof LineInputStream) ? + (LineInputStream) in : new LineInputStream(in); + + String name = null; + CPStringBuilder value = new CPStringBuilder(); + while (true) + { + String line = lin.readLine(); + if (line == null) + { + if (name != null) + { + addValue(name, value.toString()); + } + break; + } + int len = line.length(); + if (len < 2) + { + if (name != null) + { + addValue(name, value.toString()); + } + break; + } + char c1 = line.charAt(0); + if (c1 == ' ' || c1 == '\t') + { + // Continuation + int last = len - 1; + if (line.charAt(last) != '\r') + ++last; + value.append(line.substring(0, last)); + } + else + { + if (name != null) + { + addValue(name, value.toString()); + } + + int di = line.indexOf(':'); + name = line.substring(0, di); + value.setLength(0); + do + { + di++; + } + while (di < len && line.charAt(di) == ' '); + int last = len - 1; + if (line.charAt(last) != '\r') + ++last; + value.append(line.substring(di, last)); + } + } + } + + + /** + * Add a header to this set of headers. If there is an existing + * header with the same name, it is not effected. + * + * @param name the header name + * @param value the header value + * + * @see #put(String, String) + */ + public void addValue(String name, String value) + { + headers.add(headers.size(), new HeaderElement(name, value)); + } + + /** + * Get a new Map containing all the headers. The keys of the Map + * are Strings (the header names). The headers will be included + * case-sensitive in the map so that querying must be done with the + * correct case of the needed header name. The values of the Map are + * unmodifiable Lists containing Strings (the header values). + * + *

+ * The returned map is modifiable. Changing it will not effect this + * collection of Headers in any way.

+ * + * @return a Map containing all the headers. + */ + public Map> getAsMap() + { + LinkedHashMap> m = new LinkedHashMap>(); + for (Iterator it = headers.iterator(); it.hasNext(); ) + { + HeaderElement e = it.next(); + ArrayList l = (ArrayList)m.get(e.name); + if (l == null) + { + l = new ArrayList(1); + l.add(e.value); + m.put(e.name, l); + } + else + l.add(0, e.value); + } + for (Iterator>> it = m.entrySet().iterator(); it.hasNext(); ) + { + Map.Entry> me = it.next(); + List l = me.getValue(); + me.setValue(Collections.unmodifiableList(l)); + } + return m; + } + + /** + * Get the name of the Nth header. + * + * @param i the header index. + * + * @return The header name, or null if index outside of range. + * + * @see #getHeaderValue(int) + */ + public String getHeaderName(int i) + { + if (i >= headers.size() || i < 0) + return null; + + return headers.get(i).name; + } + + /** + * Get the value of the Nth header. + * + * @param i the header index. + * + * @return the header value, or null if index outside of range. + * + * @see #getHeaderName(int) + */ + public String getHeaderValue(int i) + { + if (i >= headers.size() || i < 0) + return null; + + return headers.get(i).value; + } +} diff --git a/libjava/classpath/gnu/java/net/protocol/http/LimitedLengthInputStream.java b/libjava/classpath/gnu/java/net/protocol/http/LimitedLengthInputStream.java new file mode 100644 index 000000000..568f830fd --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/http/LimitedLengthInputStream.java @@ -0,0 +1,216 @@ +/* LimitedLengthInputStream.java -- + Copyright (C) 2005, 2008 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.net.protocol.http; + +import java.io.IOException; +import java.io.InputStream; + +/** + * InputStream that limits the total number of bytes that can be read + * from an underlying stream. In addition to limiting the number of + * bytes read, close() is not propagated to the underlying stream. + * + * @author David Daney (ddaney@avtrex.com) + */ +class LimitedLengthInputStream + extends InputStream +{ + private long remainingLen; + private boolean restrictLen; + private HTTPConnection connection; + private boolean eof; + private InputStream in; + private boolean doClose; + + private void handleClose() + throws IOException + { + eof = true; + + if (doClose) + in.close(); + else + connection.release(); + + in = null; + connection = null; + } + + /** + * Constructor. + * + * @param in the underlying stream + * + * @param maxLen the maximum number of bytes to read + * + * @param restrictLen if true the number of bytes that can be read + * from this stream will be limited to maxLen, otherwise the number + * of bytes is not restricted. + * + * @param con the HTTPConnection associated with this stream + * + * @param doClose if true con will be closed when finished reading, + * else it will be placed back in the connection pool. + * + */ + LimitedLengthInputStream(InputStream in, + long maxLen, + boolean restrictLen, + HTTPConnection con, + boolean doClose) + throws IOException + { + this.in = in; + this.remainingLen = maxLen; + this.restrictLen = restrictLen; + this.connection = con; + this.doClose = doClose; + + if (restrictLen) + { + if (maxLen < 0) + throw new IllegalArgumentException(); + else if (maxLen == 0) + handleClose(); // Nothing to do, release the connection. + } + } + + public synchronized int read() + throws IOException + { + if (eof) + return -1; // EOF + + int r; + + if (restrictLen) + { + r = in.read(); + if (-1 != r) + remainingLen--; + + if (0 == remainingLen) + handleClose(); + } + else + { + r = in.read(); + if (r == -1) + handleClose(); + } + + return r; + } + + public int read(byte[] buffer) + throws IOException + { + return read(buffer, 0, buffer.length); + } + + public synchronized int read(byte[] buffer, int offset, int length) + throws IOException + { + if (eof) + return -1; // EOF + + if (restrictLen && length > remainingLen) + length = (int) remainingLen; + + int r = in.read(buffer, offset, length); + + if (-1 == r) + handleClose(); + + if (restrictLen && r > 0) + { + remainingLen -= r; + if (0 == remainingLen) + handleClose(); + } + return r; + } + + public synchronized long skip(long n) + throws IOException + { + + if (eof) + return 0; + + if (restrictLen && n > remainingLen) + n = remainingLen; + + long r = in.skip(n); + + if (restrictLen) + { + remainingLen -= r; + if (0 == remainingLen) + handleClose(); + } + return r; + } + + public synchronized int available() + throws IOException + { + if (eof) + return 0; + + int a = in.available(); + if (restrictLen && a > remainingLen) + a = (int)remainingLen; + return a; + } + + public synchronized void close() + throws IOException + { + if (eof) + return; + + // If we get to here, the stream was not fully read. Just throw + // it away. + + doClose = true; + + handleClose(); + } +} diff --git a/libjava/classpath/gnu/java/net/protocol/http/Request.java b/libjava/classpath/gnu/java/net/protocol/http/Request.java new file mode 100644 index 000000000..534213eed --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/http/Request.java @@ -0,0 +1,857 @@ +/* Request.java -- + Copyright (C) 2004, 2005, 2006, 2007 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.net.protocol.http; + +import gnu.java.lang.CPStringBuilder; +import gnu.java.net.LineInputStream; +import gnu.java.util.Base64; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.ProtocolException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.text.DateFormat; +import java.text.ParseException; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.zip.GZIPInputStream; +import java.util.zip.InflaterInputStream; + +/** + * A single HTTP request. + * + * @author Chris Burdess (dog@gnu.org) + */ +public class Request +{ + + /** + * The connection context in which this request is invoked. + */ + protected final HTTPConnection connection; + + /** + * The HTTP method to invoke. + */ + protected final String method; + + /** + * The path identifying the resource. + * This string must conform to the abs_path definition given in RFC2396, + * with an optional "?query" part, and must be URI-escaped by the caller. + */ + protected final String path; + + /** + * The headers in this request. + */ + protected final Headers requestHeaders; + + /** + * The request body provider. + */ + protected RequestBodyWriter requestBodyWriter; + + /** + * Map of response header handlers. + */ + protected Map responseHeaderHandlers; + + /** + * The authenticator. + */ + protected Authenticator authenticator; + + /** + * Whether this request has been dispatched yet. + */ + private boolean dispatched; + + /** + * Constructor for a new request. + * @param connection the connection context + * @param method the HTTP method + * @param path the resource path including query part + */ + protected Request(HTTPConnection connection, String method, + String path) + { + this.connection = connection; + this.method = method; + this.path = path; + requestHeaders = new Headers(); + responseHeaderHandlers = new HashMap(); + } + + /** + * Returns the connection associated with this request. + * @see #connection + */ + public HTTPConnection getConnection() + { + return connection; + } + + /** + * Returns the HTTP method to invoke. + * @see #method + */ + public String getMethod() + { + return method; + } + + /** + * Returns the resource path. + * @see #path + */ + public String getPath() + { + return path; + } + + /** + * Returns the full request-URI represented by this request, as specified + * by HTTP/1.1. + */ + public String getRequestURI() + { + return connection.getURI() + path; + } + + /** + * Returns the headers in this request. + */ + public Headers getHeaders() + { + return requestHeaders; + } + + /** + * Returns the value of the specified header in this request. + * @param name the header name + */ + public String getHeader(String name) + { + return requestHeaders.getValue(name); + } + + /** + * Returns the value of the specified header in this request as an integer. + * @param name the header name + */ + public int getIntHeader(String name) + { + return requestHeaders.getIntValue(name); + } + + /** + * Returns the value of the specified header in this request as a date. + * @param name the header name + */ + public Date getDateHeader(String name) + { + return requestHeaders.getDateValue(name); + } + + /** + * Sets the specified header in this request. + * @param name the header name + * @param value the header value + */ + public void setHeader(String name, String value) + { + requestHeaders.put(name, value); + } + + /** + * Convenience method to set the entire request body. + * @param requestBody the request body content + */ + public void setRequestBody(byte[] requestBody) + { + setRequestBodyWriter(new ByteArrayRequestBodyWriter(requestBody)); + } + + /** + * Sets the request body provider. + * @param requestBodyWriter the handler used to obtain the request body + */ + public void setRequestBodyWriter(RequestBodyWriter requestBodyWriter) + { + this.requestBodyWriter = requestBodyWriter; + } + + /** + * Sets a callback handler to be invoked for the specified header name. + * @param name the header name + * @param handler the handler to receive the value for the header + */ + public void setResponseHeaderHandler(String name, + ResponseHeaderHandler handler) + { + responseHeaderHandlers.put(name, handler); + } + + /** + * Sets an authenticator that can be used to handle authentication + * automatically. + * @param authenticator the authenticator + */ + public void setAuthenticator(Authenticator authenticator) + { + this.authenticator = authenticator; + } + + /** + * Dispatches this request. + * A request can only be dispatched once; calling this method a second + * time results in a protocol exception. + * @exception IOException if an I/O error occurred + * @return an HTTP response object representing the result of the operation + */ + public Response dispatch() + throws IOException + { + if (dispatched) + { + throw new ProtocolException("request already dispatched"); + } + final String CRLF = "\r\n"; + final String HEADER_SEP = ": "; + final String US_ASCII = "US-ASCII"; + final String version = connection.getVersion(); + Response response; + int contentLength = -1; + boolean retry = false; + int attempts = 0; + boolean expectingContinue = false; + if (requestBodyWriter != null) + { + contentLength = requestBodyWriter.getContentLength(); + String expect = getHeader("Expect"); + if (expect != null && expect.equals("100-continue")) + { + expectingContinue = true; + } + else + { + setHeader("Content-Length", Integer.toString(contentLength)); + } + } + + try + { + // Loop while authentication fails or continue + do + { + retry = false; + + // Get socket output and input streams + OutputStream out = connection.getOutputStream(); + + // Request line + String requestUri = path; + if (connection.isUsingProxy() && + !"*".equals(requestUri) && + !"CONNECT".equals(method)) + { + requestUri = getRequestURI(); + } + String line = method + ' ' + requestUri + ' ' + version + CRLF; + out.write(line.getBytes(US_ASCII)); + // Request headers + for (Headers.HeaderElement elt : requestHeaders) + { + line = elt.name + HEADER_SEP + elt.value + CRLF; + out.write(line.getBytes(US_ASCII)); + } + out.write(CRLF.getBytes(US_ASCII)); + // Request body + if (requestBodyWriter != null && !expectingContinue) + { + byte[] buffer = new byte[4096]; + int len; + int count = 0; + + requestBodyWriter.reset(); + do + { + len = requestBodyWriter.write(buffer); + if (len > 0) + { + out.write(buffer, 0, len); + } + count += len; + } + while (len > -1 && count < contentLength); + } + out.flush(); + // Get response + while(true) + { + response = readResponse(connection.getInputStream()); + int sc = response.getCode(); + if (sc == 401 && authenticator != null) + { + if (authenticate(response, attempts++)) + { + retry = true; + } + } + else if (sc == 100) + { + if (expectingContinue) + { + requestHeaders.remove("Expect"); + setHeader("Content-Length", + Integer.toString(contentLength)); + expectingContinue = false; + retry = true; + } + else + { + // A conforming server can send an unsoliceted + // Continue response but *should* not (RFC 2616 + // sec 8.2.3). Ignore the bogus Continue + // response and get the real response that + // should follow + continue; + } + } + break; + } + } + while (retry); + } + catch (IOException e) + { + connection.close(); + throw e; + } + return response; + } + + Response readResponse(InputStream in) + throws IOException + { + String line; + int len; + + // Read response status line + LineInputStream lis = new LineInputStream(in); + + line = lis.readLine(); + if (line == null) + { + throw new ProtocolException("Peer closed connection"); + } + if (!line.startsWith("HTTP/")) + { + throw new ProtocolException(line); + } + len = line.length(); + int start = 5, end = 6; + while (line.charAt(end) != '.') + { + end++; + } + int majorVersion = Integer.parseInt(line.substring(start, end)); + start = end + 1; + end = start + 1; + while (line.charAt(end) != ' ') + { + end++; + } + int minorVersion = Integer.parseInt(line.substring(start, end)); + start = end + 1; + end = start + 3; + int code = Integer.parseInt(line.substring(start, end)); + String message = line.substring(end + 1, len - 1); + // Read response headers + Headers responseHeaders = new Headers(); + responseHeaders.parse(lis); + notifyHeaderHandlers(responseHeaders); + InputStream body = null; + + switch (code) + { + case 100: + break; + case 204: + case 205: + case 304: + body = createResponseBodyStream(responseHeaders, majorVersion, + minorVersion, in, false); + break; + default: + body = createResponseBodyStream(responseHeaders, majorVersion, + minorVersion, in, true); + } + + // Construct response + Response ret = new Response(majorVersion, minorVersion, code, + message, responseHeaders, body); + return ret; + } + + void notifyHeaderHandlers(Headers headers) + { + for (Headers.HeaderElement entry : headers) + { + // Handle Set-Cookie + if ("Set-Cookie".equalsIgnoreCase(entry.name)) + handleSetCookie(entry.value); + + ResponseHeaderHandler handler = + (ResponseHeaderHandler) responseHeaderHandlers.get(entry.name); + if (handler != null) + handler.setValue(entry.value); + } + } + + private InputStream createResponseBodyStream(Headers responseHeaders, + int majorVersion, + int minorVersion, + InputStream in, + boolean mayHaveBody) + throws IOException + { + long contentLength = -1; + + // Persistent connections are the default in HTTP/1.1 + boolean doClose = "close".equalsIgnoreCase(getHeader("Connection")) || + "close".equalsIgnoreCase(responseHeaders.getValue("Connection")) || + (connection.majorVersion == 1 && connection.minorVersion == 0) || + (majorVersion == 1 && minorVersion == 0); + + String transferCoding = responseHeaders.getValue("Transfer-Encoding"); + if ("HEAD".equals(method) || !mayHaveBody) + { + // Special case no body. + in = new LimitedLengthInputStream(in, 0, true, connection, doClose); + } + else if ("chunked".equalsIgnoreCase(transferCoding)) + { + in = new LimitedLengthInputStream(in, -1, false, connection, doClose); + + in = new ChunkedInputStream(in, responseHeaders); + } + else + { + contentLength = responseHeaders.getLongValue("Content-Length"); + + if (contentLength < 0) + doClose = true; // No Content-Length, must close. + + in = new LimitedLengthInputStream(in, contentLength, + contentLength >= 0, + connection, doClose); + } + String contentCoding = responseHeaders.getValue("Content-Encoding"); + if (contentCoding != null && !"identity".equals(contentCoding)) + { + if ("gzip".equals(contentCoding)) + { + in = new GZIPInputStream(in); + } + else if ("deflate".equals(contentCoding)) + { + in = new InflaterInputStream(in); + } + else + { + 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; + } + + boolean authenticate(Response response, int attempts) + throws IOException + { + String challenge = response.getHeader("WWW-Authenticate"); + if (challenge == null) + { + challenge = response.getHeader("Proxy-Authenticate"); + } + int si = challenge.indexOf(' '); + String scheme = (si == -1) ? challenge : challenge.substring(0, si); + if ("Basic".equalsIgnoreCase(scheme)) + { + Properties params = parseAuthParams(challenge.substring(si + 1)); + String realm = params.getProperty("realm"); + Credentials creds = authenticator.getCredentials(realm, attempts); + String userPass = creds.getUsername() + ':' + creds.getPassword(); + byte[] b_userPass = userPass.getBytes("US-ASCII"); + byte[] b_encoded = Base64.encode(b_userPass).getBytes("US-ASCII"); + String authorization = + scheme + " " + new String(b_encoded, "US-ASCII"); + setHeader("Authorization", authorization); + return true; + } + else if ("Digest".equalsIgnoreCase(scheme)) + { + Properties params = parseAuthParams(challenge.substring(si + 1)); + String realm = params.getProperty("realm"); + String nonce = params.getProperty("nonce"); + String qop = params.getProperty("qop"); + String algorithm = params.getProperty("algorithm"); + String digestUri = getRequestURI(); + Credentials creds = authenticator.getCredentials(realm, attempts); + String username = creds.getUsername(); + String password = creds.getPassword(); + connection.incrementNonce(nonce); + try + { + MessageDigest md5 = MessageDigest.getInstance("MD5"); + final byte[] COLON = { 0x3a }; + + // Calculate H(A1) + md5.reset(); + md5.update(username.getBytes("US-ASCII")); + md5.update(COLON); + md5.update(realm.getBytes("US-ASCII")); + md5.update(COLON); + md5.update(password.getBytes("US-ASCII")); + byte[] ha1 = md5.digest(); + if ("md5-sess".equals(algorithm)) + { + byte[] cnonce = generateNonce(); + md5.reset(); + md5.update(ha1); + md5.update(COLON); + md5.update(nonce.getBytes("US-ASCII")); + md5.update(COLON); + md5.update(cnonce); + ha1 = md5.digest(); + } + String ha1Hex = toHexString(ha1); + + // Calculate H(A2) + md5.reset(); + md5.update(method.getBytes("US-ASCII")); + md5.update(COLON); + md5.update(digestUri.getBytes("US-ASCII")); + if ("auth-int".equals(qop)) + { + byte[] hEntity = null; // TODO hash of entity body + md5.update(COLON); + md5.update(hEntity); + } + byte[] ha2 = md5.digest(); + String ha2Hex = toHexString(ha2); + + // Calculate response + md5.reset(); + md5.update(ha1Hex.getBytes("US-ASCII")); + md5.update(COLON); + md5.update(nonce.getBytes("US-ASCII")); + if ("auth".equals(qop) || "auth-int".equals(qop)) + { + String nc = getNonceCount(nonce); + byte[] cnonce = generateNonce(); + md5.update(COLON); + md5.update(nc.getBytes("US-ASCII")); + md5.update(COLON); + md5.update(cnonce); + md5.update(COLON); + md5.update(qop.getBytes("US-ASCII")); + } + md5.update(COLON); + md5.update(ha2Hex.getBytes("US-ASCII")); + String digestResponse = toHexString(md5.digest()); + + String authorization = scheme + + " username=\"" + username + "\"" + + " realm=\"" + realm + "\"" + + " nonce=\"" + nonce + "\"" + + " uri=\"" + digestUri + "\"" + + " response=\"" + digestResponse + "\""; + setHeader("Authorization", authorization); + return true; + } + catch (NoSuchAlgorithmException e) + { + return false; + } + } + // Scheme not recognised + return false; + } + + Properties parseAuthParams(String text) + { + int len = text.length(); + String key = null; + CPStringBuilder buf = new CPStringBuilder(); + Properties ret = new Properties(); + boolean inQuote = false; + for (int i = 0; i < len; i++) + { + char c = text.charAt(i); + if (c == '"') + { + inQuote = !inQuote; + } + else if (c == '=' && key == null) + { + key = buf.toString().trim(); + buf.setLength(0); + } + else if (c == ' ' && !inQuote) + { + String value = unquote(buf.toString().trim()); + ret.put(key, value); + key = null; + buf.setLength(0); + } + else if (c != ',' || (i <(len - 1) && text.charAt(i + 1) != ' ')) + { + buf.append(c); + } + } + if (key != null) + { + String value = unquote(buf.toString().trim()); + ret.put(key, value); + } + return ret; + } + + String unquote(String text) + { + int len = text.length(); + if (len > 0 && text.charAt(0) == '"' && text.charAt(len - 1) == '"') + { + return text.substring(1, len - 1); + } + return text; + } + + /** + * Returns the number of times the specified nonce value has been seen. + * This always returns an 8-byte 0-padded hexadecimal string. + */ + String getNonceCount(String nonce) + { + int nc = connection.getNonceCount(nonce); + String hex = Integer.toHexString(nc); + CPStringBuilder buf = new CPStringBuilder(); + for (int i = 8 - hex.length(); i > 0; i--) + { + buf.append('0'); + } + buf.append(hex); + return buf.toString(); + } + + /** + * Client nonce value. + */ + byte[] nonce; + + /** + * Generates a new client nonce value. + */ + byte[] generateNonce() + throws IOException, NoSuchAlgorithmException + { + if (nonce == null) + { + long time = System.currentTimeMillis(); + MessageDigest md5 = MessageDigest.getInstance("MD5"); + md5.update(Long.toString(time).getBytes("US-ASCII")); + nonce = md5.digest(); + } + return nonce; + } + + String toHexString(byte[] bytes) + { + char[] ret = new char[bytes.length * 2]; + for (int i = 0, j = 0; i < bytes.length; i++) + { + int c =(int) bytes[i]; + if (c < 0) + { + c += 0x100; + } + ret[j++] = Character.forDigit(c / 0x10, 0x10); + ret[j++] = Character.forDigit(c % 0x10, 0x10); + } + return new String(ret); + } + + /** + * Parse the specified cookie list and notify the cookie manager. + */ + void handleSetCookie(String text) + { + CookieManager cookieManager = connection.getCookieManager(); + if (cookieManager == null) + { + return; + } + String name = null; + String value = null; + String comment = null; + String domain = connection.getHostName(); + String path = this.path; + int lsi = path.lastIndexOf('/'); + if (lsi != -1) + { + path = path.substring(0, lsi); + } + boolean secure = false; + Date expires = null; + + int len = text.length(); + String attr = null; + CPStringBuilder buf = new CPStringBuilder(); + boolean inQuote = false; + for (int i = 0; i <= len; i++) + { + char c =(i == len) ? '\u0000' : text.charAt(i); + if (c == '"') + { + inQuote = !inQuote; + } + else if (!inQuote) + { + if (c == '=' && attr == null) + { + attr = buf.toString().trim(); + buf.setLength(0); + } + else if (c == ';' || i == len || c == ',') + { + String val = unquote(buf.toString().trim()); + if (name == null) + { + name = attr; + value = val; + } + else if ("Comment".equalsIgnoreCase(attr)) + { + comment = val; + } + else if ("Domain".equalsIgnoreCase(attr)) + { + domain = val; + } + else if ("Path".equalsIgnoreCase(attr)) + { + path = val; + } + else if ("Secure".equalsIgnoreCase(val)) + { + secure = true; + } + else if ("Max-Age".equalsIgnoreCase(attr)) + { + int delta = Integer.parseInt(val); + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(System.currentTimeMillis()); + cal.add(Calendar.SECOND, delta); + expires = cal.getTime(); + } + else if ("Expires".equalsIgnoreCase(attr)) + { + DateFormat dateFormat = new HTTPDateFormat(); + try + { + expires = dateFormat.parse(val); + } + catch (ParseException e) + { + // if this isn't a valid date, it may be that + // the value was returned unquoted; in that case, we + // want to continue buffering the value + buf.append(c); + continue; + } + } + attr = null; + buf.setLength(0); + // case EOL + if (i == len || c == ',') + { + Cookie cookie = new Cookie(name, value, comment, domain, + path, secure, expires); + cookieManager.setCookie(cookie); + } + if (c == ',') + { + // Reset cookie fields + name = null; + value = null; + comment = null; + domain = connection.getHostName(); + path = this.path; + if (lsi != -1) + { + path = path.substring(0, lsi); + } + secure = false; + expires = null; + } + } + else + { + buf.append(c); + } + } + else + { + buf.append(c); + } + } + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/http/RequestBodyWriter.java b/libjava/classpath/gnu/java/net/protocol/http/RequestBodyWriter.java new file mode 100644 index 000000000..aa5b78a54 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/http/RequestBodyWriter.java @@ -0,0 +1,68 @@ +/* RequestBodyWriter.java -- + 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.net.protocol.http; + +/** + * Callback interface for writing request body content. + * + * @author Chris Burdess (dog@gnu.org) + */ +public interface RequestBodyWriter +{ + + /** + * Returns the total number of bytes that will be written in a single pass + * by this writer. + */ + int getContentLength(); + + /** + * Initialises the writer. + * This will be called before each pass. + */ + void reset(); + + /** + * Writes body content to the supplied buffer. + * @param buffer the content buffer + * @return the number of bytes written + */ + int write(byte[] buffer); + +} diff --git a/libjava/classpath/gnu/java/net/protocol/http/Response.java b/libjava/classpath/gnu/java/net/protocol/http/Response.java new file mode 100644 index 000000000..084cf75fa --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/http/Response.java @@ -0,0 +1,223 @@ +/* Response.java -- + 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.net.protocol.http; + +import java.io.InputStream; +import java.util.Date; + +/** + * An HTTP response. + * + * @author Chris Burdess (dog@gnu.org) + */ +public class Response +{ + + /** + * The HTTP major version of the server issuing the response. + */ + protected final int majorVersion; + + /** + * The HTTP minor version of the server issuing the response. + */ + protected final int minorVersion; + + /** + * The HTTP status code of the response. + */ + protected final int code; + + /** + * Human-readable text of the response. + */ + protected final String message; + + /** + * The response headers. + */ + protected final Headers headers; + + /** + * An InputStream that returns the body of the response. + */ + protected final InputStream body; + + /** + * Constructs a new response with the specified parameters. + */ + protected Response(int majorVersion, int minorVersion, int code, + String message, Headers headers, InputStream body) + { + this.majorVersion = majorVersion; + this.minorVersion = minorVersion; + this.code = code; + this.message = message; + this.headers = headers; + this.body = body; + } + + /** + * Returns the HTTP major version of the server issuing the response. + * @see #majorVersion + */ + public int getMajorVersion() + { + return majorVersion; + } + + /** + * Returns the HTTP minor version of the server issuing the response. + * @see #minorVersion + */ + public int getMinorVersion() + { + return minorVersion; + } + + /** + * Returns the HTTP status code of the response. + * @see #code + */ + public int getCode() + { + return code; + } + + /** + * Returns the class of the response. This is the most significant + * digit of the status code. + *
+ *
1xx
Informational response
+ *
2xx
Success
+ *
3xx
Redirection
+ *
4xx
Client error
+ *
5xx
Server error
+ *
+ */ + public int getCodeClass() + { + return code / 100; + } + + /** + * Returns the human-readable text of the response. + * @see #message + */ + public String getMessage() + { + return message; + } + + /** + * Returns the headers in the response. + */ + public Headers getHeaders() + { + return headers; + } + + /** + * Returns the header value for the specified name. + * @param name the header name + */ + public String getHeader(String name) + { + return headers.getValue(name); + } + + /** + * Returns the header value for the specified name as an integer. + * @param name the header name + */ + public int getIntHeader(String name) + { + return headers.getIntValue(name); + } + + /** + * Returns the header value for the specified name as a long. + * @param name the header name + */ + public long getLongHeader(String name) + { + return headers.getLongValue(name); + } + + /** + * Returns the header value for the specified name as a date. + * @param name the header name + */ + public Date getDateHeader(String name) + { + 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. + * + * @return the body of the response + */ + public InputStream getBody() + { + return body; + } +} diff --git a/libjava/classpath/gnu/java/net/protocol/http/ResponseHeaderHandler.java b/libjava/classpath/gnu/java/net/protocol/http/ResponseHeaderHandler.java new file mode 100644 index 000000000..ca863440e --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/http/ResponseHeaderHandler.java @@ -0,0 +1,56 @@ +/* ResponseHeaderHandler.java -- + 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.net.protocol.http; + +/** + * Callback interface for objects that wish to be notified of response + * header values. + * @see Request#setResponseHeaderHandler(String, ResponseHeaderHandler) + * + * @author Chris Burdess (dog@gnu.org) + */ +public interface ResponseHeaderHandler +{ + + /** + * Sets the value for the header associated with this handler. + */ + void setValue(String value); + +} diff --git a/libjava/classpath/gnu/java/net/protocol/http/SimpleCookieManager.java b/libjava/classpath/gnu/java/net/protocol/http/SimpleCookieManager.java new file mode 100644 index 000000000..f08204769 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/http/SimpleCookieManager.java @@ -0,0 +1,137 @@ +/* CookieManager.java -- + 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.net.protocol.http; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * A simple non-persistent cookie manager. This class can be extended to + * provide cookie persistence. + * + * @author Chris Burdess (dog@gnu.org) + */ +public class SimpleCookieManager + implements CookieManager +{ + + /** + * The cookie cache. + * This is a dictionary mapping domains to maps of cookies by name. + */ + protected Map> cookies; + + /** + * Constructor. + */ + public SimpleCookieManager() + { + cookies = new HashMap>(); + } + + public void setCookie(Cookie cookie) + { + String domain = cookie.getDomain(); + Map map = cookies.get(domain); + if (map == null) + { + map = new HashMap(); + cookies.put(domain, map); + } + String name = cookie.getName(); + map.put(name, cookie); // will replace a cookie of the same name + } + + public Cookie[] getCookies(String host, boolean secure, String path) + { + ArrayList matches = new ArrayList(); + Date now = new Date(); + if (Character.isLetter(host.charAt(0))) + { + int di = host.indexOf('.'); + while (di != -1) + { + addCookies(matches, host, secure, path, now); + host = host.substring(di); + di = host.indexOf('.', 1); + } + } + addCookies(matches, host, secure, path, now); + Cookie[] ret = new Cookie[matches.size()]; + matches.toArray(ret); + return ret; + } + + private void addCookies(ArrayList matches, String domain, + boolean secure, String path, Date now) + { + Map map = cookies.get(domain); + if (map != null) + { + ArrayList expired = new ArrayList(); + for (Map.Entry entry : map.entrySet()) + { + Cookie cookie = entry.getValue(); + Date expires = cookie.getExpiryDate(); + if (expires != null && expires.before(now)) + { + expired.add(entry.getKey()); + continue; + } + if (secure && !cookie.isSecure()) + { + continue; + } + if (path.startsWith(cookie.getPath())) + { + matches.add(cookie); + } + } + // Good housekeeping + for (Iterator i = expired.iterator(); i.hasNext(); ) + { + map.remove(i.next()); + } + } + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/http/package.html b/libjava/classpath/gnu/java/net/protocol/http/package.html new file mode 100644 index 000000000..8cf7c1e16 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/http/package.html @@ -0,0 +1,76 @@ + + + + +GNU Classpath - gnu.java.net.protocol.http + + + +

+This package contains an HTTP/1.1 client, as described in RFC 2616. +It supports the following features: +

    +
  • Persistent connections
  • +
  • Basic and Digest authentication (RFC 2617)
  • +
  • HTTPS
  • +
  • HTTP proxies
  • +
  • HTTP/1.0 compatibility
  • +
  • Support for WebDAV methods and other HTTP extensions
  • +
  • Automatic decoding of the chunked transfer-coding
  • +
  • Parsing of HTTP date headers
  • +
  • Support for the 100-continue expectation
  • +
+

+ +

+The API is similar to the neon +WebDAV/HTTP library. A logical connection to the server is instantiated, +and multiple requests can be issued for this connection. Each request +has an atomic dispatch method which returns the response. +All I/O, authentication, etc is handled by registering callback objects +with the request prior to dispatch, which are notified during the dispatch +procedure as necessary. Simple byte-array content callbacks are supplied +which can manage any request/response content that fits in available memory. +

+ +

+An URL stream handler is provided, supporting the full HttpURLConnection +specification. +

+ + diff --git a/libjava/classpath/gnu/java/net/protocol/https/Handler.java b/libjava/classpath/gnu/java/net/protocol/https/Handler.java new file mode 100644 index 000000000..dbb619905 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/https/Handler.java @@ -0,0 +1,75 @@ +/* Handler.java -- + Copyright (C) 2004, 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.java.net.protocol.https; + +import gnu.java.net.protocol.http.HTTPConnection; +import gnu.java.net.protocol.http.HTTPURLConnection; + +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; + +/** + * An HTTPS URL stream handler. + * + * @author Chris Burdess (dog@gnu.org) + */ +public class Handler + extends URLStreamHandler +{ + + /** + * Returns the default HTTPS port (443). + */ + protected int getDefaultPort() + { + return HTTPConnection.HTTPS_PORT; + } + + /** + * Returns an HTTPURLConnection for the given URL. + */ + public URLConnection openConnection(URL url) + throws IOException + { + return new HTTPURLConnection(url); + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/jar/Connection.java b/libjava/classpath/gnu/java/net/protocol/jar/Connection.java new file mode 100644 index 000000000..85d27bfc9 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/jar/Connection.java @@ -0,0 +1,232 @@ +/* Connection - jar url connection for java.net + Copyright (C) 1999, 2002, 2003, 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.java.net.protocol.jar; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.JarURLConnection; +import java.net.MalformedURLException; +import java.net.ProtocolException; +import java.net.URL; +import java.net.URLConnection; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Hashtable; +import java.util.Locale; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.zip.ZipFile; + +/** + * This subclass of java.net.JarURLConnection models a URLConnection via + * the "jar" protocol. + * + * @author Kresten Krab Thorup (krab@gnu.org) + */ +public final class Connection extends JarURLConnection +{ + /** + * HTTP-style DateFormat, used to format the last-modified header. + * Lazy initialized since jar files are used during bootstrapping. + */ + private static SimpleDateFormat dateFormat; + + private JarFile jar_file; + private JarEntry jar_entry; + private URL jar_url; + + public static class JarFileCache + { + private static Hashtable cache + = new Hashtable(); + private static final int READBUFSIZE = 4*1024; + + public static synchronized JarFile get (URL url, boolean useCaches) + throws IOException + { + JarFile jf; + if (useCaches) + { + jf = cache.get (url); + if (jf != null) + return jf; + } + + if ("file".equals (url.getProtocol())) + { + String fn = url.getFile(); + fn = gnu.java.net.protocol.file.Connection.unquote(fn); + File f = new File (fn); + jf = new JarFile (f, true, ZipFile.OPEN_READ); + } + else + { + URLConnection urlconn = url.openConnection(); + InputStream is = urlconn.getInputStream(); + byte[] buf = new byte [READBUFSIZE]; + File f = File.createTempFile ("cache", "jar"); + FileOutputStream fos = new FileOutputStream (f); + int len = 0; + + while ((len = is.read (buf)) != -1) + { + fos.write (buf, 0, len); + } + + fos.close(); + // Always verify the Manifest, open read only and delete when done. + jf = new JarFile (f, true, + ZipFile.OPEN_READ | ZipFile.OPEN_DELETE); + } + + if (useCaches) + cache.put (url, jf); + + return jf; + } + } + + protected Connection(URL url) + throws MalformedURLException + { + super(url); + } + + public synchronized void connect() throws IOException + { + // Call is ignored if already connected. + if (connected) + return; + + jar_url = getJarFileURL(); + jar_file = JarFileCache.get (jar_url, useCaches); + String entry_name = getEntryName(); + + if (entry_name != null + && !entry_name.equals ("")) + { + jar_entry = (JarEntry) jar_file.getEntry (entry_name); + + if(jar_entry == null) + throw new FileNotFoundException("No entry for " + entry_name + " exists."); + } + + connected = true; + } + + public InputStream getInputStream() throws IOException + { + if (!connected) + connect(); + + if (! doInput) + throw new ProtocolException("Can't open InputStream if doInput is false"); + + return jar_file.getInputStream (jar_entry); + } + + public synchronized JarFile getJarFile() throws IOException + { + if (!connected) + connect(); + + if (! doInput) + throw new ProtocolException("Can't open JarFile if doInput is false"); + + return jar_file; + } + + public String getHeaderField(String field) + { + try + { + if (!connected) + connect(); + + if (field.equals("content-type")) + return guessContentTypeFromName(getJarEntry().getName()); + else if (field.equals("content-length")) + return Long.toString(getJarEntry().getSize()); + else if (field.equals("last-modified")) + { + // Both creating and manipulating dateFormat need synchronization. + synchronized (Connection.class) + { + if (dateFormat == null) + dateFormat = new SimpleDateFormat + ("EEE, dd MMM yyyy hh:mm:ss 'GMT'", + new Locale ("En", "Us", "Unix")); + + return dateFormat.format(new Date(getJarEntry().getTime())); + } + } + } + catch (IOException e) + { + // Fall through. + } + return null; + } + + public int getContentLength() + { + if (!connected) + return -1; + + return (int) jar_entry.getSize(); + } + + public long getLastModified() + { + if (!connected) + return -1; + + try + { + return getJarEntry().getTime(); + } + catch (IOException e) + { + return -1; + } + } +} diff --git a/libjava/classpath/gnu/java/net/protocol/jar/Handler.java b/libjava/classpath/gnu/java/net/protocol/jar/Handler.java new file mode 100644 index 000000000..7d6103e93 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/jar/Handler.java @@ -0,0 +1,217 @@ +/* gnu.java.net.protocol.jar.Handler - jar protocol handler for java.net + Copyright (C) 1999, 2002, 2003, 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.java.net.protocol.jar; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.net.URLParseError; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.StringTokenizer; + +/** + * @author Kresten Krab Thorup (krab@gnu.org) + */ +public class Handler extends URLStreamHandler +{ + /** + * A do nothing constructor + */ + public Handler() + { + } + + /** + * This method returs a new JarURLConnection for the specified URL + * + * @param url The URL to return a connection for + * + * @return The URLConnection + * + * @exception IOException If an error occurs + */ + protected URLConnection openConnection(URL url) throws IOException + { + return new Connection(url); + } + + /** + * This method overrides URLStreamHandler's for parsing url of protocol "jar" + * + * @param url The URL object in which to store the results + * @param url_string The String-ized URL to parse + * @param start The position in the string to start scanning from + * @param end The position in the string to stop scanning + */ + protected void parseURL (URL url, String url_string, int start, int end) + { + // This method does not throw an exception or return a value. Thus our + // strategy when we encounter an error in parsing is to return without + // doing anything. + String file = url.getFile(); + + if (!file.equals("")) + { //has context url + url_string = url_string.substring (start, end); + if (url_string.startsWith("/")) + { //url string is an absolute path + int idx = file.lastIndexOf ("!/"); + + if (idx < 0) + throw new URLParseError("no !/ in spec"); + + file = file.substring (0, idx + 1) + url_string; + } + else if (url_string.length() > 0) + { + int idx = file.lastIndexOf ("/"); + if (idx == -1) //context path is weird + file = "/" + url_string; + else if (idx == (file.length() - 1)) + //just concatenate two parts + file = file + url_string; + else + // according to Java API Documentation, here is a little different + // with URLStreamHandler.parseURL + // but JDK seems doesn't handle it well + file = file.substring(0, idx + 1) + url_string; + } + + setURL (url, "jar", url.getHost(), url.getPort(), flat(file), null); + return; + } + + // Bunches of things should be true. Make sure. + if (end < start) + return; + if (end - start < 2) + return; + if (start > url_string.length()) + return; + + // Skip remains of protocol + url_string = url_string.substring (start, end); + + int jar_stop; + if ((jar_stop = url_string.indexOf("!/")) < 0) + throw new URLParseError("no !/ in spec"); + + try + { + new URL(url_string.substring (0, jar_stop)); + } + catch (MalformedURLException e) + { + throw new URLParseError("invalid inner URL: " + e.getMessage()); + } + + if (!url.getProtocol().equals ("jar") ) + throw new URLParseError("unexpected protocol " + url.getProtocol()); + + setURL (url, "jar", url.getHost(), url.getPort(), url_string, null); + } + + /** + * Makes the given jar url string 'flat' by removing any . and .. from + * jar file path because ZipFile entries can only handle flat paths. + * Inside jar files '/' is always the path separator. + */ + private static String flat(String url_string) + { + int jar_stop = url_string.indexOf("!/"); + String jar_path = url_string.substring(jar_stop + 1, url_string.length()); + + if (jar_path.indexOf("/.") < 0) + return url_string; + + ArrayList tokens = new ArrayList(); + StringTokenizer st = new StringTokenizer(jar_path, "/"); + while (st.hasMoreTokens()) + { + String token = st.nextToken(); + if (token.equals(".")) + continue; + else if (token.equals("..")) + { + if (! tokens.isEmpty()) + tokens.remove(tokens.size() - 1); + } + else + tokens.add(token); + } + + CPStringBuilder path = new CPStringBuilder(url_string.length()); + path.append(url_string.substring(0, jar_stop + 1)); + + Iterator it = tokens.iterator(); + while (it.hasNext()) + path.append('/').append(it.next()); + + return path.toString(); + } + + /** + * This method converts a Jar URL object into a String. + * + * @param url The URL object to convert + */ + protected String toExternalForm (URL url) + { + String file = url.getFile(); + String ref = url.getRef(); + + // return "jar:" + file; + // Performance!!: + // Do the concatenation manually to avoid resize StringBuffer's + // internal buffer. The length of ref is not taken into consideration + // as it's a rare path. + CPStringBuilder sb = new CPStringBuilder (file.length() + 5); + sb.append ("jar:"); + sb.append (file); + if (ref != null) + sb.append('#').append(ref); + return sb.toString(); + } +} diff --git a/libjava/classpath/gnu/java/net/protocol/jar/package.html b/libjava/classpath/gnu/java/net/protocol/jar/package.html new file mode 100644 index 000000000..dcd263d59 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/jar/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.net.protocol.jar + + +

+ + + diff --git a/libjava/classpath/gnu/java/nio/ChannelInputStream.java b/libjava/classpath/gnu/java/nio/ChannelInputStream.java new file mode 100644 index 000000000..5cad678c6 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/ChannelInputStream.java @@ -0,0 +1,89 @@ +/* ChannelInputStream.java -- + Copyright (C) 2003 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.nio; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.channels.IllegalBlockingModeException; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.SelectableChannel; + +/** + * @author Michael Koch + */ +public final class ChannelInputStream extends InputStream +{ + private ReadableByteChannel ch; + + public ChannelInputStream (ReadableByteChannel ch) + { + super(); + + this.ch = ch; + } + + public int read(byte[] buf, int off, int len) throws IOException + { + if (ch instanceof SelectableChannel + && (! ((SelectableChannel) ch).isBlocking())) + throw new IllegalBlockingModeException(); + + ByteBuffer b = ByteBuffer.wrap(buf, off, len); + return ch.read(b); + } + + public int read() throws IOException + { + if (ch instanceof SelectableChannel + && (! ((SelectableChannel) ch).isBlocking())) + throw new IllegalBlockingModeException(); + + ByteBuffer buffer = ByteBuffer.allocate(1); + int result = ch.read(buffer); + + if (result == -1) + return -1; + + if (result == 0) + throw new IOException("Could not read from channel"); + + return buffer.get(0) & 0xff; + } +} diff --git a/libjava/classpath/gnu/java/nio/ChannelOutputStream.java b/libjava/classpath/gnu/java/nio/ChannelOutputStream.java new file mode 100644 index 000000000..606f3775d --- /dev/null +++ b/libjava/classpath/gnu/java/nio/ChannelOutputStream.java @@ -0,0 +1,67 @@ +/* ChannelOutputStream.java -- + Copyright (C) 2003 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.nio; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.channels.WritableByteChannel; + +/** + * @author Michael Koch + */ +public final class ChannelOutputStream extends OutputStream +{ + private WritableByteChannel ch; + + public ChannelOutputStream (WritableByteChannel ch) + { + super(); + + this.ch = ch; + } + + public void write (int value) throws IOException + { + ByteBuffer buffer = ByteBuffer.allocate (1); + buffer.put ((byte) (value & 0xff)); + buffer.flip(); + ch.write (buffer); + } +} diff --git a/libjava/classpath/gnu/java/nio/ChannelReader.java b/libjava/classpath/gnu/java/nio/ChannelReader.java new file mode 100644 index 000000000..3c1456a36 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/ChannelReader.java @@ -0,0 +1,217 @@ +/* ChannelReader.java -- + 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.java.nio; + +import java.io.IOException; +import java.io.Reader; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.channels.ReadableByteChannel; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CoderResult; +import java.nio.charset.CodingErrorAction; + +/** + * A Reader implementation that works using a ReadableByteChannel and a + * CharsetDecoder. + * + *

+ * This is a bridge between NIO <-> IO character decoding. + *

+ * + * @author Robert Schuster + */ +public class ChannelReader extends Reader +{ + + private static final int DEFAULT_BUFFER_CAP = 8192; + + private ReadableByteChannel channel; + + private CharsetDecoder decoder; + + private ByteBuffer byteBuffer; + + private CharBuffer charBuffer; + + public ChannelReader(ReadableByteChannel channel, CharsetDecoder decoder, + int minBufferCap) + { + this.channel = channel; + this.decoder = decoder; + + // JDK reports errors, so we do the same. + decoder.onMalformedInput(CodingErrorAction.REPORT); + decoder.onUnmappableCharacter(CodingErrorAction.REPORT); + decoder.reset(); + + int size = (minBufferCap == -1) ? DEFAULT_BUFFER_CAP : minBufferCap; + + // Allocates the buffers and prepares them for reading, because that is the + // first operation being done on them. + byteBuffer = ByteBuffer.allocate(size); + byteBuffer.flip(); + charBuffer = CharBuffer.allocate((int) (size * decoder.averageCharsPerByte())); + } + + public int read(char[] buf, int offset, int count) throws IOException + { + synchronized (lock) + { + // I declared channel being null meaning that the reader is closed. + if (!channel.isOpen()) + throw new IOException("Reader was already closed."); + + // I declared decoder being null meaning that there is no more data to read + // and convert. + if (decoder == null) + return -1; + + // Stores the amount of character being read. It -1 so that if no conversion + // occured the caller will see this as an 'end of file'. + int sum = -1; + + // Copies any characters which may be left from the last invocation into the + // destination array. + if (charBuffer.remaining() > 0) + { + sum = Math.min(count, charBuffer.remaining()); + charBuffer.get(buf, offset, sum); + + // Updates the control variables according to the latest copy operation. + offset += sum; + count -= sum; + } + + // Copies the character which have not been put in the destination array to + // the beginning. If data is actually copied count will be 0. If no data is + // copied count is >0 and we can now convert some more characters. + charBuffer.compact(); + + int converted = 0; + boolean last = false; + + while (count != 0) + { + // Tries to convert some bytes (Which will intentionally fail in the + // first place because we have not read any bytes yet.) + CoderResult result = decoder.decode(byteBuffer, charBuffer, last); + if (result.isMalformed() || result.isUnmappable()) + { + // JDK throws exception when bytes are malformed for sure. + // FIXME: Unsure what happens when a character is simply + // unmappable. + result.throwException(); + } + + // Marks that we should end this loop regardless whether the caller + // wants more chars or not, when this was the last conversion. + if (last) + { + decoder = null; + } + else if (result.isUnderflow()) + { + // We need more bytes to do the conversion. + + // Copies the not yet converted bytes to the beginning making it + // being able to receive more bytes. + byteBuffer.compact(); + + // Reads in another bunch of bytes for being converted. + if (channel.read(byteBuffer) == -1) + { + // If there is no more data available in the channel we mark + // that state for the final character conversion run which is + // done in the next loop iteration. + last = true; + } + + // Prepares the byteBuffer for the next character conversion run. + byteBuffer.flip(); + } + + // Prepares the charBuffer for being drained. + charBuffer.flip(); + + converted = Math.min(count, charBuffer.remaining()); + charBuffer.get(buf, offset, converted); + + // Copies characters which have not yet being copied into the char-Array + // to the beginning making it possible to read them later (If data is + // really copied here, then the caller has received enough characters so + // far.). + charBuffer.compact(); + + // Updates the control variables according to the latest copy operation. + offset += converted; + count -= converted; + + // Updates the amount of transferred characters. + sum += converted; + + if (decoder == null) + { + break; + } + + // Now that more characters have been transfered we let the loop decide + // what to do next. + } + + // Makes the charBuffer ready for reading on the next invocation. + charBuffer.flip(); + + return sum; + } + } + + public void close() throws IOException + { + synchronized (lock) + { + channel.close(); + + // Makes sure all intermediate data is released by the decoder. + if (decoder != null) + decoder.reset(); + } + } + +} diff --git a/libjava/classpath/gnu/java/nio/ChannelWriter.java b/libjava/classpath/gnu/java/nio/ChannelWriter.java new file mode 100644 index 000000000..2441fb395 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/ChannelWriter.java @@ -0,0 +1,190 @@ +/* ChannelWriter.java -- nio / writer bridge + 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.nio; + +import java.io.IOException; +import java.io.Writer; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.channels.WritableByteChannel; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CoderResult; + +/** + * A Writer implementation that works by wrapping an NIO channel. + */ +public class ChannelWriter + extends Writer +{ + private static final int DEFAULT_BUFFER_CAP = 8192; + + /** + * The output channel. + */ + private WritableByteChannel byteChannel; + + /** + * The encoder to use. + */ + private CharsetEncoder enc; + + /** + * The byte buffer. Translated characters are stored here on their way out. + */ + private ByteBuffer byteBuffer; + + /** + * The character buffer. Characters are stored here on their way into + * the encoder. + */ + private CharBuffer charBuffer; + + private void writeBuffer() throws IOException + { + byteBuffer.flip(); + byteChannel.write(byteBuffer); + } + + /** + * Create a new instance, given the output byte channel, the encoder + * to use, and the minimum buffer capacity. + */ + public ChannelWriter(WritableByteChannel ch, CharsetEncoder enc, + int minBufferCap) + { + this.byteChannel = ch; + this.enc = enc; + if (minBufferCap == -1) + minBufferCap = DEFAULT_BUFFER_CAP; + this.byteBuffer + = ByteBuffer.allocate((int) (minBufferCap * enc.maxBytesPerChar())); + this.charBuffer = CharBuffer.allocate(minBufferCap); + this.charBuffer.clear(); + } + + /* (non-Javadoc) + * @see java.io.Writer#flush() + */ + public void flush() throws IOException + { + // Presumably if we have characters in our buffer, it is + // due to an underflow. So we don't bother trying to flush + // that here. + } + + /* (non-Javadoc) + * @see java.io.Writer#close() + */ + public void close() throws IOException + { + synchronized (lock) + { + if (enc == null) + throw new IOException("writer already closed"); + + byteBuffer.clear(); + charBuffer.flip(); + CoderResult res = enc.encode(charBuffer, byteBuffer, true); + if (res.isError() || res.isMalformed() || res.isUnmappable()) + res.throwException(); + writeBuffer(); + + byteBuffer.clear(); + res = enc.flush(byteBuffer); + if (res.isError() || res.isMalformed() || res.isUnmappable()) + res.throwException(); + writeBuffer(); + enc = null; + } + } + + /* (non-Javadoc) + * @see java.io.Writer#write(char[], int, int) + */ + public void write(char[] buf, int offset, int len) throws IOException + { + synchronized (lock) + { + if (enc == null) + throw new IOException("writer already closed"); + int lastLen = -1; + while (len > 0) + { + // Copy data into our character buffer. + int allowed = Math.min(charBuffer.remaining(), len); + charBuffer.put(buf, offset, allowed); + // Update for the next pass through the loop. + offset += allowed; + len -= allowed; + charBuffer.flip(); + // If we didn't make any progress, we want to clean up + // and save our state for the next write(). + if (len == lastLen) + { + if (len <= charBuffer.remaining()) + { + charBuffer.put(buf, offset, len); + charBuffer.flip(); + } + else + { + CharBuffer ncb = CharBuffer.allocate(charBuffer.length() + + len); + ncb.put(charBuffer); + ncb.put(buf, offset, len); + charBuffer = ncb; + } + break; + } + lastLen = len; + + // Convert. + byteBuffer.clear(); + CoderResult res = enc.encode(charBuffer, byteBuffer, false); + // Compact here, as we want to leave the buffer in the + // right state for any future put()s. + charBuffer.compact(); + if (res.isError() || res.isMalformed() || res.isUnmappable()) + res.throwException(); + // Write the byte buffer to the output channel. + writeBuffer(); + } + } + } +} diff --git a/libjava/classpath/gnu/java/nio/DatagramChannelImpl.java b/libjava/classpath/gnu/java/nio/DatagramChannelImpl.java new file mode 100644 index 000000000..1132796dd --- /dev/null +++ b/libjava/classpath/gnu/java/nio/DatagramChannelImpl.java @@ -0,0 +1,240 @@ +/* DatagramChannelImpl.java -- + Copyright (C) 2002, 2003, 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.nio; + +import gnu.java.net.PlainDatagramSocketImpl; +import java.io.IOException; +import java.net.DatagramSocket; +import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.DatagramChannel; +import java.nio.channels.NotYetConnectedException; +import java.nio.channels.spi.SelectorProvider; + +/** + * @author Michael Koch + */ +public final class DatagramChannelImpl extends DatagramChannel + implements VMChannelOwner +{ + private NIODatagramSocket socket; + private VMChannel channel; + + /** + * Indicates whether this channel initiated whatever operation + * is being invoked on our datagram socket. + */ + private boolean inChannelOperation; + + protected DatagramChannelImpl (SelectorProvider provider) + throws IOException + { + super (provider); + socket = new NIODatagramSocket (new PlainDatagramSocketImpl(), this); + channel = new VMChannel(); + channel.initSocket(false); + configureBlocking(true); + } + + /** + * Indicates whether our datagram socket should ignore whether + * we are set to non-blocking mode. Certain operations on our + * socket throw an IllegalBlockingModeException if + * we are in non-blocking mode, except if the operation + * is initiated by us. + */ + public final boolean isInChannelOperation() + { + return inChannelOperation; + } + + /** + * Sets our indicator of whether we are initiating an I/O operation + * on our socket. + */ + public final void setInChannelOperation(boolean b) + { + inChannelOperation = b; + } + + public DatagramSocket socket () + { + return socket; + } + + protected void implCloseSelectableChannel () + throws IOException + { + channel.close(); + } + + protected void implConfigureBlocking (boolean blocking) + throws IOException + { + channel.setBlocking(blocking); + } + + public DatagramChannel connect (SocketAddress remote) + throws IOException + { + if (!isOpen()) + throw new ClosedChannelException(); + + try + { + channel.connect((InetSocketAddress) remote, 0); + } + catch (ClassCastException cce) + { + throw new IOException("unsupported socked address type"); + } + return this; + } + + public DatagramChannel disconnect () + throws IOException + { + channel.disconnect(); + return this; + } + + public boolean isConnected() + { + try + { + return channel.getPeerAddress() != null; + } + catch (IOException ioe) + { + return false; + } + } + + public int write (ByteBuffer src) + throws IOException + { + if (!isConnected ()) + throw new NotYetConnectedException (); + + return channel.write(src); + } + + public long write (ByteBuffer[] srcs, int offset, int length) + throws IOException + { + if (!isConnected()) + throw new NotYetConnectedException(); + + if ((offset < 0) + || (offset > srcs.length) + || (length < 0) + || (length > (srcs.length - offset))) + throw new IndexOutOfBoundsException(); + + /* We are connected, meaning we will write these bytes to + * the host we connected to, so we don't need to explicitly + * give the host. */ + return channel.writeGathering(srcs, offset, length); + } + + public int read (ByteBuffer dst) + throws IOException + { + if (!isConnected ()) + throw new NotYetConnectedException (); + + return channel.read(dst); + } + + public long read (ByteBuffer[] dsts, int offset, int length) + throws IOException + { + if (!isConnected()) + throw new NotYetConnectedException(); + + if ((offset < 0) + || (offset > dsts.length) + || (length < 0) + || (length > (dsts.length - offset))) + throw new IndexOutOfBoundsException(); + + /* Likewise, see the comment int write above. */ + return channel.readScattering(dsts, offset, length); + } + + public SocketAddress receive (ByteBuffer dst) + throws IOException + { + if (!isOpen()) + throw new ClosedChannelException(); + + try + { + begin(); + return channel.receive(dst); + } + finally + { + end(true); + } + } + + public int send (ByteBuffer src, SocketAddress target) + throws IOException + { + if (!isOpen()) + throw new ClosedChannelException(); + + if (!(target instanceof InetSocketAddress)) + throw new IOException("can only send to inet socket addresses"); + + InetSocketAddress dst = (InetSocketAddress) target; + if (dst.isUnresolved()) + throw new IOException("Target address not resolved"); + + return channel.send(src, dst); + } + + public VMChannel getVMChannel() + { + return channel; + } +} diff --git a/libjava/classpath/gnu/java/nio/DatagramChannelSelectionKey.java b/libjava/classpath/gnu/java/nio/DatagramChannelSelectionKey.java new file mode 100644 index 000000000..93837f341 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/DatagramChannelSelectionKey.java @@ -0,0 +1,68 @@ +/* DatagramChannelSelectionKey.java -- + Copyright (C) 2003, 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.java.nio; + +import java.io.IOException; +import java.nio.channels.spi.AbstractSelectableChannel; + +/** + * @author Michael Koch + */ +public final class DatagramChannelSelectionKey + extends SelectionKeyImpl +{ + public DatagramChannelSelectionKey (AbstractSelectableChannel channel, + SelectorImpl selector) + { + super (channel, selector); + } + + // FIXME don't use file descriptor integers + public int getNativeFD() + { + try + { + return ((DatagramChannelImpl) ch).getVMChannel().getState().getNativeFD(); + } + catch (IOException ioe) + { + throw new IllegalStateException(ioe); + } + } +} diff --git a/libjava/classpath/gnu/java/nio/EpollSelectionKeyImpl.java b/libjava/classpath/gnu/java/nio/EpollSelectionKeyImpl.java new file mode 100644 index 000000000..c0b7720e3 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/EpollSelectionKeyImpl.java @@ -0,0 +1,122 @@ +/* EpollSelectionKeyImpl.java -- selection key for the epoll selector. + 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.nio; + +import java.io.IOException; +import java.nio.channels.CancelledKeyException; +import java.nio.channels.SelectableChannel; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.spi.AbstractSelectionKey; + +/** + * @author Casey Marshall (csm@gnu.org) + */ +public class EpollSelectionKeyImpl extends AbstractSelectionKey +{ + final int fd; + private final EpollSelectorImpl selector; + private final SelectableChannel channel; + int interestOps; + int selectedOps; + int key; + boolean valid; + boolean cancelled; + + EpollSelectionKeyImpl(EpollSelectorImpl selector, + SelectableChannel channel, int fd) + { + this.selector = selector; + this.channel = channel; + this.fd = fd; + } + + /* (non-Javadoc) + * @see java.nio.channels.SelectionKey#channel() + */ + public SelectableChannel channel() + { + return channel; + } + + /* (non-Javadoc) + * @see java.nio.channels.SelectionKey#interestOps() + */ + public int interestOps() + { + return interestOps; + } + + /* (non-Javadoc) + * @see java.nio.channels.SelectionKey#interestOps(int) + */ + public SelectionKey interestOps(int ops) + { + if (cancelled) + throw new CancelledKeyException(); + if ((ops & ~(channel.validOps())) != 0) + throw new IllegalArgumentException("unsupported channel ops"); + try + { + selector.epoll_modify(this, ops); + interestOps = ops; + } + catch (IOException ioe) + { + throw new IllegalArgumentException(ioe); + } + return this; + } + + /* (non-Javadoc) + * @see java.nio.channels.SelectionKey#readyOps() + */ + public int readyOps() + { + return selectedOps; + } + + /* (non-Javadoc) + * @see java.nio.channels.SelectionKey#selector() + */ + public Selector selector() + { + return selector; + } +} diff --git a/libjava/classpath/gnu/java/nio/EpollSelectorImpl.java b/libjava/classpath/gnu/java/nio/EpollSelectorImpl.java new file mode 100644 index 000000000..f74b087c2 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/EpollSelectorImpl.java @@ -0,0 +1,399 @@ +/* EpollSelectorImpl.java -- selector implementation using epoll + 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.nio; + +import gnu.classpath.Configuration; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.SelectableChannel; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.spi.AbstractSelectableChannel; +import java.nio.channels.spi.AbstractSelector; +import java.nio.channels.spi.SelectorProvider; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +/** + * An implementation of {@link Selector} that uses the epoll event + * notification mechanism on GNU/Linux. + * + * @author Casey Marshall (csm@gnu.org) + */ +public class EpollSelectorImpl extends AbstractSelector +{ + // XXX is this reasonable? Does it matter? + private static final int DEFAULT_EPOLL_SIZE = 128; + private static final int sizeof_struct_epoll_event; + + private static final int OP_ACCEPT = SelectionKey.OP_ACCEPT; + private static final int OP_CONNECT = SelectionKey.OP_CONNECT; + private static final int OP_READ = SelectionKey.OP_READ; + private static final int OP_WRITE = SelectionKey.OP_WRITE; + + /** our epoll file descriptor. */ + private int epoll_fd; + + private final HashMap keys; + private Set selectedKeys; + private Thread waitingThread; + private ByteBuffer events; + + private static final int INITIAL_CAPACITY; + private static final int MAX_DOUBLING_CAPACITY; + private static final int CAPACITY_INCREMENT; + + static + { + if (Configuration.INIT_LOAD_LIBRARY) + System.loadLibrary("javanio"); + + if (epoll_supported()) + sizeof_struct_epoll_event = sizeof_struct(); + else + sizeof_struct_epoll_event = -1; + + INITIAL_CAPACITY = 64 * sizeof_struct_epoll_event; + MAX_DOUBLING_CAPACITY = 1024 * sizeof_struct_epoll_event; + CAPACITY_INCREMENT = 128 * sizeof_struct_epoll_event; + } + + public EpollSelectorImpl(SelectorProvider provider) + throws IOException + { + super(provider); + epoll_fd = epoll_create(DEFAULT_EPOLL_SIZE); + keys = new HashMap(); + selectedKeys = null; + events = ByteBuffer.allocateDirect(INITIAL_CAPACITY); + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#keys() + */ + public Set keys() + { + return new HashSet(keys.values()); + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#select() + */ + public int select() throws IOException + { + return doSelect(-1); + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#select(long) + */ + public int select(long timeout) throws IOException + { + if (timeout > Integer.MAX_VALUE) + throw new IllegalArgumentException("timeout is too large"); + if (timeout < 0) + throw new IllegalArgumentException("invalid timeout"); + return doSelect((int) timeout); + } + + private int doSelect(int timeout) throws IOException + { + synchronized (keys) + { + Set cancelledKeys = cancelledKeys(); + synchronized (cancelledKeys) + { + for (Iterator it = cancelledKeys.iterator(); it.hasNext(); ) + { + EpollSelectionKeyImpl key = (EpollSelectionKeyImpl) it.next(); + epoll_delete(epoll_fd, key.fd); + key.valid = false; + keys.remove(Integer.valueOf(key.fd)); + it.remove(); + deregister(key); + } + + // Clear out closed channels. The fds are removed from the epoll + // fd when closed, so there is no need to remove them manually. + for (Iterator it = keys.values().iterator(); it.hasNext(); ) + { + EpollSelectionKeyImpl key = (EpollSelectionKeyImpl) it.next(); + SelectableChannel ch = key.channel(); + if (ch instanceof VMChannelOwner) + { + if (!((VMChannelOwner) ch).getVMChannel().getState().isValid()) + it.remove(); + } + } + + // Don't bother if we have nothing to select. + if (keys.isEmpty()) + return 0; + + int ret; + try + { + begin(); + waitingThread = Thread.currentThread(); + ret = epoll_wait(epoll_fd, events, keys.size(), timeout); + } + finally + { + Thread.interrupted(); + waitingThread = null; + end(); + } + + HashSet s = new HashSet(ret); + for (int i = 0; i < ret; i++) + { + events.position(i * sizeof_struct_epoll_event); + ByteBuffer b = events.slice(); + int fd = selected_fd(b); + EpollSelectionKeyImpl key + = (EpollSelectionKeyImpl) keys.get(Integer.valueOf(fd)); + if (key == null) + throw new IOException("fd was selected, but no key found"); + key.selectedOps = selected_ops(b) & key.interestOps; + s.add(key); + } + + reallocateBuffer(); + + selectedKeys = s; + return ret; + } + } + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#selectedKeys() + */ + public Set selectedKeys() + { + if (selectedKeys == null) + return Collections.EMPTY_SET; + return selectedKeys; + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#selectNow() + */ + public int selectNow() throws IOException + { + return doSelect(0); + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#wakeup() + */ + public Selector wakeup() + { + try + { + waitingThread.interrupt(); + } + catch (NullPointerException npe) + { + // Ignored, thrown if we are not in a blocking op. + } + return this; + } + + /* (non-Javadoc) + * @see java.nio.channels.spi.AbstractSelector#implCloseSelector() + */ + protected void implCloseSelector() throws IOException + { + VMChannel.close(epoll_fd); + } + + /* (non-Javadoc) + * @see java.nio.channels.spi.AbstractSelector#register(java.nio.channels.spi.AbstractSelectableChannel, int, java.lang.Object) + */ + protected SelectionKey register(AbstractSelectableChannel ch, int ops, Object att) + { + if (!(ch instanceof VMChannelOwner)) + throw new IllegalArgumentException("unsupported channel type"); + + VMChannel channel = ((VMChannelOwner) ch).getVMChannel(); + try + { + int native_fd = channel.getState().getNativeFD(); + synchronized (keys) + { + if (keys.containsKey(Integer.valueOf(native_fd))) + throw new IllegalArgumentException("channel already registered"); + EpollSelectionKeyImpl result = + new EpollSelectionKeyImpl(this, ch, native_fd); + if ((ops & ~(ch.validOps())) != 0) + throw new IllegalArgumentException("invalid ops for channel"); + result.interestOps = ops; + result.selectedOps = 0; + result.valid = true; + result.attach(att); + result.key = System.identityHashCode(result); + epoll_add(epoll_fd, result.fd, ops); + keys.put(Integer.valueOf(native_fd), result); + reallocateBuffer(); + return result; + } + } + catch (IOException ioe) + { + throw new IllegalArgumentException(ioe); + } + } + + private void reallocateBuffer() + { + // Ensure we have enough space for all potential events that may be + // returned. + if (events.capacity() < keys.size() * sizeof_struct_epoll_event) + { + int cap = events.capacity(); + if (cap < MAX_DOUBLING_CAPACITY) + cap <<= 1; + else + cap += CAPACITY_INCREMENT; + events = ByteBuffer.allocateDirect(cap); + } + // Ensure that the events buffer is not too large, given the number of + // events registered. + else if (events.capacity() > keys.size() * sizeof_struct_epoll_event * 2 + 1 + && events.capacity() > INITIAL_CAPACITY) + { + int cap = events.capacity() >>> 1; + events = ByteBuffer.allocateDirect(cap); + } + } + + void epoll_modify(EpollSelectionKeyImpl key, int ops) throws IOException + { + epoll_modify(epoll_fd, key.fd, ops); + } + + /** + * Tell if epoll is supported by this system, and support was compiled in. + * + * @return True if this system supports event notification with epoll. + */ + public static native boolean epoll_supported(); + + + /** + * Returns the size of `struct epoll_event'. + * + * @return The size of `struct epoll_event'. + */ + private static native int sizeof_struct(); + + + /** + * Open a new epoll file descriptor. + * + * @param size The size hint for the new epoll descriptor. + * @return The new file descriptor integer. + * @throws IOException If allocating a new epoll descriptor fails. + */ + private static native int epoll_create(int size) throws IOException; + + /** + * Add a file descriptor to this selector. + * + * @param efd The epoll file descriptor. + * @param fd The file descriptor to add (or modify). + * @param ops The interest opts. + */ + private static native void epoll_add(int efd, int fd, int ops) + throws IOException; + + /** + * Modify the interest ops of the key selecting for the given FD. + * + * @param efd The epoll file descriptor. + * @param fd The file descriptor to modify. + * @param ops The ops. + * @throws IOException + */ + private static native void epoll_modify(int efd, int fd, int ops) + throws IOException; + + /** + * Remove a file descriptor from this selector. + * + * @param efd The epoll file descriptor. + * @param fd The file descriptor. + * @throws IOException + */ + private static native void epoll_delete(int efd, int fd) throws IOException; + + /** + * Select events. + * + * @param efd The epoll file descriptor. + * @param state The buffer to hold selected events. + * @param n The number of events that may be put in `state'. + * @param timeout The timeout. + * @return The number of events selected. + * @throws IOException + */ + private static native int epoll_wait(int efd, ByteBuffer state, int n, int timeout) + throws IOException; + + /** + * Fetch the fd value from a selected struct epoll_event. + * + * @param struct The direct buffer holding the struct. + * @return The fd value. + */ + private static native int selected_fd(ByteBuffer struct); + + /** + * Fetch the enabled operations from a selected struct epoll_event. + * + * @param struct The direct buffer holding the struct. + * @return The selected operations. + */ + private static native int selected_ops(ByteBuffer struct); +} diff --git a/libjava/classpath/gnu/java/nio/FileChannelImpl.java b/libjava/classpath/gnu/java/nio/FileChannelImpl.java new file mode 100644 index 000000000..c17227d3d --- /dev/null +++ b/libjava/classpath/gnu/java/nio/FileChannelImpl.java @@ -0,0 +1,572 @@ +/* FileChannelImpl.java -- + Copyright (C) 2002, 2004, 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.java.nio; + +import gnu.classpath.Configuration; +import gnu.java.nio.FileLockImpl; +import gnu.java.nio.VMChannel; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.MappedByteBuffer; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.FileChannel; +import java.nio.channels.FileLock; +import java.nio.channels.NonReadableChannelException; +import java.nio.channels.NonWritableChannelException; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; + +/** + * This file is not user visible ! + * But alas, Java does not have a concept of friendly packages + * so this class is public. + * Instances of this class are created by invoking getChannel + * Upon a Input/Output/RandomAccessFile object. + */ +public final class FileChannelImpl extends FileChannel +{ + // These are mode values for open(). + public static final int READ = 1; + public static final int WRITE = 2; + public static final int APPEND = 4; + + // EXCL is used only when making a temp file. + public static final int EXCL = 8; + public static final int SYNC = 16; + public static final int DSYNC = 32; + + public static final FileChannelImpl in; + public static final FileChannelImpl out; + public static final FileChannelImpl err; + + //private static native void init(); + + static + { + if (Configuration.INIT_LOAD_LIBRARY) + { + System.loadLibrary("javanio"); + } + + //init(); + + FileChannelImpl ch = null; + try + { + ch = new FileChannelImpl(VMChannel.getStdin(), READ); + } + catch (IOException ioe) + { + throw new Error(ioe); + } + in = ch; + + ch = null; + try + { + ch = new FileChannelImpl(VMChannel.getStdout(), WRITE); + } + catch (IOException ioe) + { + throw new Error(ioe); + } + out = ch; + + ch = null; + try + { + ch = new FileChannelImpl(VMChannel.getStderr(), WRITE); + } + catch (IOException ioe) + { + throw new Error(ioe); + } + err = ch; + } + + /** + * This is the actual native file descriptor value + */ + private VMChannel ch; + + private int mode; + + final String description; + + /* Open a file. MODE is a combination of the above mode flags. */ + /* This is a static factory method, so that VM implementors can decide + * substitute subclasses of FileChannelImpl. */ + public static FileChannelImpl create(File file, int mode) + throws IOException + { + return new FileChannelImpl(file, mode); + } + + private FileChannelImpl(File file, int mode) + throws IOException + { + String path = file.getPath(); + description = path; + this.mode = mode; + this.ch = new VMChannel(); + ch.openFile(path, mode); + + // First open the file and then check if it is a a directory + // to avoid race condition. + if (file.isDirectory()) + { + try + { + close(); + } + catch (IOException e) + { + /* ignore it */ + } + + throw new FileNotFoundException(description + " is a directory"); + } + } + + /** + * Constructor for default channels in, out and err. + * + * Used by init() (native code). + * + * @param fd the file descriptor (0, 1, 2 for stdin, stdout, stderr). + * + * @param mode READ or WRITE + */ + FileChannelImpl (VMChannel ch, int mode) + { + this.mode = mode; + this.description = "descriptor(" + ch.getState() + ")"; + this.ch = ch; + } + + public int available() throws IOException + { + return ch.available(); + } + + private long implPosition() throws IOException + { + return ch.position(); + } + + private void seek(long newPosition) throws IOException + { + ch.seek(newPosition); + } + + private void implTruncate(long size) throws IOException + { + ch.truncate(size); + } + + public void unlock(long pos, long len) throws IOException + { + ch.unlock(pos, len); + } + + public long size () throws IOException + { + return ch.size(); + } + + protected void implCloseChannel() throws IOException + { + ch.close(); + } + + /** + * Makes sure the Channel is properly closed. + */ + protected void finalize() throws IOException + { + if (ch.getState().isValid()) + close(); + } + + public int read (ByteBuffer dst) throws IOException + { + return ch.read(dst); + } + + public int read (ByteBuffer dst, long position) + throws IOException + { + if (position < 0) + throw new IllegalArgumentException ("position: " + position); + long oldPosition = implPosition (); + position (position); + int result = read(dst); + position (oldPosition); + + return result; + } + + public int read() throws IOException + { + return ch.read(); + } + + public long read (ByteBuffer[] dsts, int offset, int length) + throws IOException + { + return ch.readScattering(dsts, offset, length); + } + + public int write (ByteBuffer src) throws IOException + { + return ch.write(src); + } + + public int write (ByteBuffer src, long position) + throws IOException + { + if (position < 0) + throw new IllegalArgumentException ("position: " + position); + + if (!isOpen ()) + throw new ClosedChannelException (); + + if ((mode & WRITE) == 0) + throw new NonWritableChannelException (); + + int result; + long oldPosition; + + oldPosition = implPosition (); + seek (position); + result = write(src); + seek (oldPosition); + + return result; + } + + public void write (int b) throws IOException + { + ch.write(b); + } + + public long write(ByteBuffer[] srcs, int offset, int length) + throws IOException + { + return ch.writeGathering(srcs, offset, length); + } + + public MappedByteBuffer map (FileChannel.MapMode mode, + long position, long size) + throws IOException + { + char nmode = 0; + if (mode == MapMode.READ_ONLY) + { + nmode = 'r'; + if ((this.mode & READ) == 0) + throw new NonReadableChannelException(); + } + else if (mode == MapMode.READ_WRITE || mode == MapMode.PRIVATE) + { + nmode = mode == MapMode.READ_WRITE ? '+' : 'c'; + if ((this.mode & WRITE) != WRITE) + throw new NonWritableChannelException(); + if ((this.mode & READ) != READ) + throw new NonReadableChannelException(); + } + else + throw new IllegalArgumentException ("mode: " + mode); + + if (position < 0 || size < 0 || size > Integer.MAX_VALUE) + throw new IllegalArgumentException ("position: " + position + + ", size: " + size); + return ch.map(nmode, position, (int) size); + } + + /** + * msync with the disk + */ + public void force (boolean metaData) throws IOException + { + if (!isOpen ()) + throw new ClosedChannelException (); + + ch.flush(metaData); + } + + // like transferTo, but with a count of less than 2Gbytes + private int smallTransferTo (long position, int count, + WritableByteChannel target) + throws IOException + { + ByteBuffer buffer; + try + { + // Try to use a mapped buffer if we can. If this fails for + // any reason we'll fall back to using a ByteBuffer. + buffer = map (MapMode.READ_ONLY, position, count); + } + catch (IOException e) + { + buffer = ByteBuffer.allocate (count); + read (buffer, position); + buffer.flip(); + } + + return target.write (buffer); + } + + public long transferTo (long position, long count, + WritableByteChannel target) + throws IOException + { + if (position < 0 + || count < 0) + throw new IllegalArgumentException ("position: " + position + + ", count: " + count); + + if (!isOpen ()) + throw new ClosedChannelException (); + + if ((mode & READ) == 0) + throw new NonReadableChannelException (); + + final int pageSize = 65536; + long total = 0; + + while (count > 0) + { + int transferred + = smallTransferTo (position, (int)Math.min (count, pageSize), + target); + if (transferred < 0) + break; + total += transferred; + position += transferred; + count -= transferred; + } + + return total; + } + + // like transferFrom, but with a count of less than 2Gbytes + private int smallTransferFrom (ReadableByteChannel src, long position, + int count) + throws IOException + { + ByteBuffer buffer = null; + + if (src instanceof FileChannel) + { + try + { + // Try to use a mapped buffer if we can. If this fails + // for any reason we'll fall back to using a ByteBuffer. + buffer = ((FileChannel)src).map (MapMode.READ_ONLY, position, + count); + } + catch (IOException e) + { + } + } + + if (buffer == null) + { + buffer = ByteBuffer.allocate (count); + src.read (buffer); + buffer.flip(); + } + + return write (buffer, position); + } + + public long transferFrom (ReadableByteChannel src, long position, + long count) + throws IOException + { + if (position < 0 + || count < 0) + throw new IllegalArgumentException ("position: " + position + + ", count: " + count); + + if (!isOpen ()) + throw new ClosedChannelException (); + + if ((mode & WRITE) == 0) + throw new NonWritableChannelException (); + + final int pageSize = 65536; + long total = 0; + + while (count > 0) + { + int transferred = smallTransferFrom (src, position, + (int)Math.min (count, pageSize)); + if (transferred < 0) + break; + total += transferred; + position += transferred; + count -= transferred; + } + + return total; + } + + // Shared sanity checks between lock and tryLock methods. + private void lockCheck(long position, long size, boolean shared) + throws IOException + { + if (position < 0 + || size < 0) + throw new IllegalArgumentException ("position: " + position + + ", size: " + size); + + if (!isOpen ()) + throw new ClosedChannelException(); + + if (shared && ((mode & READ) == 0)) + throw new NonReadableChannelException(); + + if (!shared && ((mode & WRITE) == 0)) + throw new NonWritableChannelException(); + } + + public FileLock tryLock (long position, long size, boolean shared) + throws IOException + { + lockCheck(position, size, shared); + + boolean completed = false; + try + { + begin(); + boolean lockable = ch.lock(position, size, shared, false); + completed = true; + return (lockable + ? new FileLockImpl(this, position, size, shared) + : null); + } + finally + { + end(completed); + } + } + + public FileLock lock (long position, long size, boolean shared) + throws IOException + { + lockCheck(position, size, shared); + + boolean completed = false; + try + { + boolean lockable = ch.lock(position, size, shared, true); + completed = true; + return (lockable + ? new FileLockImpl(this, position, size, shared) + : null); + } + finally + { + end(completed); + } + } + + public long position () + throws IOException + { + if (!isOpen ()) + throw new ClosedChannelException (); + + return implPosition (); + } + + public FileChannel position (long newPosition) + throws IOException + { + if (newPosition < 0) + throw new IllegalArgumentException ("newPosition: " + newPosition); + + if (!isOpen ()) + throw new ClosedChannelException (); + + // FIXME note semantics if seeking beyond eof. + // We should seek lazily - only on a write. + seek (newPosition); + return this; + } + + public FileChannel truncate (long size) + throws IOException + { + if (size < 0) + throw new IllegalArgumentException ("size: " + size); + + if (!isOpen ()) + throw new ClosedChannelException (); + + if ((mode & WRITE) == 0) + throw new NonWritableChannelException (); + + if (size < size ()) + implTruncate (size); + + return this; + } + + public String toString() + { + return (super.toString() + + "[ fd: " + ch.getState() + + "; mode: " + Integer.toOctalString(mode) + + "; " + description + " ]"); + } + + /** + * @return The native file descriptor. + * / + public int getNativeFD() + { + return fd; + }*/ +} diff --git a/libjava/classpath/gnu/java/nio/FileLockImpl.java b/libjava/classpath/gnu/java/nio/FileLockImpl.java new file mode 100644 index 000000000..e714ea358 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/FileLockImpl.java @@ -0,0 +1,102 @@ +/* FileLockImpl.java -- FileLock associated with a FileChannelImpl. + Copyright (C) 2002, 2004, 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.java.nio; + +import java.io.IOException; +import java.nio.channels.FileLock; + +/** + * A FileLock associated with a FileChannelImpl. + * + * @author Michael Koch + * @since 1.4 + */ +public final class FileLockImpl extends FileLock +{ + /** + * Whether or not this lock is valid, false when channel is closed or + * release has been explicitly called. + */ + private boolean valid; + + public FileLockImpl (FileChannelImpl channel, long position, + long size, boolean shared) + { + super (channel, position, size, shared); + valid = true; + } + + /** + * Releases this lock. + */ + protected void finalize() + { + try + { + release(); + } + catch (IOException e) + { + // Ignore this. + } + } + + /** + * Whether or not this lock is valid, false when channel is closed or + * release has been explicitly called. + */ + public boolean isValid() + { + if (valid) + valid = channel().isOpen(); + return valid; + } + + /** + * Releases the lock if it is still valid. Marks this lock as invalid. + */ + public void release() throws IOException + { + if (isValid()) + { + valid = false; + ((FileChannelImpl) channel()).unlock(position(), size()); + } + } +} diff --git a/libjava/classpath/gnu/java/nio/InputStreamChannel.java b/libjava/classpath/gnu/java/nio/InputStreamChannel.java new file mode 100644 index 000000000..9bdfe3238 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/InputStreamChannel.java @@ -0,0 +1,88 @@ +/* InputStreamChannel.java -- + Copyright (C) 2003 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.nio; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.ReadableByteChannel; + +/** + * @author Michael Koch + */ +public final class InputStreamChannel implements ReadableByteChannel +{ + private boolean closed = false; + private InputStream in; + + public InputStreamChannel (InputStream in) + { + super(); + this.in = in; + } + + public void close() throws IOException + { + if (!closed) + { + in.close(); + closed = true; + } + } + + public boolean isOpen() + { + return !closed; + } + + public int read (ByteBuffer dst) throws IOException + { + if (!isOpen()) + throw new ClosedChannelException(); + + byte[] buffer = new byte [dst.remaining()]; + int readBytes = in.read (buffer); + + if (readBytes > 0) + dst.put (buffer, 0, readBytes); + + return readBytes; + } +} diff --git a/libjava/classpath/gnu/java/nio/KqueueSelectionKeyImpl.java b/libjava/classpath/gnu/java/nio/KqueueSelectionKeyImpl.java new file mode 100644 index 000000000..9fe6b6613 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/KqueueSelectionKeyImpl.java @@ -0,0 +1,187 @@ +/* KqueueSelectionKeyImpl.java -- selection key for kqueue/kevent. + 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.nio; + + +import java.nio.channels.SelectableChannel; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.spi.AbstractSelectionKey; + +/** + * @author Casey Marshall (csm@gnu.org) + */ +public class KqueueSelectionKeyImpl extends AbstractSelectionKey +{ + int interestOps; + int readyOps; + int activeOps = 0; + int key; + int fd; + + /** The selector we were created for. */ + private final KqueueSelectorImpl selector; + + /** The channel we are attached to. */ + private final SelectableChannel channel; + + private final VMChannelOwner natChannel; + + public KqueueSelectionKeyImpl(KqueueSelectorImpl selector, + SelectableChannel channel) + { + this.selector = selector; + this.channel = channel; + natChannel = (VMChannelOwner) channel; + interestOps = 0; + readyOps = 0; + } + + /* (non-Javadoc) + * @see java.nio.channels.SelectionKey#channel() + */ + //@Override + public SelectableChannel channel() + { + return channel; + } + + /* (non-Javadoc) + * @see java.nio.channels.SelectionKey#interestOps() + */ + //@Override + public int interestOps() + { + return interestOps; + } + + /* (non-Javadoc) + * @see java.nio.channels.SelectionKey#interestOps(int) + */ + //@Override + public SelectionKey interestOps(int ops) + { + if (!isValid()) + throw new IllegalStateException("key is invalid"); + if ((ops & ~channel.validOps()) != 0) + throw new IllegalArgumentException("channel does not support all operations"); + + selector.setInterestOps(this, ops); + return this; + } + + /* (non-Javadoc) + * @see java.nio.channels.SelectionKey#readyOps() + */ + //@Override + public int readyOps() + { + return readyOps; + } + + /* (non-Javadoc) + * @see java.nio.channels.SelectionKey#selector() + */ + //@Override + public Selector selector() + { + return selector; + } + + public String toString() + { + if (!isValid()) + return super.toString() + " [ fd: " + fd + " <> ]"; + return super.toString() + " [ fd: " + fd + " interest ops: {" + + ((interestOps & OP_ACCEPT) != 0 ? " OP_ACCEPT" : "") + + ((interestOps & OP_CONNECT) != 0 ? " OP_CONNECT" : "") + + ((interestOps & OP_READ) != 0 ? " OP_READ" : "") + + ((interestOps & OP_WRITE) != 0 ? " OP_WRITE" : "") + + " }; ready ops: {" + + ((readyOps & OP_ACCEPT) != 0 ? " OP_ACCEPT" : "") + + ((readyOps & OP_CONNECT) != 0 ? " OP_CONNECT" : "") + + ((readyOps & OP_READ) != 0 ? " OP_READ" : "") + + ((readyOps & OP_WRITE) != 0 ? " OP_WRITE" : "") + + " } ]"; + } + + public int hashCode() + { + return fd; + } + + public boolean equals(Object o) + { + if (!(o instanceof KqueueSelectionKeyImpl)) + return false; + KqueueSelectionKeyImpl that = (KqueueSelectionKeyImpl) o; + return that.fd == this.fd && that.channel.equals(this.channel); + } + + + boolean isReadActive() + { + return (activeOps & (OP_READ | OP_ACCEPT)) != 0; + } + + boolean isReadInterested() + { + return (interestOps & (OP_READ | OP_ACCEPT)) != 0; + } + + boolean isWriteActive() + { + return (activeOps & (OP_WRITE | OP_CONNECT)) != 0; + } + + boolean isWriteInterested() + { + return (interestOps & (OP_WRITE | OP_CONNECT)) != 0; + } + + boolean needCommitRead() + { + return isReadActive() == (!isReadInterested()); + } + + boolean needCommitWrite() + { + return isWriteActive() == (!isWriteInterested()); + } +} diff --git a/libjava/classpath/gnu/java/nio/KqueueSelectorImpl.java b/libjava/classpath/gnu/java/nio/KqueueSelectorImpl.java new file mode 100644 index 000000000..e696c0d72 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/KqueueSelectorImpl.java @@ -0,0 +1,527 @@ +/* KqueueSelectorImpl.java -- Selector for systems with kqueue event notification. + 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.nio; + + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.channels.ClosedSelectorException; +import java.nio.channels.SelectableChannel; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.spi.AbstractSelectableChannel; +import java.nio.channels.spi.AbstractSelector; +import java.nio.channels.spi.SelectorProvider; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +/** + * A {@link Selector} implementation that uses the kqueue + * event notification facility. + * + * @author Casey Marshall (csm@gnu.org) + */ +public class KqueueSelectorImpl extends AbstractSelector +{ + // Prepended underscore to field name to make it distinct + // from the method with the similar name. + private static final int _sizeof_struct_kevent; + + private static final int MAX_DOUBLING_CAPACITY = 16384; + private static final int CAP_INCREMENT = 1024; + private static final int INITIAL_CAPACITY; + + static + { + try + { + System.loadLibrary("javanio"); + } + catch (Exception x) + { + x.printStackTrace(); + } + + if (kqueue_supported ()) + _sizeof_struct_kevent = sizeof_struct_kevent(); + else + _sizeof_struct_kevent = -1; + INITIAL_CAPACITY = 16 * _sizeof_struct_kevent; + } + + /** + * Tell if kqueue-based selectors are supported on this system. + * + * @return True if this system has kqueue support, and support for it was + * compiled in to Classpath. + */ + public static native boolean kqueue_supported(); + + /* Our native file descriptor. */ + private int kq; + + private HashMap/**/ keys; + private HashSet/**/ selected; + private Thread blockedThread; + private ByteBuffer events; + + private static final int OP_ACCEPT = SelectionKey.OP_ACCEPT; + private static final int OP_CONNECT = SelectionKey.OP_CONNECT; + private static final int OP_READ = SelectionKey.OP_READ; + private static final int OP_WRITE = SelectionKey.OP_WRITE; + + public KqueueSelectorImpl(SelectorProvider provider) throws IOException + { + super(provider); + kq = implOpen(); + keys = new HashMap/**/(); + events = ByteBuffer.allocateDirect(INITIAL_CAPACITY); + } + + protected void implCloseSelector() throws IOException + { + implClose(kq); + kq = -1; + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#keys() + */ + public Set keys() + { + if (!isOpen()) + throw new ClosedSelectorException(); + + return new HashSet(keys.values()); + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#select() + */ + public int select() throws IOException + { + return doSelect(-1); + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#select(long) + */ + public int select(long timeout) throws IOException + { + if (timeout == 0) + timeout = -1; + return doSelect(timeout); + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#selectedKeys() + */ + public Set selectedKeys() + { + if (!isOpen()) + throw new ClosedSelectorException(); + + return selected; + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#selectNow() + */ + public int selectNow() throws IOException + { + return doSelect(0); + } + + /* (non-Javadoc) + * @see java.nio.channels.Selector#wakeup() + */ + public Selector wakeup() + { + if (blockedThread != null) + blockedThread.interrupt(); + return this; + } + + public String toString() + { + return super.toString() + " [ fd: " + kq + " ]"; + } + + public boolean equals(Object o) + { + if (!(o instanceof KqueueSelectorImpl)) + return false; + + return ((KqueueSelectorImpl) o).kq == kq; + } + + int doSelect(long timeout) throws IOException + { + Set cancelled = cancelledKeys(); + synchronized (cancelled) + { + synchronized (keys) + { + for (Iterator it = cancelled.iterator(); it.hasNext(); ) + { + KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) it.next(); + key.interestOps = 0; + } + + int events_size = (2 * _sizeof_struct_kevent) * keys.size(); + int num_events = 0; + + for (Iterator it = keys.entrySet().iterator(); it.hasNext(); ) + { + Map.Entry e = (Map.Entry) it.next(); + KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) e.getValue(); + + SelectableChannel ch = key.channel(); + if (ch instanceof VMChannelOwner) + { + if (!((VMChannelOwner) ch).getVMChannel().getState().isValid()) + { + // closed channel; removed from kqueue automatically. + it.remove(); + continue; + } + } + + // If this key is registering a read filter, add it to the buffer. + if (key.needCommitRead()) + { + kevent_set(events, num_events, key.fd, + key.interestOps & (OP_READ | OP_ACCEPT), + key.activeOps & (OP_READ | OP_ACCEPT), key.key); + num_events++; + } + + // If this key is registering a write filter, add it to the buffer. + if (key.needCommitWrite()) + { + kevent_set(events, num_events, key.fd, + key.interestOps & (OP_WRITE | OP_CONNECT), + key.activeOps & (OP_WRITE | OP_CONNECT), key.key); + num_events++; + } + } + events.rewind().limit(events.capacity()); + + //System.out.println("dump of keys to select:"); + //dump_selection_keys(events.duplicate()); + + int n = 0; + try + { + //System.out.println("[" + kq + "] kevent enter selecting from " + keys.size()); + begin(); + blockedThread = Thread.currentThread(); + if (blockedThread.isInterrupted()) + timeout = 0; + n = kevent(kq, events, num_events, + events.capacity() / _sizeof_struct_kevent, timeout); + } + finally + { + end(); + blockedThread = null; + Thread.interrupted(); + //System.out.println("[" + kq + "kevent exit selected " + n); + } + + //System.out.println("dump of keys selected:"); + //dump_selection_keys((ByteBuffer) events.duplicate().limit(n * _sizeof_struct_kevent)); + + // Commit the operations we've just added in the call to kevent. + for (Iterator it = keys.values().iterator(); it.hasNext(); ) + { + KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) it.next(); + key.activeOps = key.interestOps; + } + + selected = new HashSet/**/(n); + int x = 0; + for (int i = 0; i < n; i++) + { + events.position(x).limit(x + _sizeof_struct_kevent); + x += _sizeof_struct_kevent; + int y = fetch_key(events.slice()); + KqueueSelectionKeyImpl key = + (KqueueSelectionKeyImpl) keys.get(new Integer(y)); + + if (key == null) + { + System.out.println("WARNING! no key found for selected key " + y); + continue; + } + // Keys that have been cancelled may be returned here; don't + // add them to the selected set. + if (!key.isValid()) + continue; + key.readyOps = ready_ops(events.slice(), key.interestOps); + selected.add(key); + } + + // Finally, remove the cancelled keys. + for (Iterator it = cancelled.iterator(); it.hasNext(); ) + { + KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) it.next(); + keys.remove(new Integer(key.key)); + deregister(key); + it.remove(); + } + + reallocateBuffer(); + + return selected.size(); + } + } + } + + protected SelectionKey register(AbstractSelectableChannel channel, + int interestOps, + Object attachment) + { + int native_fd = -1; + try + { + if (channel instanceof VMChannelOwner) + native_fd = ((VMChannelOwner) channel).getVMChannel() + .getState().getNativeFD(); + else + throw new IllegalArgumentException("cannot handle channel type " + + channel.getClass().getName()); + } + catch (IOException ioe) + { + throw new IllegalArgumentException("channel is closed or invalid"); + } + + KqueueSelectionKeyImpl result = new KqueueSelectionKeyImpl(this, channel); + result.interestOps = interestOps; + result.attach(attachment); + result.fd = native_fd; + result.key = System.identityHashCode(result); + synchronized (keys) + { + while (keys.containsKey(new Integer(result.key))) + result.key++; + keys.put(new Integer(result.key), result); + reallocateBuffer(); + } + return result; + } + + void setInterestOps(KqueueSelectionKeyImpl key, int ops) + { + synchronized (keys) + { + key.interestOps = ops; + } + } + + /** + * Reallocate the events buffer. This is the destination buffer for + * events returned by kevent. This method will: + * + * * Grow the buffer if there is insufficent space for all registered + * events. + * * Shrink the buffer if it is more than twice the size needed. + * + */ + private void reallocateBuffer() + { + synchronized (keys) + { + if (events.capacity() < (2 * _sizeof_struct_kevent) * keys.size()) + { + int cap = events.capacity(); + if (cap >= MAX_DOUBLING_CAPACITY) + cap += CAP_INCREMENT; + else + cap = cap << 1; + + events = ByteBuffer.allocateDirect(cap); + } + else if (events.capacity() > 4 * (_sizeof_struct_kevent) * keys.size() + 1 + && events.capacity() > INITIAL_CAPACITY) + { + int cap = events.capacity(); + cap = cap >>> 1; + events = ByteBuffer.allocateDirect(cap); + } + } + } + + //synchronized void updateOps(KqueueSelectionKeyImpl key, int interestOps) + //{ + // updateOps(key, interestOps, 0, false); + //} + + /*void updateOps(KqueueSelectionKeyImpl key, int interestOps, + int activeOps, int fd) + { + //System.out.println(">> updating kqueue selection key:"); + //dump_selection_keys(key.nstate.duplicate()); + //System.out.println("<<"); + synchronized (keys) + { + kevent_set(key.nstate, fd, interestOps, activeOps, key.key); + } + //System.out.println(">> updated kqueue selection key:"); + //dump_selection_keys(key.nstate.duplicate()); + //System.out.println("<<"); + }*/ + + private void dump_selection_keys(ByteBuffer keys) + { + // WARNING! This method is not guaranteed to be portable! This works + // on darwin/x86, but the sizeof and offsetof these fields may be + // different on other platforms! + int i = 0; + keys.order(ByteOrder.nativeOrder()); + while (keys.hasRemaining()) + { + System.out.println("struct kevent { ident: " + + Integer.toString(keys.getInt()) + + " filter: " + + Integer.toHexString(keys.getShort() & 0xFFFF) + + " flags: " + + Integer.toHexString(keys.getShort() & 0xFFFF) + + " fflags: " + + Integer.toHexString(keys.getInt()) + + " data: " + + Integer.toHexString(keys.getInt()) + + " udata: " + + Integer.toHexString(keys.getInt()) + + " }"); + } + } + + /** + * Return the size of a struct kevent on this system. + * + * @return The size of struct kevent. + */ + private static native int sizeof_struct_kevent(); + + /** + * Opens a kqueue descriptor. + * + * @return The new kqueue descriptor. + * @throws IOException If opening fails. + */ + private static native int implOpen() throws IOException; + + /** + * Closes the kqueue file descriptor. + * + * @param kq The kqueue file descriptor. + * @throws IOException + */ + private static native void implClose(int kq) throws IOException; + + /** + * Initialize the specified native state for the given interest ops. + * + * @param nstate The native state structures; in this buffer should be + * the struct kevents created for a key. + * @param fd The file descriptor. If 0, the native FD is unmodified. + * @param interestOps The operations to enable. + * @param key A unique key that will reference the associated key later. + * @param delete Set to true if this event should be deleted from the + * kqueue (if false, this event is added/updated). + */ + private static native void kevent_set(ByteBuffer nstate, int i, int fd, + int interestOps, int activeOps, int key); + + /** + * Poll for events. The source events are stored in events, + * which is also where polled events will be placed. + * + * @param events The events to poll. This buffer is also the destination + * for events read from the queue. + * @param nevents The number of events to poll (that is, the number of + * events in the events buffer). + * @param nout The maximum number of events that may be returned. + * @param timeout The timeout. A timeout of -1 returns immediately; a timeout + * of 0 waits indefinitely. + * @return The number of events read. + */ + private static native int kevent(int kq, ByteBuffer events, int nevents, + int nout, long timeout); + + /** + * Fetch a polled key from a native state buffer. For each kevent key we + * create, we put the native state info (one or more struct + * kevents) in that key's {@link KqueueSelectionKeyImpl#nstate} + * buffer, and place the pointer of the key in the udata field + * of that structure. This method fetches that pointer from the given + * buffer (assumed to be a struct kqueue) and returns it. + * + * @param nstate The buffer containing the struct kqueue to read. + * @return The key object. + */ + private static native int fetch_key(ByteBuffer nstate); + + /** + * Fetch the ready ops of the associated native state. That is, this + * inspects the first argument as a struct kevent, looking + * at its operation (the input is assumed to have been returned via a + * previous call to kevent), and translating that to the + * appropriate Java bit set, based on the second argument. + * + * @param nstate The native state. + * @param interestOps The enabled operations for the key. + * @return The bit set representing the ready operations. + */ + private static native int ready_ops(ByteBuffer nstate, int interestOps); + + /** + * Check if kevent returned EV_EOF for a selection key. + * + * @param nstate The native state. + * @return True if the kevent call returned EOF. + */ + private static native boolean check_eof(ByteBuffer nstate); +} diff --git a/libjava/classpath/gnu/java/nio/NIOConstants.java b/libjava/classpath/gnu/java/nio/NIOConstants.java new file mode 100644 index 000000000..bb5b3b7f9 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/NIOConstants.java @@ -0,0 +1,47 @@ +/* NIOConstants.java -- + Copyright (C) 2003 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.nio; + +/** + * @author Michael Koch + */ +public final class NIOConstants +{ + public static final int DEFAULT_TIMEOUT = 50; +} diff --git a/libjava/classpath/gnu/java/nio/NIODatagramSocket.java b/libjava/classpath/gnu/java/nio/NIODatagramSocket.java new file mode 100644 index 000000000..b0c7b2dc2 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/NIODatagramSocket.java @@ -0,0 +1,71 @@ +/* NIODatagramSocket.java -- + Copyright (C) 2003 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.nio; + +import gnu.java.net.PlainDatagramSocketImpl; + +import java.net.DatagramSocket; +import java.nio.channels.DatagramChannel; + +/** + * @author Michael Koch + */ +public final class NIODatagramSocket extends DatagramSocket +{ + private PlainDatagramSocketImpl impl; + private DatagramChannelImpl channel; + + public NIODatagramSocket (PlainDatagramSocketImpl impl, + DatagramChannelImpl channel) + { + super (impl); + this.impl = impl; + this.channel = channel; + } + + public final PlainDatagramSocketImpl getPlainDatagramSocketImpl() + { + return impl; + } + + public final DatagramChannel getChannel() + { + return channel; + } +} diff --git a/libjava/classpath/gnu/java/nio/NIOServerSocket.java b/libjava/classpath/gnu/java/nio/NIOServerSocket.java new file mode 100644 index 000000000..5dbda6b00 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/NIOServerSocket.java @@ -0,0 +1,106 @@ +/* NIOServerSocket.java -- + Copyright (C) 2003, 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.nio; + +import gnu.java.net.PlainSocketImpl; + +import java.io.IOException; +import java.lang.reflect.Method; +import java.net.ServerSocket; +import java.net.Socket; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import java.security.AccessController; +import java.security.PrivilegedExceptionAction; + +/** + * @author Michael Koch (konqueror@gmx.de) + */ +public final class NIOServerSocket extends ServerSocket +{ + private ServerSocketChannelImpl channel; + + protected NIOServerSocket (ServerSocketChannelImpl channel) + throws IOException + { + super(); + this.channel = channel; + } + + public PlainSocketImpl getPlainSocketImpl() + { + try + { + final Object t = this; + final Method method = ServerSocket.class.getDeclaredMethod("getImpl", new Class[0]); + method.setAccessible(true); + PrivilegedExceptionAction action = new PrivilegedExceptionAction() + { + public Object run() throws Exception + { + return method.invoke(t, new Object[0]); + } + }; + return (PlainSocketImpl) AccessController.doPrivileged(action); + } + catch (Exception e) + { + // This should never happen. + Error error = new InternalError("unable to invoke method ServerSocket.getImpl()"); + error.initCause(e); + throw error; + } + } + + public ServerSocketChannel getChannel() + { + return channel; + } + + public Socket accept() throws IOException + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkListen (getLocalPort()); + + SocketChannel socketChannel = channel.provider().openSocketChannel(); + implAccept (socketChannel.socket()); + return socketChannel.socket(); + } +} diff --git a/libjava/classpath/gnu/java/nio/NIOSocket.java b/libjava/classpath/gnu/java/nio/NIOSocket.java new file mode 100644 index 000000000..a421e019a --- /dev/null +++ b/libjava/classpath/gnu/java/nio/NIOSocket.java @@ -0,0 +1,79 @@ +/* NIOSocket.java -- + Copyright (C) 2003 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.nio; + +import java.io.IOException; +import java.net.Socket; +import java.nio.channels.SocketChannel; + +/** + * @author Michael Koch + */ +public final class NIOSocket extends Socket +{ + private SocketChannelImpl channel; + + protected NIOSocket (SocketChannelImpl channel) + throws IOException + { + super (new NIOSocketImpl(channel)); + this.channel = channel; + } + + //public final PlainSocketImpl getPlainSocketImpl() + //{ + // return impl; + //} + + //final void setChannel (SocketChannelImpl channel) + //{ + // this.impl = channel.getPlainSocketImpl(); + // this.channel = channel; + //} + + public final SocketChannel getChannel() + { + return channel; + } + + public boolean isConnected() + { + return channel.isConnected(); + } +} diff --git a/libjava/classpath/gnu/java/nio/NIOSocketImpl.java b/libjava/classpath/gnu/java/nio/NIOSocketImpl.java new file mode 100644 index 000000000..15cc07dc8 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/NIOSocketImpl.java @@ -0,0 +1,110 @@ +/* NIOSocketImpl.java -- subclass of PlainSocketImpl for NIO. + 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.nio; + +import gnu.java.net.PlainSocketImpl; + +import java.io.IOException; +import java.net.InetAddress; + +/** + * @author Casey Marshall (csm@gnu.org) + */ +public class NIOSocketImpl extends PlainSocketImpl +{ + + private final SocketChannelImpl channel; + + NIOSocketImpl(SocketChannelImpl channel) throws IOException + { + this.channel = channel; + impl.getState().setChannelFD(channel.getVMChannel().getState()); + } + + /* (non-Javadoc) + * @see java.net.SocketImpl#getInetAddress() + */ + //@Override + protected InetAddress getInetAddress() + { + try + { + return channel.getVMChannel().getPeerAddress().getAddress(); + } + catch (IOException ioe) + { + return null; + } + catch (NullPointerException npe) + { + // Socket is not connected yet. + return null; + } + } + + /* (non-Javadoc) + * @see java.net.SocketImpl#getPort() + */ + //@Override + protected int getPort() + { + try + { + return channel.getVMChannel().getPeerAddress().getPort(); + } + catch (IOException ioe) + { + return -1; + } + catch (NullPointerException npe) + { + // Socket is not connected yet. + return -1; + } + } + + /* (non-Javadoc) + * @see gnu.java.net.PlainSocketImpl#create(boolean) + */ + //@Override + protected synchronized void create(boolean stream) + { + // Ignored; the socket has already been created. + } +} diff --git a/libjava/classpath/gnu/java/nio/OutputStreamChannel.java b/libjava/classpath/gnu/java/nio/OutputStreamChannel.java new file mode 100644 index 000000000..ac2e7888d --- /dev/null +++ b/libjava/classpath/gnu/java/nio/OutputStreamChannel.java @@ -0,0 +1,87 @@ +/* OutputStreamChannel.java -- + Copyright (C) 2003 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.nio; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.WritableByteChannel; + +/** + * @author Michael Koch + */ +public final class OutputStreamChannel implements WritableByteChannel +{ + private boolean closed = false; + private OutputStream out; + + public OutputStreamChannel (OutputStream out) + { + super(); + + this.out = out; + } + + public void close() throws IOException + { + if (!closed) + { + out.close(); + closed = true; + } + } + + public boolean isOpen() + { + return !closed; + } + + public int write (ByteBuffer src) throws IOException + { + if (!isOpen()) + throw new ClosedChannelException(); + + int len = src.remaining(); + byte[] buffer = new byte [len]; + src.get (buffer); + out.write (buffer); + return len; + } +} diff --git a/libjava/classpath/gnu/java/nio/PipeImpl.java b/libjava/classpath/gnu/java/nio/PipeImpl.java new file mode 100644 index 000000000..143af1a24 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/PipeImpl.java @@ -0,0 +1,178 @@ +/* PipeImpl.java -- + Copyright (C) 2002, 2003, 2004, 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.java.nio; + + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.Pipe; +import java.nio.channels.spi.SelectorProvider; + +class PipeImpl extends Pipe +{ + public static final class SourceChannelImpl extends Pipe.SourceChannel + implements VMChannelOwner + { + private VMChannel vmch; + + public SourceChannelImpl (SelectorProvider selectorProvider, + VMChannel channel) + { + super (selectorProvider); + vmch = channel; + } + + protected final void implCloseSelectableChannel() + throws IOException + { + vmch.close(); + } + + protected void implConfigureBlocking (boolean blocking) + throws IOException + { + vmch.setBlocking(blocking); + } + + public final int read (ByteBuffer src) + throws IOException + { + return vmch.read(src); + } + + public final long read (ByteBuffer[] srcs) + throws IOException + { + return vmch.readScattering(srcs, 0, srcs.length); + } + + public final synchronized long read (ByteBuffer[] srcs, int offset, + int len) + throws IOException + { + if (offset < 0 + || offset > srcs.length + || len < 0 + || len > srcs.length - offset) + throw new IndexOutOfBoundsException(); + + return vmch.readScattering(srcs, offset, len); + } + + public VMChannel getVMChannel() + { + return vmch; + } + } + + public static final class SinkChannelImpl extends Pipe.SinkChannel + implements VMChannelOwner + { + private VMChannel vmch; + + public SinkChannelImpl (SelectorProvider selectorProvider, + VMChannel channel) + { + super (selectorProvider); + vmch = channel; + } + + protected final void implCloseSelectableChannel() + throws IOException + { + vmch.close(); + } + + protected final void implConfigureBlocking (boolean blocking) + throws IOException + { + vmch.setBlocking(blocking); + } + + public final int write (ByteBuffer dst) + throws IOException + { + return vmch.write(dst); + } + + public final long write (ByteBuffer[] srcs) + throws IOException + { + return vmch.writeGathering(srcs, 0, srcs.length); + } + + public final synchronized long write (ByteBuffer[] srcs, int offset, int len) + throws IOException + { + if (offset < 0 + || offset > srcs.length + || len < 0 + || len > srcs.length - offset) + throw new IndexOutOfBoundsException(); + + return vmch.writeGathering(srcs, offset, len); + } + + public VMChannel getVMChannel() + { + return vmch; + } + } + + private SinkChannelImpl sink; + private SourceChannelImpl source; + + public PipeImpl (SelectorProvider provider) + throws IOException + { + super(); + VMChannel[] pipe = VMPipe.pipe(); + sink = new SinkChannelImpl(provider, pipe[0]); + source = new SourceChannelImpl(provider, pipe[1]); + } + + public Pipe.SinkChannel sink() + { + return sink; + } + + public Pipe.SourceChannel source() + { + return source; + } +} diff --git a/libjava/classpath/gnu/java/nio/SelectionKeyImpl.java b/libjava/classpath/gnu/java/nio/SelectionKeyImpl.java new file mode 100644 index 000000000..a26ff8726 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/SelectionKeyImpl.java @@ -0,0 +1,111 @@ +/* SelectionKeyImpl.java -- + Copyright (C) 2002, 2003, 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.nio; + +import java.nio.channels.CancelledKeyException; +import java.nio.channels.SelectableChannel; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.spi.AbstractSelectionKey; + +public abstract class SelectionKeyImpl extends AbstractSelectionKey +{ + private int readyOps; + private int interestOps; + private final SelectorImpl impl; + final SelectableChannel ch; + + public SelectionKeyImpl (SelectableChannel ch, SelectorImpl impl) + { + this.ch = ch; + this.impl = impl; + } + + public SelectableChannel channel () + { + return ch; + } + + public synchronized int readyOps () + { + if (!isValid()) + throw new CancelledKeyException(); + + return readyOps; + } + + public synchronized SelectionKey readyOps (int ops) + { + if (!isValid()) + throw new CancelledKeyException(); + + readyOps = ops; + return this; + } + + public int interestOps () + { + if (!isValid()) + throw new CancelledKeyException(); + + synchronized (impl.selectedKeys()) + { + return interestOps; + } + } + + public SelectionKey interestOps (int ops) + { + if (!isValid()) + throw new CancelledKeyException(); + + synchronized (impl.selectedKeys()) + { + interestOps = ops; + } + return this; + } + + public Selector selector () + { + return impl; + } + + /* @deprecated */ + public abstract int getNativeFD(); +} diff --git a/libjava/classpath/gnu/java/nio/SelectorImpl.java b/libjava/classpath/gnu/java/nio/SelectorImpl.java new file mode 100644 index 000000000..21238f20f --- /dev/null +++ b/libjava/classpath/gnu/java/nio/SelectorImpl.java @@ -0,0 +1,397 @@ +/* SelectorImpl.java -- + Copyright (C) 2002, 2003, 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.nio; + +import java.io.IOException; +import java.nio.channels.ClosedSelectorException; +import java.nio.channels.SelectableChannel; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.SocketChannel; +import java.nio.channels.spi.AbstractSelectableChannel; +import java.nio.channels.spi.AbstractSelector; +import java.nio.channels.spi.SelectorProvider; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +public class SelectorImpl extends AbstractSelector +{ + private Set keys; + private Set selected; + + /** + * A dummy object whose monitor regulates access to both our + * selectThread and unhandledWakeup fields. + */ + private Object selectThreadMutex = new Object (); + + /** + * Any thread that's currently blocked in a select operation. + */ + private Thread selectThread; + + /** + * Indicates whether we have an unhandled wakeup call. This can + * be due to either wakeup() triggering a thread interruption while + * a thread was blocked in a select operation (in which case we need + * to reset this thread's interrupt status after interrupting the + * select), or else that no thread was on a select operation at the + * time that wakeup() was called, in which case the following select() + * operation should return immediately with nothing selected. + */ + private boolean unhandledWakeup; + + public SelectorImpl (SelectorProvider provider) + { + super (provider); + + keys = new HashSet (); + selected = new HashSet (); + } + + protected void finalize() throws Throwable + { + close(); + } + + protected final void implCloseSelector() + throws IOException + { + // Cancel any pending select operation. + wakeup(); + + synchronized (keys) + { + synchronized (selected) + { + synchronized (cancelledKeys ()) + { + // FIXME: Release resources here. + } + } + } + } + + public final Set keys() + { + if (!isOpen()) + throw new ClosedSelectorException(); + + return Collections.unmodifiableSet (keys); + } + + public final int selectNow() + throws IOException + { + // FIXME: We're simulating an immediate select + // via a select with a timeout of one millisecond. + return select (1); + } + + public final int select() + throws IOException + { + return select (0); + } + + private final int[] getFDsAsArray (int ops) + { + int[] result; + int counter = 0; + Iterator it = keys.iterator (); + + // Count the number of file descriptors needed + while (it.hasNext ()) + { + SelectionKeyImpl key = (SelectionKeyImpl) it.next (); + + if ((key.interestOps () & ops) != 0) + { + counter++; + } + } + + result = new int[counter]; + + counter = 0; + it = keys.iterator (); + + // Fill the array with the file descriptors + while (it.hasNext ()) + { + SelectionKeyImpl key = (SelectionKeyImpl) it.next (); + + if ((key.interestOps () & ops) != 0) + { + result[counter] = key.getNativeFD(); + counter++; + } + } + + return result; + } + + public synchronized int select (long timeout) + throws IOException + { + if (!isOpen()) + throw new ClosedSelectorException(); + + synchronized (keys) + { + synchronized (selected) + { + deregisterCancelledKeys(); + + // Set only keys with the needed interest ops into the arrays. + int[] read = getFDsAsArray (SelectionKey.OP_READ + | SelectionKey.OP_ACCEPT); + int[] write = getFDsAsArray (SelectionKey.OP_WRITE + | SelectionKey.OP_CONNECT); + + // FIXME: We dont need to check this yet + int[] except = new int [0]; + + // Test to see if we've got an unhandled wakeup call, + // in which case we return immediately. Otherwise, + // remember our current thread and jump into the select. + // The monitor for dummy object selectThreadMutex regulates + // access to these fields. + + // FIXME: Not sure from the spec at what point we should + // return "immediately". Is it here or immediately upon + // entry to this function? + + // NOTE: There's a possibility of another thread calling + // wakeup() immediately after our thread releases + // selectThreadMutex's monitor here, in which case we'll + // do the select anyway. Since calls to wakeup() and select() + // among different threads happen in non-deterministic order, + // I don't think this is an issue. + synchronized (selectThreadMutex) + { + if (unhandledWakeup) + { + unhandledWakeup = false; + return 0; + } + else + { + selectThread = Thread.currentThread (); + } + } + + // Call the native select() on all file descriptors. + int result = 0; + try + { + begin(); + result = VMSelector.select (read, write, except, timeout); + } + finally + { + end(); + } + + // If our unhandled wakeup flag is set at this point, + // reset our thread's interrupt flag because we were + // awakened by wakeup() instead of an external thread + // interruption. + // + // NOTE: If we were blocked in a select() and one thread + // called Thread.interrupt() on the blocked thread followed + // by another thread calling Selector.wakeup(), then race + // conditions could make it so that the thread's interrupt + // flag is reset even though the Thread.interrupt() call + // "was there first". I don't think we need to care about + // this scenario. + synchronized (selectThreadMutex) + { + if (unhandledWakeup) + { + unhandledWakeup = false; + Thread.interrupted (); + } + selectThread = null; + } + + Iterator it = keys.iterator (); + + while (it.hasNext ()) + { + int ops = 0; + SelectionKeyImpl key = (SelectionKeyImpl) it.next (); + + // If key is already selected retrieve old ready ops. + if (selected.contains (key)) + { + ops = key.readyOps (); + } + + // Set new ready read/accept ops + for (int i = 0; i < read.length; i++) + { + if (key.getNativeFD() == read[i]) + { + if (key.channel () instanceof ServerSocketChannelImpl) + { + ops = ops | SelectionKey.OP_ACCEPT; + } + else + { + ops = ops | SelectionKey.OP_READ; + } + } + } + + // Set new ready write ops + for (int i = 0; i < write.length; i++) + { + if (key.getNativeFD() == write[i]) + { + if (key.channel() instanceof SocketChannel) + { + if (((SocketChannel) key.channel ()).isConnected ()) + ops = ops | SelectionKey.OP_WRITE; + else + ops = ops | SelectionKey.OP_CONNECT; + } + else + ops = ops | SelectionKey.OP_WRITE; + } + } + + // FIXME: We dont handle exceptional file descriptors yet. + + // If key is not yet selected add it. + if (!selected.contains (key)) + { + selected.add (key); + } + + // Set new ready ops + key.readyOps (key.interestOps () & ops); + } + deregisterCancelledKeys(); + + return result; + } + } + } + + public final Set selectedKeys() + { + if (!isOpen()) + throw new ClosedSelectorException(); + + return selected; + } + + public final Selector wakeup() + { + // IMPLEMENTATION NOTE: Whereas the specification says that + // thread interruption should trigger a call to wakeup, we + // do the reverse under the covers: wakeup triggers a thread + // interrupt followed by a subsequent reset of the thread's + // interrupt status within select(). + + // First, acquire the monitor of the object regulating + // access to our selectThread and unhandledWakeup fields. + synchronized (selectThreadMutex) + { + unhandledWakeup = true; + + // Interrupt any thread which is currently blocked in + // a select operation. + if (selectThread != null) + selectThread.interrupt (); + } + + return this; + } + + private final void deregisterCancelledKeys() + { + Set ckeys = cancelledKeys (); + synchronized (ckeys) + { + Iterator it = ckeys.iterator(); + + while (it.hasNext ()) + { + keys.remove ((SelectionKeyImpl) it.next ()); + it.remove (); + } + } + } + + protected SelectionKey register (SelectableChannel ch, int ops, Object att) + { + return register ((AbstractSelectableChannel) ch, ops, att); + } + + protected final SelectionKey register (AbstractSelectableChannel ch, int ops, + Object att) + { + SelectionKeyImpl result; + + if (ch instanceof SocketChannelImpl) + result = new SocketChannelSelectionKey (ch, this); + else if (ch instanceof DatagramChannelImpl) + result = new DatagramChannelSelectionKey (ch, this); + else if (ch instanceof ServerSocketChannelImpl) + result = new ServerSocketChannelSelectionKey (ch, this); + else if (ch instanceof gnu.java.nio.SocketChannelImpl) + result = new gnu.java.nio.SocketChannelSelectionKeyImpl((gnu.java.nio.SocketChannelImpl)ch, this); + else + throw new InternalError ("No known channel type"); + + synchronized (keys) + { + keys.add (result); + + result.interestOps (ops); + result.attach (att); + } + + return result; + } +} diff --git a/libjava/classpath/gnu/java/nio/SelectorProviderImpl.java b/libjava/classpath/gnu/java/nio/SelectorProviderImpl.java new file mode 100644 index 000000000..a205bbd61 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/SelectorProviderImpl.java @@ -0,0 +1,121 @@ +/* SelectorProviderImpl.java -- + Copyright (C) 2002, 2003 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.nio; + + +import gnu.classpath.SystemProperties; + +import java.io.IOException; +import java.nio.channels.DatagramChannel; +import java.nio.channels.Pipe; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import java.nio.channels.spi.AbstractSelector; +import java.nio.channels.spi.SelectorProvider; + +public class SelectorProviderImpl extends SelectorProvider +{ + private static final String SELECTOR_IMPL_KQUEUE = "kqueue"; + private static final String SELECTOR_IMPL_EPOLL = "epoll"; + private static final String SELECTOR_IMPL = "gnu.java.nio.selectorImpl"; + private static boolean epoll_failed = false; + + public SelectorProviderImpl () + { + } + + public DatagramChannel openDatagramChannel () + throws IOException + { + return new DatagramChannelImpl (this); + } + + public Pipe openPipe () + throws IOException + { + return new PipeImpl (this); + } + + public AbstractSelector openSelector () + throws IOException + { + String selectorImpl = "default"; + if (KqueueSelectorImpl.kqueue_supported()) + selectorImpl = SELECTOR_IMPL_KQUEUE; + if (EpollSelectorImpl.epoll_supported() && !epoll_failed) + selectorImpl = SELECTOR_IMPL_EPOLL; + selectorImpl = SystemProperties.getProperty(SELECTOR_IMPL, selectorImpl); + + if (selectorImpl.equals(SELECTOR_IMPL_KQUEUE)) + return new KqueueSelectorImpl(this); + + if (selectorImpl.equals(SELECTOR_IMPL_EPOLL)) + { + // We jump through these hoops because even though epoll may look + // like it's available (sys/epoll.h exists, and you can link against + // all the epoll functions) it may not be available in the kernel + // (especially 2.4 kernels), meaning you will get ENOSYS at run time. + // + // Madness! + try + { + return new EpollSelectorImpl(this); + } + catch (InternalError e) + { + // epoll_create throws this on ENOSYS. + epoll_failed = true; + } + } + + return new SelectorImpl (this); + } + + public ServerSocketChannel openServerSocketChannel () + throws IOException + { + return new ServerSocketChannelImpl (this); + } + + public SocketChannel openSocketChannel () + throws IOException + { + return new SocketChannelImpl (this); + } + +} diff --git a/libjava/classpath/gnu/java/nio/ServerSocketChannelImpl.java b/libjava/classpath/gnu/java/nio/ServerSocketChannelImpl.java new file mode 100644 index 000000000..567fc90c7 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/ServerSocketChannelImpl.java @@ -0,0 +1,128 @@ +/* ServerSocketChannelImpl.java -- + Copyright (C) 2002, 2003, 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.nio; + +import java.io.IOException; +import java.net.ServerSocket; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.NotYetBoundException; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import java.nio.channels.spi.SelectorProvider; + +public final class ServerSocketChannelImpl extends ServerSocketChannel + implements VMChannelOwner +{ + private VMChannel channel; + private NIOServerSocket serverSocket; + private boolean connected; + + protected ServerSocketChannelImpl (SelectorProvider provider) + throws IOException + { + super (provider); + serverSocket = new NIOServerSocket(this); + channel = serverSocket.getPlainSocketImpl().getVMChannel(); + configureBlocking(true); + } + + // XXX do we need this? + public void finalizer() + { + if (channel.getState().isValid()) + { + try + { + close (); + } + catch (Exception e) + { + } + } + } + + protected void implCloseSelectableChannel () throws IOException + { + connected = false; + channel.close(); + } + + protected void implConfigureBlocking (boolean blocking) throws IOException + { + channel.setBlocking(blocking); + } + + public SocketChannel accept () throws IOException + { + if (!isOpen()) + throw new ClosedChannelException(); + + if (!serverSocket.isBound()) + throw new NotYetBoundException(); + + boolean completed = false; + + try + { + begin(); + VMChannel client = channel.accept(); + if (client == null) + return null; + else + { + completed = true; + return new SocketChannelImpl(provider(), client, false); + } + } + finally + { + end (completed); + } + } + + public ServerSocket socket() + { + return serverSocket; + } + + public VMChannel getVMChannel() + { + return channel; + } +} diff --git a/libjava/classpath/gnu/java/nio/ServerSocketChannelSelectionKey.java b/libjava/classpath/gnu/java/nio/ServerSocketChannelSelectionKey.java new file mode 100644 index 000000000..a4b2891a2 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/ServerSocketChannelSelectionKey.java @@ -0,0 +1,65 @@ +/* ServerSocketChannelSelectionKey.java -- + Copyright (C) 2003 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.nio; + +import java.io.IOException; +import java.nio.channels.spi.AbstractSelectableChannel; + +public final class ServerSocketChannelSelectionKey + extends SelectionKeyImpl +{ + public ServerSocketChannelSelectionKey (AbstractSelectableChannel channel, + SelectorImpl selector) + { + super (channel, selector); + } + + // FIXME don't use file descriptor integers + public int getNativeFD() + { + try + { + return ((ServerSocketChannelImpl) ch).getVMChannel().getState().getNativeFD(); + } + catch (IOException ioe) + { + throw new IllegalStateException(ioe); + } + } +} diff --git a/libjava/classpath/gnu/java/nio/SocketChannelImpl.java b/libjava/classpath/gnu/java/nio/SocketChannelImpl.java new file mode 100644 index 000000000..0bb378c64 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/SocketChannelImpl.java @@ -0,0 +1,265 @@ +/* SocketChannelImpl.java -- + Copyright (C) 2002, 2003, 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.nio; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.AlreadyConnectedException; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.ConnectionPendingException; +import java.nio.channels.NoConnectionPendingException; +import java.nio.channels.NotYetConnectedException; +import java.nio.channels.SocketChannel; +import java.nio.channels.UnresolvedAddressException; +import java.nio.channels.UnsupportedAddressTypeException; +import java.nio.channels.spi.SelectorProvider; + +public final class SocketChannelImpl extends SocketChannel + implements VMChannelOwner +{ + private VMChannel channel; + //private PlainSocketImpl impl; + private NIOSocket socket; + private boolean connectionPending; + private boolean connected; + private InetSocketAddress connectAddress; + + public SocketChannelImpl(boolean create) throws IOException + { + // XXX consider adding security check; this is used by + // PlainSocketImpl. + this(new SelectorProviderImpl(), create); + } + + public SocketChannelImpl(VMChannel channel) throws IOException + { + this(new SelectorProviderImpl(), channel, false); + } + + SocketChannelImpl(SelectorProvider provider) throws IOException + { + this(provider, true); + } + + SocketChannelImpl(SelectorProvider provider, boolean create) + throws IOException + { + this(provider, new VMChannel(), create); + } + + SocketChannelImpl(SelectorProvider provider, VMChannel channel, boolean create) + throws IOException + { + super (provider); + this.channel = channel; + if (create) + channel.initSocket(true); + socket = new NIOSocket(this); + configureBlocking(true); + } + + /*SocketChannelImpl (SelectorProvider provider, + NIOSocket socket) + throws IOException + { + super (provider); + this.impl = socket.getPlainSocketImpl(); + this.socket = socket; + }*/ + + public void finalizer() + { + if (isConnected()) + { + try + { + close (); + } + catch (Exception e) + { + } + } + } + + //PlainSocketImpl getPlainSocketImpl() + //{ + // return null; // XXX + //} + + protected void implCloseSelectableChannel() throws IOException + { + channel.close(); + } + + protected void implConfigureBlocking (boolean blocking) throws IOException + { + channel.setBlocking(blocking); + } + + public boolean connect (SocketAddress remote) throws IOException + { + return connect(remote, 0); + } + + public boolean connect (SocketAddress remote, int timeout) throws IOException + { + if (!isOpen()) + throw new ClosedChannelException(); + + if (isConnected()) + throw new AlreadyConnectedException(); + + if (connectionPending) + throw new ConnectionPendingException(); + + if (!(remote instanceof InetSocketAddress)) + throw new UnsupportedAddressTypeException(); + + connectAddress = (InetSocketAddress) remote; + + if (connectAddress.isUnresolved()) + throw new UnresolvedAddressException(); + + connected = channel.connect(connectAddress, timeout); + connectionPending = !connected; + return connected; + } + + public boolean finishConnect() + throws IOException + { + if (!isOpen()) + throw new ClosedChannelException(); + + InetSocketAddress remote = channel.getPeerAddress(); + if (remote != null) + { + connectionPending = false; + return true; + } + + if (!connectionPending) + throw new NoConnectionPendingException(); + + return false; + } + + public boolean isConnected() + { + // Wait until finishConnect is called before transitioning to + // connected. + if (connectionPending) + return false; + try + { + InetSocketAddress remote = channel.getPeerAddress(); + return remote != null; + } + catch (IOException ioe) + { + ioe.printStackTrace(System.out); + return false; + } + } + + public boolean isConnectionPending () + { + return connectionPending; + } + + public Socket socket () + { + return socket; + } + + public int read(ByteBuffer dst) throws IOException + { + if (!isConnected()) + throw new NotYetConnectedException(); + + return channel.read(dst); + } + + public long read (ByteBuffer[] dsts, int offset, int length) + throws IOException + { + if (!isConnected()) + throw new NotYetConnectedException(); + + if ((offset < 0) + || (offset > dsts.length) + || (length < 0) + || (length > (dsts.length - offset))) + throw new IndexOutOfBoundsException(); + + return channel.readScattering(dsts, offset, length); + } + + public int write(ByteBuffer src) throws IOException + { + if (!isConnected()) + throw new NotYetConnectedException(); + + return channel.write(src); + } + + public long write(ByteBuffer[] srcs, int offset, int length) + throws IOException + { + if (!isConnected()) + throw new NotYetConnectedException(); + + if ((offset < 0) + || (offset > srcs.length) + || (length < 0) + || (length > (srcs.length - offset))) + throw new IndexOutOfBoundsException(); + + return channel.writeGathering(srcs, offset, length); + } + + public VMChannel getVMChannel() + { + // XXX security check? + return channel; + } +} diff --git a/libjava/classpath/gnu/java/nio/SocketChannelSelectionKey.java b/libjava/classpath/gnu/java/nio/SocketChannelSelectionKey.java new file mode 100644 index 000000000..100368995 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/SocketChannelSelectionKey.java @@ -0,0 +1,65 @@ +/* SocketChannelSelectionKey.java -- + Copyright (C) 2003 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.nio; + +import java.io.IOException; +import java.nio.channels.spi.AbstractSelectableChannel; + +public final class SocketChannelSelectionKey + extends SelectionKeyImpl +{ + public SocketChannelSelectionKey (AbstractSelectableChannel channel, + SelectorImpl selector) + { + super (channel, selector); + } + + // FIXME don't use file descriptor integers + public int getNativeFD() + { + try + { + return ((SocketChannelImpl) ch).getVMChannel().getState().getNativeFD(); + } + catch (IOException ioe) + { + throw new IllegalStateException(ioe); + } + } +} diff --git a/libjava/classpath/gnu/java/nio/SocketChannelSelectionKeyImpl.java b/libjava/classpath/gnu/java/nio/SocketChannelSelectionKeyImpl.java new file mode 100644 index 000000000..786aa361e --- /dev/null +++ b/libjava/classpath/gnu/java/nio/SocketChannelSelectionKeyImpl.java @@ -0,0 +1,78 @@ +/* SocketChannelSelectionKey.java -- Selection key for Socket Channel + 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.java.nio; + +import java.io.IOException; + + +/** + * @author Michael Barker + * + */ +public class SocketChannelSelectionKeyImpl extends SelectionKeyImpl +{ + + SocketChannelImpl ch; + + /** + * @param ch + * @param impl + */ + public SocketChannelSelectionKeyImpl(SocketChannelImpl ch, SelectorImpl impl) + { + super(ch, impl); + this.ch = ch; + } + + /** + * Returns the native file/socket descriptor as an int. + */ + public int getNativeFD() + { + try + { + return ch.getVMChannel().getState().getNativeFD(); + } + catch (IOException ioe) + { + return 0; // FIXME + } + } + +} diff --git a/libjava/classpath/gnu/java/nio/VMChannelOwner.java b/libjava/classpath/gnu/java/nio/VMChannelOwner.java new file mode 100644 index 000000000..87cbc1e94 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/VMChannelOwner.java @@ -0,0 +1,57 @@ +/* NativeFD.java -- interface for Channels that have an underlying file descriptor. + 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.nio; + +/** + * This interface is meant to be implemented by any {@link Channel} + * implementation we support that uses a platform-specific {@link VMChannel} + * at their core. This is primarily used by {@link Selector} implementations, + * for easier access to the native state. + * + * @author Casey Marshall (csm@gnu.org) + */ +interface VMChannelOwner +{ + /** + * Return the underlying platform-specific Channel instance. + * + * @return The platform channel object. + */ + VMChannel getVMChannel(); +} diff --git a/libjava/classpath/gnu/java/nio/channels/package.html b/libjava/classpath/gnu/java/nio/channels/package.html new file mode 100644 index 000000000..0c3821bea --- /dev/null +++ b/libjava/classpath/gnu/java/nio/channels/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.nio.channels + + +

+ + + diff --git a/libjava/classpath/gnu/java/nio/charset/ByteCharset.java b/libjava/classpath/gnu/java/nio/charset/ByteCharset.java new file mode 100644 index 000000000..60d06fc4b --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/ByteCharset.java @@ -0,0 +1,193 @@ +/* ByteCharset.java -- Abstract class for generic 1-byte encodings. + 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.java.nio.charset; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CoderResult; + +/** + * A generic encoding framework for single-byte encodings, utilizing a look-up + * table. + * + * This replaces the gnu.java.io.EncoderEightBitLookup class, created by Aron + * Renn. + * + * @author Sven de Marothy + * @modified Ian Rogers + */ +abstract class ByteCharset extends Charset +{ + protected final char[] lookupTable; + /** + * Char to signify the character in the table is undefined + */ + protected static final char NONE = (char) 0xFFFD; + + ByteCharset(String canonicalName, String[] aliases, char[] lookup) + { + super(canonicalName, aliases); + lookupTable = lookup; + } + + /** + * Most western charsets include ASCII, but this should be overloaded for + * others. + */ + public boolean contains(Charset cs) + { + return cs instanceof US_ASCII || (cs.getClass() == getClass()); + } + + char[] getLookupTable() + { + return lookupTable; + } + + public CharsetDecoder newDecoder() + { + return new Decoder(this); + } + + public CharsetEncoder newEncoder() + { + return new Encoder(this); + } + + private static final class Decoder extends CharsetDecoder + { + /** Lookup of byte to char mappings */ + private final char[] lookup; + + /** Helper to decode loops */ + private final ByteDecodeLoopHelper helper = new ByteDecodeLoopHelper() + { + protected boolean isMappable(byte b) + { + return lookup[(int) (b & 0xFF)] != NONE; + } + protected char mapToChar(byte b) + { + return lookup[(int) (b & 0xFF)]; + } + }; + + // Package-private to avoid a trampoline constructor. + Decoder(ByteCharset cs) + { + super(cs, 1.0f, 1.0f); + lookup = cs.getLookupTable(); + } + + protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) + { + return helper.decodeLoop(in, out); + } + } + + private static final class Encoder extends CharsetEncoder + { + /** Lookup of char to byte mappings */ + private final byte[] lookup; + + /** Helper to encode loops */ + private final ByteEncodeLoopHelper helper = new ByteEncodeLoopHelper() + { + protected boolean isMappable(char c) + { + return canEncode(c); + } + protected byte mapToByte(char c) + { + return lookup[c]; + } + }; + + // Package-private to avoid a trampoline constructor. + Encoder(ByteCharset cs) + { + super(cs, 1.0f, 1.0f); + + char[] lookup_table = cs.getLookupTable(); + + // Create the inverse look-up table. + // determine required size of encoding_table: + int max = 0; + for (int i = 0; i < lookup_table.length; i++) + { + int c = (int) lookup_table[i]; + max = (c > max && c < NONE) ? c : max; + } + + lookup = new byte[max + 1]; + + for (int i = 0; i < lookup_table.length; i++) + { + int c = (int) lookup_table[i]; + if (c != 0 && c < NONE) + { + lookup[c] = (byte) i; + } + } + } + + public boolean canEncode(char c) + { + byte b = (c < lookup.length) ? lookup[c] : 0; + return b != 0 || c == 0; + } + + public boolean canEncode(CharSequence cs) + { + for (int i = 0; i < cs.length(); ++i) + { + if (!canEncode(cs.charAt(i))) + return false; + } + return true; + } + + protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) + { + return helper.encodeLoop(in, out); + } + } +} diff --git a/libjava/classpath/gnu/java/nio/charset/ByteDecodeLoopHelper.java b/libjava/classpath/gnu/java/nio/charset/ByteDecodeLoopHelper.java new file mode 100644 index 000000000..76dc20913 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/ByteDecodeLoopHelper.java @@ -0,0 +1,164 @@ +/* ByteCharset.java -- Abstract class for generic 1-byte encodings. + 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.java.nio.charset; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.CoderResult; + +/** + * Helper class to deal with decoding loops that read a byte at a time + * + * @author Ian Rogers + */ +public abstract class ByteDecodeLoopHelper +{ + /** + * @return can the given byte be encoded + */ + protected abstract boolean isMappable(byte b); + + /** + * Map the given byte to a char, the given byte is guaranteed to be mappable + */ + protected abstract char mapToChar(byte b); + + /** + * Encodes one or more characters into one or more bytes, mapping each + * character to only one byte + * + * @param in character buffer to read from + * @param out byte buffer to write to + * @return the result state of the encoder + */ + CoderResult decodeLoop(ByteBuffer in, CharBuffer out) + { + if (in.hasArray() && out.hasArray()) + { + return arrayDecodeLoop(in, out); + } else + { + return normalDecodeLoop(in, out); + } + } + + /** + * Encode loop using get and put operations + */ + private CoderResult normalDecodeLoop(ByteBuffer in, CharBuffer out) + { + int outRemaining = out.remaining(); + int inRemaining = in.remaining(); + while (inRemaining > 0 && outRemaining > 0) + { + byte b = in.get(); + inRemaining--; + + if (!isMappable(b)) + { + in.position(in.position() - 1); + return CoderResult.unmappableForLength(1); + } + char c = mapToChar(b); + out.put(c); + outRemaining--; + } + if (inRemaining > 0) + { + return CoderResult.OVERFLOW; + } else + { + return CoderResult.UNDERFLOW; + } + } + + /** + * Encode loop using array read and write operations + */ + private CoderResult arrayDecodeLoop(ByteBuffer in, CharBuffer out) + { + byte[] inArray = in.array(); + char[] outArray = out.array(); + int inPos = in.arrayOffset() + in.position(); + int outPos = out.arrayOffset() + out.position(); + int inRemaining = in.remaining(); + int outRemaining = out.remaining(); + CoderResult result; + + bailOut: + if (inRemaining <= outRemaining) + { + for (int i = 0; i < inRemaining; i++) + { + byte b = inArray[inPos]; + inPos++; + if (!isMappable(b)) + { + inPos--; + result = CoderResult.unmappableForLength(1); + break bailOut; + } + char c = mapToChar(b); + outArray[outPos] = c; + outPos++; + } + result = CoderResult.UNDERFLOW; + } + else + { + for (int i = 0; i < outRemaining; i++) + { + byte b = inArray[inPos]; + inPos++; + if (!isMappable(b)) + { + inPos--; + result = CoderResult.unmappableForLength(1); + break bailOut; + } + char c = mapToChar(b); + outArray[outPos] = c; + outPos++; + } + result = CoderResult.OVERFLOW; + } + in.position(inPos - in.arrayOffset()); + out.position(outPos - out.arrayOffset()); + return result; + } +} diff --git a/libjava/classpath/gnu/java/nio/charset/ByteEncodeLoopHelper.java b/libjava/classpath/gnu/java/nio/charset/ByteEncodeLoopHelper.java new file mode 100644 index 000000000..60e6d9bb0 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/ByteEncodeLoopHelper.java @@ -0,0 +1,165 @@ +/* ByteCharset.java -- Abstract class for generic 1-byte encodings. + 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.java.nio.charset; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.CoderResult; + +/** + * Helper class to deal with encoding loops that write a byte at a time + * + * @author Ian Rogers + */ +public abstract class ByteEncodeLoopHelper +{ + /** + * @return can the given character be encoded + */ + protected abstract boolean isMappable(char c); + + /** + * Map the given character to a byte, the given character is guaranteed to be + * mappable + */ + protected abstract byte mapToByte(char c); + + /** + * Encodes one or more characters into one or more bytes, mapping each + * character to only one byte + * + * @param in character buffer to read from + * @param out byte buffer to write to + * @return the result state of the encoder + */ + CoderResult encodeLoop(CharBuffer in, ByteBuffer out) + { + if (in.hasArray() && out.hasArray()) + { + return arrayEncodeLoop(in, out); + } else + { + return normalEncodeLoop(in, out); + } + } + + /** + * Encode loop using get and put operations + */ + private CoderResult normalEncodeLoop(CharBuffer in, ByteBuffer out) + { + int outRemaining = out.remaining(); + int inRemaining = in.remaining(); + while (inRemaining > 0 && outRemaining > 0) + { + char c = in.get(); + inRemaining--; + + if (!isMappable(c)) + { + in.position(in.position() - 1); + return CoderResult.unmappableForLength(1); + } + byte b = mapToByte(c); + out.put(b); + outRemaining--; + } + if (inRemaining > 0) + { + return CoderResult.OVERFLOW; + } else + { + return CoderResult.UNDERFLOW; + } + } + + /** + * Encode loop using array read and write operations + */ + private CoderResult arrayEncodeLoop(CharBuffer in, ByteBuffer out) + { + char[] inArray = in.array(); + byte[] outArray = out.array(); + int inPos = in.arrayOffset() + in.position(); + int outPos = out.arrayOffset() + out.position(); + int inRemaining = in.remaining(); + int outRemaining = out.remaining(); + CoderResult result; + + bailOut: + if (inRemaining <= outRemaining) + { + for (int i = 0; i < inRemaining; i++) + { + char inChar = inArray[inPos]; + inPos++; + if (!isMappable(inChar)) + { + inPos--; + result = CoderResult.unmappableForLength(1); + break bailOut; + } + byte b = mapToByte(inChar); + outArray[outPos] = b; + outPos++; + } + result = CoderResult.UNDERFLOW; + } + else + { + for (int i = 0; i < outRemaining; i++) + { + char inChar = inArray[inPos]; + inPos++; + if (!isMappable(inChar)) + { + inPos--; + result = CoderResult.unmappableForLength(1); + break bailOut; + } + byte b = mapToByte(inChar); + outArray[outPos] = b; + outPos++; + } + result = CoderResult.OVERFLOW; + } + in.position(inPos - in.arrayOffset()); + out.position(outPos - out.arrayOffset()); + return result; + } +} diff --git a/libjava/classpath/gnu/java/nio/charset/Cp424.java b/libjava/classpath/gnu/java/nio/charset/Cp424.java new file mode 100644 index 000000000..14915bf47 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/Cp424.java @@ -0,0 +1,86 @@ +/* Cp424.java -- Charset implementation for the Cp424 character set. + 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.java.nio.charset; + +public final class Cp424 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x009C, 0x0009, 0x0086, 0x007F, + 0x0097, 0x008D, 0x008E, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x009D, 0x0085, 0x0008, 0x0087, + 0x0018, 0x0019, 0x0092, 0x008F, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x000A, 0x0017, 0x001B, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x0005, 0x0006, 0x0007, + 0x0090, 0x0091, 0x0016, 0x0093, 0x0094, 0x0095, 0x0096, 0x0004, + 0x0098, 0x0099, 0x009A, 0x009B, 0x0014, 0x0015, 0x009E, 0x001A, + 0x0020, 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, + 0x05D7, 0x05D8, 0x00A2, 0x002E, 0x003C, 0x0028, 0x002B, 0x007C, + 0x0026, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, + 0x05E0, 0x05E1, 0x0021, 0x0024, 0x002A, 0x0029, 0x003B, 0x00AC, + 0x002D, 0x002F, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, + 0x05E8, 0x05E9, 0x00A6, 0x002C, 0x0025, 0x005F, 0x003E, 0x003F, + NONE, 0x05EA, NONE, NONE, 0x00A0, NONE, NONE, NONE, + 0x2017, 0x0060, 0x003A, 0x0023, 0x0040, 0x0027, 0x003D, 0x0022, + NONE, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x00AB, 0x00BB, NONE, NONE, NONE, 0x00B1, + 0x00B0, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, 0x0070, + 0x0071, 0x0072, NONE, NONE, NONE, 0x00B8, NONE, 0x00A4, + 0x00B5, 0x007E, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, + 0x0079, 0x007A, NONE, NONE, NONE, NONE, NONE, 0x00AE, + 0x005E, 0x00A3, 0x00A5, 0x00B7, 0x00A9, 0x00A7, 0x00B6, 0x00BC, + 0x00BD, 0x00BE, 0x005B, 0x005D, 0x00AF, 0x00A8, 0x00B4, 0x00D7, + 0x007B, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x00AD, NONE, NONE, NONE, NONE, NONE, + 0x007D, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, 0x0050, + 0x0051, 0x0052, 0x00B9, NONE, NONE, NONE, NONE, NONE, + 0x005C, 0x00F7, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, 0x0058, + 0x0059, 0x005A, 0x00B2, NONE, NONE, NONE, NONE, NONE, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x00B3, NONE, NONE, NONE, NONE, 0x009F + }; + + public Cp424() { + super("Cp424", new String[] {}, lookup); + } + +} // class Cp424 diff --git a/libjava/classpath/gnu/java/nio/charset/Cp437.java b/libjava/classpath/gnu/java/nio/charset/Cp437.java new file mode 100644 index 000000000..f60c3add2 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/Cp437.java @@ -0,0 +1,87 @@ +/* Cp437.java -- Charset implementation for the Cp437 character set. + 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.java.nio.charset; + +public final class Cp437 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, + 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, + 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, + 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, + 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, + 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, + 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, + 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 + }; + + public Cp437() + { + super("Cp437", new String[]{}, lookup); + } + +} // class Cp437 diff --git a/libjava/classpath/gnu/java/nio/charset/Cp737.java b/libjava/classpath/gnu/java/nio/charset/Cp737.java new file mode 100644 index 000000000..5dbd4a463 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/Cp737.java @@ -0,0 +1,87 @@ +/* Cp737.java -- Charset implementation for the Cp737 character set. + 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.java.nio.charset; + +public final class Cp737 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, + 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0, + 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, + 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, + 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, + 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, + 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, + 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03C9, 0x03AC, 0x03AD, 0x03AE, 0x03CA, 0x03AF, 0x03CC, 0x03CD, + 0x03CB, 0x03CE, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C, 0x038E, + 0x038F, 0x00B1, 0x2265, 0x2264, 0x03AA, 0x03AB, 0x00F7, 0x2248, + 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 + }; + + public Cp737() + { + super("Cp737", new String[] {}, lookup); + } + +} // class Cp737 diff --git a/libjava/classpath/gnu/java/nio/charset/Cp775.java b/libjava/classpath/gnu/java/nio/charset/Cp775.java new file mode 100644 index 000000000..ba3128e30 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/Cp775.java @@ -0,0 +1,87 @@ +/* Cp775.java -- Charset implementation for the Cp775 character set. + 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.java.nio.charset; + +public final class Cp775 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107, + 0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A, + 0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4, + 0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6, + 0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0104, 0x010C, 0x0118, + 0x0116, 0x2563, 0x2551, 0x2557, 0x255D, 0x012E, 0x0160, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0172, 0x016A, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x017D, + 0x0105, 0x010D, 0x0119, 0x0117, 0x012F, 0x0161, 0x0173, 0x016B, + 0x017E, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x00D3, 0x00DF, 0x014C, 0x0143, 0x00F5, 0x00D5, 0x00B5, 0x0144, + 0x0136, 0x0137, 0x013B, 0x013C, 0x0146, 0x0112, 0x0145, 0x2019, + 0x00AD, 0x00B1, 0x201C, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x201E, + 0x00B0, 0x2219, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 + }; + + public Cp775() + { + super("Cp775", new String[] {}, lookup); + } + +} // class Cp775 diff --git a/libjava/classpath/gnu/java/nio/charset/Cp850.java b/libjava/classpath/gnu/java/nio/charset/Cp850.java new file mode 100644 index 000000000..fef468994 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/Cp850.java @@ -0,0 +1,87 @@ +/* Cp850.java -- Charset implementation for the Cp850 character set. + 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.java.nio.charset; + +public final class Cp850 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, + 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, + 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, + 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, + 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE, + 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, + 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, + 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4, + 0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, + 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 + }; + + public Cp850() + { + super("Cp850", new String[] {}, lookup); + } + +} // class Cp850 diff --git a/libjava/classpath/gnu/java/nio/charset/Cp852.java b/libjava/classpath/gnu/java/nio/charset/Cp852.java new file mode 100644 index 000000000..eea99610d --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/Cp852.java @@ -0,0 +1,87 @@ +/* Cp852.java -- Charset implementation for the Cp852 character set. + 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.java.nio.charset; + +public final class Cp852 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7, + 0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106, + 0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A, + 0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E, + 0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x011A, + 0x015E, 0x2563, 0x2551, 0x2557, 0x255D, 0x017B, 0x017C, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0102, 0x0103, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x0111, 0x0110, 0x010E, 0x00CB, 0x010F, 0x0147, 0x00CD, 0x00CE, + 0x011B, 0x2518, 0x250C, 0x2588, 0x2584, 0x0162, 0x016E, 0x2580, + 0x00D3, 0x00DF, 0x00D4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161, + 0x0154, 0x00DA, 0x0155, 0x0170, 0x00FD, 0x00DD, 0x0163, 0x00B4, + 0x00AD, 0x02DD, 0x02DB, 0x02C7, 0x02D8, 0x00A7, 0x00F7, 0x00B8, + 0x00B0, 0x00A8, 0x02D9, 0x0171, 0x0158, 0x0159, 0x25A0, 0x00A0 + }; + + public Cp852() + { + super("Cp852", new String[] {}, lookup); + } + +} // class Cp852 diff --git a/libjava/classpath/gnu/java/nio/charset/Cp855.java b/libjava/classpath/gnu/java/nio/charset/Cp855.java new file mode 100644 index 000000000..d148d32b4 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/Cp855.java @@ -0,0 +1,87 @@ +/* Cp855.java -- Charset implementation for the Cp855 character set. + 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.java.nio.charset; + +public final class Cp855 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, + 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408, + 0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C, + 0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A, + 0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414, + 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445, 0x0425, 0x0438, + 0x0418, 0x2563, 0x2551, 0x2557, 0x255D, 0x0439, 0x0419, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x043A, 0x041A, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x043B, 0x041B, 0x043C, 0x041C, 0x043D, 0x041D, 0x043E, 0x041E, + 0x043F, 0x2518, 0x250C, 0x2588, 0x2584, 0x041F, 0x044F, 0x2580, + 0x042F, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443, + 0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044C, 0x042C, 0x2116, + 0x00AD, 0x044B, 0x042B, 0x0437, 0x0417, 0x0448, 0x0428, 0x044D, + 0x042D, 0x0449, 0x0429, 0x0447, 0x0427, 0x00A7, 0x25A0, 0x00A0 + }; + + public Cp855() + { + super("Cp855", new String[] {"cp-855",}, lookup); + } + +} // class Cp855 diff --git a/libjava/classpath/gnu/java/nio/charset/Cp857.java b/libjava/classpath/gnu/java/nio/charset/Cp857.java new file mode 100644 index 000000000..0d990ec2c --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/Cp857.java @@ -0,0 +1,88 @@ +/* Cp857.java -- Charset implementation for the Cp857 character set. + 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.java.nio.charset; + +public final class Cp857 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, + 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, + 0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F, + 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, + 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4, + 0x00BA, 0x00AA, 0x00CA, 0x00CB, 0x00C8, NONE, 0x00CD, 0x00CE, + 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580, + 0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, NONE, + 0x00D7, 0x00DA, 0x00DB, 0x00D9, 0x00EC, 0x00FF, 0x00AF, 0x00B4, + 0x00AD, 0x00B1, NONE, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, + 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0 + }; + + public Cp857() + { + super("Cp857", new String[] {"cp-857"}, lookup); + } + +} // class Cp857 diff --git a/libjava/classpath/gnu/java/nio/charset/Cp860.java b/libjava/classpath/gnu/java/nio/charset/Cp860.java new file mode 100644 index 000000000..4e15329ca --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/Cp860.java @@ -0,0 +1,88 @@ +/* Cp860.java -- Charset implementation for the Cp860 character set. + 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.java.nio.charset; + +public final class Cp860 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E3, 0x00E0, 0x00C1, 0x00E7, + 0x00EA, 0x00CA, 0x00E8, 0x00CD, 0x00D4, 0x00EC, 0x00C3, 0x00C2, + 0x00C9, 0x00C0, 0x00C8, 0x00F4, 0x00F5, 0x00F2, 0x00DA, 0x00F9, + 0x00CC, 0x00D5, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x20A7, 0x00D3, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, + 0x00BF, 0x00D2, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, + 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, + 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, + 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, + 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 + }; + + public Cp860() + { + super("Cp860", new String[] {"cp-860"}, lookup); + } + +} // class Cp860 diff --git a/libjava/classpath/gnu/java/nio/charset/Cp861.java b/libjava/classpath/gnu/java/nio/charset/Cp861.java new file mode 100644 index 000000000..e5a103f67 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/Cp861.java @@ -0,0 +1,88 @@ +/* Cp861.java -- Charset implementation for the Cp861 character set. + 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.java.nio.charset; + +public final class Cp861 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, + 0x00EA, 0x00EB, 0x00E8, 0x00D0, 0x00F0, 0x00DE, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00FE, 0x00FB, 0x00DD, + 0x00FD, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00C1, 0x00CD, 0x00D3, 0x00DA, + 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, + 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, + 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, + 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, + 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 + }; + + public Cp861() + { + super("Cp861", new String[] {"cp-861"}, lookup); + } + +} // class Cp861 diff --git a/libjava/classpath/gnu/java/nio/charset/Cp862.java b/libjava/classpath/gnu/java/nio/charset/Cp862.java new file mode 100644 index 000000000..873357433 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/Cp862.java @@ -0,0 +1,88 @@ +/* Cp862.java -- Charset implementation for the Cp862 character set. + 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.java.nio.charset; + +public final class Cp862 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, + 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, + 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, + 0x05E8, 0x05E9, 0x05EA, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, + 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, + 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, + 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, + 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, + 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 + }; + + public Cp862() + { + super("Cp862", new String[] {"Cp-862"}, lookup); + } + +} // class Cp862 diff --git a/libjava/classpath/gnu/java/nio/charset/Cp863.java b/libjava/classpath/gnu/java/nio/charset/Cp863.java new file mode 100644 index 000000000..3a86f3e2d --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/Cp863.java @@ -0,0 +1,88 @@ +/* Cp863.java -- Charset implementation for the Cp863 character set. + 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.java.nio.charset; + +public final class Cp863 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00C2, 0x00E0, 0x00B6, 0x00E7, + 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x2017, 0x00C0, 0x00A7, + 0x00C9, 0x00C8, 0x00CA, 0x00F4, 0x00CB, 0x00CF, 0x00FB, 0x00F9, + 0x00A4, 0x00D4, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x00DB, 0x0192, + 0x00A6, 0x00B4, 0x00F3, 0x00FA, 0x00A8, 0x00B8, 0x00B3, 0x00AF, + 0x00CE, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00BE, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, + 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, + 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, + 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, + 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 + }; + + public Cp863() + { + super("Cp863", new String[] {"Cp-863"}, lookup); + } + +} // class Cp863 diff --git a/libjava/classpath/gnu/java/nio/charset/Cp864.java b/libjava/classpath/gnu/java/nio/charset/Cp864.java new file mode 100644 index 000000000..990e3723d --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/Cp864.java @@ -0,0 +1,88 @@ +/* Cp864.java -- Charset implementation for the Cp864 character set. + 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.java.nio.charset; + +public final class Cp864 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x066A, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x00B0, 0x00B7, 0x2219, 0x221A, 0x2592, 0x2500, 0x2502, 0x253C, + 0x2524, 0x252C, 0x251C, 0x2534, 0x2510, 0x250C, 0x2514, 0x2518, + 0x03B2, 0x221E, 0x03C6, 0x00B1, 0x00BD, 0x00BC, 0x2248, 0x00AB, + 0x00BB, 0xFEF7, 0xFEF8, NONE, NONE, 0xFEFB, 0xFEFC, NONE, + 0x00A0, 0x00AD, 0xFE82, 0x00A3, 0x00A4, 0xFE84, NONE, NONE, + 0xFE8E, 0xFE8F, 0xFE95, 0xFE99, 0x060C, 0xFE9D, 0xFEA1, 0xFEA5, + 0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, + 0x0668, 0x0669, 0xFED1, 0x061B, 0xFEB1, 0xFEB5, 0xFEB9, 0x061F, + 0x00A2, 0xFE80, 0xFE81, 0xFE83, 0xFE85, 0xFECA, 0xFE8B, 0xFE8D, + 0xFE91, 0xFE93, 0xFE97, 0xFE9B, 0xFE9F, 0xFEA3, 0xFEA7, 0xFEA9, + 0xFEAB, 0xFEAD, 0xFEAF, 0xFEB3, 0xFEB7, 0xFEBB, 0xFEBF, 0xFEC1, + 0xFEC5, 0xFECB, 0xFECF, 0x00A6, 0x00AC, 0x00F7, 0x00D7, 0xFEC9, + 0x0640, 0xFED3, 0xFED7, 0xFEDB, 0xFEDF, 0xFEE3, 0xFEE7, 0xFEEB, + 0xFEED, 0xFEEF, 0xFEF3, 0xFEBD, 0xFECC, 0xFECE, 0xFECD, 0xFEE1, + 0xFE7D, 0x0651, 0xFEE5, 0xFEE9, 0xFEEC, 0xFEF0, 0xFEF2, 0xFED0, + 0xFED5, 0xFEF5, 0xFEF6, 0xFEDD, 0xFED9, 0xFEF1, 0x25A0, NONE + }; + + public Cp864() + { + super("Cp864", new String[] {"Cp-864"}, lookup); + } + +} // class Cp864 diff --git a/libjava/classpath/gnu/java/nio/charset/Cp865.java b/libjava/classpath/gnu/java/nio/charset/Cp865.java new file mode 100644 index 000000000..a708a8560 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/Cp865.java @@ -0,0 +1,88 @@ +/* Cp865.java -- Charset implementation for the Cp865 character set. + 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.java.nio.charset; + +public final class Cp865 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, + 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5, + 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, + 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192, + 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, + 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00A4, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, + 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, + 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, + 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, + 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, + 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0 + }; + + public Cp865() + { + super("Cp865", new String[] {"Cp-865"}, lookup); + } + +} // class Cp865 diff --git a/libjava/classpath/gnu/java/nio/charset/Cp866.java b/libjava/classpath/gnu/java/nio/charset/Cp866.java new file mode 100644 index 000000000..0f3c23044 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/Cp866.java @@ -0,0 +1,88 @@ +/* Cp866.java -- Charset implementation for the Cp866 character set. + 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.java.nio.charset; + +public final class Cp866 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, + 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567, + 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, + 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, + 0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E, + 0x00B0, 0x2219, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0 + }; + + public Cp866() + { + super("Cp866", new String[] {"cp-866"}, lookup); + } + +} // class Cp866 diff --git a/libjava/classpath/gnu/java/nio/charset/Cp869.java b/libjava/classpath/gnu/java/nio/charset/Cp869.java new file mode 100644 index 000000000..091e2e7b4 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/Cp869.java @@ -0,0 +1,88 @@ +/* Cp869.java -- Charset implementation for the Cp869 character set. + 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.java.nio.charset; + +public final class Cp869 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + NONE, NONE, NONE, NONE, NONE, NONE, 0x0386, NONE, + 0x00B7, 0x00AC, 0x00A6, 0x2018, 0x2019, 0x0388, 0x2015, 0x0389, + 0x038A, 0x03AA, 0x038C, NONE, NONE, 0x038E, 0x03AB, 0x00A9, + 0x038F, 0x00B2, 0x00B3, 0x03AC, 0x00A3, 0x03AD, 0x03AE, 0x03AF, + 0x03CA, 0x0390, 0x03CC, 0x03CD, 0x0391, 0x0392, 0x0393, 0x0394, + 0x0395, 0x0396, 0x0397, 0x00BD, 0x0398, 0x0399, 0x00AB, 0x00BB, + 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x039A, 0x039B, 0x039C, + 0x039D, 0x2563, 0x2551, 0x2557, 0x255D, 0x039E, 0x039F, 0x2510, + 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x03A0, 0x03A1, + 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x03A3, + 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, + 0x03B3, 0x2518, 0x250C, 0x2588, 0x2584, 0x03B4, 0x03B5, 0x2580, + 0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, + 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x0384, + 0x00AD, 0x00B1, 0x03C5, 0x03C6, 0x03C7, 0x00A7, 0x03C8, 0x0385, + 0x00B0, 0x00A8, 0x03C9, 0x03CB, 0x03B0, 0x03CE, 0x25A0, 0x00A0 + }; + + public Cp869() + { + super("Cp869", new String[] {"Cp-869"}, lookup); + } + +} // class Cp869 diff --git a/libjava/classpath/gnu/java/nio/charset/Cp874.java b/libjava/classpath/gnu/java/nio/charset/Cp874.java new file mode 100644 index 000000000..d399c723c --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/Cp874.java @@ -0,0 +1,87 @@ +/* Cp874.java -- Charset implementation for the Cp874 character set. + 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.java.nio.charset; + +public final class Cp874 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x20AC, NONE, NONE, NONE, NONE, 0x2026, NONE, NONE, + NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, + NONE, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, + 0x00A0, 0x0E01, 0x0E02, 0x0E03, 0x0E04, 0x0E05, 0x0E06, 0x0E07, + 0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, 0x0E0E, 0x0E0F, + 0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, 0x0E15, 0x0E16, 0x0E17, + 0x0E18, 0x0E19, 0x0E1A, 0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, 0x0E1F, + 0x0E20, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27, + 0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F, + 0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37, + 0x0E38, 0x0E39, 0x0E3A, NONE, NONE, NONE, NONE, 0x0E3F, + 0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, 0x0E45, 0x0E46, 0x0E47, + 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D, 0x0E4E, 0x0E4F, + 0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57, + 0x0E58, 0x0E59, 0x0E5A, 0x0E5B, NONE, NONE, NONE, NONE + }; + + public Cp874() + { + super("Cp874", new String[] {}, lookup); + } + +} // class Cp874 diff --git a/libjava/classpath/gnu/java/nio/charset/EncodingHelper.java b/libjava/classpath/gnu/java/nio/charset/EncodingHelper.java new file mode 100644 index 000000000..f99818551 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/EncodingHelper.java @@ -0,0 +1,161 @@ +/* EncodingHelper.java -- Useful character encoding methods. + 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.java.nio.charset; + +import java.util.HashMap; +import java.nio.charset.IllegalCharsetNameException; +import java.nio.charset.UnsupportedCharsetException; +import java.nio.charset.Charset; +import java.io.UnsupportedEncodingException; + +/** + * This class provides some useful utility methods + * for charset encoding for the java.lang and java.io methods. + * + * @author Sven de Marothy + */ +public class EncodingHelper +{ + + /** + * Contains the mapping from java.io canonical names + * to java.nio canonical names. + */ + private static final HashMap canonicalNames; + + static { + canonicalNames = new HashMap(); + canonicalNames.put("US-ASCII", "ASCII"); + canonicalNames.put("windows-1250", "Cp1250"); + canonicalNames.put("windows-1251", "Cp1251"); + canonicalNames.put("windows-1252", "Cp1252"); + canonicalNames.put("windows-1253", "Cp1253"); + canonicalNames.put("windows-1254", "Cp1254"); + canonicalNames.put("windows-1257", "Cp1257"); + canonicalNames.put("ISO-8859-1", "ISO8859_1"); + canonicalNames.put("ISO-8859-2", "ISO8859_2"); + canonicalNames.put("ISO-8859-4", "ISO8859_4"); + canonicalNames.put("ISO-8859-5", "ISO8859_5"); + canonicalNames.put("ISO-8859-7", "ISO8859_7"); + canonicalNames.put("ISO-8859-9", "ISO8859_9"); + canonicalNames.put("ISO-8859-13", "ISO8859_13"); + canonicalNames.put("ISO-8859-15", "ISO8859_15"); + canonicalNames.put("KOI8-R", "KOI8_R"); + canonicalNames.put("UTF-8", "UTF8"); + canonicalNames.put("UTF-16BE", "UnicodeBigUnmarked"); + canonicalNames.put("UTF-16LE", "UnicodeLittleUnmarked"); + canonicalNames.put("windows-1255", "Cp1255"); + canonicalNames.put("windows-1256", "Cp1256"); + canonicalNames.put("windows-1258", "Cp1258"); + canonicalNames.put("ISO-8859-3", "ISO8859_3"); + canonicalNames.put("ISO-8859-6", "ISO8859_6"); + canonicalNames.put("ISO-8859-8", "ISO8859_8"); + } + + /** + * Returns the name of the default encoding, + * falls back on defaults to Latin-1 if there's a problem. + */ + public static String getDefaultEncoding() + { + try + { + return System.getProperty("file.encoding"); + } catch(SecurityException e) { + } catch(IllegalArgumentException e) { + } + // XXX - Throw an error here? For now, default to the 'safe' encoding. + return "8859_1"; + } + + /** + * Returns the java.io canonical name of a charset given with the + * java.nio canonical name. If the charset does not have a java.io + * canonical name, the input string is returned. + */ + public static String getOldCanonical(String newCanonical) + { + String oldCanonical = (String) canonicalNames.get(newCanonical); + return (oldCanonical != null)?oldCanonical : newCanonical; + } + + public static boolean isISOLatin1(String s) + { + if(s.equals("ISO-8859-1") || + s.equals("8859_1") || + s.equals("ISO_8859-1") || + s.equals("latin1") || + s.equals("ISO8859_1") || + s.equals("ISO_8859_1")) + return true; + return false; + } + + /** + * Gets a charset, throwing the java.io exception and not + * the java.nio exception if an error occurs. + */ + public static Charset getCharset(String name) + throws UnsupportedEncodingException + { + try + { + return Charset.forName(name); + } + catch(IllegalCharsetNameException e) + { + throw new UnsupportedEncodingException("Charset "+name+" not found."); + } + catch(UnsupportedCharsetException e) + { + throw new UnsupportedEncodingException("Charset "+name+" not found."); + } + } + + /** + * Returns the default charset without throwing any exceptions. The default + * charset is UTF8. + * + * @return the default charset + */ + public static Charset getDefaultCharset() + { + return new UTF_8(); + } +} diff --git a/libjava/classpath/gnu/java/nio/charset/ISO_8859_1.java b/libjava/classpath/gnu/java/nio/charset/ISO_8859_1.java new file mode 100644 index 000000000..eb7c5ec59 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/ISO_8859_1.java @@ -0,0 +1,165 @@ +/* ISO_8859_1.java -- + Copyright (C) 2002, 2004, 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.java.nio.charset; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CoderResult; + +/** + * ISO-8859-1 charset. + * + * @author Jesse Rosenstock + * @modified Ian Rogers + */ +final class ISO_8859_1 extends Charset +{ + ISO_8859_1 () + { + /* Canonical charset name chosen according to: + * http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html + */ + super ("ISO-8859-1", new String[] { + /* These names are provided by + * http://www.iana.org/assignments/character-sets + */ + "iso-ir-100", + "ISO_8859-1", + "latin1", + "l1", + "IBM819", + "CP819", + "csISOLatin1", + "8859_1", + /* These names are provided by + * http://oss.software.ibm.com/cgi-bin/icu/convexp?s=ALL + */ + "ISO8859_1", + "ISO_8859_1", + "ibm-819", + "ISO_8859-1:1987", + "819", + "ISO8859-1" + }); + + } + + public boolean contains (Charset cs) + { + return cs instanceof US_ASCII || cs instanceof ISO_8859_1; + } + + public CharsetDecoder newDecoder () + { + return new Decoder (this); + } + + public CharsetEncoder newEncoder () + { + return new Encoder (this); + } + + private static final class Decoder extends CharsetDecoder + { + /** Helper to decode loops */ + private static final ByteDecodeLoopHelper helper = new ByteDecodeLoopHelper() + { + protected boolean isMappable(byte b) + { + return true; + } + protected char mapToChar(byte b) + { + return (char)(b & 0xFF); + } + }; + + // Package-private to avoid a trampoline constructor. + Decoder (Charset cs) + { + super (cs, 1.0f, 1.0f); + } + + protected CoderResult decodeLoop (ByteBuffer in, CharBuffer out) + { + return helper.decodeLoop(in, out); + } + } + + private static final class Encoder extends CharsetEncoder + { + /** Helper to encode loops */ + private static final ByteEncodeLoopHelper helper = new ByteEncodeLoopHelper() + { + protected boolean isMappable(char c) + { + return c <= 0xff; + } + protected byte mapToByte(char c) + { + return (byte)c; + } + }; + // Package-private to avoid a trampoline constructor. + Encoder (Charset cs) + { + super (cs, 1.0f, 1.0f); + } + + public boolean canEncode(char c) + { + return c <= 0xff; + } + + public boolean canEncode(CharSequence cs) + { + for (int i = 0; i < cs.length(); ++i) + if (! canEncode(cs.charAt(i))) + return false; + return true; + } + + protected CoderResult encodeLoop (CharBuffer in, ByteBuffer out) + { + return helper.encodeLoop(in, out); + } + } +} diff --git a/libjava/classpath/gnu/java/nio/charset/ISO_8859_13.java b/libjava/classpath/gnu/java/nio/charset/ISO_8859_13.java new file mode 100644 index 000000000..5e2748974 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/ISO_8859_13.java @@ -0,0 +1,102 @@ +/* ISO_8859_13.java -- Charset for ISO-8859-13 iso latin character set. + 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.java.nio.charset; + +/** + * Encoding table for ISO-8859-13, ISO Latin-7 char set. + */ +public final class ISO_8859_13 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x201D, 0x00A2, 0x00A3, 0x00A4, 0x201E, 0x00A6, 0x00A7, + 0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00C6, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x201C, 0x00B5, 0x00B6, 0x00B7, + 0x00F8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6, + 0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112, + 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B, + 0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7, + 0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF, + 0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113, + 0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C, + 0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7, + 0x0173, 0x0142, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x2019 + }; + + public ISO_8859_13() + { + super("ISO-8859-13", new String[] { + "ISO8859_13", + "8859_13", + "ibm-921_P100-1995", + "ibm-921", + "iso_8859_13", + "iso8859_13", + "iso-8859-13", + "8859_13", + "cp921", + "921" + }, lookup); + } + +} // class ISO_8859_13 diff --git a/libjava/classpath/gnu/java/nio/charset/ISO_8859_15.java b/libjava/classpath/gnu/java/nio/charset/ISO_8859_15.java new file mode 100644 index 000000000..dc5e9e55a --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/ISO_8859_15.java @@ -0,0 +1,109 @@ +/* ISO_8859_15.java -- Charset for ISO-8859-15 iso latin character set. + 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.java.nio.charset; + +/** + * Encoding table for ISO-8859-15, ISO Latin-9 char set. + */ +public final class ISO_8859_15 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x20AC, 0x00A5, 0x0160, 0x00A7, + 0x0161, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x017D, 0x00B5, 0x00B6, 0x00B7, + 0x017E, 0x00B9, 0x00BA, 0x00BB, 0x0152, 0x0153, 0x0178, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF + }; + + public ISO_8859_15() + { + super("ISO-8859-15", new String[] { + "8859_15", + "iso8859_15", + "iso-8859-15", + "8859-15", + "latin9", + "iso_8859_15", + "ibm-923_P100-1998", + "ibm-923", + "Latin-9", + "l9", + "latin0", + "csisolatin0", + "csisolatin9", + "iso8859_15_fdis", + "cp923", + "923", + "windows-28605" + }, lookup); + } + +} // class ISO_8859_15 diff --git a/libjava/classpath/gnu/java/nio/charset/ISO_8859_2.java b/libjava/classpath/gnu/java/nio/charset/ISO_8859_2.java new file mode 100644 index 000000000..7a086923d --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/ISO_8859_2.java @@ -0,0 +1,108 @@ +/* ISO_8859_2.java -- Charset for ISO-8859-2 Character set. + 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.java.nio.charset; + +/** + * Encoding table for ISO-8859-2, ISO Latin-2 char set. + */ +public final class ISO_8859_2 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + * Note: ranges 0-1F and 7f-97 aren't defined in the spec file aron used. + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0104, 0x02D8, 0x0141, 0x00A4, 0x013D, 0x015A, 0x00A7, + 0x00A8, 0x0160, 0x015E, 0x0164, 0x0179, 0x00AD, 0x017D, 0x017B, + 0x00B0, 0x0105, 0x02DB, 0x0142, 0x00B4, 0x013E, 0x015B, 0x02C7, + 0x00B8, 0x0161, 0x015F, 0x0165, 0x017A, 0x02DD, 0x017E, 0x017C, + 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E, + 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7, + 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF, + 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F, + 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7, + 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9 + }; + + public ISO_8859_2() + { + super("ISO-8859-2", new String[] { + "ISO8859_2", + "8859_2", + "ibm-912_P100-1995", + "ibm-912", + "iso_8859_2", + "iso8859_2", + "iso-8859-2", + "ISO_8859-2:1987", + "latin2", + "csISOLatin2", + "iso-ir-101", + "l2", + "cp912", + "912", + "windows-28592" + }, lookup); + } + +} // class ISO_8859_2 diff --git a/libjava/classpath/gnu/java/nio/charset/ISO_8859_3.java b/libjava/classpath/gnu/java/nio/charset/ISO_8859_3.java new file mode 100644 index 000000000..a3c1ea692 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/ISO_8859_3.java @@ -0,0 +1,107 @@ +/* ISO_8859_3.java -- Charset for ISO-8859-3 Character set. + 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.java.nio.charset; + +/** + * Encoding table for ISO-8859-3, ISO Latin-3 char set. + */ +public final class ISO_8859_3 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0126, 0x02D8, 0x00A3, 0x00A4, NONE, 0x0124, 0x00A7, + 0x00A8, 0x0130, 0x015E, 0x011E, 0x0134, 0x00AD, NONE, 0x017B, + 0x00B0, 0x0127, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x0125, 0x00B7, + 0x00B8, 0x0131, 0x015F, 0x011F, 0x0135, 0x00BD, NONE, 0x017C, + 0x00C0, 0x00C1, 0x00C2, NONE, 0x00C4, 0x010A, 0x0108, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + NONE, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x0120, 0x00D6, 0x00D7, + 0x011C, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x016C, 0x015C, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, NONE, 0x00E4, 0x010B, 0x0109, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + NONE, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x0121, 0x00F6, 0x00F7, + 0x011D, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x016D, 0x015D, 0x02D9 + }; + + public ISO_8859_3() + { + super("ISO-8859-3", new String[] { + "ISO8859_3", + "8859_3", + "ibm-913_P100-2000", + "ibm-913", + "iso_8859_3", + "iso8859_3", + "iso-8859-3", + "ISO_8859-3:1988", + "latin3", + "csISOLatin3", + "iso-ir-109", + "l3", + "cp913", + "913", + "windows-28593" + }, lookup); + } + +} // class ISO_8859_3 diff --git a/libjava/classpath/gnu/java/nio/charset/ISO_8859_4.java b/libjava/classpath/gnu/java/nio/charset/ISO_8859_4.java new file mode 100644 index 000000000..3e92dbe64 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/ISO_8859_4.java @@ -0,0 +1,108 @@ +/* ISO_8859_4.java -- Charset for ISO-8859-4 Character set. + 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.java.nio.charset; + +/** + * Encoding table for ISO-8859-4, ISO Latin-4 char set. + */ +public final class ISO_8859_4 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + * Note: ranges 0-1F and 7f-9f aren't defined in the spec file aron used. + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0104, 0x0138, 0x0156, 0x00A4, 0x0128, 0x013B, 0x00A7, + 0x00A8, 0x0160, 0x0112, 0x0122, 0x0166, 0x00AD, 0x017D, 0x00AF, + 0x00B0, 0x0105, 0x02DB, 0x0157, 0x00B4, 0x0129, 0x013C, 0x02C7, + 0x00B8, 0x0161, 0x0113, 0x0123, 0x0167, 0x014A, 0x017E, 0x014B, + 0x0100, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x012E, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x0116, 0x00CD, 0x00CE, 0x012A, + 0x0110, 0x0145, 0x014C, 0x0136, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x0172, 0x00DA, 0x00DB, 0x00DC, 0x0168, 0x016A, 0x00DF, + 0x0101, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x012F, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x0117, 0x00ED, 0x00EE, 0x012B, + 0x0111, 0x0146, 0x014D, 0x0137, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x0173, 0x00FA, 0x00FB, 0x00FC, 0x0169, 0x016B, 0x02D9 + }; + + public ISO_8859_4() + { + super("ISO-8859-4", new String[] { + "ISO8859_4", + "8859_4", + "ibm-914_P100-1995", + "ibm-914", + "iso_8859_4", + "iso8859_4", + "iso-8859-4", + "latin4", + "csISOLatin4", + "iso-ir-110", + "ISO_8859-4:1988", + "l4", + "cp914", + "914", + "windows-28594" + }, lookup); + } + +} // class ISO_8859_4 diff --git a/libjava/classpath/gnu/java/nio/charset/ISO_8859_5.java b/libjava/classpath/gnu/java/nio/charset/ISO_8859_5.java new file mode 100644 index 000000000..17d11e077 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/ISO_8859_5.java @@ -0,0 +1,106 @@ +/* ISO_8859_5.java -- Charset for ISO-8859-5 cyrillic character set. + 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.java.nio.charset; + +/** + * Encoding table for ISO-8859-5, ISO cyrillic char set. + */ +public final class ISO_8859_5 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, + 0x0408, 0x0409, 0x040A, 0x040B, 0x040C, 0x00AD, 0x040E, 0x040F, + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, + 0x2116, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, + 0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x00A7, 0x045E, 0x045F + }; + + public ISO_8859_5() + { + super("ISO-8859-5", new String[] { + "ISO8859_5", + "8859_5", + "ibm-915_P100-1995", + "ibm-915", + "iso_8859_5", + "iso8859_5", + "iso-8859-5", + "cyrillic", + "csISOLatinCyrillic", + "iso-ir-144", + "ISO_8859-5:1988", + "cp915", + "915", + "windows-28595" + }, lookup); + } + +} // class ISO_8859_5 diff --git a/libjava/classpath/gnu/java/nio/charset/ISO_8859_6.java b/libjava/classpath/gnu/java/nio/charset/ISO_8859_6.java new file mode 100644 index 000000000..47dca4e37 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/ISO_8859_6.java @@ -0,0 +1,110 @@ +/* ISO_8859_6.java -- Charset for ISO-8859-6 iso Arabic character set. + 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.java.nio.charset; + +/** + * Encoding table for ISO-8859-6, ISO Arabic char set. + */ +public final class ISO_8859_6 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, NONE, NONE, NONE, 0x00A4, NONE, NONE, NONE, + NONE, NONE, NONE, NONE, 0x060C, 0x00AD, NONE, NONE, + NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, + NONE, NONE, NONE, 0x061B, NONE, NONE, NONE, 0x061F, + NONE, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, + 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, + 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x0637, + 0x0638, 0x0639, 0x063A, NONE, NONE, NONE, NONE, NONE, + 0x0640, 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, + 0x0648, 0x0649, 0x064A, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, + 0x0650, 0x0651, 0x0652, NONE, NONE, NONE, NONE, NONE, + NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE + }; + + public ISO_8859_6() + { + super("ISO-8859-6", new String[] { + "8859_6", + "ibm-1089_P100-1995", + "ibm-1089", + "iso_8859_6", + "iso8859_6", + "iso-8859-6", + "arabic", + "csISOLatinArabic", + "iso-ir-127", + "ISO_8859-6:1987", + "ECMA-114", + "ASMO-708", + "8859_6", + "cp1089", + "1089", + "windows-28596", + "ISO-8859-6-I", + "ISO-8859-6-E" + }, lookup); + } + +} // class ISO_8859_6 diff --git a/libjava/classpath/gnu/java/nio/charset/ISO_8859_7.java b/libjava/classpath/gnu/java/nio/charset/ISO_8859_7.java new file mode 100644 index 000000000..19428cf8a --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/ISO_8859_7.java @@ -0,0 +1,109 @@ +/* ISO_8859_7.java -- Charset for ISO-8859-7 Character set. + 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.java.nio.charset; + +/** + * Encoding table for ISO-8859-7, ISO Latin/Greek char set. + */ +public final class ISO_8859_7 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x02BD, 0x02BC, 0x00A3, NONE, NONE, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, NONE, 0x00AB, 0x00AC, 0x00AD, NONE, 0x2015, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x0385, 0x0386, 0x00B7, + 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F, + 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, + 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, + 0x03A0, 0x03A1, NONE, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, + 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF, + 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, + 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, + 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, + 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, NONE + }; + + public ISO_8859_7() + { + super("ISO-8859-7", new String[] { + "ISO8859_7", + "8859_7", + "ibm-813_P100-1995", + "ibm-813", + "iso_8859_7", + "iso8859_7", + "iso-8859-7", + "greek", + "greek8", + "ELOT_928", + "ECMA-118", + "csISOLatinGreek", + "iso-ir-126", + "ISO_8859-7:1987", + "cp813", + "813", + "windows-28597" + }, lookup); + } + +} // class ISO_8859_7 diff --git a/libjava/classpath/gnu/java/nio/charset/ISO_8859_8.java b/libjava/classpath/gnu/java/nio/charset/ISO_8859_8.java new file mode 100644 index 000000000..fc60d39b5 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/ISO_8859_8.java @@ -0,0 +1,108 @@ +/* ISO_8859_8.java -- Charset for ISO-8859-8 iso Hebrew character set. + 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.java.nio.charset; + +/** + * Encoding table for ISO-8859-8, ISO Latin/Hebrew char set. + */ +public final class ISO_8859_8 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, NONE, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x203E, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, NONE, + NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, + NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, + NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, + NONE, NONE, NONE, NONE, NONE, NONE, NONE, 0x2017, + 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, + 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, + 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, + 0x05E8, 0x05E9, 0x05EA, NONE, NONE, NONE, NONE, NONE + }; + + public ISO_8859_8() + { + super("ISO-8859-8", new String[] { + "ISO8859_8", + "8859_8", + "ibm-916_P100-1995", + "ibm-916", + "iso_8859_8", + "iso8859_8", + "iso-8859-8", + "hebrew", + "csISOLatinHebrew", + "iso-ir-138", + "ISO_8859-8:1988", + "ISO-8859-8-I", + "ISO-8859-8-E", + "cp916", + "916", + "windows-28598" + }, lookup); + } + +} // class ISO_8859_8 diff --git a/libjava/classpath/gnu/java/nio/charset/ISO_8859_9.java b/libjava/classpath/gnu/java/nio/charset/ISO_8859_9.java new file mode 100644 index 000000000..70d987c8f --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/ISO_8859_9.java @@ -0,0 +1,108 @@ +/* ISO_8859_9.java -- Charset for ISO-8859-9 iso latin character set. + 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.java.nio.charset; + +/** + * Encoding table for ISO-8859-9, ISO Latin-5 char set. + */ +public final class ISO_8859_9 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015E, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF + }; + + public ISO_8859_9() + { + super("ISO-8859-9", new String[] { + "ISO8859_9", + "8859_9", + "ibm-920_P100-1995", + "ibm-920", + "iso8859_9", + "iso-8859-9", + "iso_8859_9", + "latin5", + "csISOLatin5", + "iso-ir-148", + "ISO_8859-9:1989", + "l5", + "cp920", + "920", + "windows-28599", + "ECMA-128" + }, lookup); + } + +} // class ISO_8859_9 diff --git a/libjava/classpath/gnu/java/nio/charset/KOI_8.java b/libjava/classpath/gnu/java/nio/charset/KOI_8.java new file mode 100644 index 000000000..f9dc4b1f6 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/KOI_8.java @@ -0,0 +1,100 @@ +/* KOI_8.java -- Charset for KOI-8 cyrillic character set. + 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.java.nio.charset; + +/** + * Encoding table for the KOI8 cyrillic char set. + */ +public final class KOI_8 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524, + 0x252C, 0x2534, 0x253C, 0x2580, 0x2584, 0x2588, 0x258C, 0x2590, + 0x2591, 0x2592, 0x2593, 0x2320, 0x25A0, 0x2219, 0x221A, 0x2248, + 0x2264, 0x2265, 0x00A0, 0x2321, 0x00B0, 0x00B2, 0x00B7, 0x00F7, + 0x2550, 0x2551, 0x2552, 0x0451, 0x2553, 0x2554, 0x2555, 0x2556, + 0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x255C, 0x255D, 0x255E, + 0x255F, 0x2560, 0x2561, 0x0401, 0x2562, 0x2563, 0x2564, 0x2565, + 0x2566, 0x2567, 0x2568, 0x2569, 0x256A, 0x256B, 0x256C, 0x00A9, + 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, + 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, + 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, + 0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A, + 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, + 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, + 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, + 0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A + }; + + public KOI_8() + { + super("KOI8-R", new String[] { + "KOI8_R", + "KOI8", + "KOI-8", + "KOI_8", + "koi8-r", + "koi8r", + "koi-8-r", + "koi" + }, lookup); + } + +} // class KOI_8 diff --git a/libjava/classpath/gnu/java/nio/charset/MS874.java b/libjava/classpath/gnu/java/nio/charset/MS874.java new file mode 100644 index 000000000..ed1f7c64f --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/MS874.java @@ -0,0 +1,87 @@ +/* MS874.java -- Charset implementation for the MS874 Thai character set. + 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.java.nio.charset; + +public final class MS874 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x20AC, NONE, NONE, NONE, NONE, 0x2026, NONE, NONE, + NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, + NONE, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, + 0x00A0, 0x0E01, 0x0E02, 0x0E03, 0x0E04, 0x0E05, 0x0E06, 0x0E07, + 0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, 0x0E0E, 0x0E0F, + 0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, 0x0E15, 0x0E16, 0x0E17, + 0x0E18, 0x0E19, 0x0E1A, 0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, 0x0E1F, + 0x0E20, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27, + 0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F, + 0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37, + 0x0E38, 0x0E39, 0x0E3A, NONE, NONE, NONE, NONE, 0x0E3F, + 0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, 0x0E45, 0x0E46, 0x0E47, + 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D, 0x0E4E, 0x0E4F, + 0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57, + 0x0E58, 0x0E59, 0x0E5A, 0x0E5B, NONE, NONE, NONE, NONE + }; + + public MS874() + { + super("MS874", new String[] {}, lookup); + } + +} // class MS874 diff --git a/libjava/classpath/gnu/java/nio/charset/MacCentralEurope.java b/libjava/classpath/gnu/java/nio/charset/MacCentralEurope.java new file mode 100644 index 000000000..ee31a5dad --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/MacCentralEurope.java @@ -0,0 +1,87 @@ +/* MacCentralEurope.java -- Charset implementation for the MacCentralEurope character set. + 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.java.nio.charset; + +public final class MacCentralEurope extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, NONE, + 0x00C4, 0x0100, 0x0101, 0x00C9, 0x0104, 0x00D6, 0x00DC, 0x00E1, + 0x0105, 0x010C, 0x00E4, 0x010D, 0x0106, 0x0107, 0x00E9, 0x0179, + 0x017A, 0x010E, 0x00ED, 0x010F, 0x0112, 0x0113, 0x0116, 0x00F3, + 0x0117, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x011A, 0x011B, 0x00FC, + 0x2020, 0x00B0, 0x0118, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF, + 0x00AE, 0x00A9, 0x2122, 0x0119, 0x00A8, 0x2260, 0x0123, 0x012E, + 0x012F, 0x012A, 0x2264, 0x2265, 0x012B, 0x0136, 0x2202, 0x2211, + 0x0142, 0x013B, 0x013C, 0x013D, 0x013E, 0x0139, 0x013A, 0x0145, + 0x0146, 0x0143, 0x00AC, 0x221A, 0x0144, 0x0147, 0x2206, 0x00AB, + 0x00BB, 0x2026, 0x00A0, 0x0148, 0x0150, 0x00D5, 0x0151, 0x014C, + 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA, + 0x014D, 0x0154, 0x0155, 0x0158, 0x2039, 0x203A, 0x0159, 0x0156, + 0x0157, 0x0160, 0x201A, 0x201E, 0x0161, 0x015A, 0x015B, 0x00C1, + 0x0164, 0x0165, 0x00CD, 0x017D, 0x017E, 0x016A, 0x00D3, 0x00D4, + 0x016B, 0x016E, 0x00DA, 0x016F, 0x0170, 0x0171, 0x0172, 0x0173, + 0x00DD, 0x00FD, 0x0137, 0x017B, 0x0141, 0x017C, 0x0122, 0x02C7 + }; + + public MacCentralEurope() + { + super("MacCentralEurope", new String[] {}, lookup); + } + +} // class MacCentralEurope diff --git a/libjava/classpath/gnu/java/nio/charset/MacCroatian.java b/libjava/classpath/gnu/java/nio/charset/MacCroatian.java new file mode 100644 index 000000000..acf018414 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/MacCroatian.java @@ -0,0 +1,87 @@ +/* MacCroatian.java -- Charset implementation for the MacCroatian character set. + 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.java.nio.charset; + +public final class MacCroatian extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, NONE, + 0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1, + 0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8, + 0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3, + 0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC, + 0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF, + 0x00AE, 0x0160, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x017D, 0x00D8, + 0x221E, 0x00B1, 0x2264, 0x2265, 0x2206, 0x00B5, 0x2202, 0x2211, + 0x220F, 0x0161, 0x222B, 0x00AA, 0x00BA, 0x03A9, 0x017E, 0x00F8, + 0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x0106, 0x00AB, + 0x010C, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153, + 0x0110, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA, + 0xF8FF, 0x00A9, 0x2044, 0x20AC, 0x2039, 0x203A, 0x00C6, 0x00BB, + 0x2013, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x0107, 0x00C1, + 0x010D, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4, + 0x0111, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC, + 0x00AF, 0x03C0, 0x00CB, 0x02DA, 0x00B8, 0x00CA, 0x00E6, 0x02C7 + }; + + public MacCroatian() + { + super("MacCroatian", new String[] {}, lookup); + } + +} // class MacCroatian diff --git a/libjava/classpath/gnu/java/nio/charset/MacCyrillic.java b/libjava/classpath/gnu/java/nio/charset/MacCyrillic.java new file mode 100644 index 000000000..a788fd2ad --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/MacCyrillic.java @@ -0,0 +1,87 @@ +/* MacCyrillic.java -- Charset implementation for the MacCyrillic character set. + 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.java.nio.charset; + +public final class MacCyrillic extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, NONE, + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x2020, 0x00B0, 0x0490, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x0406, + 0x00AE, 0x00A9, 0x2122, 0x0402, 0x0452, 0x2260, 0x0403, 0x0453, + 0x221E, 0x00B1, 0x2264, 0x2265, 0x0456, 0x00B5, 0x0491, 0x0408, + 0x0404, 0x0454, 0x0407, 0x0457, 0x0409, 0x0459, 0x040A, 0x045A, + 0x0458, 0x0405, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB, + 0x00BB, 0x2026, 0x00A0, 0x040B, 0x045B, 0x040C, 0x045C, 0x0455, + 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x201E, + 0x040E, 0x045E, 0x040F, 0x045F, 0x2116, 0x0401, 0x0451, 0x044F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x20AC + }; + + public MacCyrillic() + { + super("MacCyrillic", new String[] {}, lookup); + } + +} // class MacCyrillic diff --git a/libjava/classpath/gnu/java/nio/charset/MacDingbat.java b/libjava/classpath/gnu/java/nio/charset/MacDingbat.java new file mode 100644 index 000000000..71ef82b13 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/MacDingbat.java @@ -0,0 +1,87 @@ +/* MacDingbat.java -- Charset implementation for the MacDingbat character set. + 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.java.nio.charset; + +public final class MacDingbat extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x2701, 0x2702, 0x2703, 0x2704, 0x260E, 0x2706, 0x2707, + 0x2708, 0x2709, 0x261B, 0x261E, 0x270C, 0x270D, 0x270E, 0x270F, + 0x2710, 0x2711, 0x2712, 0x2713, 0x2714, 0x2715, 0x2716, 0x2717, + 0x2718, 0x2719, 0x271A, 0x271B, 0x271C, 0x271D, 0x271E, 0x271F, + 0x2720, 0x2721, 0x2722, 0x2723, 0x2724, 0x2725, 0x2726, 0x2727, + 0x2605, 0x2729, 0x272A, 0x272B, 0x272C, 0x272D, 0x272E, 0x272F, + 0x2730, 0x2731, 0x2732, 0x2733, 0x2734, 0x2735, 0x2736, 0x2737, + 0x2738, 0x2739, 0x273A, 0x273B, 0x273C, 0x273D, 0x273E, 0x273F, + 0x2740, 0x2741, 0x2742, 0x2743, 0x2744, 0x2745, 0x2746, 0x2747, + 0x2748, 0x2749, 0x274A, 0x274B, 0x25CF, 0x274D, 0x25A0, 0x274F, + 0x2750, 0x2751, 0x2752, 0x25B2, 0x25BC, 0x25C6, 0x2756, 0x25D7, + 0x2758, 0x2759, 0x275A, 0x275B, 0x275C, 0x275D, 0x275E, NONE, + 0x2768, 0x2769, 0x276A, 0x276B, 0x276C, 0x276D, 0x276E, 0x276F, + 0x2770, 0x2771, 0x2772, 0x2773, 0x2774, 0x2775, NONE, NONE, + NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, + NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, + NONE, 0x2761, 0x2762, 0x2763, 0x2764, 0x2765, 0x2766, 0x2767, + 0x2663, 0x2666, 0x2665, 0x2660, 0x2460, 0x2461, 0x2462, 0x2463, + 0x2464, 0x2465, 0x2466, 0x2467, 0x2468, 0x2469, 0x2776, 0x2777, + 0x2778, 0x2779, 0x277A, 0x277B, 0x277C, 0x277D, 0x277E, 0x277F, + 0x2780, 0x2781, 0x2782, 0x2783, 0x2784, 0x2785, 0x2786, 0x2787, + 0x2788, 0x2789, 0x278A, 0x278B, 0x278C, 0x278D, 0x278E, 0x278F, + 0x2790, 0x2791, 0x2792, 0x2793, 0x2794, 0x2192, 0x2194, 0x2195, + 0x2798, 0x2799, 0x279A, 0x279B, 0x279C, 0x279D, 0x279E, 0x279F, + 0x27A0, 0x27A1, 0x27A2, 0x27A3, 0x27A4, 0x27A5, 0x27A6, 0x27A7, + 0x27A8, 0x27A9, 0x27AA, 0x27AB, 0x27AC, 0x27AD, 0x27AE, 0x27AF, + NONE, 0x27B1, 0x27B2, 0x27B3, 0x27B4, 0x27B5, 0x27B6, 0x27B7, + 0x27B8, 0x27B9, 0x27BA, 0x27BB, 0x27BC, 0x27BD, 0x27BE, NONE + }; + + public MacDingbat() + { + super("MacDingbat", new String[] {}, lookup); + } + +} // class MacDingbat diff --git a/libjava/classpath/gnu/java/nio/charset/MacGreek.java b/libjava/classpath/gnu/java/nio/charset/MacGreek.java new file mode 100644 index 000000000..39ca84554 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/MacGreek.java @@ -0,0 +1,87 @@ +/* MacGreek.java -- Charset implementation for the MacGreek character set. + 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.java.nio.charset; + +public final class MacGreek extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, NONE, + 0x00C4, 0x00B9, 0x00B2, 0x00C9, 0x00B3, 0x00D6, 0x00DC, 0x0385, + 0x00E0, 0x00E2, 0x00E4, 0x0384, 0x00A8, 0x00E7, 0x00E9, 0x00E8, + 0x00EA, 0x00EB, 0x00A3, 0x2122, 0x00EE, 0x00EF, 0x2022, 0x00BD, + 0x2030, 0x00F4, 0x00F6, 0x00A6, 0x20AC, 0x00F9, 0x00FB, 0x00FC, + 0x2020, 0x0393, 0x0394, 0x0398, 0x039B, 0x039E, 0x03A0, 0x00DF, + 0x00AE, 0x00A9, 0x03A3, 0x03AA, 0x00A7, 0x2260, 0x00B0, 0x00B7, + 0x0391, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x0392, 0x0395, 0x0396, + 0x0397, 0x0399, 0x039A, 0x039C, 0x03A6, 0x03AB, 0x03A8, 0x03A9, + 0x03AC, 0x039D, 0x00AC, 0x039F, 0x03A1, 0x2248, 0x03A4, 0x00AB, + 0x00BB, 0x2026, 0x00A0, 0x03A5, 0x03A7, 0x0386, 0x0388, 0x0153, + 0x2013, 0x2015, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x0389, + 0x038A, 0x038C, 0x038E, 0x03AD, 0x03AE, 0x03AF, 0x03CC, 0x038F, + 0x03CD, 0x03B1, 0x03B2, 0x03C8, 0x03B4, 0x03B5, 0x03C6, 0x03B3, + 0x03B7, 0x03B9, 0x03BE, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BF, + 0x03C0, 0x03CE, 0x03C1, 0x03C3, 0x03C4, 0x03B8, 0x03C9, 0x03C2, + 0x03C7, 0x03C5, 0x03B6, 0x03CA, 0x03CB, 0x0390, 0x03B0, 0x00AD + }; + + public MacGreek() + { + super("MacGreek", new String[] {}, lookup); + } + +} // class MacGreek diff --git a/libjava/classpath/gnu/java/nio/charset/MacIceland.java b/libjava/classpath/gnu/java/nio/charset/MacIceland.java new file mode 100644 index 000000000..352314641 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/MacIceland.java @@ -0,0 +1,87 @@ +/* MacIceland.java -- Charset implementation for the MacIceland character set. + 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.java.nio.charset; + +public final class MacIceland extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, NONE, + 0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1, + 0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8, + 0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3, + 0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC, + 0x00DD, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF, + 0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8, + 0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211, + 0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x03A9, 0x00E6, 0x00F8, + 0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB, + 0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153, + 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA, + 0x00FF, 0x0178, 0x2044, 0x20AC, 0x00D0, 0x00F0, 0x00DE, 0x00FE, + 0x00FD, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1, + 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4, + 0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC, + 0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7 + }; + + public MacIceland() + { + super("MacIceland", new String[] {}, lookup); + } + +} // class MacIceland diff --git a/libjava/classpath/gnu/java/nio/charset/MacRoman.java b/libjava/classpath/gnu/java/nio/charset/MacRoman.java new file mode 100644 index 000000000..f1611b398 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/MacRoman.java @@ -0,0 +1,87 @@ +/* MacRoman.java -- Charset implementation for the MacRoman character set. + 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.java.nio.charset; + +public final class MacRoman extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, NONE, + 0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1, + 0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8, + 0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3, + 0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC, + 0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF, + 0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8, + 0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211, + 0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x03A9, 0x00E6, 0x00F8, + 0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB, + 0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153, + 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA, + 0x00FF, 0x0178, 0x2044, 0x20AC, 0x2039, 0x203A, 0xFB01, 0xFB02, + 0x2021, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1, + 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4, + 0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC, + 0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7 + }; + + public MacRoman() + { + super("MacRoman", new String[] {}, lookup); + } + +} // class MacRoman diff --git a/libjava/classpath/gnu/java/nio/charset/MacRomania.java b/libjava/classpath/gnu/java/nio/charset/MacRomania.java new file mode 100644 index 000000000..00a299b1e --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/MacRomania.java @@ -0,0 +1,87 @@ +/* MacRomania.java -- Charset implementation for the MacRomania character set. + 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.java.nio.charset; + +public final class MacRomania extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, NONE, + 0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1, + 0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8, + 0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3, + 0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC, + 0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF, + 0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x0102, 0x0218, + 0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211, + 0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x03A9, 0x0103, 0x0219, + 0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB, + 0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153, + 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA, + 0x00FF, 0x0178, 0x2044, 0x20AC, 0x2039, 0x203A, 0x021A, 0x021B, + 0x2021, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1, + 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4, + 0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC, + 0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7 + }; + + public MacRomania() + { + super("MacRomania", new String[] {}, lookup); + } + +} // class MacRomania diff --git a/libjava/classpath/gnu/java/nio/charset/MacSymbol.java b/libjava/classpath/gnu/java/nio/charset/MacSymbol.java new file mode 100644 index 000000000..a5e6f9428 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/MacSymbol.java @@ -0,0 +1,87 @@ +/* MacSymbol.java -- Charset implementation for the MacSymbol character set. + 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.java.nio.charset; + +public final class MacSymbol extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x2200, 0x0023, 0x2203, 0x0025, 0x0026, 0x220D, + 0x0028, 0x0029, 0x2217, 0x002B, 0x002C, 0x2212, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x2245, 0x0391, 0x0392, 0x03A7, 0x0394, 0x0395, 0x03A6, 0x0393, + 0x0397, 0x0399, 0x03D1, 0x039A, 0x039B, 0x039C, 0x039D, 0x039F, + 0x03A0, 0x0398, 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03C2, 0x03A9, + 0x039E, 0x03A8, 0x0396, 0x005B, 0x2234, 0x005D, 0x22A5, 0x005F, + 0xF8E5, 0x03B1, 0x03B2, 0x03C7, 0x03B4, 0x03B5, 0x03C6, 0x03B3, + 0x03B7, 0x03B9, 0x03D5, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BF, + 0x03C0, 0x03B8, 0x03C1, 0x03C3, 0x03C4, 0x03C5, 0x03D6, 0x03C9, + 0x03BE, 0x03C8, 0x03B6, 0x007B, 0x007C, 0x007D, 0x223C, NONE, + NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, + NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, + NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, + NONE, NONE, NONE, NONE, NONE, NONE, NONE, NONE, + 0x20AC, 0x03D2, 0x2032, 0x2264, 0x2044, 0x221E, 0x0192, 0x2663, + 0x2666, 0x2665, 0x2660, 0x2194, 0x2190, 0x2191, 0x2192, 0x2193, + 0x00B0, 0x00B1, 0x2033, 0x2265, 0x00D7, 0x221D, 0x2202, 0x2022, + 0x00F7, 0x2260, 0x2261, 0x2248, 0x2026, 0xF8E6, 0x23AF, 0x21B5, + 0x2135, 0x2111, 0x211C, 0x2118, 0x2297, 0x2295, 0x2205, 0x2229, + 0x222A, 0x2283, 0x2287, 0x2284, 0x2282, 0x2286, 0x2208, 0x2209, + 0x2220, 0x2207, 0x00AE, 0x00A9, 0x2122, 0x220F, 0x221A, 0x22C5, + 0x00AC, 0x2227, 0x2228, 0x21D4, 0x21D0, 0x21D1, 0x21D2, 0x21D3, + 0x22C4, 0x3008, NONE, NONE, NONE, 0x2211, 0x239B, 0x239C, + 0x239D, 0x23A1, 0x23A2, 0x23A3, 0x23A7, 0x23A8, 0x23A9, 0x23AA, + 0xF8FF, 0x3009, 0x222B, 0x2320, 0x23AE, 0x2321, 0x239E, 0x239F, + 0x23A0, 0x23A4, 0x23A5, 0x23A6, 0x23AB, 0x23AC, 0x23AD, NONE + }; + + public MacSymbol() + { + super("MacSymbol", new String[] {}, lookup); + } + +} // class MacSymbol diff --git a/libjava/classpath/gnu/java/nio/charset/MacThai.java b/libjava/classpath/gnu/java/nio/charset/MacThai.java new file mode 100644 index 000000000..b726c70de --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/MacThai.java @@ -0,0 +1,87 @@ +/* MacThai.java -- Charset implementation for the MacThai character set. + 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.java.nio.charset; + +public final class MacThai extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, NONE, + 0x00AB, 0x00BB, 0x2026, NONE, NONE, NONE, NONE, NONE, + NONE, NONE, NONE, NONE, NONE, 0x201C, 0x201D, NONE, + NONE, 0x2022, NONE, NONE, NONE, NONE, NONE, NONE, + NONE, NONE, NONE, NONE, NONE, 0x2018, 0x2019, NONE, + 0x00A0, 0x0E01, 0x0E02, 0x0E03, 0x0E04, 0x0E05, 0x0E06, 0x0E07, + 0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, 0x0E0E, 0x0E0F, + 0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, 0x0E15, 0x0E16, 0x0E17, + 0x0E18, 0x0E19, 0x0E1A, 0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, 0x0E1F, + 0x0E20, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27, + 0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F, + 0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37, + 0x0E38, 0x0E39, 0x0E3A, 0x2060, 0x200B, 0x2013, 0x2014, 0x0E3F, + 0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, 0x0E45, 0x0E46, 0x0E47, + 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D, 0x2122, 0x0E4F, + 0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57, + 0x0E58, 0x0E59, 0x00AE, 0x00A9, NONE, NONE, NONE, NONE + }; + + public MacThai() + { + super("MacThai", new String[] {}, lookup); + } + +} // class MacThai diff --git a/libjava/classpath/gnu/java/nio/charset/MacTurkish.java b/libjava/classpath/gnu/java/nio/charset/MacTurkish.java new file mode 100644 index 000000000..259802a3f --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/MacTurkish.java @@ -0,0 +1,87 @@ +/* MacTurkish.java -- Charset implementation for the MacTurkish character set. + 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.java.nio.charset; + +public final class MacTurkish extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, NONE, + 0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1, + 0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8, + 0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3, + 0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC, + 0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF, + 0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8, + 0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211, + 0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x03A9, 0x00E6, 0x00F8, + 0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB, + 0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153, + 0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA, + 0x00FF, 0x0178, 0x011E, 0x011F, 0x0130, 0x0131, 0x015E, 0x015F, + 0x2021, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1, + 0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4, + 0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0xF8A0, 0x02C6, 0x02DC, + 0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7 + }; + + public MacTurkish() + { + super("MacTurkish", new String[] {}, lookup); + } + +} // class MacTurkish diff --git a/libjava/classpath/gnu/java/nio/charset/Provider.java b/libjava/classpath/gnu/java/nio/charset/Provider.java new file mode 100644 index 000000000..8fc42e5f6 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/Provider.java @@ -0,0 +1,271 @@ +/* Provider.java -- + Copyright (C) 2002, 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.java.nio.charset; + +import java.nio.charset.Charset; +import java.nio.charset.spi.CharsetProvider; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; + +/** + * Charset provider for the required charsets. Used by + * {@link Charset#charsetForName} and * {@link Charset#availableCharsets}. + * + * Note: This class is a privileged class, because it can be instantiated without + * requiring the RuntimePermission("charsetProvider"). There is a check in + * java.nio.charset.spi.CharsetProvider to skip the security check if the provider + * is an instance of this class. + * + * @author Jesse Rosenstock + * @author Robert Schuster (thebohemian@gmx.net) + * @see Charset + */ +public final class Provider extends CharsetProvider +{ + private static Provider singleton; + + /** + * Map from charset name to charset canonical name. The strings + * are all lower-case to allow case-insensitive retrieval of + * Charset instances. + */ + private final HashMap canonicalNames; + + /** + * Map from lower-case canonical name to Charset. + * TODO: We may want to use soft references. We would then need to keep + * track of the class name to regenerate the object. + */ + private final HashMap charsets; + + /** + * We don't load all available charsets at the start + */ + private boolean extendedLoaded; + + // Package private to avoid an accessor method in PrivilegedAction below. + Provider () + { + extendedLoaded = false; + canonicalNames = new HashMap (); + charsets = new HashMap (); + + // US-ASCII aka ISO646-US + addCharset (new US_ASCII ()); + + // ISO-8859-1 aka ISO-LATIN-1 + addCharset (new ISO_8859_1 ()); + + // UTF-8 + addCharset (new UTF_8 ()); + + // UTF-16BE + addCharset (new UTF_16BE ()); + + // UTF-16LE + addCharset (new UTF_16LE ()); + + // UTF-16 + addCharset (new UTF_16 ()); + + // UTF-16LE (marked) + addCharset (new UnicodeLittle ()); + + // Windows-1250 aka cp-1250 (East European) + addCharset (new Windows1250 ()); + + // Windows-1251 (Cyrillic) + addCharset (new Windows1251 ()); + + // Windows-1252 aka cp-1252 (Latin-1) + addCharset (new Windows1252 ()); + + // Windows-1253 (Greek) + addCharset (new Windows1253 ()); + + // Windows-1254 (Turkish) + addCharset (new Windows1254 ()); + + // Windows-1257 (Baltic) + addCharset (new Windows1257 ()); + + // ISO-8859-2 aka ISO-LATIN-2 + addCharset (new ISO_8859_2 ()); + + // ISO-8859-4 aka ISO-LATIN-4 + addCharset (new ISO_8859_4 ()); + + // ISO-8859-5 (Cyrillic) + addCharset (new ISO_8859_5 ()); + + // ISO-8859-7 (Greek) + addCharset (new ISO_8859_7 ()); + + // ISO-8859-9 aka ISO-LATIN-5 + addCharset (new ISO_8859_9 ()); + + // ISO-8859-13 aka ISO-LATIN-7 + addCharset (new ISO_8859_13 ()); + + // ISO-8859-15 aka ISO-LATIN-9 + addCharset (new ISO_8859_15 ()); + + // KOI8 (Cyrillic) + addCharset (new KOI_8 ()); + } + + /** + * Load non-mandatory charsets. + */ + private synchronized void loadExtended () + { + if (extendedLoaded) + return; + + addCharset (new ISO_8859_3 ()); // ISO-8859-3 aka ISO-LATIN-3 + addCharset (new ISO_8859_6 ()); // ISO-8859-6 (Arabic) + addCharset (new ISO_8859_8 ()); // ISO-8859-8 (Hebrew) + + // Some more codepages + addCharset (new Cp424()); + addCharset (new Cp437()); + addCharset (new Cp737()); + addCharset (new Cp775()); + addCharset (new Cp850()); + addCharset (new Cp852()); + addCharset (new Cp855()); // IBM Cyrillic + addCharset (new Cp857()); // IBM Turkish + addCharset (new Cp860()); // MSDOS Portugese + addCharset (new Cp861()); // MSDOS Icelandic + addCharset (new Cp862()); // PC Hebrew + addCharset (new Cp863()); // MSDOS Can. French + addCharset (new Cp864()); // PC Arabic + addCharset (new Cp865()); // MSDOS Nordic + addCharset (new Cp866()); // MSDOS Russian + addCharset (new Cp869()); // IBM modern Greek + addCharset (new Cp874()); // IBM Thai + + addCharset (new MacCentralEurope()); + addCharset (new MacCroatian()); + addCharset (new MacCyrillic()); + addCharset (new MacDingbat()); + addCharset (new MacGreek()); + addCharset (new MacIceland()); + addCharset (new MacRoman()); + addCharset (new MacRomania()); + addCharset (new MacSymbol()); + addCharset (new MacThai()); + addCharset (new MacTurkish()); + addCharset (new MS874()); + + addCharset (new Windows1255()); + addCharset (new Windows1256()); + addCharset (new Windows1258()); + + extendedLoaded = true; + } + + public Iterator charsets () + { + loadExtended(); + return Collections.unmodifiableCollection (charsets.values ()) + .iterator (); + } + + /** + * Returns a Charset instance by converting the given + * name to lower-case, looking up the canonical charset + * name and finally looking up the Charset with that name. + * + *

The lookup is therefore case-insensitive.

+ * + * @returns The Charset having charsetName + * as its alias or null if no such Charset exist. + */ + public Charset charsetForName (String charsetName) + { + Charset cs = (Charset) charsets.get(canonicalNames.get(charsetName.toLowerCase())); + if (cs == null) + { + loadExtended(); + cs = (Charset) charsets.get(canonicalNames.get(charsetName.toLowerCase())); + } + return cs; + } + + /** + * Puts a Charset under its canonical name into the 'charsets' map. + * Then puts a mapping from all its alias names to the canonical name. + * + *

All names are converted to lower-case

. + * + * @param cs + */ + private void addCharset (Charset cs) + { + String canonicalName = cs.name().toLowerCase(); + charsets.put (canonicalName, cs); + + /* Adds a mapping between the canonical name + * itself making a lookup using that name + * no special case. + */ + canonicalNames.put(canonicalName, canonicalName); + + for (Iterator i = cs.aliases ().iterator (); i.hasNext (); ) + canonicalNames.put (((String) i.next()).toLowerCase(), canonicalName); + } + + public static synchronized Provider provider () + { + // The default provider is safe to instantiate. + if (singleton == null) + singleton = AccessController.doPrivileged + (new PrivilegedAction() + { + public Provider run() + { + return new Provider(); + } + }); + return singleton; + } +} diff --git a/libjava/classpath/gnu/java/nio/charset/US_ASCII.java b/libjava/classpath/gnu/java/nio/charset/US_ASCII.java new file mode 100644 index 000000000..373b37a1f --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/US_ASCII.java @@ -0,0 +1,162 @@ +/* US_ASCII.java -- + Copyright (C) 2002, 2004, 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.java.nio.charset; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CoderResult; + +/** + * US-ASCII charset. + * + * @author Jesse Rosenstock + * @modified Ian Rogers + */ +final class US_ASCII extends Charset +{ + US_ASCII () + { + /* Canonical charset name chosen according to: + * http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html + */ + super ("US-ASCII", new String[] { + /* These names are provided by + * http://www.iana.org/assignments/character-sets + */ + "iso-ir-6", + "ANSI_X3.4-1986", + "ISO_646.irv:1991", + "ASCII", + "ISO646-US", + "ASCII", + "us", + "IBM367", + "cp367", + "csASCII", + /* These names are provided by + * http://oss.software.ibm.com/cgi-bin/icu/convexp?s=ALL + */ + "ANSI_X3.4-1968", "iso_646.irv:1983", "ascii7", "646", + "windows-20127" + }); + } + + public boolean contains (Charset cs) + { + return cs instanceof US_ASCII; + } + + public CharsetDecoder newDecoder () + { + return new Decoder (this); + } + + public CharsetEncoder newEncoder () + { + return new Encoder (this); + } + + private static final class Decoder extends CharsetDecoder + { + /** Helper to decode loops */ + private static final ByteDecodeLoopHelper helper = new ByteDecodeLoopHelper() + { + protected boolean isMappable(byte b) + { + return b >= 0; + } + protected char mapToChar(byte b) + { + return (char)b; + } + }; + + // Package-private to avoid a trampoline constructor. + Decoder (Charset cs) + { + super (cs, 1.0f, 1.0f); + } + + protected CoderResult decodeLoop (ByteBuffer in, CharBuffer out) + { + return helper.decodeLoop(in, out); + } + } + + private static final class Encoder extends CharsetEncoder + { + /** Helper to encode loops */ + private static final ByteEncodeLoopHelper helper = new ByteEncodeLoopHelper() + { + protected boolean isMappable(char c) + { + return c <= 0x7f; + } + protected byte mapToByte(char c) + { + return (byte)c; + } + }; + // Package-private to avoid a trampoline constructor. + Encoder (Charset cs) + { + super (cs, 1.0f, 1.0f); + } + + public boolean canEncode(char c) + { + return c <= 0x7f; + } + + public boolean canEncode(CharSequence cs) + { + for (int i = 0; i < cs.length(); ++i) + if (! canEncode(cs.charAt(i))) + return false; + return true; + } + + protected CoderResult encodeLoop (CharBuffer in, ByteBuffer out) + { + return helper.encodeLoop(in, out); + } + } +} diff --git a/libjava/classpath/gnu/java/nio/charset/UTF_16.java b/libjava/classpath/gnu/java/nio/charset/UTF_16.java new file mode 100644 index 000000000..d91b15a7f --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/UTF_16.java @@ -0,0 +1,80 @@ +/* UTF_16.java -- + Copyright (C) 2002, 2004, 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.java.nio.charset; + +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; + +/** + * UTF-16 charset. + * + * @author Jesse Rosenstock + */ +final class UTF_16 extends Charset +{ + UTF_16 () + { + super ("UTF-16", new String[] { + // witnessed by the internet + "UTF16", + /* These names are provided by + * http://oss.software.ibm.com/cgi-bin/icu/convexp?s=ALL + */ + "ISO-10646-UCS-2", "unicode", "csUnicode", "ucs-2", "UnicodeBig" + }); + } + + public boolean contains (Charset cs) + { + return cs instanceof US_ASCII || cs instanceof ISO_8859_1 + || cs instanceof UTF_8 || cs instanceof UTF_16BE + || cs instanceof UTF_16LE || cs instanceof UTF_16; + } + + public CharsetDecoder newDecoder () + { + return new UTF_16Decoder (this, UTF_16Decoder.UNKNOWN_ENDIAN); + } + + public CharsetEncoder newEncoder () + { + return new UTF_16Encoder (this, UTF_16Encoder.BIG_ENDIAN, true); + } +} diff --git a/libjava/classpath/gnu/java/nio/charset/UTF_16BE.java b/libjava/classpath/gnu/java/nio/charset/UTF_16BE.java new file mode 100644 index 000000000..1299b015e --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/UTF_16BE.java @@ -0,0 +1,84 @@ +/* UTF_16BE.java -- + Copyright (C) 2002, 2004, 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.java.nio.charset; + +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; + +/** + * UTF-16BE charset. + * + * @author Jesse Rosenstock + */ +final class UTF_16BE extends Charset +{ + UTF_16BE () + { + super ("UTF-16BE", new String[] { + // witnessed by the internet + "UTF16BE", + /* These names are provided by + * http://oss.software.ibm.com/cgi-bin/icu/convexp?s=ALL + */ + "x-utf-16be", "ibm-1200", "ibm-1201", "ibm-5297", + "ibm-13488", "ibm-17584", "windows-1201", "cp1200", "cp1201", + "UTF16_BigEndian", + // see http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html + "UnicodeBigUnmarked" + }); + } + + public boolean contains (Charset cs) + { + return cs instanceof US_ASCII || cs instanceof ISO_8859_1 + || cs instanceof UTF_8 || cs instanceof UTF_16BE + || cs instanceof UTF_16LE || cs instanceof UTF_16; + } + + public CharsetDecoder newDecoder () + { + return new UTF_16Decoder (this, UTF_16Decoder.BIG_ENDIAN); + } + + public CharsetEncoder newEncoder () + { + return new UTF_16Encoder (this, UTF_16Encoder.BIG_ENDIAN, false); + } +} diff --git a/libjava/classpath/gnu/java/nio/charset/UTF_16Decoder.java b/libjava/classpath/gnu/java/nio/charset/UTF_16Decoder.java new file mode 100644 index 000000000..e078a6919 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/UTF_16Decoder.java @@ -0,0 +1,167 @@ +/* UTF_16Decoder.java -- + Copyright (C) 2002, 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.java.nio.charset; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CoderResult; + +/** + * Decoder for UTF-16, UTF-15LE, and UTF-16BE. + * + * @author Jesse Rosenstock + */ +final class UTF_16Decoder extends CharsetDecoder +{ + // byte orders + static final int BIG_ENDIAN = 0; + static final int LITTLE_ENDIAN = 1; + static final int UNKNOWN_ENDIAN = 2; + static final int MAYBE_BIG_ENDIAN = 3; + static final int MAYBE_LITTLE_ENDIAN = 4; + + private static final char BYTE_ORDER_MARK = 0xFEFF; + private static final char REVERSED_BYTE_ORDER_MARK = 0xFFFE; + + private final int originalByteOrder; + private int byteOrder; + + UTF_16Decoder (Charset cs, int byteOrder) + { + super (cs, 0.5f, 1.0f); + this.originalByteOrder = byteOrder; + this.byteOrder = byteOrder; + } + + protected CoderResult decodeLoop (ByteBuffer in, CharBuffer out) + { + // TODO: Optimize this in the case in.hasArray() / out.hasArray() + + int inPos = in.position (); + try + { + while (in.remaining () >= 2) + { + byte b1 = in.get (); + byte b2 = in.get (); + + // handle byte order mark + if (byteOrder == UNKNOWN_ENDIAN || + byteOrder == MAYBE_BIG_ENDIAN || + byteOrder == MAYBE_LITTLE_ENDIAN) + { + char c = (char) (((b1 & 0xFF) << 8) | (b2 & 0xFF)); + if (c == BYTE_ORDER_MARK) + { + if (byteOrder == MAYBE_LITTLE_ENDIAN) + { + return CoderResult.malformedForLength (2); + } + byteOrder = BIG_ENDIAN; + inPos += 2; + continue; + } + else if (c == REVERSED_BYTE_ORDER_MARK) + { + if (byteOrder == MAYBE_BIG_ENDIAN) + { + return CoderResult.malformedForLength (2); + } + byteOrder = LITTLE_ENDIAN; + inPos += 2; + continue; + } + else + { + // assume big or little endian, do not consume bytes, + // continue with normal processing + byteOrder = (byteOrder == MAYBE_LITTLE_ENDIAN ? + LITTLE_ENDIAN : BIG_ENDIAN); + } + } + + // FIXME: Change so you only do a single comparison here. + char c = (byteOrder == BIG_ENDIAN + ? (char) (((b1 & 0xFF) << 8) | (b2 & 0xFF)) + : (char) (((b2 & 0xFF) << 8) | (b1 & 0xFF))); + + if (0xD800 <= c && c <= 0xDFFF) + { + // c is a surrogate + + // make sure c is a high surrogate + if (c > 0xDBFF) + return CoderResult.malformedForLength (2); + if (in.remaining () < 2) + return CoderResult.UNDERFLOW; + byte b3 = in.get (); + byte b4 = in.get (); + char d = (byteOrder == BIG_ENDIAN + ? (char) (((b3 & 0xFF) << 8) | (b4 & 0xFF)) + : (char) (((b4 & 0xFF) << 8) | (b3 & 0xFF))); + // make sure d is a low surrogate + if (d < 0xDC00 || d > 0xDFFF) + return CoderResult.malformedForLength (2); + out.put (c); + out.put (d); + inPos += 4; + } + else + { + if (!out.hasRemaining ()) + return CoderResult.UNDERFLOW; + out.put (c); + inPos += 2; + } + } + + return CoderResult.UNDERFLOW; + } + finally + { + in.position (inPos); + } + } + + protected void implReset () + { + byteOrder = originalByteOrder; + } +} diff --git a/libjava/classpath/gnu/java/nio/charset/UTF_16Encoder.java b/libjava/classpath/gnu/java/nio/charset/UTF_16Encoder.java new file mode 100644 index 000000000..5283be491 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/UTF_16Encoder.java @@ -0,0 +1,145 @@ +/* UTF_16Encoder.java -- + Copyright (C) 2002 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.nio.charset; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CoderResult; + +/** + * Encoder for UTF-16, UTF-15LE, and UTF-16BE. + * + * @author Jesse Rosenstock + */ +final class UTF_16Encoder extends CharsetEncoder +{ + // byte orders + static final int BIG_ENDIAN = 0; + static final int LITTLE_ENDIAN = 1; + + private static final char BYTE_ORDER_MARK = 0xFEFF; + + private final ByteOrder byteOrder; + private final boolean useByteOrderMark; + private boolean needsByteOrderMark; + + UTF_16Encoder (Charset cs, int byteOrder, boolean useByteOrderMark) + { + super (cs, 2.0f, + useByteOrderMark ? 4.0f : 2.0f, + byteOrder == BIG_ENDIAN + ? new byte[] { (byte) 0xFF, (byte) 0xFD } + : new byte[] { (byte) 0xFD, (byte) 0xFF }); + this.byteOrder = (byteOrder == BIG_ENDIAN) ? + ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN; + this.useByteOrderMark = useByteOrderMark; + this.needsByteOrderMark = useByteOrderMark; + } + + protected CoderResult encodeLoop (CharBuffer in, ByteBuffer out) + { + // TODO: Optimize this in the case in.hasArray() / out.hasArray() + + ByteOrder originalBO = out.order(); + out.order(byteOrder); + + if (needsByteOrderMark) + { + if (out.remaining () < 2) + { + out.order(originalBO); + return CoderResult.OVERFLOW; + } + out.putChar (BYTE_ORDER_MARK); + needsByteOrderMark = false; + } + + int inPos = in.position (); + try + { + while (in.hasRemaining ()) + { + char c = in.get (); + if (0xD800 <= c && c <= 0xDFFF) + { + // c is a surrogate + + // make sure c is a high surrogate + if (c > 0xDBFF) + return CoderResult.malformedForLength (1); + if (in.remaining () < 1) + return CoderResult.UNDERFLOW; + char d = in.get (); + // make sure d is a low surrogate + if (d < 0xDC00 || d > 0xDFFF) + return CoderResult.malformedForLength (1); + out.putChar (c); + out.putChar (d); + inPos += 2; + } + else + { + if (out.remaining () < 2) + { + out.order(originalBO); + return CoderResult.OVERFLOW; + } + out.putChar (c); + inPos++; + } + } + out.order(originalBO); + return CoderResult.UNDERFLOW; + } + finally + { + in.position (inPos); + } + } + + protected void implReset () + { + needsByteOrderMark = useByteOrderMark; + } + + // TODO: override canEncode(char) and canEncode(CharSequence) + // for performance +} diff --git a/libjava/classpath/gnu/java/nio/charset/UTF_16LE.java b/libjava/classpath/gnu/java/nio/charset/UTF_16LE.java new file mode 100644 index 000000000..bede38aa8 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/UTF_16LE.java @@ -0,0 +1,83 @@ +/* UTF_16LE.java -- + Copyright (C) 2002, 2004, 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.java.nio.charset; + +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; + +/** + * UTF-16LE charset. + * + * @author Jesse Rosenstock + */ +final class UTF_16LE extends Charset +{ + UTF_16LE () + { + super ("UTF-16LE", new String[] { + // witnessed by the internet + "UTF16LE", + /* These names are provided by + * http://oss.software.ibm.com/cgi-bin/icu/convexp?s=ALL + */ + "x-utf-16le", "ibm-1202", "ibm-13490", "ibm-17586", + "UTF16_LittleEndian", + // see http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html + "UnicodeLittleUnmarked" + }); + } + + public boolean contains (Charset cs) + { + return cs instanceof US_ASCII || cs instanceof ISO_8859_1 + || cs instanceof UTF_8 || cs instanceof UTF_16BE + || cs instanceof UTF_16LE || cs instanceof UTF_16; + } + + public CharsetDecoder newDecoder () + { + return new UTF_16Decoder (this, UTF_16Decoder.LITTLE_ENDIAN); + } + + public CharsetEncoder newEncoder () + { + return new UTF_16Encoder (this, UTF_16Encoder.LITTLE_ENDIAN, false); + } +} diff --git a/libjava/classpath/gnu/java/nio/charset/UTF_8.java b/libjava/classpath/gnu/java/nio/charset/UTF_8.java new file mode 100644 index 000000000..0423efe51 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/UTF_8.java @@ -0,0 +1,311 @@ +/* UTF_8.java -- + Copyright (C) 2002, 2004, 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.java.nio.charset; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CoderResult; + +/** + * UTF-8 charset. + * + *

UTF-8 references: + *

+ * + * @author Jesse Rosenstock + */ +final class UTF_8 extends Charset +{ + UTF_8 () + { + super ("UTF-8", new String[] { + /* These names are provided by + * http://oss.software.ibm.com/cgi-bin/icu/convexp?s=ALL + */ + "ibm-1208", "ibm-1209", "ibm-5304", "ibm-5305", + "windows-65001", "cp1208", + // see http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html + "UTF8" + }); + } + + public boolean contains (Charset cs) + { + return cs instanceof US_ASCII || cs instanceof ISO_8859_1 + || cs instanceof UTF_8 || cs instanceof UTF_16BE + || cs instanceof UTF_16LE || cs instanceof UTF_16; + } + + public CharsetDecoder newDecoder () + { + return new Decoder (this); + } + + public CharsetEncoder newEncoder () + { + return new Encoder (this); + } + + private static final class Decoder extends CharsetDecoder + { + // Package-private to avoid a trampoline constructor. + Decoder (Charset cs) + { + super (cs, 1f, 1f); + } + + protected CoderResult decodeLoop (ByteBuffer in, CharBuffer out) + { + // TODO: Optimize this in the case in.hasArray() / out.hasArray() + int inPos = in.position(); + try + { + while (in.hasRemaining ()) + { + char c; + byte b1 = in.get (); + int highNibble = ((b1 & 0xFF) >> 4) & 0xF; + switch (highNibble) + { + case 0: case 1: case 2: case 3: + case 4: case 5: case 6: case 7: + if (out.remaining () < 1) + return CoderResult.OVERFLOW; + out.put ((char) b1); + inPos++; + break; + + case 0xC: case 0xD: + byte b2; + if (in.remaining () < 1) + return CoderResult.UNDERFLOW; + if (out.remaining () < 1) + return CoderResult.OVERFLOW; + if (!isContinuation (b2 = in.get ())) + return CoderResult.malformedForLength (1); + c = (char) (((b1 & 0x1F) << 6) | (b2 & 0x3F)); + // check that we had the shortest encoding + if (c <= 0x7F) + return CoderResult.malformedForLength (2); + out.put (c); + inPos += 2; + break; + + case 0xE: + byte b3; + if (in.remaining () < 2) + return CoderResult.UNDERFLOW; + if (out.remaining () < 1) + return CoderResult.OVERFLOW; + if (!isContinuation (b2 = in.get ())) + return CoderResult.malformedForLength (1); + if (!isContinuation (b3 = in.get ())) + return CoderResult.malformedForLength (1); + c = (char) (((b1 & 0x0F) << 12) + | ((b2 & 0x3F) << 6) + | (b3 & 0x3F)); + // check that we had the shortest encoding + if (c <= 0x7FF) + return CoderResult.malformedForLength (3); + out.put (c); + inPos += 3; + break; + + case 0xF: + byte b4; + if (in.remaining () < 3) + return CoderResult.UNDERFLOW; + if((b1&0x0F) > 4) + return CoderResult.malformedForLength (4); + if (out.remaining () < 2) + return CoderResult.OVERFLOW; + if (!isContinuation (b2 = in.get ())) + return CoderResult.malformedForLength (3); + if (!isContinuation (b3 = in.get ())) + return CoderResult.malformedForLength (2); + if (!isContinuation (b4 = in.get ())) + return CoderResult.malformedForLength (1); + int n = (((b1 & 0x3) << 18) + | ((b2 & 0x3F) << 12) + | ((b3 & 0x3F) << 6) + | (b4 & 0x3F)) - 0x10000; + char c1 = (char)(0xD800 | (n & 0xFFC00)>>10); + char c2 = (char)(0xDC00 | (n & 0x003FF)); + out.put (c1); + out.put (c2); + inPos += 4; + break; + + default: + return CoderResult.malformedForLength (1); + } + } + + return CoderResult.UNDERFLOW; + } + finally + { + // In case we did a get(), then encountered an error, reset the + // position to before the error. If there was no error, this + // will benignly reset the position to the value it already has. + in.position (inPos); + } + } + + private static boolean isContinuation (byte b) + { + return (b & 0xC0) == 0x80; + } + } + + private static final class Encoder extends CharsetEncoder + { + // Package-private to avoid a trampoline constructor. + Encoder (Charset cs) + { + // According to + // http://www-106.ibm.com/developerworks/unicode/library/utfencodingforms/index.html + // On average, English takes slightly over one unit per code point. + // Most Latin-script languages take about 1.1 bytes. Greek, Russian, + // Arabic and Hebrew take about 1.7 bytes, and most others (including + // Japanese, Chinese, Korean and Hindi) take about 3 bytes. + // We assume we will be dealing with latin scripts, and use 1.1 + // for averageBytesPerChar. + super (cs, 1.1f, 4.0f); + } + + protected CoderResult encodeLoop (CharBuffer in, ByteBuffer out) + { + int inPos = in.position(); + try + { + // TODO: Optimize this in the case in.hasArray() / out.hasArray() + while (in.hasRemaining ()) + { + int remaining = out.remaining (); + char c = in.get (); + + // UCS-4 range (hex.) UTF-8 octet sequence (binary) + // 0000 0000-0000 007F 0xxxxxxx + // 0000 0080-0000 07FF 110xxxxx 10xxxxxx + // 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx + + // Scalar Value UTF-16 byte 1 byte 2 byte 3 byte 4 + // 0000 0000 0xxx xxxx 0000 0000 0xxx xxxx 0xxx xxxx + // 0000 0yyy yyxx xxxx 0000 0yyy yyxx xxxx 110y yyyy 10xx xxxx + // zzzz yyyy yyxx xxxx zzzz yyyy yyxx xxxx 1110 zzzz 10yy yyyy 10xx xxxx + // u uuuu zzzz yyyy yyxx xxxx 1101 10ww wwzz zzyy 1111 0uuu 10uu zzzz 10yy yyyy 10xx xxxx + // + 1101 11yy yyxx xxxx + // Note: uuuuu = wwww + 1 + if (c <= 0x7F) + { + if (remaining < 1) + return CoderResult.OVERFLOW; + out.put ((byte) c); + inPos++; + } + else if (c <= 0x7FF) + { + if (remaining < 2) + return CoderResult.OVERFLOW; + out.put ((byte) (0xC0 | (c >> 6))); + out.put ((byte) (0x80 | (c & 0x3F))); + inPos++; + } + else if (0xD800 <= c && c <= 0xDFFF) + { + if (remaining < 4) + return CoderResult.OVERFLOW; + + // we got a low surrogate without a preciding high one + if (c > 0xDBFF) + return CoderResult.malformedForLength (1); + + // high surrogates + if (!in.hasRemaining ()) + return CoderResult.UNDERFLOW; + + char d = in.get (); + + // make sure d is a low surrogate + if (d < 0xDC00 || d > 0xDFFF) + return CoderResult.malformedForLength (1); + + // make the 32 bit value + // int value2 = (c - 0xD800) * 0x400 + (d - 0xDC00) + 0x10000; + int value = (((c & 0x3FF) << 10) | (d & 0x3FF)) + 0x10000; + // assert value == value2; + out.put ((byte) (0xF0 | ((value >> 18) & 0x07))); + out.put ((byte) (0x80 | ((value >> 12) & 0x3F))); + out.put ((byte) (0x80 | ((value >> 6) & 0x3F))); + out.put ((byte) (0x80 | ((value ) & 0x3F))); + inPos += 2; + } + else + { + if (remaining < 3) + return CoderResult.OVERFLOW; + + out.put ((byte) (0xE0 | (c >> 12))); + out.put ((byte) (0x80 | ((c >> 6) & 0x3F))); + out.put ((byte) (0x80 | (c & 0x3F))); + inPos++; + } + } + + return CoderResult.UNDERFLOW; + } + finally + { + // In case we did a get(), then encountered an error, reset the + // position to before the error. If there was no error, this + // will benignly reset the position to the value it already has. + in.position (inPos); + } + } + } +} diff --git a/libjava/classpath/gnu/java/nio/charset/UnicodeLittle.java b/libjava/classpath/gnu/java/nio/charset/UnicodeLittle.java new file mode 100644 index 000000000..2fa22cf32 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/UnicodeLittle.java @@ -0,0 +1,74 @@ +/* UnicodeLittle.java -- + 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.java.nio.charset; + +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; + +/** + * UTF-16 little endian with a byte-order mark + * Included for java.io completeness. + * ("UTF-16" is equal to UnicodeBig, and + * UTF-16BE/LE do not have a BOM + */ +final class UnicodeLittle extends Charset +{ + UnicodeLittle () + { + super ("UnicodeLittle", new String[] {}); + } + + public boolean contains (Charset cs) + { + return cs instanceof US_ASCII || cs instanceof ISO_8859_1 + || cs instanceof UTF_8 || cs instanceof UTF_16BE + || cs instanceof UTF_16LE || cs instanceof UTF_16; + } + + public CharsetDecoder newDecoder () + { + return new UTF_16Decoder (this, UTF_16Decoder.MAYBE_LITTLE_ENDIAN); + } + + public CharsetEncoder newEncoder () + { + return new UTF_16Encoder (this, UTF_16Encoder.LITTLE_ENDIAN, true); + } +} diff --git a/libjava/classpath/gnu/java/nio/charset/Windows1250.java b/libjava/classpath/gnu/java/nio/charset/Windows1250.java new file mode 100644 index 000000000..5845873e1 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/Windows1250.java @@ -0,0 +1,101 @@ +/* Windows1250.java -- Charset for Windows-1250 Character set. + 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.java.nio.charset; + +/** + * Encoding table for Windows-1250-Latin-1, + * aka cp1250 or Windows-1250 or whatever. + */ +public final class Windows1250 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x20AC, 0xFFFD, 0x201A, 0xFFFD, 0x201E, 0x2026, 0x2020, 0x2021, + 0xFFFD, 0x2030, 0x0160, 0x2039, 0x015A, 0x0164, 0x017D, 0x0179, + 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0xFFFD, 0x2122, 0x0161, 0x203A, 0x015B, 0x0165, 0x017E, 0x017A, + 0x00A0, 0x02C7, 0x02D8, 0x0141, 0x00A4, 0x0104, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x015E, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x017B, + 0x00B0, 0x00B1, 0x02DB, 0x0142, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x0105, 0x015F, 0x00BB, 0x013D, 0x02DD, 0x013E, 0x017C, + 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E, + 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7, + 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF, + 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F, + 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7, + 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9 + }; + + public Windows1250() + { + super("windows-1250", new String[] { + "Windows1250", + "ibm-5346_P100-1998", + "ibm-5346", + "cp1250", + "cp-1250", + "cp_1250", + "windows1250", + "windows_1250" + }, lookup); + } + +} // class Windows1250 diff --git a/libjava/classpath/gnu/java/nio/charset/Windows1251.java b/libjava/classpath/gnu/java/nio/charset/Windows1251.java new file mode 100644 index 000000000..052d0ea38 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/Windows1251.java @@ -0,0 +1,99 @@ +/* Windows1251.java -- Charset for Windows-1251 Cyrillic character set. + 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.java.nio.charset; + +/** + * Encoding table for Windows-1251 Cyrillic char set. + * aka cp1251 or Windows-1251 or whatever. + */ +public final class Windows1251 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021, + 0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F, + 0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + NONE, 0x2122, 0x0459, 0x203A, 0x045A, 0x045C, 0x045B, 0x045F, + 0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7, + 0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407, + 0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7, + 0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457, + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F + }; + + public Windows1251() + { + super("windows-1251", new String[] { + "Windows1251", + "cp1251", + "cp-1251", + "cp_1251", + "windows1251", + "windows_1251" + }, lookup); + } + +} // class Windows1251 diff --git a/libjava/classpath/gnu/java/nio/charset/Windows1252.java b/libjava/classpath/gnu/java/nio/charset/Windows1252.java new file mode 100644 index 000000000..738f62a33 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/Windows1252.java @@ -0,0 +1,98 @@ +/* Windows1252.java -- Charset for Windows-1252 Character set. + 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.java.nio.charset; + +/** + * Encoding table for Windows-1252-Latin-1, + * aka cp1252 or Windows-1252 or whatever. + */ +public final class Windows1252 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x20AC, NONE, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, NONE, 0x017D, NONE, + NONE, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, NONE, 0x017E, 0x0178, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF + }; + + public Windows1252() + { + super("windows-1252", new String[] { + "Windows1252", + "ibm-5348_P100-1997", + "ibm-5348", + "windows-1252", + "cp1252", + "cp-1252" + }, lookup); + } + +} // class Windows1252 diff --git a/libjava/classpath/gnu/java/nio/charset/Windows1253.java b/libjava/classpath/gnu/java/nio/charset/Windows1253.java new file mode 100644 index 000000000..711215851 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/Windows1253.java @@ -0,0 +1,99 @@ +/* Windows1253.java -- Charset for Windows-1253 Greek character set. + 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.java.nio.charset; + +/** + * Encoding table for Windows-1253 Greek char set. + * aka cp1253 or Windows-1253 or whatever. + */ +public final class Windows1253 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x20AC, NONE, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + NONE, 0x2030, NONE, 0x2039, NONE, NONE, NONE, NONE, + NONE, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + NONE, 0x2122, NONE, 0x203A, NONE, NONE, NONE, NONE, + 0x00A0, 0x0385, 0x0386, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, NONE, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x2015, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x00B5, 0x00B6, 0x00B7, + 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F, + 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, + 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, + 0x03A0, 0x03A1, NONE, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, + 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF, + 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, + 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, + 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, + 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, NONE + }; + + public Windows1253() + { + super("windows-1253", new String[] { + "Windows1253", + "cp1253", + "cp-1253", + "cp_1253", + "windows1253", + "windows_1253" + }, lookup); + } + +} // class Windows1253 diff --git a/libjava/classpath/gnu/java/nio/charset/Windows1254.java b/libjava/classpath/gnu/java/nio/charset/Windows1254.java new file mode 100644 index 000000000..cad2057ff --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/Windows1254.java @@ -0,0 +1,99 @@ +/* Windows1254.java -- Charset for Windows-1254 Turkish character set. + 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.java.nio.charset; + +/** + * Encoding table for Windows-1254 Turkish char set. + * aka cp1254 or Windows-1254 or whatever. + */ +public final class Windows1254 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x20AC, NONE, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, NONE, NONE, NONE, + NONE, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, NONE, NONE, 0x0178, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015E, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF + }; + + public Windows1254() + { + super("windows-1254", new String[] { + "Windows1254", + "cp1254", + "cp-1254", + "cp_1254", + "windows1254", + "windows_1254" + }, lookup); + } + +} // class Windows1254 diff --git a/libjava/classpath/gnu/java/nio/charset/Windows1255.java b/libjava/classpath/gnu/java/nio/charset/Windows1255.java new file mode 100644 index 000000000..0d954f6ce --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/Windows1255.java @@ -0,0 +1,99 @@ +/* Windows1255.java -- Charset for Windows-1255 Character set. + 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.java.nio.charset; + +/** + * Encoding table for Windows-1255 Hebrew char set. + * aka cp1255 or Windows-1255 or whatever. + */ +public final class Windows1255 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x20AC, 0xFFFD, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0xFFFD, 0x2039, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0xFFFD, 0x203A, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x20AA, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7, + 0x05B8, 0x05B9, 0xFFFD, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF, + 0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05F0, 0x05F1, 0x05F2, 0x05F3, + 0x05F4, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, + 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, + 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, + 0x05E8, 0x05E9, 0x05EA, 0xFFFD, 0xFFFD, 0x200E, 0x200F, 0xFFFD + }; + + public Windows1255() + { + super("windows-1255", new String[] { + "Windows1255", + "cp1255", + "cp-1255", + "cp_1255", + "windows1255", + "windows_1255" + }, lookup); + } + +} // class Windows1255 diff --git a/libjava/classpath/gnu/java/nio/charset/Windows1256.java b/libjava/classpath/gnu/java/nio/charset/Windows1256.java new file mode 100644 index 000000000..ac822e63d --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/Windows1256.java @@ -0,0 +1,99 @@ +/* Windows1256.java -- Charset for Windows-1256 Arabic character set. + 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.java.nio.charset; + +/** + * Encoding table for Windows-1256 Arabic char set. + * aka cp1256 or Windows-1256 or whatever. + */ +public final class Windows1256 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x20AC, 0x067E, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0679, 0x2039, 0x0152, 0x0686, 0x0698, 0x0688, + 0x06AF, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x06A9, 0x2122, 0x0691, 0x203A, 0x0153, 0x200C, 0x200D, 0x06BA, + 0x00A0, 0x060C, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x06BE, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x061B, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x061F, + 0x06C1, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, + 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, + 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x00D7, + 0x0637, 0x0638, 0x0639, 0x063A, 0x0640, 0x0641, 0x0642, 0x0643, + 0x00E0, 0x0644, 0x00E2, 0x0645, 0x0646, 0x0647, 0x0648, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0649, 0x064A, 0x00EE, 0x00EF, + 0x064B, 0x064C, 0x064D, 0x064E, 0x00F4, 0x064F, 0x0650, 0x00F7, + 0x0651, 0x00F9, 0x0652, 0x00FB, 0x00FC, 0x200E, 0x200F, 0x06D2 + }; + + public Windows1256() + { + super("windows-1256", new String[] { + "Windows1256", + "cp1256", + "cp-1256", + "cp_1256", + "windows1256", + "windows_1256" + }, lookup); + } + +} // class Windows1256 diff --git a/libjava/classpath/gnu/java/nio/charset/Windows1257.java b/libjava/classpath/gnu/java/nio/charset/Windows1257.java new file mode 100644 index 000000000..af7b61350 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/Windows1257.java @@ -0,0 +1,99 @@ +/* Windows1257.java -- Charset for Windows-1257 Baltic character set. + 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.java.nio.charset; + +/** + * Encoding table for Windows-1257 Baltic char set. + * aka cp1257 or Windows-1257 or whatever. + */ +public final class Windows1257 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x20AC, NONE, 0x201A, NONE, 0x201E, 0x2026, 0x2020, 0x2021, + NONE, 0x2030, NONE, 0x2039, NONE, 0x00A8, 0x02C7, 0x00B8, + NONE, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + NONE, 0x2122, NONE, 0x203A, NONE, 0x00AF, 0x02DB, NONE, + 0x00A0, NONE, 0x00A2, 0x00A3, 0x00A4, NONE, 0x00A6, 0x00A7, + 0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00C6, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00F8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6, + 0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112, + 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B, + 0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7, + 0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF, + 0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113, + 0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C, + 0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7, + 0x0173, 0x0142, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x02D9 + }; + + public Windows1257() + { + super("windows-1257", new String[] { + "Windows1257", + "cp1257", + "cp-1257", + "cp_1257", + "windows1257", + "windows_1257" + }, lookup); + } + +} // class Windows1257 diff --git a/libjava/classpath/gnu/java/nio/charset/Windows1258.java b/libjava/classpath/gnu/java/nio/charset/Windows1258.java new file mode 100644 index 000000000..7fd55d99c --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/Windows1258.java @@ -0,0 +1,99 @@ +/* Windows1258.java -- Charset for Windows-1258 Vietnamese character set. + 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.java.nio.charset; + +/** + * Encoding table for Windows-1258 Arabic char set. + * aka cp1258 or Windows-1258 or whatever. + */ +public final class Windows1258 extends ByteCharset +{ + + /** + * This is the lookup table for this encoding + */ + private static final char[] lookup = + { + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, + 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, + 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, + 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, + 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, + 0x0028, 0x0029, 0x002A, 0x002B, 0x002C, 0x002D, 0x002E, 0x002F, + 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, + 0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F, + 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, + 0x0048, 0x0049, 0x004A, 0x004B, 0x004C, 0x004D, 0x004E, 0x004F, + 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, + 0x0058, 0x0059, 0x005A, 0x005B, 0x005C, 0x005D, 0x005E, 0x005F, + 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, + 0x0068, 0x0069, 0x006A, 0x006B, 0x006C, 0x006D, 0x006E, 0x006F, + 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, + 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x007E, 0x007F, + 0x20AC, NONE, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, NONE, 0x2039, 0x0152, NONE, NONE, NONE, + NONE, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, NONE, 0x203A, 0x0153, NONE, NONE, 0x0178, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x0300, 0x00CD, 0x00CE, 0x00CF, + 0x0110, 0x00D1, 0x0309, 0x00D3, 0x00D4, 0x01A0, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x01AF, 0x0303, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0301, 0x00ED, 0x00EE, 0x00EF, + 0x0111, 0x00F1, 0x0323, 0x00F3, 0x00F4, 0x01A1, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x01B0, 0x20AB, 0x00FF + }; + + public Windows1258() + { + super("windows-1258", new String[] { + "Windows1258", + "cp1258", + "cp-1258", + "cp_1258", + "windows1258", + "windows_1258" + }, lookup); + } + +} // class Windows1258 diff --git a/libjava/classpath/gnu/java/nio/charset/iconv/IconvCharset.java b/libjava/classpath/gnu/java/nio/charset/iconv/IconvCharset.java new file mode 100644 index 000000000..2c59267b5 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/iconv/IconvCharset.java @@ -0,0 +1,85 @@ +/* IconvCharset.java -- Wrapper for iconv charsets. + 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.java.nio.charset.iconv; + +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; + +public final class IconvCharset extends Charset +{ + private IconvMetaData info; + + public IconvCharset(IconvMetaData info) + { + super(info.nioCanonical(), info.aliases()); + this.info = info; + if (newEncoder() == null || newDecoder() == null) + throw new IllegalArgumentException(); + } + + public boolean contains(Charset cs) + { + return false; + } + + public CharsetDecoder newDecoder() + { + try + { + return new IconvDecoder(this, info); + } + catch (IllegalArgumentException e) + { + return null; + } + } + + public CharsetEncoder newEncoder() + { + try + { + return new IconvEncoder(this, info); + } + catch (IllegalArgumentException e) + { + return null; + } + } +} diff --git a/libjava/classpath/gnu/java/nio/charset/iconv/IconvDecoder.java b/libjava/classpath/gnu/java/nio/charset/iconv/IconvDecoder.java new file mode 100644 index 000000000..86f7107f2 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/iconv/IconvDecoder.java @@ -0,0 +1,110 @@ +/* IconvDecoder.java -- + 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.java.nio.charset.iconv; + +import gnu.classpath.Pointer; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CoderResult; + +final class IconvDecoder extends CharsetDecoder +{ + IconvDecoder(Charset cs, IconvMetaData info) + { + super(cs, info.averageCharsPerByte(), info.maxCharsPerByte()); + openIconv(info.iconvName()); + } + + private Pointer data; + private int inremaining; + private int outremaining; + + private native void openIconv(String name); + + private native int decode(byte[] in, char[] out, int posIn, int remIn, + int posOut, int remOut); + + private native void closeIconv(); + + protected CoderResult decodeLoop(ByteBuffer in, CharBuffer out) + { + int remIn = in.remaining(); + int inPos = in.position(); + int outPos = out.position(); + int remOut = out.remaining(); + byte[] inArr; + int ret; + + if (in.hasArray()) + inArr = in.array(); + else + { + inArr = new byte[remIn]; + in.get(inArr); + } + + if (out.hasArray()) + { + ret = decode(inArr, out.array(), inPos, remIn, outPos, remOut); + out.position(outPos + (remOut - outremaining)); + } + else + { + char[] outArr = new char[remOut]; + ret = decode(inArr, outArr, inPos, remIn, outPos, remOut); + out.put(outArr, 0, (remOut - outremaining)); + } + in.position(inPos + (remIn - inremaining)); + + if (ret == 1) + return CoderResult.malformedForLength(1); + + if (in.remaining() == 0) + return CoderResult.UNDERFLOW; + return CoderResult.OVERFLOW; + } + + protected void finalize() + { + closeIconv(); + } +} diff --git a/libjava/classpath/gnu/java/nio/charset/iconv/IconvEncoder.java b/libjava/classpath/gnu/java/nio/charset/iconv/IconvEncoder.java new file mode 100644 index 000000000..4f7a34b28 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/iconv/IconvEncoder.java @@ -0,0 +1,110 @@ +/* IconvEncoder.java -- + 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.java.nio.charset.iconv; + +import gnu.classpath.Pointer; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CoderResult; + +final class IconvEncoder extends CharsetEncoder +{ + private Pointer data; + private int inremaining; + private int outremaining; + + private native void openIconv(String name); + + private native int encode(char[] in, byte[] out, int posIn, int remIn, + int posOut, int remOut); + + private native void closeIconv(); + + IconvEncoder(Charset cs, IconvMetaData info) + { + super(cs, info.averageBytesPerChar(), info.maxBytesPerChar()); + openIconv(info.iconvName()); + } + + protected CoderResult encodeLoop(CharBuffer in, ByteBuffer out) + { + int inPos = in.position(); + int outPos = out.position(); + int remIn = in.remaining(); + int remOut = out.remaining(); + char[] inArr; + int ret; + + if (in.hasArray()) + inArr = in.array(); + else + { + inArr = new char[remIn]; + in.get(inArr); + } + + if (out.hasArray()) + { + ret = encode(inArr, out.array(), inPos, remIn, outPos, remOut); + out.position(outPos + (remOut - outremaining)); + } + else + { + byte[] outArr = new byte[remOut]; + ret = encode(inArr, outArr, inPos, remIn, outPos, remOut); + out.put(outArr, 0, (remOut - outremaining)); + } + in.position(inPos + (remIn - inremaining)); + + if (ret == 1) + return CoderResult.malformedForLength(1); + + if (in.remaining() == 0) + return CoderResult.UNDERFLOW; + return CoderResult.OVERFLOW; + } + + protected void finalize() + { + closeIconv(); + } +} diff --git a/libjava/classpath/gnu/java/nio/charset/iconv/IconvMetaData.java b/libjava/classpath/gnu/java/nio/charset/iconv/IconvMetaData.java new file mode 100644 index 000000000..c4686a25a --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/iconv/IconvMetaData.java @@ -0,0 +1,450 @@ +/* IconvMetaData.java -- + 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.java.nio.charset.iconv; + +import java.util.HashMap; +import java.util.Vector; + +/** + * This is ugly glue. iconv doesn't have character metadata, + * so we include it here. + * + * TODO: Add more charsets which GNU iconv and the JDK support which aren't + * included here. + * + * @author Sven de Marothy + */ +final class IconvMetaData +{ + /** + * Map of names (and aliases) to metadata instances + */ + private static HashMap names; + + /** + * Vector of MetaData instances + */ + private static Vector charsets; + + /** + * Name to use with iconv (may differ from the nio canonical. + */ + private String iconvName; + + /** + * Average number of bytes per char. + */ + private float averageBperC; + + /** + * Maximum number of bytes per char. + */ + private float maxBperC; + + /** + * Average number of chars per byte. + */ + private float averageCperB; + + /** + * Maximum number of chars per byte. + */ + private float maxCperB; + + /** + * NIO canonical name. + */ + private String nioCanonical; + + /** + * Charset aliases. + */ + private String[] aliases; + + IconvMetaData(String nioCanonical, float averageBperC, float maxBperC, + float averageCperB, float maxCperB, String[] aliases, + String iconvName) + { + this.nioCanonical = nioCanonical; + this.iconvName = iconvName; + + this.averageBperC = averageBperC; + this.maxBperC = maxBperC; + this.averageCperB = averageCperB; + this.maxCperB = maxCperB; + this.aliases = aliases; + + names.put(nioCanonical, this); + names.put(iconvName, this); + for (int i = 0; i < aliases.length; i++) + names.put(aliases[i], this); + charsets.add(this); + } + + static Vector charsets() + { + return charsets; + } + + String[] aliases() + { + return aliases; + } + + String nioCanonical() + { + return nioCanonical; + } + + String iconvName() + { + return iconvName; + } + + float maxBytesPerChar() + { + return maxBperC; + } + + float maxCharsPerByte() + { + return maxCperB; + } + + float averageBytesPerChar() + { + return averageBperC; + } + + float averageCharsPerByte() + { + return averageCperB; + } + + static IconvMetaData get(String s) + { + return (IconvMetaData) names.get(s); + } + + static void setup() + { + names = new HashMap(); + charsets = new Vector(); + new IconvMetaData("Big5", 2.0f, 2.0f, 0.5f, 1.0f, + new String[] { "big-5", "csBig5" }, "Big5"); + + new IconvMetaData("Big5-HKSCS", 2.0f, 2.0f, 0.5f, 1.0f, + new String[] { "big5-hkscs", "Big5_HKSCS", "big5hkscs" }, + "Big5-HKSCS"); + + new IconvMetaData("EUC-CN", 2.0f, 2.0f, 0.5f, 1.0f, new String[] { }, + "EUC-CN"); + + new IconvMetaData("EUC-JP", 3.0f, 3.0f, 0.5f, 1.0f, + new String[] + { + "eucjis", "x-eucjp", "csEUCPkdFmtjapanese", "eucjp", + "Extended_UNIX_Code_Packed_Format_for_Japanese", + "x-euc-jp", "euc_jp" + }, "EUC-JP"); + + new IconvMetaData("EUC-KR", 2.0f, 2.0f, 0.5f, 1.0f, + new String[] + { + "ksc5601", "5601", "ksc5601_1987", "ksc_5601", + "ksc5601-1987", "euc_kr", "ks_c_5601-1987", "euckr", + "csEUCKR" + }, "EUC-KR"); + + new IconvMetaData("EUC-TW", 4.0f, 4.0f, 2.0f, 2.0f, + new String[] { "cns11643", "euc_tw", "euctw", }, "EUC-TW"); + + new IconvMetaData("GB18030", 4.0f, 4.0f, 1.0f, 2.0f, + new String[] { "gb18030-2000", }, "GB18030"); + + new IconvMetaData("GBK", 2.0f, 2.0f, 0.5f, 1.0f, new String[] { "GBK" }, + "GBK"); + + new IconvMetaData("ISO-2022-CN-CNS", 4.0f, 4.0f, 2.0f, 2.0f, + new String[] { "ISO2022CN_CNS" }, "ISO-2022-CN"); // will this work? + + new IconvMetaData("ISO-2022-CN-GB", 4.0f, 4.0f, 2.0f, 2.0f, + new String[] { "ISO2022CN_GB" }, "ISO-2022-CN"); // same here? + + new IconvMetaData("ISO-2022-KR", 4.0f, 4.0f, 1.0f, 1.0f, + new String[] { "ISO2022KR", "csISO2022KR" }, + "ISO-2022-KR"); + + new IconvMetaData("ISO-8859-1", 1.0f, 1.0f, 1.0f, 1.0f, + new String[] + { + "iso-ir-100", "ISO_8859-1", "latin1", "l1", "IBM819", + "CP819", "csISOLatin1", "8859_1", "ISO8859_1", + "ISO_8859_1", "ibm-819", "ISO_8859-1:1987", "819" + }, "ISO-8859-1"); + + new IconvMetaData("ISO-8859-13", 1.0f, 1.0f, 1.0f, 1.0f, + new String[] + { + "ISO8859_13", "8859_13", "ibm-921_P100-1995", "ibm-921", + "iso_8859_13", "iso8859_13", "iso-8859-13", "8859_13", + "cp921", "921" + }, "ISO-8859-13"); + + new IconvMetaData("ISO-8859-15", 1.0f, 1.0f, 1.0f, 1.0f, + new String[] + { + "8859_15", "csISOlatin9", "IBM923", "cp923", "923", + "LATIN0", "csISOlatin0", "ISO8859_15_FDIS", "L9", + "IBM-923", "ISO8859-15", "LATIN9", "ISO_8859-15", + "ISO-8859-15", + }, "ISO-8859-15"); + + new IconvMetaData("ISO-8859-2", 1.0f, 1.0f, 1.0f, 1.0f, + new String[] + { + "ISO8859_2", "8859_2", "ibm-912_P100-1995", "ibm-912", + "iso_8859_2", "iso8859_2", "iso-8859-2", + "ISO_8859-2:1987", "latin2", "csISOLatin2", + "iso-ir-101", "l2", "cp912", "912", "windows-28592" + }, "ISO-8859-2"); + + new IconvMetaData("ISO-8859-3", 1.0f, 1.0f, 1.0f, 1.0f, + new String[] + { + "ISO8859_3", "8859_3", "ibm-913_P100-2000", "ibm-913", + "iso_8859_3", "iso8859_3", "iso-8859-3", + "ISO_8859-3:1988", "latin3", "csISOLatin3", + "iso-ir-109", "l3", "cp913", "913", "windows-28593" + }, "ISO-8859-3"); + + new IconvMetaData("ISO-8859-4", 1.0f, 1.0f, 1.0f, 1.0f, + new String[] + { + "ISO8859_4", "8859_4", "ibm-914_P100-1995", "ibm-914", + "iso_8859_4", "iso8859_4", "iso-8859-4", "latin4", + "csISOLatin4", "iso-ir-110", "ISO_8859-4:1988", "l4", + "cp914", "914", "windows-28594" + }, "ISO-8859-4"); + + new IconvMetaData("ISO-8859-5", 1.0f, 1.0f, 1.0f, 1.0f, + new String[] + { + "ISO8859_5", "8859_5", "ibm-915_P100-1995", "ibm-915", + "iso_8859_5", "iso8859_5", "iso-8859-5", "cyrillic", + "csISOLatinCyrillic", "iso-ir-144", "ISO_8859-5:1988", + "cp915", "915", "windows-28595" + }, "ISO-8859-5"); + + new IconvMetaData("ISO-8859-6", 1.0f, 1.0f, 1.0f, 1.0f, + new String[] + { + "8859_6", "ibm-1089_P100-1995", "ibm-1089", + "iso_8859_6", "iso8859_6", "iso-8859-6", "arabic", + "csISOLatinArabic", "iso-ir-127", "ISO_8859-6:1987", + "ECMA-114", "ASMO-708", "8859_6", "cp1089", "1089", + "windows-28596", "ISO-8859-6-I", "ISO-8859-6-E" + }, "ISO-8859-6"); + + new IconvMetaData("ISO-8859-7", 1.0f, 1.0f, 1.0f, 1.0f, + new String[] + { + "ISO8859_7", "8859_7", "ibm-813_P100-1995", "ibm-813", + "iso_8859_7", "iso8859_7", "iso-8859-7", "greek", + "greek8", "ELOT_928", "ECMA-118", "csISOLatinGreek", + "iso-ir-126", "ISO_8859-7:1987", "cp813", "813", + "windows-28597" + }, "ISO-8859-7"); + + new IconvMetaData("ISO-8859-8", 1.0f, 1.0f, 1.0f, 1.0f, + new String[] + { + "ISO8859_8", "8859_8", "ibm-916_P100-1995", "ibm-916", + "iso_8859_8", "iso8859_8", "iso-8859-8", "hebrew", + "csISOLatinHebrew", "iso-ir-138", "ISO_8859-8:1988", + "ISO-8859-8-I", "ISO-8859-8-E", "cp916", "916", + "windows-28598" + }, "ISO-8859-8"); + + new IconvMetaData("ISO-8859-9", 1.0f, 1.0f, 1.0f, 1.0f, + new String[] + { + "ISO8859_9", "8859_9", "ibm-920_P100-1995", "ibm-920", + "iso8859_9", "iso-8859-9", "iso_8859_9", "latin5", + "csISOLatin5", "iso-ir-148", "ISO_8859-9:1989", "l5", + "cp920", "920", "windows-28599", "ECMA-128" + }, "ISO-8859-9"); + + new IconvMetaData("Johab", 2.0f, 2.0f, 0.5f, 1.0f, + new String[] { "ms1361", "ksc5601_1992", "ksc5601-1992", }, + "Johab"); + + new IconvMetaData("KOI8-R", 1.0f, 1.0f, 1.0f, 1.0f, + new String[] + { + "KOI8_R", "KOI8", "KOI-8", "KOI_8", "koi8-r", "koi8r", + "koi-8-r", "koi" + }, "KOI8-R"); + + new IconvMetaData("Shift_JIS", 2.0f, 2.0f, 0.5f, 1.0f, + new String[] + { + "shift-jis", "x-sjis", "ms_kanji", "shift_jis", + "csShiftJIS", "sjis", "pck", + }, "Shift_JIS"); + + new IconvMetaData("TIS-620", 1.0f, 1.0f, 1.0f, 1.0f, new String[] { }, + "TIS-620"); + + new IconvMetaData("US-ASCII", 1.0f, 1.0f, 1.0f, 1.0f, + new String[] + { + "IBM367", "ISO646-US", "ANSI_X3.4-1986", "cp367", + "ASCII", "iso_646.irv:1983", "646", "us", "iso-ir-6", + "csASCII", "ANSI_X3.4-1968", "ISO_646.irv:1991", + }, "US-ASCII"); + + new IconvMetaData("UTF-16", 2.0f, 4.0f, 0.5f, 1.0f, + new String[] + { + "UTF_16", "UTF16", "ISO-10646-UCS-2", "unicode", + "csUnicode", "ucs-2", "UnicodeBig" + }, "UTF-16"); + + new IconvMetaData("UTF-16BE", 2.0f, 2.0f, 0.5f, 1.0f, + new String[] + { + "X-UTF-16BE", "UTF_16BE", "UTF16BE", "ISO-10646-UCS-2", + "x-utf-16be", "ibm-1200", "ibm-1201", "ibm-5297", + "ibm-13488", "ibm-17584", "windows-1201", "cp1200", + "cp1201", "UnicodeBigUnmarked" + }, "UTF-16BE"); + + new IconvMetaData("UTF-16LE", 2.0f, 2.0f, 0.5f, 1.0f, + new String[] + { + "UTF_16LE", "UTF16LE", "X-UTF-16LE", "ibm-1202", + "ibm-13490", "ibm-17586", "UTF16_LittleEndian", + "UnicodeLittleUnmarked" + }, "UTF-16LE"); + + new IconvMetaData("UTF-8", 1.1f, 4.0f, 1.0f, 2.0f, + new String[] + { + "UTF8", "ibm-1208", "ibm-1209", "ibm-5304", "ibm-5305", + "windows-65001", "cp1208" + }, "UTF-8"); + + new IconvMetaData("windows-1250", 1.0f, 1.0f, 1.0f, 1.0f, + new String[] + { + "Windows1250", "ibm-5346_P100-1998", "ibm-5346", + "cp1250", "cp-1250", "cp_1250", "windows1250", + "windows_1250" + }, "windows-1250"); + + new IconvMetaData("windows-1251", 1.0f, 1.0f, 1.0f, 1.0f, + new String[] + { + "Windows1251", "cp1251", "cp-1251", "cp_1251", + "windows1251", "windows_1251" + }, "windows-1251"); + + new IconvMetaData("windows-1252", 1.0f, 1.0f, 1.0f, 1.0f, + new String[] + { + "Windows1252", "ibm-5348_P100-1997", "ibm-5348", + "windows-1252", "cp1252", "cp-1252" + }, "windows-1252"); + + new IconvMetaData("windows-1253", 1.0f, 1.0f, 1.0f, 1.0f, + new String[] + { + "Windows1253", "cp1253", "cp-1253", "cp_1253", + "windows1253", "windows_1253" + }, "windows-1253"); + + new IconvMetaData("windows-1254", 1.0f, 1.0f, 1.0f, 1.0f, + new String[] + { + "Windows1254", "cp1254", "cp-1254", "cp_1254", + "windows1254", "windows_1254" + }, "windows-1254"); + + new IconvMetaData("windows-1255", 1.0f, 1.0f, 1.0f, 1.0f, + new String[] + { + "Windows1255", "cp1255", "cp-1255", "cp_1255", + "windows1255", "windows_1255" + }, "windows-1255"); + + new IconvMetaData("windows-1256", 1.0f, 1.0f, 1.0f, 1.0f, + new String[] + { + "Windows1255", "cp1256", "cp-1256", "cp_1256", + "windows1256", "windows_1256" + }, "windows-1256"); + + new IconvMetaData("windows-1257", 1.0f, 1.0f, 1.0f, 1.0f, + new String[] + { + "Windows1255", "cp1257", "cp-1257", "cp_1257", + "windows1257", "windows_1257" + }, "windows-1257"); + + new IconvMetaData("windows-1258", 1.0f, 1.0f, 1.0f, 1.0f, + new String[] + { + "Windows1255", "cp1258", "cp-1258", "cp_1258", + "windows1258", "windows_1258" + }, "windows-1258"); + + new IconvMetaData("windows-936", 2.0f, 2.0f, 0.5f, 1.0f, + new String[] { "cp936", "ms-936", "ms936", "ms_936" }, + "windows-936"); + + new IconvMetaData("windows-949", 2.0f, 2.0f, 0.5f, 1.0f, + new String[] { "cp949", "ms-949", "ms_949", "ms949" }, + "cp949"); + + new IconvMetaData("windows-950", 2.0f, 2.0f, 0.5f, 1.0f, + new String[] { "cp950", "ms_950", "ms-950", "ms950", }, + "cp950"); + } +} diff --git a/libjava/classpath/gnu/java/nio/charset/iconv/IconvProvider.java b/libjava/classpath/gnu/java/nio/charset/iconv/IconvProvider.java new file mode 100644 index 000000000..1d5ca1052 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/iconv/IconvProvider.java @@ -0,0 +1,110 @@ +/* IconvProvider.java -- + 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.java.nio.charset.iconv; + +import java.nio.charset.Charset; +import java.nio.charset.spi.CharsetProvider; +import java.util.Iterator; +import java.util.Vector; + +/** + * Charset provider wrapping iconv. + * + * Note: This class is a privileged class, because it can be instantiated without + * requiring the RuntimePermission("charsetProvider"). There is a check in + * java.nio.charset.spi.CharsetProvider to skip the security check if the provider + * is an instance of this class. + * + * @author Sven de Marothy + */ +public final class IconvProvider extends CharsetProvider +{ + private static IconvProvider singleton; + + // Declaring the construtor public may violate the use of singleton. + // But it must be public so that an instance of this class can be + // created by Class.newInstance(), which is the case when this provider is + // defined in META-INF/services/java.nio.charset.spi.CharsetProvider. + public IconvProvider() + { + IconvMetaData.setup(); + } + + public Iterator charsets() + { + Vector names = IconvMetaData.charsets(); + Vector charsets = new Vector(); + for (int i = 0; i < names.size(); i++) + { + try + { + charsets.add(new IconvCharset((IconvMetaData) names.elementAt(i))); + } + catch (IllegalArgumentException e) + { + } + } + return charsets.iterator(); + } + + public Charset charsetForName(String charsetName) + { + try + { + IconvMetaData info = IconvMetaData.get(charsetName); + + // Try anyway if the set isn't found. + if (info == null) + info = new IconvMetaData(charsetName, 2.0f, 2.0f, 2.0f, 2.0f, + new String[] { }, charsetName); + return new IconvCharset(info); + } + catch (IllegalArgumentException e) + { + return null; + } + } + + public static synchronized IconvProvider provider() + { + if (singleton == null) + singleton = new IconvProvider(); + return singleton; + } +} diff --git a/libjava/classpath/gnu/java/nio/charset/package.html b/libjava/classpath/gnu/java/nio/charset/package.html new file mode 100644 index 000000000..002516da3 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.nio.charset + + +

+ + + diff --git a/libjava/classpath/gnu/java/nio/package.html b/libjava/classpath/gnu/java/nio/package.html new file mode 100644 index 000000000..87f0d9bf3 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.nio + + +

+ + + diff --git a/libjava/classpath/gnu/java/rmi/RMIMarshalledObjectInputStream.java b/libjava/classpath/gnu/java/rmi/RMIMarshalledObjectInputStream.java new file mode 100644 index 000000000..f96310750 --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/RMIMarshalledObjectInputStream.java @@ -0,0 +1,71 @@ +/* gnu.java.rmi.RMIMarshalledObjectInputStream + Copyright (C) 2002 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; + +import gnu.java.rmi.server.RMIObjectInputStream; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.ObjectInputStream; + +/** + * This class is only for java.rmi.MarshalledObject to deserialize object from + * objBytes and locBytes + */ + +public class RMIMarshalledObjectInputStream extends RMIObjectInputStream +{ + private ObjectInputStream locStream; + + public RMIMarshalledObjectInputStream(byte[] objBytes, byte[] locBytes) throws IOException + { + super(new ByteArrayInputStream(objBytes)); + if(locBytes != null) + locStream = new ObjectInputStream(new ByteArrayInputStream(locBytes)); + } + + //This method overrides RMIObjectInputStream's + protected Object getAnnotation() throws IOException, ClassNotFoundException + { + if(locStream == null) + return null; + return locStream.readObject(); + } + +} // End of RMIMarshalledObjectInputStream diff --git a/libjava/classpath/gnu/java/rmi/RMIMarshalledObjectOutputStream.java b/libjava/classpath/gnu/java/rmi/RMIMarshalledObjectOutputStream.java new file mode 100644 index 000000000..3bdf9239f --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/RMIMarshalledObjectOutputStream.java @@ -0,0 +1,78 @@ +/* gnu.java.rmi.RMIMarshalledObjectOutputStream + Copyright (C) 2002, 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.rmi; + +import gnu.java.rmi.server.RMIObjectOutputStream; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.OutputStream; + +/** + * This class is only for java.rmi.MarshalledObject to serialize object and + * got objBytes and locBytes + */ +public class RMIMarshalledObjectOutputStream extends RMIObjectOutputStream +{ + private ObjectOutputStream locStream; + private ByteArrayOutputStream locBytesStream; + + public RMIMarshalledObjectOutputStream(OutputStream objStream) throws IOException + { + super(objStream); + locBytesStream = new ByteArrayOutputStream(256); + locStream = new ObjectOutputStream(locBytesStream); + } + + //This method overrides RMIObjectOutputStream's. + protected void setAnnotation(String annotation) throws IOException{ + locStream.writeObject(annotation); + } + + public void flush() throws IOException { + super.flush(); + locStream.flush(); + } + + public byte[] getLocBytes(){ + return locBytesStream.toByteArray(); + } + +} // End of RMIMarshalledObjectOutputStream diff --git a/libjava/classpath/gnu/java/rmi/activation/ActivationSystemTransient.java b/libjava/classpath/gnu/java/rmi/activation/ActivationSystemTransient.java new file mode 100644 index 000000000..975e13fd1 --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/activation/ActivationSystemTransient.java @@ -0,0 +1,406 @@ +/* ActivationSystemTransient.java -- The transient RMI object activation system. + 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.activation; + +import java.rmi.MarshalledObject; +import java.rmi.RemoteException; +import java.rmi.activation.ActivationDesc; +import java.rmi.activation.ActivationException; +import java.rmi.activation.ActivationGroup; +import java.rmi.activation.ActivationGroupDesc; +import java.rmi.activation.ActivationGroupID; +import java.rmi.activation.ActivationID; +import java.rmi.activation.ActivationInstantiator; +import java.rmi.activation.ActivationMonitor; +import java.rmi.activation.ActivationSystem; +import java.rmi.activation.Activator; +import java.rmi.activation.UnknownGroupException; +import java.rmi.activation.UnknownObjectException; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; + +/** + * Provides the default transient activation system. + * + * @author Audrius Meskauskas (audriusa@bioinformatics.org) + */ +public class ActivationSystemTransient + extends DefaultActivationSystem + implements ActivationSystem, ActivationMonitor, Activator +{ + /** + * Maps group identifiers into group descriptions. + */ + protected final BidiTable groupDescs; + + /** + * Maps object identifiers into object activation descriptions + */ + protected final BidiTable descriptions; + + /** + * Maps group identifiers into already activated groups. + */ + protected transient final Map groupInstantiators = new Hashtable(); + + /** + * The cache of the activated objects, maps activation ids to remote + * object stubs. + */ + protected transient final Map activatedObjects = new HashMap(); + + /** + * The object incarnation counter. + */ + static long groupIncarnations = 0; + + /** + * The singleton of this activation system + */ + static ActivationSystem singleton; + + /** + * Set to true to print the event messages to console. + */ + public static boolean debug = false; + + + /** + * Creates the group which uses the given maps to store the data. + */ + protected ActivationSystemTransient(BidiTable objectDescriptions, + BidiTable groupDescriptiopns) + { + descriptions = objectDescriptions; + groupDescs = groupDescriptiopns; + } + + /** + * Creates the group with transient maps. + */ + protected ActivationSystemTransient() + { + this (new BidiTable(), new BidiTable()); + } + + public static ActivationSystem getInstance() + { + if (singleton == null) + singleton = new ActivationSystemTransient(); + return singleton; + } + + /** + * Activate the given object (try cache first if force = false) + */ + public MarshalledObject activate(ActivationID id, boolean force) + throws ActivationException, UnknownObjectException, RemoteException + { + if (! force) + { + synchronized (activatedObjects) + { + MarshalledObject object = (MarshalledObject) activatedObjects.get(id); + if (object != null) + return object; + } + } + + ActivationDesc desc = (ActivationDesc) descriptions.get(id); + if (desc == null) + throw new UnknownObjectException("Activating unknown object "+ + id == null ? "null" : id.toString()); + + ActivationInstantiator group = + (ActivationInstantiator) groupInstantiators.get(desc.getGroupID()); + + if (group == null) + { + // The group is not active - must be activated. + ActivationGroupID gid = desc.getGroupID(); + ActivationGroupDesc adesc = (ActivationGroupDesc) groupDescs.get(gid); + + if (adesc == null) + throw new UnknownGroupException("Activating unknown group " + + gid + " for "+ id+" this "+this); + + synchronized (ActivationSystemTransient.class) + { + groupIncarnations++; + } + + group = ActivationGroup.createGroup(gid, adesc, groupIncarnations); + activeGroup(gid, group, groupIncarnations); + } + + MarshalledObject object = group.newInstance(id, desc); + + synchronized (activatedObjects) + { + activatedObjects.put(id, object); + } + return object; + } + + /** + * Returns the activation monitor (THIS) and remebers the instantiator, used + * by that group. + */ + public ActivationMonitor activeGroup(ActivationGroupID id, + ActivationInstantiator group, + long incarnation) + throws UnknownGroupException, ActivationException, RemoteException + { + groupInstantiators.put(id, group); + return this; + } + + /** + * Get the activation descriptor for the given activation id. + * + * @return the activation descriptor, never null. + * @throws UnknownObjectException if such object is unknown. + */ + public ActivationDesc getActivationDesc(ActivationID id) + throws ActivationException, UnknownObjectException, RemoteException + { + ActivationDesc desc = (ActivationDesc) descriptions.get(id); + if (desc == null) + throw new UnknownObjectException("No desc for "+ + id == null ? "null" : id.toString()); + return desc; + } + + /** + * Get the descriptor of the given activation group. + * + * @return the activation group descriptor, never null. + * @throws UnknownGroupException if such group is unknown + */ + public ActivationGroupDesc getActivationGroupDesc(ActivationGroupID groupId) + throws ActivationException, UnknownGroupException, RemoteException + { + ActivationGroupDesc desc = (ActivationGroupDesc) groupDescs.get(groupId); + if (desc == null) + throw new UnknownGroupException(groupId == null ? "null" + : groupId.toString()); + return desc; + } + + /** + * Create the activation group id and put this id-descriptor combination into + * the group map. The new ID will only be created if this description has not + * already been registered, otherwise the id of the registered description + * will be returned. + */ + public ActivationGroupID registerGroup(ActivationGroupDesc groupDesc) + throws ActivationException, RemoteException + { + ActivationGroupID id = (ActivationGroupID) groupDescs.getKey(groupDesc); + if (id == null) + { + id = new ActivationGroupID(this); + groupDescs.put(id, groupDesc); + } + if (debug) + System.out.println("Register group " + id +":"+groupDesc+" this "+this); + + return id; + } + + /** + * Create the object activation id and put this id-descriptor combination into + * the group map. The new ID will only be created if this description has not + * already been registered, otherwise the id of the registered description + * will be returned. + */ + public ActivationID registerObject(ActivationDesc desc) + throws ActivationException, UnknownGroupException, RemoteException + { + ActivationID id = (ActivationID) descriptions.getKey(desc); + if (id == null) + { + id = new ActivationID(this); + descriptions.put(id, desc); + } + + if (debug) + System.out.println("Register object " + id +":"+desc+" this "+this); + + return id; + } + + /** + * Replace the activation descriptor, return the previous descriptor. + */ + public ActivationDesc setActivationDesc(ActivationID id, ActivationDesc desc) + throws ActivationException, UnknownObjectException, + UnknownGroupException, RemoteException + { + ActivationDesc prev = getActivationDesc(id); + descriptions.put(id, desc); + return prev; + } + + /** + * Replace the activation group descriptor, return the previous descriptor. + */ + public ActivationGroupDesc setActivationGroupDesc( + ActivationGroupID groupId, + ActivationGroupDesc groupDesc) + throws ActivationException, UnknownGroupException, RemoteException + { + ActivationGroupDesc prev = getActivationGroupDesc(groupId); + groupDescs.put(groupId, groupDesc); + return prev; + } + + /** + * Calls .shutdown on all bidirectional tables (has no effect if these + * table are not persistent). + */ + public void shutdown() throws RemoteException + { + descriptions.shutdown(); + groupDescs.shutdown(); + } + + /** + * Remove the group from the group map + */ + public void unregisterGroup(ActivationGroupID groupId) throws ActivationException, + UnknownGroupException, RemoteException + { + if (! groupDescs.containsKey(groupId)) + throw new UnknownGroupException("Unknown group "+groupId); + + groupDescs.removeKey(groupId); + groupInstantiators.remove(groupId); + } + + /** + * Remove the object id from the active object and description maps. + */ + public void unregisterObject(ActivationID id) throws ActivationException, + UnknownObjectException, RemoteException + { + if (! descriptions.containsKey(id)) + throw new UnknownObjectException("Unregistering unknown object"); + descriptions.removeKey(id); + + synchronized (activatedObjects) + { + activatedObjects.remove(id); + } + } + + /** + * Put the object into active object map. + */ + public void activeObject(ActivationID id, MarshalledObject obj) + throws UnknownObjectException, RemoteException + { + if (! descriptions.containsKey(id)) + throw new UnknownObjectException("Activating unknown object "+ + id+" this "+this); + try + { + synchronized (activatedObjects) + { + activatedObjects.put(id, obj.get()); + } + } + catch (RemoteException e) + { + throw e; + } + catch (Exception e) + { + UnknownObjectException un = new UnknownObjectException( + "Cannot get Remote for MarshalledObject of "+id); + un.detail = e; + throw un; + } + } + + /** + * Check if the group is known. Remove all active objects, belonging to + * that group, from the active object cache. + */ + public void inactiveGroup(ActivationGroupID groupId, long incarnation) + throws UnknownGroupException, RemoteException + { + if (! groupInstantiators.containsKey(groupId)) + throw new UnknownGroupException("Inactivating unkwnon group"); + + groupInstantiators.remove(groupId); + + // Remove all members of this group from the cache. + synchronized (activatedObjects) + { + Iterator iter = activatedObjects.keySet().iterator(); + ActivationID id; + ActivationDesc desc; + while (iter.hasNext()) + { + id = (ActivationID) iter.next(); + desc = (ActivationDesc) descriptions.get(id); + if (desc.getGroupID().equals(groupId)) + activatedObjects.remove(id); + } + } + } + + /** + * Removes this id from the active object cache. + */ + public void inactiveObject(ActivationID id) throws UnknownObjectException, + RemoteException + { + if (! descriptions.containsKey(id)) + throw new UnknownObjectException("Inactivating unknown object"); + + synchronized (activatedObjects) + { + activatedObjects.remove(id); + } + } +} diff --git a/libjava/classpath/gnu/java/rmi/activation/BidiTable.java b/libjava/classpath/gnu/java/rmi/activation/BidiTable.java new file mode 100644 index 000000000..ed9d9595a --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/activation/BidiTable.java @@ -0,0 +1,163 @@ +/* BidiHasthable.java -- Bidirectional hash table. + 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.activation; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * The bidirectional hash table, maps both a to b and b to a. + * + * @author Audrius Meskauskas (audriusa@bioinformatics.org) + */ +public class BidiTable +{ + /** + * Use serialVerionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * Maps keys to values + */ + protected Map k2v; + + /** + * Maps values to keys (in reverse) + */ + protected Map v2k; + + /** + * Create a new table that is ready to use. + */ + public BidiTable() + { + k2v = new HashMap(); + v2k = new HashMap(); + } + + /** + * Create a new instance where the hashtable fields are not initialised + * (called from derivatives that intialise hashtables in they own way. + * + * @param flags currently used to mark the different constructor only. + */ + protected BidiTable(int flags) + { + } + + /** + * Get key by value + */ + public synchronized Object getKey(Object value) + { + return v2k.get(value); + } + + /** + * Put key-value pair. + */ + public synchronized void put(Object key, Object value) + { + k2v.put(key, value); + v2k.put(value, key); + } + + /** + * Get value from key + */ + public synchronized Object get(Object key) + { + return k2v.get(key); + } + + /** + * Remove the key-value pair by key + */ + public synchronized void removeKey(Object key) + { + Object value = k2v.get(key); + if (value!=null) + { + k2v.remove(key); + v2k.remove(value); + } + } + + /** + * Check if the table contains this key. + */ + public synchronized boolean containsKey(Object key) + { + return k2v.containsKey(key); + } + + /** + * This method is called before exit and may be used to write the database + * to the disk. The default method does nothing. + */ + public synchronized void shutdown() + { + } + + /** + * Get the size. + */ + public synchronized int size() + { + return k2v.size(); + } + + /** + * Get the key collection. + */ + public synchronized Object[] keys() + { + Collection keys = k2v.keySet(); + Object[] k = new Object[keys.size()]; + + Iterator iter = keys.iterator(); + for (int i = 0; i < k.length; i++) + k[i] = iter.next(); + + return k; + } +} diff --git a/libjava/classpath/gnu/java/rmi/activation/DefaultActivationGroup.java b/libjava/classpath/gnu/java/rmi/activation/DefaultActivationGroup.java new file mode 100644 index 000000000..526d2ef40 --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/activation/DefaultActivationGroup.java @@ -0,0 +1,159 @@ +/* DefaultActivationGroup.java -- Default activation group. + 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.activation; + +import gnu.java.rmi.server.ActivatableServerRef; +import gnu.java.rmi.server.UnicastServer; + +import java.lang.reflect.Constructor; +import java.rmi.MarshalledObject; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.activation.ActivationDesc; +import java.rmi.activation.ActivationException; +import java.rmi.activation.ActivationGroup; +import java.rmi.activation.ActivationGroupID; +import java.rmi.activation.ActivationID; +import java.rmi.activation.UnknownObjectException; + +/** + * The default activation group class. This activation group assumes that + * all classes are accessible via current thread context class loader. + * The remote class loading is not supported for security reasons. The + * activation always occurs in the current jre. + * + * @author Audrius Meskauskas (audriusa@Bioinformatics.org) + */ +public class DefaultActivationGroup + extends ActivationGroup +{ + /** + * Use the serialVersionUID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * Used during the group creation (required constructor). + */ + static final Class[] cConstructorTypes = new Class[] + { + ActivationID.class, + MarshalledObject.class + }; + + + /** + * Create the new default activation group. + * + * @param id the group activation id. + * @param data may contain the group initialization data (unused and can be + * null) + * @throws RemoteException if the super constructor does + */ + public DefaultActivationGroup(ActivationGroupID id, MarshalledObject data) + throws RemoteException + { + super(id); + } + + + /** + * May be overridden and used as a hook. This method is called each time + * the new object is instantiated. + */ + public void activeObject(ActivationID id, Remote obj) + throws ActivationException, UnknownObjectException, RemoteException + { + // Nothing to do (the monitor is already notified in newInstance) + } + + /** + * Create the new instance of the object, using the class name and location + * information, stored in the passed descriptor. The method expects the object + * class to have the two parameter constructor, the first parameter being the + * {@link ActivationID} and the second the {@link MarshalledObject}. + * + * @param id the object activation id + * @param desc the activation descriptor, providing the information, necessary + * to create and activate the object + * @return the marshalled object, containing the exported stub of the created + * object + * @throws ActivationException if the activation fails due any reason + */ + public MarshalledObject newInstance(ActivationID id, ActivationDesc desc) + throws ActivationException, RemoteException + { + try + { + if (ActivationSystemTransient.debug) + System.out.println("Instantiating "+desc.getClassName()); + + Remote object; + Class objectClass; + + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + objectClass = loader.loadClass(desc.getClassName()); + Constructor constructor = objectClass.getConstructor(cConstructorTypes); + object = (Remote) constructor.newInstance( + new Object[] { id, desc.getData() }); + + // Make the object accessible and create the stub. + ActivatableServerRef ref = UnicastServer.getActivatableRef(id); + Remote stub = ref.exportObject(object); + + MarshalledObject marsh = new MarshalledObject(stub); + + // Notify the activation monitor. + activeObject(id, marsh); + + // Make call to the hook that may be overridden. + activeObject(id, stub); + + return marsh; + } + catch (Exception e) + { + ActivationException acex = new ActivationException( + "Unable to activate "+ desc.getClassName() + + " from "+ desc.getLocation(), e); + throw acex; + } + } + +} diff --git a/libjava/classpath/gnu/java/rmi/activation/DefaultActivationSystem.java b/libjava/classpath/gnu/java/rmi/activation/DefaultActivationSystem.java new file mode 100644 index 000000000..3d1625052 --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/activation/DefaultActivationSystem.java @@ -0,0 +1,118 @@ +/* DefaultActivationSystem.java -- Default RMI activation system + 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.activation; + +import java.rmi.activation.ActivationSystem; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; + +/** + * Finds and returns the default activation system for this jre. + * + * @author Audrius Meskauskas (audriusa@bioinformatics.org) + */ +public abstract class DefaultActivationSystem +{ + /** + * The activation system (assigned if once found). + */ + static ActivationSystem system; + + /** + * The default activation registry port. + */ + static int ACTIVATION_REGISTRY_PORT; + + /** + * The name of the activation system registry port property. + */ + static String AS_PORT_PROPERTY = "java.rmi.activation.port"; + + /** + * The defalut name of the activation system in the activation registry. + */ + static String ACTIVATION_SYSTEM_NAME = "java.rmi.activation.ActivationSystem"; + + /** + * Get the activation system, default for this jre. If no external activation + * system exists, the internal activation system will be activated. This + * internal system is limited in capabilities and should be used exclusively + * for automated testing, to avoid necessity of starting rmi daemon during + * testing process. + */ + public static ActivationSystem get() + { + if (system == null) + try + { + // Obtain the port: + String asr = System.getProperty("java.rmi.activation.port"); + + if (asr != null) + { + try + { + ACTIVATION_REGISTRY_PORT = Integer.parseInt(asr); + if (ACTIVATION_REGISTRY_PORT <= 0) + throw new InternalError("Invalid " + asr + " value, " + + ACTIVATION_REGISTRY_PORT); + } + catch (NumberFormatException e) + { + throw new InternalError("Unable to parse " + asr + + " to integer"); + } + } + else + ACTIVATION_REGISTRY_PORT = ActivationSystem.SYSTEM_PORT; + + // Expect the naming service running first. + // The local host may want to use the shared registry + Registry r = LocateRegistry.getRegistry(ACTIVATION_REGISTRY_PORT); + ActivationSystem system = (ActivationSystem) r.lookup(ACTIVATION_SYSTEM_NAME); + return system; + } + catch (Exception ex) + { + system = ActivationSystemTransient.getInstance(); + } + + return system; + } +} diff --git a/libjava/classpath/gnu/java/rmi/dgc/DGCImpl.java b/libjava/classpath/gnu/java/rmi/dgc/DGCImpl.java new file mode 100644 index 000000000..5efbf2796 --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/dgc/DGCImpl.java @@ -0,0 +1,182 @@ +/* DGCImpl.java -- + Copyright (c) 1996, 1997, 1998, 1999, 2002, 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.java.rmi.dgc; + +import gnu.java.rmi.server.UnicastServer; +import gnu.java.rmi.server.UnicastServerRef; + +import java.rmi.RemoteException; +import java.rmi.dgc.DGC; +import java.rmi.dgc.Lease; +import java.rmi.dgc.VMID; +import java.rmi.server.ObjID; +import java.rmi.server.RMISocketFactory; +import java.util.Collection; +import java.util.TimerTask; + +/** + * The DGC implementation is used for the server side during the distributed + * garbage collection. This interface contains the two methods: dirty and clean. + * A dirty call is made when a remote reference is unmarshaled in a client. A + * corresponding clean call is made by client it no longer uses that remote + * reference. A reference to a remote object is also automatically released + * after so called lease period that starts after the dirty call is received. It + * is the client's responsibility to renew the leases, by making additional + * dirty calls before such leases expire. + */ +public class DGCImpl + extends UnicastServerRef + implements DGC +{ + /* + * The DGCImpl extends UnicastServerRef and not UnicastRemoteObject, because + * UnicastRemoteObject must exportObject automatically. + */ + + /** + * Use the serial version UID for interoperability. + */ + private static final long serialVersionUID = 1; + + /** + * Protects the array of object Id's for the scheduled period of time + * (lease). After the time expires, the protector is automatically discarded, + * making the references unprotected and hence applicable for the garbage + * collection. + */ + class RefProtector extends TimerTask + { + /** + * The corresponding server references to protect. Each Id may contain + * multiple references that are stored to collection. + */ + Collection[] references; + + /** + * Create the new instance of the reference protector that protects the + * given array of ids and exists for the given period of time. + * + * @param ids the ids to protect. + */ + RefProtector(ObjID[] ids, long timeToLive) + { + references = new Collection[ids.length]; + for (int i = 0; i < ids.length; i++) + { + references[i] = UnicastServer.getExported(ids[i]); + } + + // Schedule the existence. + LeaseRenewingTask.timer.schedule(this, timeToLive); + } + + /** + * Break all links, ensuring easy collection of the references by the gc. + */ + public void run() + { + for (int i = 0; i < references.length; i++) + { + references[i].clear(); + references[i] = null; + } + } + } + + /** + * This defauld lease value is used if the lease value, passed to the + * {@link #dirty} is equal to zero. + */ + static final long LEASE_VALUE = 600000L; + + /** + * Create the new DGC implementation. + * + * @throws RemoteException if the super constructor throws or the + * socket factory fails. + */ + public DGCImpl() throws RemoteException + { + super(new ObjID(ObjID.DGC_ID), 0, RMISocketFactory.getSocketFactory()); + } + + /** + * Mark the given objects referecnes as used on the client side. + * + * @param ids the ids of the used objects. + * @param sequenceNum the number of the call (used to detect and discard late + * calls). + * @param lease the requested lease + * @return the granted lease + */ + public Lease dirty(ObjID[] ids, long sequenceNum, Lease lease) + throws RemoteException + { + // We do not fill in VMID because in this implementation it is not used. + long leaseValue = lease.getValue(); + + // Grant the maximal default lease time if the passed value is zero. + if (leaseValue <= 0) + leaseValue = LEASE_VALUE; + + // Create (and shedule of the given existence) the new reference + // protector. + new RefProtector(ids, leaseValue); + + lease = new Lease(lease.getVMID(), leaseValue); + return lease; + } + + /** + * Mark the given objects as no longer used on the client side. + * + * @param ids the ids of the objects that are no longer used. + * @param sequenceNum the number of the call (used to detect and discard late + * calls) + * @param vmid the VMID of the client. + * @param strong make the "strong" clean call. + */ + public void clean(ObjID[] ids, long sequenceNum, VMID vmid, boolean strong) + throws RemoteException + { + // Not implemented + // TODO implement + } + +} // End of DGCImpl diff --git a/libjava/classpath/gnu/java/rmi/dgc/DGCImpl_Skel.java b/libjava/classpath/gnu/java/rmi/dgc/DGCImpl_Skel.java new file mode 100644 index 000000000..a40b48ca0 --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/dgc/DGCImpl_Skel.java @@ -0,0 +1,144 @@ +/* DGCImpl_Skel.java + Copyright (C) 2002 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. */ + + +// Skel class generated by rmic - DO NOT EDIT! + +package gnu.java.rmi.dgc; + +public final class DGCImpl_Skel + implements java.rmi.server.Skeleton +{ + private static final long interfaceHash = -669196253586618813L; + + private static final java.rmi.server.Operation[] operations = { + new java.rmi.server.Operation("void clean(java.rmi.server.ObjID[], long, java.rmi.dgc.VMID, boolean"), + new java.rmi.server.Operation("java.rmi.dgc.Lease dirty(java.rmi.server.ObjID[], long, java.rmi.dgc.Lease") + }; + + public java.rmi.server.Operation[] getOperations() { + return ((java.rmi.server.Operation[]) operations.clone()); + } + + public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall call, int opnum, long hash) throws java.lang.Exception { + if (opnum < 0) { + if (hash == -5803803475088455571L) { + opnum = 0; + } + else if (hash == -8139341527526761862L) { + opnum = 1; + } + else { + throw new java.rmi.server.SkeletonMismatchException("interface hash mismatch"); + } + } + else if (hash != interfaceHash) { + throw new java.rmi.server.SkeletonMismatchException("interface hash mismatch"); + } + + gnu.java.rmi.dgc.DGCImpl server = (gnu.java.rmi.dgc.DGCImpl)obj; + switch (opnum) { + case 0: + { + java.rmi.server.ObjID[] $param_0; + long $param_1; + java.rmi.dgc.VMID $param_2; + boolean $param_3; + try { + java.io.ObjectInput in = call.getInputStream(); + $param_0 = (java.rmi.server.ObjID[])in.readObject(); + $param_1 = (long)in.readLong(); + $param_2 = (java.rmi.dgc.VMID)in.readObject(); + $param_3 = (boolean)in.readBoolean(); + + } + catch (java.io.IOException e) { + throw new java.rmi.UnmarshalException("error unmarshalling arguments", e); + } + catch (java.lang.ClassCastException e) { + throw new java.rmi.UnmarshalException("error unmarshalling arguments", e); + } + finally { + call.releaseInputStream(); + } + server.clean($param_0, $param_1, $param_2, $param_3); + try { + java.io.ObjectOutput out = call.getResultStream(true); + } + catch (java.io.IOException e) { + throw new java.rmi.MarshalException("error marshalling return", e); + } + break; + } + + case 1: + { + java.rmi.server.ObjID[] $param_0; + long $param_1; + java.rmi.dgc.Lease $param_2; + try { + java.io.ObjectInput in = call.getInputStream(); + $param_0 = (java.rmi.server.ObjID[])in.readObject(); + $param_1 = (long)in.readLong(); + $param_2 = (java.rmi.dgc.Lease)in.readObject(); + + } + catch (java.io.IOException e) { + throw new java.rmi.UnmarshalException("error unmarshalling arguments", e); + } + catch (java.lang.ClassCastException e) { + throw new java.rmi.UnmarshalException("error unmarshalling arguments", e); + } + finally { + call.releaseInputStream(); + } + java.rmi.dgc.Lease $result = server.dirty($param_0, $param_1, $param_2); + try { + java.io.ObjectOutput out = call.getResultStream(true); + out.writeObject($result); + } + catch (java.io.IOException e) { + throw new java.rmi.MarshalException("error marshalling return", e); + } + break; + } + + default: + throw new java.rmi.UnmarshalException("invalid method number"); + } + } +} diff --git a/libjava/classpath/gnu/java/rmi/dgc/DGCImpl_Stub.java b/libjava/classpath/gnu/java/rmi/dgc/DGCImpl_Stub.java new file mode 100644 index 000000000..dac8b6f4c --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/dgc/DGCImpl_Stub.java @@ -0,0 +1,158 @@ +/* DGCImpl_Stub.java + Copyright (C) 2002 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. */ + + +// Stub class generated by rmic - DO NOT EDIT! + +package gnu.java.rmi.dgc; + +public final class DGCImpl_Stub + extends java.rmi.server.RemoteStub + implements java.rmi.dgc.DGC +{ + private static final long serialVersionUID = 2L; + + private static final long interfaceHash = -669196253586618813L; + + private static boolean useNewInvoke; + + private static final java.rmi.server.Operation[] operations = { + new java.rmi.server.Operation("void clean(java.rmi.server.ObjID[], long, java.rmi.dgc.VMID, boolean)"), + new java.rmi.server.Operation("java.rmi.dgc.Lease dirty(java.rmi.server.ObjID[], long, java.rmi.dgc.Lease)") + }; + + private static java.lang.reflect.Method $method_clean_0; + private static java.lang.reflect.Method $method_dirty_1; + + static { + try { + java.rmi.server.RemoteRef.class.getMethod("invoke", new java.lang.Class[] { java.rmi.Remote.class, java.lang.reflect.Method.class, java.lang.Object[].class, long.class }); + useNewInvoke = true; + $method_clean_0 = gnu.java.rmi.dgc.DGCImpl.class.getMethod("clean", new java.lang.Class[] {java.rmi.server.ObjID[].class, long.class, java.rmi.dgc.VMID.class, boolean.class}); + $method_dirty_1 = gnu.java.rmi.dgc.DGCImpl.class.getMethod("dirty", new java.lang.Class[] {java.rmi.server.ObjID[].class, long.class, java.rmi.dgc.Lease.class}); + + } + catch (java.lang.NoSuchMethodException e) { + useNewInvoke = false; + } + } + + public DGCImpl_Stub() { + super(); + } + public DGCImpl_Stub(java.rmi.server.RemoteRef ref) { + super(ref); + } + + public void clean(java.rmi.server.ObjID[] $param_0, long $param_1, java.rmi.dgc.VMID $param_2, boolean $param_3) throws java.rmi.RemoteException { + try { + if (useNewInvoke) { + ref.invoke(this, $method_clean_0, new java.lang.Object[] {$param_0, new java.lang.Long($param_1), $param_2, Boolean.valueOf($param_3)}, -5803803475088455571L); + } + else { + java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject)this, operations, 0, interfaceHash); + try { + java.io.ObjectOutput out = call.getOutputStream(); + out.writeObject($param_0); + out.writeLong($param_1); + out.writeObject($param_2); + out.writeBoolean($param_3); + } + catch (java.io.IOException e) { + throw new java.rmi.MarshalException("error marshalling arguments", e); + } + ref.invoke(call); + try { + java.io.ObjectInput in = call.getInputStream(); + } + catch (java.io.IOException e) { + throw new java.rmi.UnmarshalException("error unmarshalling return", e); + } + finally { + ref.done(call); + } + } + } + catch (java.rmi.RemoteException e) { + throw e; + } + catch (java.lang.Exception e) { + throw new java.rmi.UnexpectedException("undeclared checked exception", e); + } + } + + public java.rmi.dgc.Lease dirty(java.rmi.server.ObjID[] $param_0, long $param_1, java.rmi.dgc.Lease $param_2) throws java.rmi.RemoteException { + try { + if (useNewInvoke) { + java.lang.Object $result = ref.invoke(this, $method_dirty_1, new java.lang.Object[] {$param_0, new java.lang.Long($param_1), $param_2}, -8139341527526761862L); + return ((java.rmi.dgc.Lease)$result); + } + else { + java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject)this, operations, 1, interfaceHash); + try { + java.io.ObjectOutput out = call.getOutputStream(); + out.writeObject($param_0); + out.writeLong($param_1); + out.writeObject($param_2); + } + catch (java.io.IOException e) { + throw new java.rmi.MarshalException("error marshalling arguments", e); + } + ref.invoke(call); + java.rmi.dgc.Lease $result; + try { + java.io.ObjectInput in = call.getInputStream(); + $result = (java.rmi.dgc.Lease)in.readObject(); + return ($result); + } + catch (java.io.IOException e) { + throw new java.rmi.UnmarshalException("error unmarshalling return", e); + } + finally { + ref.done(call); + } + } + } + catch (java.rmi.RemoteException e) { + throw e; + } + catch (java.lang.Exception e) { + throw new java.rmi.UnexpectedException("undeclared checked exception", e); + } + } + +} diff --git a/libjava/classpath/gnu/java/rmi/dgc/LeaseRenewingTask.java b/libjava/classpath/gnu/java/rmi/dgc/LeaseRenewingTask.java new file mode 100644 index 000000000..7995af744 --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/dgc/LeaseRenewingTask.java @@ -0,0 +1,234 @@ +/* LeaseRenewingTask.java -- The task to renew the lease. + 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.dgc; + +import gnu.java.rmi.server.UnicastRef; + +import java.lang.ref.WeakReference; +import java.rmi.dgc.Lease; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Timer; +import java.util.TimerTask; +import java.util.WeakHashMap; + +/** + * The task to renew the lease to some object reference. The UnicastRef + * being renewed is stored as a weak reference. So the presence of the + * sheduled task does not prevent it from being garbage collected. If the + * reference has not been garbage collected, the task is resheduled after + * the lease is renewed. + * + * @author Audrius Meskauskas (Audriusa@Bioinformatics.org) + */ +public class LeaseRenewingTask +{ + /** + * The sheduled timer task to call the renew() method. + */ + class LeaseTimerTask extends TimerTask + { + public void run() + { + renew(); + } + } + + /** + * The default requested lease duration time (one minute by default). + */ + public static long REQUEST_LEASE_DURATION = 60000; + + /** + * The reference to the UnicastRef that must renew its lease until not + * garbage collected. The different members of this list may point to the + * different instances of the UnicastRef's, but these references are + * pointing to the same remote object (they .equals() returns + * true when comparing with each other). Using LinkedList to make + * frequent deletions from the middle easy. + */ + LinkedList ref = new LinkedList(); + + /** + * The granted (or supposed) lease. + */ + Lease lease = new Lease(null, REQUEST_LEASE_DURATION); + + /** + * The timer, shared by all lease renewing tasks. The same instance is also + * used for the reference protector discarding in DGCImpl. + */ + static Timer timer = new Timer(true); + + /** + * Maps the UnicastRef to its renewing task. + */ + static WeakHashMap existingTasks = new WeakHashMap(); + + /** + * Creates the lease renewing task that renews the lease of the given + * UnicastRef until it is not collected. This constructor requests the lease + * value from the server and schedules the lease renewal action. + * + * @param renewIt the reference that must be renewed. + */ + public LeaseRenewingTask(UnicastRef renewIt) + { + lease = notifyDGC(renewIt); + if (lease != null) + { + schedule(lease); + ref.add(new WeakReference(renewIt)); + } + } + + /** + * Schedule periodic leases for the given UnicastRef reference. + * + * @param renewIt the reference, for that the leases must be scheduled. + */ + public static void scheduleLeases(UnicastRef renewIt) + { + // No need to schedule leases for null. + if (renewIt == null) + return; + try { + synchronized (existingTasks) + { + // Check maybe the task for refreshing this remote object already + // exists. + LeaseRenewingTask task = (LeaseRenewingTask) existingTasks.get(renewIt); + + if (task != null) + { + // Extend the reference list only. The scheduling must be + // alredy done with the previous lease. + synchronized (task.ref) + { + task.ref.add(new WeakReference(renewIt)); + } + } + else + existingTasks.put(renewIt, new LeaseRenewingTask(renewIt)); + } + } + catch (Exception ex) + { + InternalError ierr = new InternalError("Lease for "+renewIt); + ierr.initCause(ex); + throw ierr; + } + } + + /** + * Shedule the renewing call, taking into consideration that the following + * lease was granted. + * + * @param lease the lease that was granted. + */ + public void schedule(Lease lease) + { + long value = lease.getValue(); + + // Shedule a 10 % earlier because some time is needed for the message + // to reach the server. + long reduced = (value * 90)/100; + if (reduced == 0) + reduced = value; + + timer.schedule(new LeaseTimerTask(), reduced); + } + + /** + * Renew the lease. + */ + public void renew() + { + Object renewIt = null; + // Iterate throw the list of associated references. If all are + // discarded, there is no need to renew. + synchronized (ref) + { + Iterator iter = ref.iterator(); + WeakReference w; + while (iter.hasNext() && renewIt == null) + { + w = (WeakReference) iter.next(); + renewIt = w.get(); + if (renewIt == null) + // Discard the weak reference if its target has been garbage + // collected. + iter.remove(); + } + } + + if (renewIt!=null) + { + Lease lease = notifyDGC( (UnicastRef) renewIt); + + // Schedule the next renewing session. + if (lease!=null) + schedule(lease); + } + { + // All references collected - discard this entry. + } + } + + /** + * Notify DGC that we still hold this reference. + * + * @param renewIt the reference we still have (must not be null). + */ + public Lease notifyDGC(UnicastRef renewIt) + { + try + { + return renewIt.notifyDGC(lease); + } + catch (Exception e) + { + // Failed to notify. + // TODO Take some relevant action in the case if we failed + // to notify the remote object owner. + return null; + } + } + +} diff --git a/libjava/classpath/gnu/java/rmi/dgc/package.html b/libjava/classpath/gnu/java/rmi/dgc/package.html new file mode 100644 index 000000000..3ed81cfdd --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/dgc/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.rmi.dgc + + +

+ + + diff --git a/libjava/classpath/gnu/java/rmi/package.html b/libjava/classpath/gnu/java/rmi/package.html new file mode 100644 index 000000000..53b5f5e57 --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.rmi + + +

+ + + diff --git a/libjava/classpath/gnu/java/rmi/registry/RegistryImpl.java b/libjava/classpath/gnu/java/rmi/registry/RegistryImpl.java new file mode 100644 index 000000000..acdd463b1 --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/registry/RegistryImpl.java @@ -0,0 +1,154 @@ +/* RegistryImpl.java -- + Copyright (c) 1996, 1997, 1998, 1999, 2002, 2005, 2008, 2009, 2010, 2011 + 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.registry; + +import gnu.java.rmi.server.UnicastServerRef; + +import java.rmi.AccessException; +import java.rmi.AlreadyBoundException; +import java.rmi.NotBoundException; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.rmi.server.ObjID; +import java.rmi.server.RMIClientSocketFactory; +import java.rmi.server.RMIServerSocketFactory; +import java.rmi.server.RMISocketFactory; +import java.rmi.server.UnicastRemoteObject; +import java.util.Enumeration; +import java.util.Hashtable; + +public class RegistryImpl + extends UnicastRemoteObject implements Registry { + +private Hashtable bindings = new Hashtable(); + +public RegistryImpl(int port) throws RemoteException { + this(port, RMISocketFactory.getSocketFactory(), RMISocketFactory.getSocketFactory()); +} + +public RegistryImpl(int port, RMIClientSocketFactory cf, RMIServerSocketFactory sf) throws RemoteException { + super(new UnicastServerRef(new ObjID(ObjID.REGISTRY_ID), port, sf)); + // The following is unnecessary, because UnicastRemoteObject export itself automatically. + //((UnicastServerRef)getRef()).exportObject(this); +} + +public Remote lookup(String name) throws RemoteException, NotBoundException, AccessException { + Object obj = bindings.get(name); + if (obj == null) { + throw new NotBoundException(name); + } + return ((Remote)obj); +} + +public void bind(String name, Remote obj) throws RemoteException, AlreadyBoundException, AccessException { + if (bindings.containsKey(name)) { + throw new AlreadyBoundException(name); + } + bindings.put(name, obj); +} + +public void unbind(String name) throws RemoteException, NotBoundException, AccessException { + Object obj = bindings.remove(name); + if (obj == null) { + throw new NotBoundException(name); + } +} + +public void rebind(String name, Remote obj) throws RemoteException, AccessException { + bindings.put(name, obj); +} + +public String[] list() throws RemoteException, AccessException { + int size = bindings.size(); + String[] strings = new String[size]; + Enumeration e = bindings.keys(); + for (int i = 0; i < size; i++) { + strings[i] = (String)e.nextElement(); + } + return (strings); +} + +public static void version() { + System.out.println("rmiregistry (" + + System.getProperty("java.vm.name") + + ") " + + System.getProperty("java.vm.version")); + System.out.println("Copyright 2011 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); +} + +public static void help() { + System.out.println( +"Usage: rmiregistry [OPTION | PORT]\n" + +"\n" + +" --help Print this help, then exit\n" + +" --version Print version number, then exit\n"); + System.exit(0); +} + +public static void main(String[] args) { + int port = Registry.REGISTRY_PORT; + if (args.length > 0) { + if (args[0].equals("--version")) { + version(); + } + else if (args[0].equals("--help")) { + help(); + } + try { + port = Integer.parseInt(args[0]); + } + catch (NumberFormatException _) { + System.err.println("Bad port number - using default"); + } + } + + try { + Registry impl = LocateRegistry.createRegistry(port); + } + catch (RemoteException _) { + System.err.println("Registry failed"); + } +} + +} diff --git a/libjava/classpath/gnu/java/rmi/registry/RegistryImpl_Skel.java b/libjava/classpath/gnu/java/rmi/registry/RegistryImpl_Skel.java new file mode 100644 index 000000000..defa3bf61 --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/registry/RegistryImpl_Skel.java @@ -0,0 +1,227 @@ +/* RegistryImpl_Skel.java + Copyright (C) 2002 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. */ + + +// Skel class generated by rmic - DO NOT EDIT! + +package gnu.java.rmi.registry; + +public final class RegistryImpl_Skel + implements java.rmi.server.Skeleton +{ + private static final long interfaceHash = 4905912898345647071L; + + private static final java.rmi.server.Operation[] operations = { + new java.rmi.server.Operation("void bind(java.lang.String, java.rmi.Remote"), + new java.rmi.server.Operation("java.lang.String[] list("), + new java.rmi.server.Operation("java.rmi.Remote lookup(java.lang.String"), + new java.rmi.server.Operation("void rebind(java.lang.String, java.rmi.Remote"), + new java.rmi.server.Operation("void unbind(java.lang.String") + }; + + public java.rmi.server.Operation[] getOperations() { + return ((java.rmi.server.Operation[]) operations.clone()); + } + + public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall call, int opnum, long hash) throws java.lang.Exception { + if (opnum < 0) { + if (hash == 7583982177005850366L) { + opnum = 0; + } + else if (hash == 2571371476350237748L) { + opnum = 1; + } + else if (hash == -7538657168040752697L) { + opnum = 2; + } + else if (hash == -8381844669958460146L) { + opnum = 3; + } + else if (hash == 7305022919901907578L) { + opnum = 4; + } + else { + throw new java.rmi.server.SkeletonMismatchException("interface hash mismatch"); + } + } + else if (hash != interfaceHash) { + throw new java.rmi.server.SkeletonMismatchException("interface hash mismatch"); + } + + gnu.java.rmi.registry.RegistryImpl server = (gnu.java.rmi.registry.RegistryImpl)obj; + switch (opnum) { + case 0: + { + java.lang.String $param_0; + java.rmi.Remote $param_1; + try { + java.io.ObjectInput in = call.getInputStream(); + $param_0 = (java.lang.String)in.readObject(); + $param_1 = (java.rmi.Remote)in.readObject(); + + } + catch (java.io.IOException e) { + throw new java.rmi.UnmarshalException("error unmarshalling arguments", e); + } + catch (java.lang.ClassCastException e) { + throw new java.rmi.UnmarshalException("error unmarshalling arguments", e); + } + finally { + call.releaseInputStream(); + } + server.bind($param_0, $param_1); + try { + java.io.ObjectOutput out = call.getResultStream(true); + } + catch (java.io.IOException e) { + throw new java.rmi.MarshalException("error marshalling return", e); + } + break; + } + + case 1: + { + try { + java.io.ObjectInput in = call.getInputStream(); + + } + catch (java.io.IOException e) { + throw new java.rmi.UnmarshalException("error unmarshalling arguments", e); + } + finally { + call.releaseInputStream(); + } + java.lang.String[] $result = server.list(); + try { + java.io.ObjectOutput out = call.getResultStream(true); + out.writeObject($result); + } + catch (java.io.IOException e) { + throw new java.rmi.MarshalException("error marshalling return", e); + } + break; + } + + case 2: + { + java.lang.String $param_0; + try { + java.io.ObjectInput in = call.getInputStream(); + $param_0 = (java.lang.String)in.readObject(); + + } + catch (java.io.IOException e) { + throw new java.rmi.UnmarshalException("error unmarshalling arguments", e); + } + catch (java.lang.ClassCastException e) { + throw new java.rmi.UnmarshalException("error unmarshalling arguments", e); + } + finally { + call.releaseInputStream(); + } + java.rmi.Remote $result = server.lookup($param_0); + try { + java.io.ObjectOutput out = call.getResultStream(true); + out.writeObject($result); + } + catch (java.io.IOException e) { + throw new java.rmi.MarshalException("error marshalling return", e); + } + break; + } + + case 3: + { + java.lang.String $param_0; + java.rmi.Remote $param_1; + try { + java.io.ObjectInput in = call.getInputStream(); + $param_0 = (java.lang.String)in.readObject(); + $param_1 = (java.rmi.Remote)in.readObject(); + + } + catch (java.io.IOException e) { + throw new java.rmi.UnmarshalException("error unmarshalling arguments", e); + } + catch (java.lang.ClassCastException e) { + throw new java.rmi.UnmarshalException("error unmarshalling arguments", e); + } + finally { + call.releaseInputStream(); + } + server.rebind($param_0, $param_1); + try { + java.io.ObjectOutput out = call.getResultStream(true); + } + catch (java.io.IOException e) { + throw new java.rmi.MarshalException("error marshalling return", e); + } + break; + } + + case 4: + { + java.lang.String $param_0; + try { + java.io.ObjectInput in = call.getInputStream(); + $param_0 = (java.lang.String)in.readObject(); + + } + catch (java.io.IOException e) { + throw new java.rmi.UnmarshalException("error unmarshalling arguments", e); + } + catch (java.lang.ClassCastException e) { + throw new java.rmi.UnmarshalException("error unmarshalling arguments", e); + } + finally { + call.releaseInputStream(); + } + server.unbind($param_0); + try { + java.io.ObjectOutput out = call.getResultStream(true); + } + catch (java.io.IOException e) { + throw new java.rmi.MarshalException("error marshalling return", e); + } + break; + } + + default: + throw new java.rmi.UnmarshalException("invalid method number"); + } + } +} diff --git a/libjava/classpath/gnu/java/rmi/registry/RegistryImpl_Stub.java b/libjava/classpath/gnu/java/rmi/registry/RegistryImpl_Stub.java new file mode 100644 index 000000000..786a5e180 --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/registry/RegistryImpl_Stub.java @@ -0,0 +1,293 @@ +/* RegistryImpl_Stub.java + Copyright (C) 2002 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. */ + + +// Stub class generated by rmic - DO NOT EDIT! + +package gnu.java.rmi.registry; + +public final class RegistryImpl_Stub + extends java.rmi.server.RemoteStub + implements java.rmi.registry.Registry +{ + private static final long serialVersionUID = 2L; + + private static final long interfaceHash = 4905912898345647071L; + + private static boolean useNewInvoke; + + private static final java.rmi.server.Operation[] operations = { + new java.rmi.server.Operation("void bind(java.lang.String, java.rmi.Remote)"), + new java.rmi.server.Operation("java.lang.String[] list()"), + new java.rmi.server.Operation("java.rmi.Remote lookup(java.lang.String)"), + new java.rmi.server.Operation("void rebind(java.lang.String, java.rmi.Remote)"), + new java.rmi.server.Operation("void unbind(java.lang.String)") + }; + + private static java.lang.reflect.Method $method_bind_0; + private static java.lang.reflect.Method $method_list_1; + private static java.lang.reflect.Method $method_lookup_2; + private static java.lang.reflect.Method $method_rebind_3; + private static java.lang.reflect.Method $method_unbind_4; + + static { + try { + java.rmi.server.RemoteRef.class.getMethod("invoke", new java.lang.Class[] { java.rmi.Remote.class, java.lang.reflect.Method.class, java.lang.Object[].class, long.class }); + useNewInvoke = false; + $method_bind_0 = gnu.java.rmi.registry.RegistryImpl.class.getMethod("bind", new java.lang.Class[] {java.lang.String.class, java.rmi.Remote.class}); + $method_list_1 = gnu.java.rmi.registry.RegistryImpl.class.getMethod("list", new java.lang.Class[] {}); + $method_lookup_2 = gnu.java.rmi.registry.RegistryImpl.class.getMethod("lookup", new java.lang.Class[] {java.lang.String.class}); + $method_rebind_3 = gnu.java.rmi.registry.RegistryImpl.class.getMethod("rebind", new java.lang.Class[] {java.lang.String.class, java.rmi.Remote.class}); + $method_unbind_4 = gnu.java.rmi.registry.RegistryImpl.class.getMethod("unbind", new java.lang.Class[] {java.lang.String.class}); + + } + catch (java.lang.NoSuchMethodException e) { + useNewInvoke = false; + } + } + + public RegistryImpl_Stub() { + super(); + } + public RegistryImpl_Stub(java.rmi.server.RemoteRef ref) { + super(ref); + } + + public void bind(java.lang.String $param_0, java.rmi.Remote $param_1) throws java.rmi.AccessException, java.rmi.AlreadyBoundException, java.rmi.RemoteException { + try { + if (useNewInvoke) { + ref.invoke(this, $method_bind_0, new java.lang.Object[] {$param_0, $param_1}, 7583982177005850366L); + } + else { + java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject)this, operations, 0, interfaceHash); + try { + java.io.ObjectOutput out = call.getOutputStream(); + out.writeObject($param_0); + out.writeObject($param_1); + } + catch (java.io.IOException e) { + throw new java.rmi.MarshalException("error marshalling arguments", e); + } + ref.invoke(call); + try { + java.io.ObjectInput in = call.getInputStream(); + } + catch (java.io.IOException e) { + throw new java.rmi.UnmarshalException("error unmarshalling return", e); + } + finally { + ref.done(call); + } + } + } + catch (java.rmi.AccessException e) { + throw e; + } + catch (java.rmi.AlreadyBoundException e) { + throw e; + } + catch (java.rmi.RemoteException e) { + throw e; + } + catch (java.lang.Exception e) { + throw new java.rmi.UnexpectedException("undeclared checked exception", e); + } + } + + public java.lang.String[] list() throws java.rmi.AccessException, java.rmi.RemoteException { + try { + if (useNewInvoke) { + java.lang.Object $result = ref.invoke(this, $method_list_1, null, 2571371476350237748L); + return ((java.lang.String[])$result); + } + else { + java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject)this, operations, 1, interfaceHash); + try { + java.io.ObjectOutput out = call.getOutputStream(); + } + catch (java.io.IOException e) { + throw new java.rmi.MarshalException("error marshalling arguments", e); + } + ref.invoke(call); + java.lang.String[] $result; + try { + java.io.ObjectInput in = call.getInputStream(); + $result = (java.lang.String[])in.readObject(); + return ($result); + } + catch (java.io.IOException e) { + throw new java.rmi.UnmarshalException("error unmarshalling return", e); + } + finally { + ref.done(call); + } + } + } + catch (java.rmi.AccessException e) { + throw e; + } + catch (java.rmi.RemoteException e) { + throw e; + } + catch (java.lang.Exception e) { + throw new java.rmi.UnexpectedException("undeclared checked exception", e); + } + } + + public java.rmi.Remote lookup(java.lang.String $param_0) throws java.rmi.AccessException, java.rmi.NotBoundException, java.rmi.RemoteException { + try { + if (useNewInvoke) { + java.lang.Object $result = ref.invoke(this, $method_lookup_2, new java.lang.Object[] {$param_0}, -7538657168040752697L); + return ((java.rmi.Remote)$result); + } + else { + java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject)this, operations, 2, interfaceHash); + try { + java.io.ObjectOutput out = call.getOutputStream(); + out.writeObject($param_0); + } + catch (java.io.IOException e) { + throw new java.rmi.MarshalException("error marshalling arguments", e); + } + ref.invoke(call); + java.rmi.Remote $result; + try { + java.io.ObjectInput in = call.getInputStream(); + $result = (java.rmi.Remote)in.readObject(); + return ($result); + } + catch (java.io.IOException e) { + throw new java.rmi.UnmarshalException("error unmarshalling return", e); + } + finally { + ref.done(call); + } + } + } + catch (java.rmi.AccessException e) { + throw e; + } + catch (java.rmi.NotBoundException e) { + throw e; + } + catch (java.rmi.RemoteException e) { + throw e; + } + catch (java.lang.Exception e) { + throw new java.rmi.UnexpectedException("undeclared checked exception", e); + } + } + + public void rebind(java.lang.String $param_0, java.rmi.Remote $param_1) throws java.rmi.AccessException, java.rmi.RemoteException { + try { + if (useNewInvoke) { + ref.invoke(this, $method_rebind_3, new java.lang.Object[] {$param_0, $param_1}, -8381844669958460146L); + } + else { + java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject)this, operations, 3, interfaceHash); + try { + java.io.ObjectOutput out = call.getOutputStream(); + out.writeObject($param_0); + out.writeObject($param_1); + } + catch (java.io.IOException e) { + throw new java.rmi.MarshalException("error marshalling arguments", e); + } + ref.invoke(call); + try { + java.io.ObjectInput in = call.getInputStream(); + } + catch (java.io.IOException e) { + throw new java.rmi.UnmarshalException("error unmarshalling return", e); + } + finally { + ref.done(call); + } + } + } + catch (java.rmi.AccessException e) { + throw e; + } + catch (java.rmi.RemoteException e) { + throw e; + } + catch (java.lang.Exception e) { + throw new java.rmi.UnexpectedException("undeclared checked exception", e); + } + } + + public void unbind(java.lang.String $param_0) throws java.rmi.AccessException, java.rmi.NotBoundException, java.rmi.RemoteException { + try { + if (useNewInvoke) { + ref.invoke(this, $method_unbind_4, new java.lang.Object[] {$param_0}, 7305022919901907578L); + } + else { + java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject)this, operations, 4, interfaceHash); + try { + java.io.ObjectOutput out = call.getOutputStream(); + out.writeObject($param_0); + } + catch (java.io.IOException e) { + throw new java.rmi.MarshalException("error marshalling arguments", e); + } + ref.invoke(call); + try { + java.io.ObjectInput in = call.getInputStream(); + } + catch (java.io.IOException e) { + throw new java.rmi.UnmarshalException("error unmarshalling return", e); + } + finally { + ref.done(call); + } + } + } + catch (java.rmi.AccessException e) { + throw e; + } + catch (java.rmi.NotBoundException e) { + throw e; + } + catch (java.rmi.RemoteException e) { + throw e; + } + catch (java.lang.Exception e) { + throw new java.rmi.UnexpectedException("undeclared checked exception", e); + } + } + +} diff --git a/libjava/classpath/gnu/java/rmi/registry/package.html b/libjava/classpath/gnu/java/rmi/registry/package.html new file mode 100644 index 000000000..3750359d6 --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/registry/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.rmi.registry + + +

+ + + diff --git a/libjava/classpath/gnu/java/rmi/server/ActivatableRef.java b/libjava/classpath/gnu/java/rmi/server/ActivatableRef.java new file mode 100644 index 000000000..a6faaca2e --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/server/ActivatableRef.java @@ -0,0 +1,179 @@ +/* ActivatableRef.java -- Activatable server reference + 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.io.ObjectInput; +import java.io.ObjectOutput; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.activation.ActivationException; +import java.rmi.activation.ActivationID; +import java.rmi.server.ObjID; +import java.rmi.server.RMIClientSocketFactory; +import java.rmi.server.RemoteObject; +import java.rmi.server.RemoteObjectInvocationHandler; +import java.rmi.server.RemoteRef; + +/** + * The activatable reference works like UnicastRef, but if the remote object + * appears to be not accessible, it tries to reactivate it before reporting + * any errors. Apart the fields of the UnicastRef, the activatable reference + * contains the ActivationID that is used for this activation. + * + * @author Audrius Meskauskas (Audriusa@Bioinformatics.org) + */ +public class ActivatableRef extends UnicastRef +{ + /** + * Use serial version UID for iteroperability + */ + private static final long serialVersionUID = 1; + + /** + * The activation id. + */ + ActivationID actId; + + /** + * Delegate call to the superclass. + */ + public ActivatableRef() + { + super(); + } + + /** + * Delegate call to the superclass. + */ + public ActivatableRef(ObjID objid, String host, int port, + RMIClientSocketFactory csf) + { + super(objid, host, port, csf); + } + + /** + * Delegate call to the superclass. + */ + public ActivatableRef(ObjID objid) + { + super(objid); + } + + /** + * Get the referencing class. + */ + public String getRefClass(ObjectOutput out) + { + return "ActivatableRef"; + } + + /** + * Read the content from the input stream. + */ + public void readExternal(ObjectInput in) throws IOException, + ClassNotFoundException + { + actId = (ActivationID) in.readObject(); + String type = in.readUTF(); + // XXX handle type.equals("") (null reference) + super.readExternal(in); + } + + /** + * Write the content to the output stream. + */ + public void writeExternal(ObjectOutput out) throws IOException + { + out.writeObject(actId); + // XXX write a "" if the "nested" reference is a null reference + out.writeUTF("UnicastRef2"); + super.writeExternal(out); + } + + /** + * Invoke the remote method on the given object and try to activate the object + * if it is not reacheable with the current manager. + */ + protected Object invokeCommon(Remote obj, Method method, Object[] params, + int opnum, long hash) throws Exception + { + UnicastConnection conn; + try + { + conn = manager.getConnection(); + } + catch (IOException e1) + { + // Connection failed: try to activate. + Remote reactivated = actId.activate(false); + + if (reactivated instanceof RemoteObject) + { + RemoteRef ref = ((RemoteObject) reactivated).getRef(); + manager = ((UnicastRef) ref).manager; + } + else if (Proxy.isProxyClass(reactivated.getClass())) + { + RemoteObjectInvocationHandler hander = + (RemoteObjectInvocationHandler) + Proxy.getInvocationHandler(reactivated); + + RemoteRef ref = hander.getRef(); + manager = ((UnicastRef) ref).manager; + } + else + throw new ActivationException("Activating into unsupported class " + + reactivated.getClass()); + + try + { + conn = manager.getConnection(); + } + catch (IOException e2) + { + throw new RemoteException("connection failed to host: " + + manager.serverName, e1); + } + } + return invokeCommon(conn, obj, method, params, opnum, hash); + } +} diff --git a/libjava/classpath/gnu/java/rmi/server/ActivatableServerRef.java b/libjava/classpath/gnu/java/rmi/server/ActivatableServerRef.java new file mode 100644 index 000000000..31e825a25 --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/server/ActivatableServerRef.java @@ -0,0 +1,227 @@ +/* ActivatableServerRef.java -- The activatable server reference + 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.io.ObjectInput; +import java.io.ObjectOutput; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.activation.ActivationID; +import java.rmi.server.ObjID; +import java.rmi.server.RMIServerSocketFactory; +import java.rmi.server.RemoteStub; +import java.rmi.server.Skeleton; + +/** + * The activatable server reference works like UnicastServerReference, but it + * additionally activates the associated object on demand, during the first + * incoming call. When UnicastServerReference takes the working reference, + * the ActivatableServerRef takes the activation id instead. + * + * @author Audrius Meskauskas (Audriusa@Bioinformatics.org) + */ +public class ActivatableServerRef extends UnicastServerRef +{ + /** + * Use SVUID for interoperability + */ + private static final long serialVersionUID = 1; + + /** + * The object activation id. + */ + public ActivationID actId; + + /** + * Used by serialization only + */ + public ActivatableServerRef() + { + super(); + } + + /** + * Create the new activatable server reference that will activate object on + * the first call using the given activation id. + */ + public ActivatableServerRef(ObjID id, ActivationID anId, int aPort, + RMIServerSocketFactory ssFactory) + throws RemoteException + { + super(id, aPort, ssFactory); + actId = anId; + + // The object ID will be placed in the object map and should deliver + // incoming call to {@link #incommingMessageCall}. The object itself + // is currently null. + UnicastServer.exportActivatableObject(this); + } + + /** + * Inactivate the object (stop the server). + */ + public void inactivate() + { + manager.stopServer(); + } + + /** + * Activate the object (normally during the first call). + */ + protected void activate() throws RemoteException + { + try + { + Remote self = actId.activate(false); + + // This will call UnicastServer.exportObject, replacing null by + // the activated object (self) in the object map. + exportObject(self); + } + catch (RemoteException rex) + { + throw rex; + } + catch (Exception exc) + { + RemoteException rx = new RemoteException("Activation failed."); + rx.detail = exc; + throw rx; + } + } + + /** + * If the object is not active, activate it first. + */ + public Object incomingMessageCall(UnicastConnection conn, int method, + long hash) throws Exception + { + if (myself == null) + activate(); + return super.incomingMessageCall(conn, method, hash); + } + + /** + * Export object and ensure it is present in the server activation table + * as well. + */ + public Remote exportObject(Remote obj) throws RemoteException + { + Remote r = super.exportObject(obj); + UnicastServer.registerActivatable(this); + return r; + } + + /** + * Export object and ensure it is present in the server activation table as + * well. + * + * @param aClass the class being exported, must implement Remote. + */ + public Remote exportClass(Class aClass) throws RemoteException + { + if (!Remote.class.isAssignableFrom(aClass)) + throw new InternalError(aClass.getName()+" must implement Remote"); + + String ignoreStubs; + + ClassLoader loader =aClass.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 = aClass; + + // where ist the _Stub? (check superclasses also) + Class 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(aClass, this); + + // Build hash of methods which may be called. + buildMethodHash(aClass, true); + + UnicastServer.registerActivatable(this); + return stub; + } + + /** + * Get the referencing class. + */ + public String getRefClass(ObjectOutput out) + { + return "ActivatableRef"; + } + + /** + * Read the content from the input stream. + */ + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException + { + super.readExternal(in); + actId = (ActivationID) in.readObject(); + } + + /** + * Write the content to the output stream. + */ + public void writeExternal(ObjectOutput out) throws IOException + { + super.writeExternal(out); + out.writeObject(actId); + } + +} diff --git a/libjava/classpath/gnu/java/rmi/server/CombinedClassLoader.java b/libjava/classpath/gnu/java/rmi/server/CombinedClassLoader.java new file mode 100644 index 000000000..3d01d0987 --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/server/CombinedClassLoader.java @@ -0,0 +1,135 @@ +/* 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 (cl!=null && !sLoaders.contains(cl)) + sLoaders.add(cl); + } + + 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 loaders[i].loadClass(name); + } + catch (ClassNotFoundException e) + { + // try another. + } + } + return super.findClass(name); + } + + /** + * Find resource with the given name. + */ + protected URL findResource(String name) + { + for (int i = 0; i < loaders.length; i++) + { + URL resource = loaders[i].getResource(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 = loaders[i].getResources(name); + if (resource != null) + return resource; + } + return super.findResources(name); } +} diff --git a/libjava/classpath/gnu/java/rmi/server/ConnectionRunnerPool.java b/libjava/classpath/gnu/java/rmi/server/ConnectionRunnerPool.java new file mode 100644 index 000000000..86660fea7 --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/server/ConnectionRunnerPool.java @@ -0,0 +1,156 @@ +/* gnu.java.rmi.server.ConnectionRunnerPool + Copyright (C) 2002, 2004, 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.java.rmi.server; + +import java.util.ArrayList; +import java.util.Arrays; + +//Should I generalize this class? + +class ConnectionRunnerPool +{ + + public static + class ConnectionRunner extends Thread{ + private UnicastConnection conn; + private volatile boolean exiting = false; + + public ConnectionRunner(ThreadGroup group, String id){ + super(group, id); + } + + public synchronized void run(){ + while(!exiting){ + if(conn == null) + try{ + wait(); + }catch(InterruptedException e){ + continue; + } + else{ + conn.run(); + conn = null; + synchronized(ConnectionRunnerPool.class){ + freelist.add(this); + if(freelist.size() == 1) + ConnectionRunnerPool.class.notifyAll(); + } + } + } + } + + public synchronized void dispatch(UnicastConnection conn){ + this.conn = conn; + notify(); + } + + void exit(){ + exiting = true; + if(conn != null) + try{ + join(500); + }catch(InterruptedException e){} + interrupt(); + } + + } + + // Should this value equal to number of CPU? + private static int size = 5; + private static int max_size = 10; + + // Package-private to avoid a trampoline. + static ArrayList freelist; + + private static ThreadGroup group = new ThreadGroup("pool"); + + static { + ConnectionRunner[] pools = new ConnectionRunner[size]; + for(int i = 0; i < pools.length; i++){ + pools[i] = new ConnectionRunner(group, Integer.toString(i)); + pools[i].setContextClassLoader(Thread.currentThread().getContextClassLoader()); + pools[i].start(); + } + freelist = new ArrayList(Arrays.asList(pools)); + } + + public static void setSize(int size_){ + size = size_; + } + + public static void setMaxSize(int size){ + max_size = size; + } + + private static synchronized ConnectionRunner getConnectionRunner() + { + if(freelist.size() == 0){ + if(size < max_size){ + ++size; + ConnectionRunner a = new ConnectionRunner(group, Integer.toString(size)); + a.start(); + freelist.add(a); + }else + while(freelist.size() == 0) + try{ + ConnectionRunnerPool.class.wait(); + }catch(InterruptedException e){} + } + + // always let the first in pool most busy or other scheduling plan?? + ConnectionRunner a = (ConnectionRunner)freelist.get(0); + freelist.remove(a); + return a; + } + + public static void dispatchConnection(UnicastConnection conn) + { + ConnectionRunner r = getConnectionRunner(); + r.dispatch(conn); + } + + public static void exit() + { + Thread[] list = new Thread[group.activeCount()]; + group.enumerate(list); + for(int i = 0; i < list.length; i++) + ((ConnectionRunner)list[i]).exit(); + } + +} diff --git a/libjava/classpath/gnu/java/rmi/server/ProtocolConstants.java b/libjava/classpath/gnu/java/rmi/server/ProtocolConstants.java new file mode 100644 index 000000000..72fbefe61 --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/server/ProtocolConstants.java @@ -0,0 +1,62 @@ +/* ProtocolConstants.java -- + Copyright (c) 1996, 1997, 1998, 1999 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; + +public interface ProtocolConstants +{ + int PROTOCOL_HEADER = 0x4a524d49; // JRMI + int PROTOCOL_VERSION = 2; + + int STREAM_PROTOCOL = 0x4b; + int SINGLE_OP_PROTOCOL = 0x4c; + int MULTIPLEX_PROTOCOL = 0x4d; + + int PROTOCOL_ACK = 0x4e; + int PROTOCOL_NACK = 0x4f; + + int MESSAGE_CALL = 0x50; + int MESSAGE_CALL_ACK = 0x51; + int MESSAGE_PING = 0x52; + int MESSAGE_PING_ACK = 0x53; + int MESSAGE_DGCACK = 0x54; + + int RETURN_ACK = 0x01; + int RETURN_NACK = 0x02; + + int DEFAULT_PROTOCOL = STREAM_PROTOCOL; +} diff --git a/libjava/classpath/gnu/java/rmi/server/RMIClassLoaderImpl.java b/libjava/classpath/gnu/java/rmi/server/RMIClassLoaderImpl.java new file mode 100644 index 000000000..b090d3444 --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/server/RMIClassLoaderImpl.java @@ -0,0 +1,357 @@ +/* RMIClassLoaderImpl.java -- FIXME: briefly describe file purpose + 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.java.rmi.server; + +import gnu.java.lang.CPStringBuilder; + +import java.lang.reflect.Proxy; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.rmi.server.RMIClassLoaderSpi; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.Map; +import java.util.StringTokenizer; + +/** + * The default implementation of {@link java.rmi.server.RMIClassLoaderSpi}. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class RMIClassLoaderImpl extends RMIClassLoaderSpi +{ + private static class MyClassLoader extends URLClassLoader + { + // Package-private to avoid a trampoline constructor. + MyClassLoader (URL[] urls, ClassLoader parent, String annotation) + { + super (urls, parent); + this.annotation = annotation; + } + + public static String urlToAnnotation (URL[] urls) + { + if (urls.length == 0) + return null; + + CPStringBuilder annotation = new CPStringBuilder (64 * urls.length); + + for (int i = 0; i < urls.length; i++) + { + annotation.append (urls [i].toExternalForm()); + annotation.append (' '); + } + + return annotation.toString(); + } + + public final String getClassAnnotation() + { + return annotation; + } + + private final String annotation; + } + + /** + * This class is used to identify a cached classloader by its codebase and + * the context classloader that is its parent. + */ + private static class CacheKey + { + private String mCodeBase; + private ClassLoader mContextClassLoader; + + public CacheKey (String theCodebase, ClassLoader theContextClassLoader) + { + mCodeBase = theCodebase; + mContextClassLoader = theContextClassLoader; + } + + /** + * @return true if the codebase and the context classloader are equal + */ + public boolean equals (Object theOther) + { + if (theOther instanceof CacheKey) + { + CacheKey key = (CacheKey) theOther; + + return (equals (this.mCodeBase,key.mCodeBase) + && equals (this.mContextClassLoader, key.mContextClassLoader)); + } + return false; + } + + /** + * Test if the two objects are equal or both null. + * @param theOne + * @param theOther + * @return + */ + private boolean equals (Object theOne, Object theOther) + { + return theOne != null ? theOne.equals (theOther) : theOther == null; + } + + /** + * @return hashCode + */ + public int hashCode() + { + return ((mCodeBase != null ? mCodeBase.hashCode() : 0) + ^(mContextClassLoader != null ? mContextClassLoader.hashCode() : -1)); + } + + public String toString() + { + return "[" + mCodeBase + "," + mContextClassLoader + "]"; + } + + } + + private static RMIClassLoaderImpl instance = null; + + private static Map cacheLoaders; //map annotations to loaders + private static Map cacheAnnotations; //map loaders to annotations + //class loader for defaultAnnotation + private static MyClassLoader defaultClassLoader; + + //defaultAnnotation is got from system property + // "java.rmi.server.defaultAnnotation" + private static String defaultAnnotation; + + //URL object for defaultAnnotation + private static URL defaultCodebase; + + static + { + // 89 is a nice prime number for Hashtable initial capacity + cacheLoaders = new Hashtable (89); + cacheAnnotations = new Hashtable (89); + + defaultAnnotation = System.getProperty ("java.rmi.server.defaultAnnotation"); + + try + { + if (defaultAnnotation != null) + defaultCodebase = new URL (defaultAnnotation); + } + catch (Exception _) + { + defaultCodebase = null; + } + + if (defaultCodebase != null) + { + defaultClassLoader = new MyClassLoader (new URL[] { defaultCodebase }, null, + defaultAnnotation); + // XXX using getContextClassLoader here *cannot* be right + cacheLoaders.put (new CacheKey (defaultAnnotation, + Thread.currentThread().getContextClassLoader()), + defaultClassLoader); + } + } + + /** + * This is a singleton class and may only be instantiated once from within + * the {@link #getInstance} method. + */ + private RMIClassLoaderImpl() + { + } + + /** + * Returns an instance of RMIClassLoaderImpl. + * + * @return an instance of RMIClassLoaderImpl + */ + public static RMIClassLoaderSpi getInstance() + { + if (instance == null) + instance = new RMIClassLoaderImpl(); + return instance; + } + + public Class loadClass(String codeBase, String name, + ClassLoader defaultLoader) + throws MalformedURLException, ClassNotFoundException + { + try + { + if (defaultLoader != null) + return Class.forName(name, false, defaultLoader); + } + catch (ClassNotFoundException e) + { + } + + return Class.forName(name, false, getClassLoader(codeBase)); + } + + public Class loadProxyClass(String codeBase, String[] interfaces, + ClassLoader defaultLoader) + throws MalformedURLException, ClassNotFoundException + { + Class clss[] = new Class[interfaces.length]; + + for (int i = 0; i < interfaces.length; i++) + { + clss[i] = loadClass(codeBase, interfaces[i], defaultLoader); + } + + // Chain all class loaders (they may differ). + ArrayList loaders = new ArrayList(clss.length); + ClassLoader loader = null; + for (int i = 0; i < clss.length; i++) + { + loader = clss[i].getClassLoader(); + if (! loaders.contains(loader)) + { + loaders.add(0, loader); + } + } + if (loaders.size() > 1) + { + loader = new CombinedClassLoader(loaders); + } + + try + { + return Proxy.getProxyClass(loader, clss); + } + catch (IllegalArgumentException e) + { + throw new ClassNotFoundException(null, e); + } + } + + /** + * Gets a classloader for the given codebase and with the current + * context classloader as parent. + * + * @param codebase + * + * @return a classloader for the given codebase + * + * @throws MalformedURLException if the codebase contains a malformed URL + */ + public ClassLoader getClassLoader(String codebase) + throws MalformedURLException + { + if (codebase == null || codebase.length() == 0) + return Thread.currentThread().getContextClassLoader(); + + ClassLoader loader; + CacheKey loaderKey = new CacheKey + (codebase, Thread.currentThread().getContextClassLoader()); + loader = (ClassLoader) cacheLoaders.get (loaderKey); + + if (loader == null) + { + //create an entry in cacheLoaders mapping a loader to codebases. + // codebases are separated by " " + StringTokenizer tok = new StringTokenizer (codebase, " "); + ArrayList urls = new ArrayList(); + + while (tok.hasMoreTokens()) + urls.add (new URL(tok.nextToken())); + + loader = new MyClassLoader((URL[]) urls.toArray(new URL [urls.size()]), + Thread.currentThread().getContextClassLoader(), + codebase); + cacheLoaders.put (loaderKey, loader); + } + + return loader; + } + + /** + * Returns a string representation of the network location where a remote + * endpoint can get the class-definition of the given class. + * + * @param cl + * + * @return a space seperated list of URLs where the class-definition + * of cl may be found + */ + public String getClassAnnotation(Class cl) + { + ClassLoader loader = cl.getClassLoader(); + + if (loader == null + || loader == ClassLoader.getSystemClassLoader()) + { + return System.getProperty ("java.rmi.server.codebase"); + } + + if (loader instanceof MyClassLoader) + { + return ((MyClassLoader) loader).getClassAnnotation(); + } + + String s = (String) cacheAnnotations.get (loader); + + if (s != null) + return s; + + if (loader instanceof URLClassLoader) + { + URL[] urls = ((URLClassLoader) loader).getURLs(); + + if (urls.length == 0) + return null; + + CPStringBuilder annotation = new CPStringBuilder (64 * urls.length); + + for (int i = 0; i < urls.length; i++) + { + annotation.append (urls [i].toExternalForm()); + annotation.append (' '); + } + + s = annotation.toString(); + cacheAnnotations.put (loader, s); + return s; + } + + return System.getProperty ("java.rmi.server.codebase"); + } +} diff --git a/libjava/classpath/gnu/java/rmi/server/RMIDefaultSocketFactory.java b/libjava/classpath/gnu/java/rmi/server/RMIDefaultSocketFactory.java new file mode 100644 index 000000000..7115ba543 --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/server/RMIDefaultSocketFactory.java @@ -0,0 +1,59 @@ +/* RMIDefaultSocketFactory.java -- + Copyright (c) 1996, 1997, 1998, 1999, 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.java.rmi.server; + +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; +import java.rmi.server.RMISocketFactory; + +public class RMIDefaultSocketFactory + extends RMISocketFactory { + +public RMIDefaultSocketFactory() { +} + +public Socket createSocket(String host, int port) throws IOException { + return (new Socket(host, port)); +} + +public ServerSocket createServerSocket(int port) throws IOException { + return (new ServerSocket(port)); +} + +} diff --git a/libjava/classpath/gnu/java/rmi/server/RMIHashes.java b/libjava/classpath/gnu/java/rmi/server/RMIHashes.java new file mode 100644 index 000000000..03eb09fd0 --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/server/RMIHashes.java @@ -0,0 +1,99 @@ +/* RMIHashes.java -- + Copyright (c) 1996, 1997, 1998, 1999, 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.rmi.server; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.lang.reflect.TypeSignature; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.lang.reflect.Method; +import java.security.MessageDigest; + +public class RMIHashes +{ + //There're other places using DigestOutputStream to generate hash in classpath, but I think the way I used + //here is more efficient, anyway, you can switch to DigestOutputStream by doing like "//or:" comments say. + + //or:add this statement: private static final NullOutputStream nullOutputStream = new NullOutputStream (); + public static long getMethodHash(Method meth) + { + //Object Serialization Spec 8.3 + try + { + MessageDigest md = MessageDigest.getInstance ("SHA"); + //or:remove this statement: DigestOutputStream digest_out = new DigestOutputStream (nullOutputStream, md); + ByteArrayOutputStream digest_out = new ByteArrayOutputStream(); + DataOutputStream data_out = new DataOutputStream (digest_out); + + CPStringBuilder sbuf = new CPStringBuilder(); + sbuf.append(meth.getName()); + sbuf.append('('); + Class params[] = meth.getParameterTypes(); + for(int i = 0; i < params.length; i++) + sbuf.append(TypeSignature.getEncodingOfClass(params[i])); + sbuf.append(')'); + Class rcls = meth.getReturnType(); + if(rcls != Void.TYPE) + sbuf.append(TypeSignature.getEncodingOfClass(rcls)); + else + sbuf.append('V'); + + data_out.writeUTF (sbuf.toString()); + data_out.flush(); + data_out.close (); + + md.update(digest_out.toByteArray()); //or:remove this statement + byte[] sha = md.digest (); + long result = 0; + int len = sha.length < 8 ? sha.length : 8; + for (int i=0; i < len; i++) + result += (long)(sha[i] & 0xFF) << (8 * i); + return result; + }catch(Exception _){ + return -1L; + } + } + + public static long getInterfaceHash(Class clazz) + { + return clazz.hashCode (); + } +} diff --git a/libjava/classpath/gnu/java/rmi/server/RMIIncomingThread.java b/libjava/classpath/gnu/java/rmi/server/RMIIncomingThread.java new file mode 100644 index 000000000..352b48b31 --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/server/RMIIncomingThread.java @@ -0,0 +1,58 @@ +/* RMIIncomingThread.java -- + Copyright (c) 1996, 1997, 1998, 1999, 2002 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; + +public class RMIIncomingThread extends Thread { + + private String clientHost = null; + + public RMIIncomingThread(Runnable runnable, String s_clientHost) { + super(runnable); + clientHost = s_clientHost; + } + + public String toString() { + return "RMIIncoming from " + clientHost + " " + super.toString(); + } + + public String getClientHost() { + return clientHost; + } + + +} diff --git a/libjava/classpath/gnu/java/rmi/server/RMIObjectInputStream.java b/libjava/classpath/gnu/java/rmi/server/RMIObjectInputStream.java new file mode 100644 index 000000000..4ac7a0ae8 --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/server/RMIObjectInputStream.java @@ -0,0 +1,118 @@ +/* RMIObjectInputStream.java -- + Copyright (c) 1996, 1997, 1998, 1999, 2002, 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.rmi.server; + +import gnu.classpath.VMStackWalker; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectStreamClass; +import java.net.MalformedURLException; +import java.rmi.server.RMIClassLoader; + +public class RMIObjectInputStream + extends ObjectInputStream { + +public RMIObjectInputStream(InputStream strm) throws IOException { + super(strm); + enableResolveObject(true); +} + +protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { + try { + return RMIClassLoader.loadClass( + (String)getAnnotation(), + desc.getName(), + VMStackWalker.firstNonNullClassLoader()); + } + catch (MalformedURLException x) { + throw new ClassNotFoundException(desc.getName(), x); + } +} + +//Separate it for override by MarshalledObject +protected Object getAnnotation() + throws IOException, ClassNotFoundException +{ + return readObject(); +} + + + protected Class resolveProxyClass(String intfs[]) throws IOException, + ClassNotFoundException + { + try + { + return RMIClassLoader.loadProxyClass( + (String)getAnnotation(), + intfs, + VMStackWalker.firstNonNullClassLoader()); + } + catch (MalformedURLException x) + { + throw new ClassNotFoundException(null, x); + } + } + +protected Object readValue(Class valueClass) throws IOException, ClassNotFoundException { + if(valueClass.isPrimitive()){ + if(valueClass == Boolean.TYPE) + return Boolean.valueOf(readBoolean()); + if(valueClass == Byte.TYPE) + return new Byte(readByte()); + if(valueClass == Character.TYPE) + return new Character(readChar()); + if(valueClass == Short.TYPE) + return new Short(readShort()); + if(valueClass == Integer.TYPE) + return new Integer(readInt()); + if(valueClass == Long.TYPE) + return new Long(readLong()); + if(valueClass == Float.TYPE) + return new Float(readFloat()); + if(valueClass == Double.TYPE) + return new Double(readDouble()); + else + throw new Error("Unsupported primitive class: " + valueClass); + } else + return readObject(); +} + +} diff --git a/libjava/classpath/gnu/java/rmi/server/RMIObjectOutputStream.java b/libjava/classpath/gnu/java/rmi/server/RMIObjectOutputStream.java new file mode 100644 index 000000000..aaf09860c --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/server/RMIObjectOutputStream.java @@ -0,0 +1,114 @@ +/* RMIObjectOutputStream.java - + Copyright (c) 1996, 1997, 1998, 1999, 2002, 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.rmi.server; + +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.rmi.Remote; +import java.rmi.server.RMIClassLoader; +import java.rmi.server.RemoteStub; + +public class RMIObjectOutputStream + extends ObjectOutputStream { + +public RMIObjectOutputStream(OutputStream strm) throws IOException { + super(strm); + enableReplaceObject(true); +} + +//Separate it for override by MarshalledObject +protected void setAnnotation(String annotation) throws IOException{ + writeObject(annotation); +} + +protected void annotateClass(Class cls) throws IOException { + setAnnotation(RMIClassLoader.getClassAnnotation(cls)); +} + +protected void annotateProxyClass(Class cls) + throws IOException +{ + annotateClass(cls); +} + +protected Object replaceObject(Object obj) + throws IOException +{ + if((obj instanceof Remote) && !(obj instanceof RemoteStub)){ + UnicastServerRef ref = UnicastServer.getExportedRef((Remote)obj); + if (ref != null) + return ref.getStub(); + } + return obj; +} + +protected void writeValue(Object value, Class valueClass) throws IOException{ + if(valueClass.isPrimitive()){ + if(valueClass == Boolean.TYPE) + writeBoolean(((Boolean)value).booleanValue()); + else + if(valueClass == Byte.TYPE) + writeByte(((Byte)value).byteValue()); + else + if(valueClass == Character.TYPE) + writeChar(((Character)value).charValue()); + else + if(valueClass == Short.TYPE) + writeShort(((Short)value).shortValue()); + else + if(valueClass == Integer.TYPE) + writeInt(((Integer)value).intValue()); + else + if(valueClass == Long.TYPE) + writeLong(((Long)value).longValue()); + else + if(valueClass == Float.TYPE) + writeFloat(((Float)value).floatValue()); + else + if(valueClass == Double.TYPE) + writeDouble(((Double)value).doubleValue()); + else + throw new Error("Unsupported primitive class: " + valueClass); + } else + writeObject(value); +} + +} diff --git a/libjava/classpath/gnu/java/rmi/server/RMIVoidValue.java b/libjava/classpath/gnu/java/rmi/server/RMIVoidValue.java new file mode 100644 index 000000000..8e5546d35 --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/server/RMIVoidValue.java @@ -0,0 +1,51 @@ +/* RMIVoidValue.java -- + Copyright (c) 2003 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; + +/** + * Package private class used to indicate a void return type. + * INSTANCE is the only object of this class ever made. + */ +final class RMIVoidValue +{ + static RMIVoidValue INSTANCE = new RMIVoidValue(); + + private RMIVoidValue() + { + } +} diff --git a/libjava/classpath/gnu/java/rmi/server/UnicastConnection.java b/libjava/classpath/gnu/java/rmi/server/UnicastConnection.java new file mode 100644 index 000000000..8245e0469 --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/server/UnicastConnection.java @@ -0,0 +1,231 @@ +/* UnicastConnection.java -- + Copyright (c) 1996, 1997, 1998, 1999, 2002, 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.rmi.server; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.net.Socket; +import java.rmi.RemoteException; + +public class UnicastConnection + implements Runnable, ProtocolConstants { + +UnicastConnectionManager manager; +Socket sock; +DataInputStream din; +DataOutputStream dout; +ObjectInputStream oin; +ObjectOutputStream oout; + +// reviveTime and expireTime make UnicastConnection pool-able +long reviveTime = 0; +long expireTime = Long.MAX_VALUE; + +UnicastConnection(UnicastConnectionManager man, Socket sock) { + this.manager = man; + this.sock = sock; +} + +void acceptConnection() throws IOException { +//System.out.println("Accepting connection on " + sock); + //Use BufferedXXXStream would be more efficient + din = new DataInputStream(new BufferedInputStream(sock.getInputStream())); + dout = new DataOutputStream(new BufferedOutputStream(sock.getOutputStream())); + + int sig = din.readInt(); + if (sig != PROTOCOL_HEADER) { + throw new IOException("bad protocol header"); + } + short ver = din.readShort(); + if (ver != PROTOCOL_VERSION) { + throw new IOException("bad protocol version"); + } + int protocol = din.readUnsignedByte(); + if (protocol != SINGLE_OP_PROTOCOL) { + // Send an ACK + dout.writeByte(PROTOCOL_ACK); + + // Send my hostname and port + dout.writeUTF(manager.serverName); + dout.writeInt(manager.serverPort); + dout.flush(); + + // Read their hostname and port + String rhost = din.readUTF(); + int rport = din.readInt(); + } + // Okay, ready to roll ... +} + +void makeConnection(int protocol) throws IOException { + //Use BufferedXXXStream would be more efficient + din = new DataInputStream(new BufferedInputStream(sock.getInputStream())); + + dout = new DataOutputStream(new BufferedOutputStream(sock.getOutputStream())); + + // Send header + dout.writeInt(PROTOCOL_HEADER); + dout.writeShort(PROTOCOL_VERSION); + dout.writeByte(protocol); + dout.flush(); + + if (protocol != SINGLE_OP_PROTOCOL) { + // Get back ack. + int ack = din.readUnsignedByte(); + if (ack != PROTOCOL_ACK) { + throw new RemoteException("Unsupported protocol"); + } + + // Read in host and port + String dicard_rhost = din.readUTF(); + int discard_rport = din.readInt(); + + // Send them my endpoint + dout.writeUTF(manager.serverName); + dout.writeInt(manager.serverPort); + dout.flush(); + } + // Okay, ready to roll ... +} + +DataInputStream getDataInputStream() throws IOException { + return (din); +} + +DataOutputStream getDataOutputStream() throws IOException { + return (dout); +} + +/* +* +* get ObjectInputStream for reading more objects +* +*/ +ObjectInputStream getObjectInputStream() throws IOException { + if (oin == null) { + throw new IOException("no ObjectInputtream for reading more objects"); + } + return (oin); +} + +/** +* +* starts ObjectInputStream. +* +*/ +ObjectInputStream startObjectInputStream() throws IOException { + return (oin = new RMIObjectInputStream(din)); +} + +/** +* +* get ObjectOutputStream for sending more objects +* +*/ +ObjectOutputStream getObjectOutputStream() throws IOException { + if (oout == null) { + throw new IOException("no ObjectOutputStream for sending more objects"); + } + return (oout); +} + +/** +* +* starts ObjectOutputStream. +* +*/ +ObjectOutputStream startObjectOutputStream() throws IOException { + return (oout = new RMIObjectOutputStream(dout)); +} + +void disconnect() { + try { + if(oout != null) + oout.close(); + sock.close(); + } + catch (IOException _) { + } + + oin = null; + oout = null; + din = null; + dout = null; + sock = null; +} + +public static final long CONNECTION_TIMEOUT = 10000L; + +static boolean isExpired(UnicastConnection conn, long l){ + if (l <= conn.expireTime ) + return false; + return true; +} + +static void resetTime(UnicastConnection conn){ + long l = System.currentTimeMillis(); + conn.reviveTime = l; + conn.expireTime = l + CONNECTION_TIMEOUT; +} + +/** + * We run connects on the server. Dispatch it then discard it. + */ +public void run() { + do{ + try { + UnicastServer.dispatch(this); + //don't discardConnection explicitly, only when + // exception happens or the connection's expireTime + // comes + } catch (Exception e ){ + manager.discardConnection(this); + break; + } + }while(true); +} + + +} diff --git a/libjava/classpath/gnu/java/rmi/server/UnicastConnectionManager.java b/libjava/classpath/gnu/java/rmi/server/UnicastConnectionManager.java new file mode 100644 index 000000000..981d11792 --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/server/UnicastConnectionManager.java @@ -0,0 +1,468 @@ +/* UnicastConnectionManager.java -- + Copyright (c) 1996, 1997, 1998, 1999, 2002, 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.rmi.server; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.UnknownHostException; +import java.rmi.RemoteException; +import java.rmi.server.RMIClientSocketFactory; +import java.rmi.server.RMIServerSocketFactory; +import java.rmi.server.RMISocketFactory; +import java.util.ArrayList; +import java.util.ConcurrentModificationException; +import java.util.Hashtable; +import java.util.Iterator; + +public class UnicastConnectionManager + implements Runnable, ProtocolConstants { + +private static String localhost; +// use different maps for server/client type UnicastConnectionManager +private static Hashtable servers = new Hashtable(); +// Package-private to avoid trampolines. +static Hashtable clients = new Hashtable(); +ArrayList connections; //client connection pool + +// make serverThread volatile for poll +private volatile Thread serverThread; +private ServerSocket ssock; +String serverName; +int serverPort; + +// Package-private to avoid a trampoline. +static Thread scavenger; + +// If client and server are in the same VM, serverobj represents server +Object serverobj; + +private static RMISocketFactory defaultSocketFactory = RMISocketFactory.getSocketFactory(); +private RMIServerSocketFactory serverFactory; +private RMIClientSocketFactory clientFactory; + +// The following is for debug +private static int ncsock = 0; //count of client socket +private static int nssock = 0; //count of server socket +private static int ncmanager = 0; //count of client manager +private static int nsmanager = 0; //count of server manager + +private static final boolean debug = false; + +private static final Object GLOBAL_LOCK = new Object(); + +static { + try { + //Use host address instead of host name to avoid name resolving issues + //localhost = InetAddress.getLocalHost().getHostName(); + localhost = InetAddress.getLocalHost().getHostAddress(); + } + catch (UnknownHostException _) { + localhost = "localhost"; + } + + +} + +//Only one scavenger thread running globally +private static void startScavenger(){ + scavenger = new Thread(new Runnable(){ + public void run(){ + if (debug) System.out.println("************* start scavenger."); + boolean liveon = true; + while (liveon){ + // Sleep for the expire timeout + try{ + Thread.sleep(UnicastConnection.CONNECTION_TIMEOUT); + }catch(InterruptedException _ie){ + break; + } + liveon = false; + // Scavenge all clients' connections that're expired + Iterator iter = clients.values().iterator(); + long l = System.currentTimeMillis(); + try{ + while(iter.hasNext()){ + UnicastConnectionManager man = (UnicastConnectionManager)iter.next(); + ArrayList conns = man.connections; + synchronized(conns) { // is the lock a little coarser? + for (int last = conns.size() - 1; + last >= 0; + --last) + { + UnicastConnection conn = (UnicastConnection)conns.get(last); + if (UnicastConnection.isExpired(conn, l)){ + conns.remove(last); + conn.disconnect(); + conn = null; + }else + liveon = true; //there're still live connections + } + } + } + }catch(ConcurrentModificationException cme) { + // handle it lazily + liveon = true; + } + } + scavenger = null; + if (debug) System.out.println("************* exit scavenger."); + } + }); + // As it is used for client connection, we may put this thread + // in daemon state to prevent the VM from blocking when exiting. + scavenger.setDaemon(true); + scavenger.start(); +} + +/** + * Client UnicastConnectionManager constructor + */ +private UnicastConnectionManager(String host, int port, RMIClientSocketFactory csf) { + ssock = null; + serverName = host; + serverPort = port; + serverFactory = null; + clientFactory = csf; + connections = new ArrayList(); +} + +/** + * Server UnicastConnectionManager constructor + */ +private UnicastConnectionManager(int port, RMIServerSocketFactory ssf) throws RemoteException { + + try { + ssock = ssf.createServerSocket(port); + serverPort = ssock.getLocalPort(); + } + catch (IOException ioex) { + ssock = null; + serverPort = 0; + throw new java.rmi.server.ExportException("can not create Server Socket on port " + port,ioex); + } + // Note that for compatibility the serverName is "localhost", + // not UnicastConnectionManager.localhost, which is the name + // of the local box. A server listening on localhost:port is + // listening on the loopback interface, 127.0.0.1, but + // UnicastConnectionManager.localhost is an externally + // accessible IP address. + serverName = "localhost"; + serverFactory = ssf; + clientFactory = null; +} + +/** + * Return a client connection manager which will connect to the given + * host/port. + */ +public static synchronized UnicastConnectionManager getInstance(String host, int port, RMIClientSocketFactory csf) { +//System.out.println("getInstance: " + host + "," + port + "," + csf); + if (csf == null) { + csf = defaultSocketFactory; + } + // change host name to host address to avoid name resolving issues + try{ + host = InetAddress.getByName(host).getHostAddress(); + }catch(Exception _){} + + TripleKey key = new TripleKey(host, port, csf); + UnicastConnectionManager man = (UnicastConnectionManager)clients.get(key); + if (man == null) { + man = new UnicastConnectionManager(host, port, csf); + if (debug) { + ncmanager++; + System.out.println("\n\n ====== " + ncmanager + " client managers.\n\n"); + } + clients.put(key, man); + + // Detect if client and server are in the same VM, i.e., their keys are equal + UnicastConnectionManager svrman = (UnicastConnectionManager)servers.get(key); + if(svrman != null){ // server and client are in the same VM + man.serverobj = svrman.serverobj; + } + } + return (man); +} + +/** + * Return a server connection manager which will accept connection on the + * given port. + */ +public static synchronized UnicastConnectionManager getInstance(int port, RMIServerSocketFactory ssf) throws RemoteException { +//System.out.println("getInstance: " + port + "," + ssf); + if (ssf == null) { + ssf = defaultSocketFactory; + } + TripleKey key = new TripleKey(localhost, port, ssf); + UnicastConnectionManager man = (UnicastConnectionManager)servers.get(key); + if (man == null) { + man = new UnicastConnectionManager(port, ssf); + if (debug) { + nsmanager++; + System.out.println("\n\n ****** " + nsmanager + " server managers.\n\n"); + } + // The provided port might not be the set port. + key.port = man.serverPort; + servers.put(key, man); + } + return (man); +} + +/** + * Get a connection from this manager. + */ +public UnicastConnection getConnection() throws IOException { + if (ssock == null) { + return (getClientConnection()); + } + else { + return (getServerConnection()); + } +} + +/** + * Accept a connection to this server. + */ +private UnicastConnection getServerConnection() throws IOException { + Socket sock = ssock.accept(); + sock.setTcpNoDelay(true); //?? + UnicastConnection conn = new UnicastConnection(this, sock); + conn.acceptConnection(); + if (debug){ + nssock++; + System.out.println("\n\n ****** " + nssock + " server socks.\n\n"); + } + //System.out.println("Server connection " + sock); + return (conn); +} + +/** + * Make a conection from this client to the server. + */ +private UnicastConnection getClientConnection() throws IOException { + ArrayList conns = connections; + UnicastConnection conn; + + synchronized(conns) { + int nconn = conns.size() - 1; + + // if there're free connections in connection pool + if(nconn >= 0) { + conn = (UnicastConnection)conns.get(nconn); + //Should we check if conn is alive using Ping?? + conns.remove(nconn); + + // Check if the connection is already expired + long l = System.currentTimeMillis(); + if (!UnicastConnection.isExpired(conn, l)){ + return conn; + }else { + conn.disconnect(); + conn = null; + } + } + } + + Socket sock = clientFactory.createSocket(serverName, serverPort); + conn = new UnicastConnection(this, sock); + conn.makeConnection(DEFAULT_PROTOCOL); + + if (debug) { + ncsock++; + System.out.println("\n\n ====== " + ncsock + " client socks.\n\n"); + } + + return (conn); +} + +/** + * Get the string representation, describing the connection. + */ +public String toString() +{ + return serverName+":"+serverPort+" ("+serverobj+")"; +} + +/** + * Discard a connection when we're done with it - maybe it can be + * recycled. + */ +public void discardConnection(UnicastConnection conn) { +//System.out.println("Discarding connection " + conn); + //conn.disconnect(); + if (ssock != null) //server connection + conn.disconnect(); + else { + // To client connection, we'd like to return back to pool + UnicastConnection.resetTime(conn); + //Ensure there're only one scavenger globally + synchronized(GLOBAL_LOCK) { + connections.add(conn); //borrow this lock to garantee thread safety + if (scavenger == null) + startScavenger(); + } + } +} + +/** + * Start a server on this manager if it's a server socket and we've not + * already got one running. + */ +public void startServer() { + synchronized(this) { + if (ssock == null || serverThread != null) { + return; + } + serverThread = new Thread(this); + // The following is not necessary when java.lang.Thread's constructor do this. + // serverThread.setContextClassLoader(Thread.currentThread().getContextClassLoader()); + } + serverThread.start(); +} + +/** + * Stop a server on this manager + */ +public void stopServer() { + synchronized(this) { + if(serverThread != null){ + serverThread = null; + try{ + ssock.close(); + }catch(Exception _){} + } + } +} + +/** + * Server thread for connection manager. + */ +public void run() { + for (;serverThread != null;) { // if serverThread==null, then exit thread + try { +//System.out.println("Waiting for connection on " + serverPort); + UnicastConnection conn = getServerConnection(); + + // get address of remote host for the RMIIncomingThread object + String remoteHost = null; + if (conn.sock != null) { + remoteHost = conn.sock.getInetAddress().getHostAddress(); + } + + // use a thread pool to improve performance + //ConnectionRunnerPool.dispatchConnection(conn); + (new RMIIncomingThread(conn, remoteHost)).start(); +// (new Thread(conn)).start(); + } + catch (Exception e) { + e.printStackTrace(); + } + } +} + +/** + * Serialization routine. + */ +void write(ObjectOutput out) throws IOException { + out.writeUTF(serverName); + out.writeInt(serverPort); +} + +/** + * Serialization routine. + */ +static UnicastConnectionManager read(ObjectInput in) throws IOException { + String host = in.readUTF(); + int port = in.readInt(); + //RMIClientSocketFactory csf = ((RMIObjectInputStream)in).manager.clientFactory; + //return (getInstance(host, port, csf)); + return (getInstance(host, port, null)); +} + +} + +/** + * This is use as the hashkey for the client/server connections. + */ +class TripleKey { + +String host; +int port; +Object other; + +TripleKey(String host, int port, Object other) { + this.host = host; + this.port = port; + this.other = other; +} + +/** + * Hash code just include the host and other - we ignore the port since + * this has unusual matching behaviour. + */ +public int hashCode() { + return (host.hashCode() ^ other.hashCode()); +} + +public boolean equals(Object obj) { + if (obj instanceof TripleKey) { + TripleKey other = (TripleKey)obj; + if (this.host.equals(other.host) && + this.other == other.other && + (this.port == other.port /* || this.port == 0 || other.port == 0*/)) { + return (true); + } + } + return (false); +} + + /** + * Get the string representation, describing the connection. + */ + public String toString() + { + return host+":"+port+" ("+other+")"; + } + +} diff --git a/libjava/classpath/gnu/java/rmi/server/UnicastRef.java b/libjava/classpath/gnu/java/rmi/server/UnicastRef.java new file mode 100644 index 000000000..ca2bab51a --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/server/UnicastRef.java @@ -0,0 +1,524 @@ +/* UnicastRef.java -- + Copyright (c) 1996, 1997, 1998, 1999, 2002, 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.java.rmi.server; + +import gnu.java.rmi.dgc.LeaseRenewingTask; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectInputStream; +import java.io.ObjectOutput; +import java.io.ObjectOutputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.rmi.ConnectException; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.dgc.Lease; +import java.rmi.server.ObjID; +import java.rmi.server.Operation; +import java.rmi.server.RMIClientSocketFactory; +import java.rmi.server.RemoteCall; +import java.rmi.server.RemoteObject; +import java.rmi.server.RemoteRef; +import java.rmi.server.UID; + +public class UnicastRef + implements RemoteRef, ProtocolConstants +{ + + /** + * Use serial version UID for iteroperability + */ + private static final long serialVersionUID = 1; + + public ObjID objid; + + UnicastConnectionManager manager; + + /** + * Used by serialization, and let subclass capable of having default + * constructor + */ + // must be public otherwise java.rmi.RemoteObject cannot instantiate this + // class + // -- iP + public UnicastRef() + { + } + + public UnicastRef(ObjID objid, String host, int port, + RMIClientSocketFactory csf) + { + this(objid); + manager = UnicastConnectionManager.getInstance(host, port, csf); + } + + public UnicastRef(ObjID objid) + { + this.objid = objid; + } + + public Object invoke(Remote obj, Method method, Object[] params, long opnum) + throws Exception + { + // Check if client and server are in the same VM, then local call can be + // used to + // replace remote call, but it's somewhat violating remote semantic. + Object svrobj = manager.serverobj; + + // Make sure that the server object is compatible. It could be loaded from a + // different + // classloader --iP + if (svrobj != null && method.getDeclaringClass().isInstance(svrobj)) + { + // local call + Object ret = null; + try + { + ret = method.invoke(svrobj, params); + } + catch (InvocationTargetException e) + { + throw (Exception) e.getTargetException(); + } + // System.out.println("\n\n ***** local call: " + method + "\nreturn: " + // + ret + "\n\n"); + return ret; + } + // System.out.println("***************** remote call:" + + // manager.serverPort); + return (invokeCommon(obj, method, params, - 1, opnum)); + } + + /** + * The ordinary number of the DGC messages. + */ + static long dgcSequence; + + /** + * The DGC object id, also serves as a synchronization target to increment the + * dgcSequence safely. + */ + static final ObjID dgcId = new ObjID(ObjID.DGC_ID); + + ObjID[] this_id; + + /** + * The number of the method "dirty" in the DGC. + */ + static int DIRTY = 1; + + /** + * The DGC interface hash code. + */ + static final long dgcInterfaceHash = - 669196253586618813L; + + /** + * Notify the DGC of the remote side that we still hold this object. + */ + public Lease notifyDGC(Lease lease) throws Exception + { + long seq; + synchronized (dgcId) + { + seq = dgcSequence++; + } + + if (this_id == null) + this_id = new ObjID[] { objid }; + + UnicastConnection conn; + try + { + conn = manager.getConnection(); + } + catch (IOException e1) + { + throw new RemoteException("connection failed to host: " + + manager.serverName, e1); + } + + ObjectOutputStream out; + DataOutputStream dout; + try + { + dout = conn.getDataOutputStream(); + dout.writeByte(MESSAGE_CALL); + + out = conn.startObjectOutputStream(); // (re)start ObjectOutputStream + + dgcId.write(out); + // The number of the operation is 1 ("dirty") + out.writeInt(DIRTY); + out.writeLong(dgcInterfaceHash); + + RMIObjectOutputStream rout = (RMIObjectOutputStream) out; + + rout.writeValue(this_id, this_id.getClass()); + rout.writeLong(seq); + rout.writeValue(lease, lease.getClass()); + + out.flush(); + } + catch (IOException e2) + { + throw new RemoteException("DGC call failed: ", e2); + } + + int returncode; + Object returnval; + DataInputStream din; + ObjectInputStream in; + UID ack; + try + { + din = conn.getDataInputStream(); + + if ((returncode = din.readUnsignedByte()) != MESSAGE_CALL_ACK) + { + conn.disconnect(); + throw new RemoteException("DGC Call not acked:" + returncode); + } + + in = conn.startObjectInputStream(); // (re)start ObjectInputStream + returncode = in.readUnsignedByte(); + ack = UID.read(in); + + if (returncode == RETURN_NACK) + { + returnval = in.readObject(); // get Exception + + } + else + { + returnval = ((RMIObjectInputStream) in).readValue(Lease.class); + } + } + catch (IOException e3) + { + throw new RemoteException("DGC call return failed: ", e3); + } + + manager.discardConnection(conn); + + if (returncode != RETURN_ACK && returnval != null) + { + if (returncode == RETURN_NACK) + throw (Exception) returnval; + else + throw new RemoteException("DGC unexpected returncode: " + returncode); + } + + return (Lease) returnval; + } + /** + * Invoke the remote method on the given object. This part is overridden by + * the activatable objects. + */ + protected Object invokeCommon(Remote obj, Method method, Object[] params, + int opnum, long hash) throws Exception + { + UnicastConnection conn; + try + { + conn = manager.getConnection(); + return invokeCommon(conn, obj, method, params, opnum, hash); + } + catch (IOException e1) + { + throw new RemoteException("connection failed to host: " + + manager.serverName, e1); + } + } + + /** + * Invoke the remote method on the given object when connection is already + * established. + */ + protected Object invokeCommon(UnicastConnection conn, Remote obj, + Method method, Object[] params, int opnum, + long hash) throws Exception + { + ObjectOutputStream out; + DataOutputStream dout; + try + { + dout = conn.getDataOutputStream(); + dout.writeByte(MESSAGE_CALL); + + out = conn.startObjectOutputStream(); // (re)start ObjectOutputStream + + objid.write(out); + out.writeInt(opnum); + out.writeLong(hash); + + // must handle primitive class and their wrapper classes + Class clss[] = method.getParameterTypes(); + for (int i = 0; i < clss.length; i++) + ((RMIObjectOutputStream) out).writeValue(params[i], clss[i]); + + out.flush(); + } + catch (IOException e2) + { + throw new RemoteException("call failed: ", e2); + } + + int returncode; + Object returnval; + DataInputStream din; + ObjectInputStream in; + UID ack; + try + { + din = conn.getDataInputStream(); + + if ((returncode = din.readUnsignedByte()) != MESSAGE_CALL_ACK) + { + conn.disconnect(); + throw new RemoteException("Call not acked:" + returncode); + } + + in = conn.startObjectInputStream(); // (re)start ObjectInputStream + returncode = in.readUnsignedByte(); + ack = UID.read(in); + + Class cls = method.getReturnType(); + + if (returncode == RETURN_NACK) + { + returnval = in.readObject(); // get Exception + + } + else if (cls == Void.TYPE) + { + returnval = null; + // in.readObject() // not required! returntype 'void' means no field + // is returned. + } + else + { + returnval = ((RMIObjectInputStream) in).readValue(cls); // get + // returnvalue + } + } + catch (IOException e3) + { + // for debug: e3.printStackTrace(); + throw new RemoteException("call return failed: ", e3); + } + + /* + * if DGCAck is necessary?? //According to RMI wire protocol, send a DGCAck // + * to indicate receiving return value dout.writeByte(MESSAGE_DGCACK); + * ack.write(dout); out.flush(); + */ + + manager.discardConnection(conn); + + if (returncode != RETURN_ACK && returnval != null) + { + if (returncode == RETURN_NACK) + throw (Exception) returnval; + else + throw new RemoteException("unexpected returncode: " + returncode); + } + + return (returnval); + } + + /** + * @deprecated + */ + public RemoteCall newCall(RemoteObject obj, Operation[] op, int opnum, + long hash) throws RemoteException + { + UnicastConnection conn; + + try + { + conn = manager.getConnection(); + } + catch (IOException e1) + { + throw new ConnectException("connection failed to host: " + + manager.serverName, e1); + } + + // obj: useless? + + return (new UnicastRemoteCall(conn, objid, opnum, hash)); + } + + /** + * @deprecated + */ + public void invoke(RemoteCall call) throws Exception + { + UnicastRemoteCall c = (UnicastRemoteCall) call; + call.executeCall(); + } + + /** + * @deprecated + */ + public void done(RemoteCall call) throws RemoteException + { + UnicastRemoteCall c = (UnicastRemoteCall) call; + try + { + c.done(); + } + catch (IOException e) + { + } + UnicastConnection conn = c.getConnection(); + manager.discardConnection(conn); + } + + public void writeExternal(ObjectOutput out) throws IOException + { + if (manager == null) + { + throw new IOException("no connection"); + } + manager.write(out); + objid.write(out); + // This byte is somewhat confusing when interoperating with JDK + out.writeByte(0); // RETURN_ACK); + } + + public void readExternal(ObjectInput in) throws IOException, + ClassNotFoundException + { + manager = UnicastConnectionManager.read(in); + objid = ObjID.read(in); + byte ack = in.readByte(); + // This byte is somewhat confusing when interoperating with JDK + if (ack != RETURN_ACK && ack != 0/* jdk ack value */) + { + throw new IOException("no ack found"); + } + + // Notify the DGC of the remote side that we hold the reference to the + // received object. Do not notify if the client and server are on the + // same virtual machine. + if (manager.serverobj == null) + LeaseRenewingTask.scheduleLeases(this); + } + + public boolean remoteEquals(RemoteRef ref) + { + throw new Error("Not implemented"); + } + + public int remoteHashCode() + { + throw new Error("Not implemented"); + } + + public String getRefClass(ObjectOutput out) + { + return ("UnicastRef"); + } + + /** + * Return the string representing the remote reference information. + */ + public String remoteToString() + { + if (manager!=null) + return manager.toString(); + else + return "null manager"; + } + + public void dump(UnicastConnection conn) + { + try + { + DataInputStream din = conn.getDataInputStream(); + for (;;) + { + int b = din.readUnsignedByte(); + System.out.print(Integer.toHexString(b)); + if (b >= 32 && b < 128) + { + System.out.print(": " + (char) b); + } + System.out.println(); + } + } + catch (IOException _) + { + } + } + + /** + * Check if this UnicastRef points to the object as the passed UnicastRef. + * Both the object Id and manager must be the same. + * + * @return true if the passed reference points to the same remote object as + * this reference, false otherwise. + */ + public boolean equals(Object other) + { + if (other instanceof UnicastRef) + { + UnicastRef r = (UnicastRef) other; + return r.manager.equals(manager) && r.objid.equals(objid); + } + else + return false; + } + + /** + * Get the hash code of this UnicastRef, combining hash code of the manager + * with hash code of the object id. + */ + public int hashCode() + { + return manager.hashCode() ^ objid.hashCode(); + } + +} diff --git a/libjava/classpath/gnu/java/rmi/server/UnicastRemoteCall.java b/libjava/classpath/gnu/java/rmi/server/UnicastRemoteCall.java new file mode 100644 index 000000000..d0d77304c --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/server/UnicastRemoteCall.java @@ -0,0 +1,525 @@ +/* UnicastRemoteCall.java + Copyright (c) 1996, 1997, 1998, 1999, 2002, 2004, 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.java.rmi.server; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.io.StreamCorruptedException; +import java.rmi.MarshalException; +import java.rmi.RemoteException; +import java.rmi.UnmarshalException; +import java.rmi.server.ObjID; +import java.rmi.server.RemoteCall; +import java.rmi.server.UID; +import java.util.Vector; + +public class UnicastRemoteCall + implements RemoteCall, ProtocolConstants +{ + + private UnicastConnection conn; + private Object result; + private Object object; + private int opnum; + private long hash; + // These are package-private due to inner class access. + Vector vec; + int ptr; + private ObjID objid; + + private ObjectOutput oout; + private ObjectInput oin; + + /** + * Incoming call. + */ + UnicastRemoteCall(UnicastConnection conn) + { + this.conn = conn; + } + + /** + * Outgoing call. + */ + UnicastRemoteCall(UnicastConnection conn, ObjID objid, int opnum, long hash) + throws RemoteException + { + this.conn = conn; + this.opnum = opnum; + this.hash = hash; + this.objid = objid; + } + + UnicastConnection getConnection() + { + return conn; + } + + public ObjectOutput getOutputStream() throws IOException + { + if (vec == null) + vec = new Vector(); + return (new DummyObjectOutputStream()); + } + + public void releaseOutputStream() throws IOException + { + if (vec != null) + { + oout = conn.getObjectOutputStream(); + + for (int i = 0; i < vec.size(); i += 2) + { + boolean primitive = ((Boolean)vec.elementAt(i)).booleanValue(); + Object data = vec.elementAt(i+1); + + // No type, this is + if (!primitive) + oout.writeObject(data); + else + { + if (data instanceof Boolean) + oout.writeBoolean(((Boolean)data).booleanValue()); + else if (data instanceof Character) + oout.writeChar(((Character)data).charValue()); + else if (data instanceof Byte) + oout.writeByte(((Byte)data).byteValue()); + else if (data instanceof Short) + oout.writeShort(((Short)data).shortValue()); + else if (data instanceof Integer) + oout.writeInt(((Integer)data).intValue()); + else if (data instanceof Long) + oout.writeLong(((Long)data).longValue()); + } + } + vec = null; + } + if(oout != null) + oout.flush(); + } + + /** + * + * (re)starts ObjectInputStream + * + */ + public ObjectInput startInputStream() throws IOException + { + if (conn != null) { + return (oin = conn.startObjectInputStream()); + } else { + return getInputStream(); // dummy Input Stream + } + + } + + public ObjectInput getInputStream() throws IOException + { + if (conn != null) + { + if(oin == null) + return (oin = conn.getObjectInputStream()); + else + return oin; + } + else + { + ptr = 0; + return (new DummyObjectInputStream()); + } + } + + public void releaseInputStream() throws IOException + { + // Does nothing. + } + + public ObjectOutput getResultStream(boolean success) + throws IOException, StreamCorruptedException + { + vec = new Vector(); + return new DummyObjectOutputStream(); + } + + public void executeCall() throws Exception + { + byte returncode; + ObjectInput oin; + + // signal the call when constructing + try + { + DataOutputStream dout = conn.getDataOutputStream(); + dout.write(MESSAGE_CALL); + + oout = conn.startObjectOutputStream(); // (re)start ObjectOutputStream + objid.write(oout); + oout.writeInt(opnum); + oout.writeLong(hash); + } + catch(IOException ex) + { + throw new MarshalException("Try to write header but failed.", ex); + } + + try + { + releaseOutputStream(); + DataInputStream din = conn.getDataInputStream(); + if (din.readByte() != MESSAGE_CALL_ACK) + throw new RemoteException("Call not acked"); + + oin = startInputStream(); + returncode = oin.readByte(); + UID.read(oin); + } + catch(IOException ex) + { + throw new UnmarshalException("Try to read header but failed:", ex); + } + + //check return code + switch(returncode) + { + case RETURN_ACK: //it's ok + return; + case RETURN_NACK: + Object returnobj; + try + { + returnobj = oin.readObject(); + } + catch(Exception ex2) + { + throw new UnmarshalException + ("Try to read exception object but failed", ex2); + } + + if(!(returnobj instanceof Exception)) + throw new UnmarshalException("Should be Exception type here: " + + returnobj); + throw (Exception)returnobj; + + default: + throw new UnmarshalException("Invalid return code"); + } + } + + public void done() throws IOException + { + // conn.disconnect(); + } + + boolean isReturnValue() + { + return vec.size() > 0; + } + + Object returnValue() + { + // This is not the first one (Boolean) but the second. + return vec.elementAt(1); + } + + Object[] getArguments() + { + return vec.toArray(); + } + + Object getObject() + { + return object; + } + + int getOpnum() + { + return opnum; + } + + long getHash() + { + return hash; + } + + void setReturnValue(Object obj) + { + vec.removeAllElements(); + vec.addElement(obj); + } + + /** + * Dummy object output class. + */ + private class DummyObjectOutputStream implements ObjectOutput + { + /** + * Non-private constructor to reduce bytecode emitted. + */ + DummyObjectOutputStream() + { + } + + public void writeBoolean(boolean v) throws IOException + { + vec.addElement(Boolean.TRUE); + vec.addElement(Boolean.valueOf(v)); + } + + public void writeByte(int v) throws IOException + { + vec.addElement(Boolean.TRUE); + vec.addElement(new Byte((byte) v)); + } + + public void writeChar(int v) throws IOException + { + vec.addElement(Boolean.TRUE); + vec.addElement(new Character((char) v)); + } + + public void writeDouble(double v) throws IOException + { + vec.addElement(Boolean.TRUE); + vec.addElement(new Double(v)); + } + + public void writeFloat(float v) throws IOException + { + vec.addElement(Boolean.TRUE); + vec.addElement(new Float(v)); + } + + public void writeInt(int v) throws IOException + { + vec.addElement(Boolean.TRUE); + vec.addElement(new Integer(v)); + } + + public void writeLong(long v) throws IOException + { + vec.addElement(Boolean.TRUE); + vec.addElement(new Long(v)); + } + + public void writeShort(int v) throws IOException + { + vec.addElement(Boolean.TRUE); + vec.addElement(new Short((short) v)); + } + + public void writeObject(Object obj) throws IOException + { + vec.addElement(Boolean.FALSE); + vec.addElement(obj); + } + + public void write(byte b[]) throws IOException + { + throw new IOException("not required"); + } + + public void write(byte b[], int off, int len) throws IOException + { + throw new IOException("not required"); + } + + public void write(int b) throws IOException + { + throw new IOException("not required"); + } + + public void writeBytes(String s) throws IOException + { + throw new IOException("not required"); + } + + public void writeChars(String s) throws IOException + { + throw new IOException("not required"); + } + + public void writeUTF(String str) throws IOException + { + throw new IOException("not required"); + } + + public void flush() throws IOException + { + } + + public void close() throws IOException + { + } + } // class DummyObjectOutputStream + + /** + * Dummy object input class. + */ + private class DummyObjectInputStream implements ObjectInput + { + /** + * Non-private constructor to reduce bytecode emitted. + */ + DummyObjectInputStream() + { + } + + public boolean readBoolean() throws IOException + { + Object obj = vec.elementAt(ptr++); + return ((Boolean) obj).booleanValue(); + } + + public byte readByte() throws IOException + { + Object obj = vec.elementAt(ptr++); + return ((Byte) obj).byteValue(); + } + + public char readChar() throws IOException + { + Object obj = vec.elementAt(ptr++); + return ((Character) obj).charValue(); + } + + public double readDouble() throws IOException + { + Object obj = vec.elementAt(ptr++); + return ((Double) obj).doubleValue(); + } + + public float readFloat() throws IOException + { + Object obj = vec.elementAt(ptr++); + return ((Float) obj).floatValue(); + } + + public int readInt() throws IOException + { + Object obj = vec.elementAt(ptr++); + return ((Integer) obj).intValue(); + } + + public long readLong() throws IOException + { + Object obj = vec.elementAt(ptr++); + return ((Long) obj).longValue(); + } + + public short readShort() throws IOException + { + Object obj = vec.elementAt(ptr++); + return ((Short) obj).shortValue(); + } + + public Object readObject() throws IOException + { + return vec.elementAt(ptr++); + } + + public int read(byte b[]) throws IOException + { + throw new IOException("not required"); + } + + public int read(byte b[], int off, int len) throws IOException + { + throw new IOException("not required"); + } + + public int read() throws IOException + { + throw new IOException("not required"); + } + + public long skip(long n) throws IOException + { + throw new IOException("not required"); + } + + public int available() throws IOException + { + throw new IOException("not required"); + } + + public void readFully(byte b[]) throws IOException + { + throw new IOException("not required"); + } + + public void readFully(byte b[], int off, int len) throws IOException + { + throw new IOException("not required"); + } + + public String readLine() throws IOException + { + throw new IOException("not required"); + } + + public String readUTF() throws IOException + { + throw new IOException("not required"); + } + + public int readUnsignedByte() throws IOException + { + throw new IOException("not required"); + } + + public int readUnsignedShort() throws IOException + { + throw new IOException("not required"); + } + + public int skipBytes(int n) throws IOException + { + throw new IOException("not required"); + } + + public void close() throws IOException + { + } + } // class DummyObjectInputStream + +} diff --git a/libjava/classpath/gnu/java/rmi/server/UnicastRemoteStub.java b/libjava/classpath/gnu/java/rmi/server/UnicastRemoteStub.java new file mode 100644 index 000000000..179f30179 --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/server/UnicastRemoteStub.java @@ -0,0 +1,50 @@ +/* UnicastRemoteStub.java -- + Copyright (c) 1996, 1997, 1998, 1999 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.rmi.server.RemoteRef; +import java.rmi.server.RemoteStub; + +public class UnicastRemoteStub + extends RemoteStub { + +public static void setStubRef(RemoteStub stub, RemoteRef ref) { + setRef(stub, ref); +} + +} diff --git a/libjava/classpath/gnu/java/rmi/server/UnicastServer.java b/libjava/classpath/gnu/java/rmi/server/UnicastServer.java new file mode 100644 index 000000000..db2bd2ff8 --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/server/UnicastServer.java @@ -0,0 +1,321 @@ +/* UnicastServer.java -- + Copyright (c) 1996, 1997, 1998, 1999, 2002, 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.rmi.server; + +import gnu.java.rmi.dgc.DGCImpl; +import gnu.java.util.WeakIdentityHashMap; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.rmi.NoSuchObjectException; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.ServerError; +import java.rmi.activation.ActivationException; +import java.rmi.activation.ActivationID; +import java.rmi.server.ObjID; +import java.rmi.server.UID; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; +import java.util.WeakHashMap; + +public class UnicastServer + implements ProtocolConstants +{ + + /** + * Mapping OBJID to server ref by .equals(). + */ + static private Map objects = Collections.synchronizedMap(new WeakHashMap()); + + /** + * Mapping obj itself to server ref by identity. + */ + static private Map refcache = Collections.synchronizedMap(new WeakIdentityHashMap()); + + /** + * Mapping the registered activatable objects into they server references. + */ + public static Map actIds = new Hashtable(); + + /** + * The reference to the local distributed garbage collector. + */ + static private DGCImpl dgc; + + /** + * Connect this server reference to the server, allowing the local + * implementation, associated with this object, to receive remote calls. + * + * @param obj the server reference, encloses the (usually local) remote + * object. + */ + public static void exportObject(UnicastServerRef obj) + { + startDGC(); + objects.put(obj.objid, obj); + refcache.put(obj.myself, obj); + obj.manager.startServer(); + } + + /** + * Register the activatable object into the table of the activatable + * objects. + */ + public static void registerActivatable(ActivatableServerRef ref) + { + actIds.put(ref.actId, ref); + } + + /** + * Export tha activatable object. The object id is placed into the map, + * but the object itself not. This is enough to deliver call to + * the ref.incomingMessageCall where the object will be instantiated, + * if not present. + */ + public static void exportActivatableObject(ActivatableServerRef ref) + { + startDGC(); + objects.put(ref.objid, ref); + ref.manager.startServer(); + actIds.put(ref.actId, ref); + } + + + /** + * Get the activatable server reference that is handling activation of the + * given activation id. + */ + public static ActivatableServerRef getActivatableRef(ActivationID id) + throws ActivationException + { + ActivatableServerRef ref = (ActivatableServerRef) actIds.get(id); + if (ref == null) + throw new ActivationException(id + " was not registered with this server"); + return ref; + } + + /** + * Unregister the previously registered activatable server reference. + */ + public static void unregisterActivatable(ActivationID id) + { + actIds.remove(id); + } + + // FIX ME: I haven't handle force parameter + /** + * Remove the given server reference. The remote object, associated with + * this reference, will no longer receive remote calls via this server. + */ + public static boolean unexportObject(UnicastServerRef obj, boolean force) + { + objects.remove(obj.objid); + refcache.remove(obj.myself); + obj.manager.stopServer(); + + if (obj instanceof ActivatableServerRef) + { + ActivationID id = ((ActivatableServerRef) obj).actId; + unregisterActivatable(id); + } + return true; + } + + /** + * Get the exported reference of the given Remote. The identity map is used, + * the non-null value will only be returned if exactly the passed remote + * is part of the registered UnicastServerRef. + * + * @param remote the Remote that is connected to this server via + * {@link UnicastServerRef}. + * + * @return the UnicastServerRef that is used to connect the passed + * remote with this server or null, if this Remote is not connected + * to this server. + */ + public static UnicastServerRef getExportedRef(Remote remote) + { + return (UnicastServerRef) refcache.get(remote); + } + + /** + * Get the server references to the object, previously exported via this + * server. As the identity map is scanned, more than one reference may match + * this Id. + * + * @param id the id of the exported object + * @return the server reference to this object, null if none. + */ + public static Collection getExported(Object id) + { + synchronized (objects) + { + ArrayList list = new ArrayList(); + Iterator iter = objects.entrySet().iterator(); + Map.Entry e; + Object key; + while (iter.hasNext()) + { + e = (Map.Entry) iter.next(); + key = e.getKey(); + if (key != null && key.equals(id)) + list.add(e.getValue()); + } + return list; + } + } + + private static synchronized void startDGC() + { + if (dgc == null) + { + try + { + dgc = new DGCImpl(); + // Changed DGCImpl to inherit UnicastServerRef directly + // ((UnicastServerRef)dgc.getRef()).exportObject(dgc); + dgc.exportObject(dgc); + } + catch (RemoteException e) + { + e.printStackTrace(); + } + } + } + + public static void dispatch(UnicastConnection conn) throws Exception + { + switch (conn.getDataInputStream().readUnsignedByte()) + { + case MESSAGE_CALL: + incomingMessageCall(conn); + break; + case MESSAGE_PING: + // jdk sends a ping before each method call -> answer it! + DataOutputStream out = conn.getDataOutputStream(); + out.writeByte(MESSAGE_PING_ACK); + out.flush(); + break; + default: + throw new Exception("bad method type"); + } + } + + /** + * This method is invoked when the remote call is received. The method + * dispatches the call to the responsible object, connected to this + * server via UnicastServerReference. + */ + private static void incomingMessageCall(UnicastConnection conn) + throws IOException + { + ObjectInputStream in = conn.startObjectInputStream(); // (re)start + // ObjectInputStream + + ObjID objid = ObjID.read(in); + int method = in.readInt(); + long hash = in.readLong(); + + // System.out.println("ObjID: " + objid + ", method: " + method + ", hash: " + // + hash); + + // Use the objid to locate the relevant UnicastServerRef + UnicastServerRef uref = (UnicastServerRef) objects.get(objid); + Object returnval; + int returncode = RETURN_ACK; + // returnval is from Method.invoke(), so we must check the return class to + // see + // if it's primitive type + Class returncls = null; + if (uref != null) + { + try + { + // Dispatch the call to it. + returnval = uref.incomingMessageCall(conn, method, hash); + returncls = uref.getMethodReturnType(method, hash); + } + catch (Exception e) + { + returnval = e; + returncode = RETURN_NACK; + } + catch (Error e) + { + returnval = new ServerError( + "Server error, ObjID: " + objid + + ", method: " + method + ", hash: "+ hash, e); + returncode = RETURN_NACK; + } + } + else + { + returnval = new NoSuchObjectException("ObjID: " + objid); + returncode = RETURN_NACK; + } + + conn.getDataOutputStream().writeByte(MESSAGE_CALL_ACK); + + ObjectOutputStream out = conn.startObjectOutputStream(); // (re)start + // ObjectOutputStream + + out.writeByte(returncode); + (new UID()).write(out); + + // System.out.println("returnval=" + returnval + " returncls=" + returncls); + + if (returnval != null && returncls != null) + ((RMIObjectOutputStream) out).writeValue(returnval, returncls); + + // 1.1/1.2 void return type detection: + else if (! (returnval instanceof RMIVoidValue || returncls == Void.TYPE)) + out.writeObject(returnval); + + out.flush(); + } + +} diff --git a/libjava/classpath/gnu/java/rmi/server/UnicastServerRef.java b/libjava/classpath/gnu/java/rmi/server/UnicastServerRef.java new file mode 100644 index 000000000..59a9f080b --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/server/UnicastServerRef.java @@ -0,0 +1,481 @@ +/* UnicastServerRef.java -- + Copyright (c) 1996, 1997, 1998, 1999, 2002, 2003, 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.rmi.server; + +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.Skeleton; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Iterator; + +/** + * This class connects the local, remotely available (exported) object to + * the local RMI server that accepts the remote calls. + */ +public class UnicastServerRef + 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. + */ + protected Skeleton skel; + + /** + * The stub, associated with the exported remote object (may be proxy class). + */ + protected Remote stub; + + /** + * The method table (RMI hash code to method) of the methods of the + * exported object. + */ + protected 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 = 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); + } + + return stub; + } + + /** + * 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); + } + + /** + * 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. + */ + protected 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. + */ + protected 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. + */ + protected 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; + } + + /** + * This method is called from the {@link UnicastServer#incomingMessageCall} + * to deliver the remote call to this object. + */ + 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( + myself.getClass().getName()+" hash "+hash); + } + + 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("JDK 1.1 call - Skeleton required"); + + 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/libjava/classpath/gnu/java/rmi/server/package.html b/libjava/classpath/gnu/java/rmi/server/package.html new file mode 100644 index 000000000..08c105b49 --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/server/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.rmi.server + + +

+ + + diff --git a/libjava/classpath/gnu/java/security/.cvsignore b/libjava/classpath/gnu/java/security/.cvsignore new file mode 100644 index 000000000..11f6639eb --- /dev/null +++ b/libjava/classpath/gnu/java/security/.cvsignore @@ -0,0 +1 @@ +Configuration.java diff --git a/libjava/classpath/gnu/java/security/Configuration.java.in b/libjava/classpath/gnu/java/security/Configuration.java.in new file mode 100644 index 000000000..1deb543d4 --- /dev/null +++ b/libjava/classpath/gnu/java/security/Configuration.java.in @@ -0,0 +1,56 @@ +/* Configuration.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.java.security; + +/** + * This file defines compile-time constants that can be accessed by + * our crypto code. All crypto code should use and define such + * constants here instead of using the gnu.classpath.Configuration class. + */ +public interface Configuration +{ + + /** + * The value of DEBUG is substituted according to whether the + * "--enable-debug" argument was passed to configure. Code + * which is made conditional based on the value of this flag - typically + * code that generates debugging output - will be removed by the optimizer + * in a non-debug build. + */ + boolean DEBUG = @LIBDEBUG@; +} diff --git a/libjava/classpath/gnu/java/security/Engine.java b/libjava/classpath/gnu/java/security/Engine.java new file mode 100644 index 000000000..969fcef6c --- /dev/null +++ b/libjava/classpath/gnu/java/security/Engine.java @@ -0,0 +1,282 @@ +/* Engine -- generic getInstance method. + Copyright (C) 2003, 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; + +import gnu.java.lang.CPStringBuilder; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.util.Enumeration; + +/** + * Generic implementation of the getInstance methods in the various + * engine classes in java.security. + *

+ * These classes ({@link java.security.Signature} for example) can be + * thought of as the "chrome, upholstery, and steering wheel", and the SPI + * (service provider interface, e.g. {@link java.security.SignatureSpi}) + * classes can be thought of as the "engine" -- providing the actual + * functionality of whatever cryptographic algorithm the instance + * represents. + * + * @see Provider + * @author Casey Marshall + */ +public final class Engine +{ + + // Constants. + // ------------------------------------------------------------------------ + + /** Prefix for aliases. */ + private static final String ALG_ALIAS = "Alg.Alias."; + + /** Maximum number of aliases to try. */ + private static final int MAX_ALIASES = 5; + + /** Argument list for no-argument constructors. */ + private static final Object[] NO_ARGS = new Object[0]; + + // Constructor. + // ------------------------------------------------------------------------ + + /** This class cannot be instantiated. */ + private Engine() { } + + /** + * Return the implementation for algorithm for service service + * from provider. The service is e.g. "Signature", and the algorithm + * "DSA". + * + * @param service The service name. + * @param algorithm The name of the algorithm to get. + * @param provider The provider to get the implementation from. + * @return The engine class for the specified algorithm; the object returned + * is typically a subclass of the SPI class for that service, but + * callers should check that this is so. + * @throws NoSuchAlgorithmException If the implementation cannot be found or + * cannot be instantiated. + * @throws InvocationTargetException If the SPI class's constructor throws an + * exception. + * @throws IllegalArgumentException If any of the three arguments is null. + */ + public static Object getInstance(String service, String algorithm, + Provider provider) + throws InvocationTargetException, NoSuchAlgorithmException + { + return getInstance(service, algorithm, provider, NO_ARGS); + } + + /** + * Return the implementation for algorithm for service service + * from provider, passing initArgs to the SPI class's + * constructor (which cannot be null; pass a zero-length array if the SPI + * takes no arguments). The service is e.g. "Signature", and the algorithm + * "DSA". + * + * @param service The service name. + * @param algorithm The name of the algorithm to get. + * @param provider The provider to get the implementation from. + * @param initArgs The arguments to pass to the SPI class's constructor + * (cannot be null). + * @return The engine class for the specified algorithm; the object returned + * is typically a subclass of the SPI class for that service, but + * callers should check that this is so. + * @throws NoSuchAlgorithmException If the implementation cannot be found or + * cannot be instantiated. + * @throws InvocationTargetException If the SPI class's constructor throws an + * exception. + * @throws IllegalArgumentException If any of the four arguments is + * null or if either service, or + * algorithm is an empty string. + */ + public static Object getInstance(String service, String algorithm, + Provider provider, Object[] initArgs) + throws InvocationTargetException, NoSuchAlgorithmException + { + if (service == null) + throw new IllegalArgumentException("service MUST NOT be null"); + service = service.trim(); + if (service.length() == 0) + throw new IllegalArgumentException("service MUST NOT be empty"); + if (algorithm == null) + throw new IllegalArgumentException("algorithm MUST NOT be null"); + algorithm = algorithm.trim(); + if (algorithm.length() == 0) + throw new IllegalArgumentException("algorithm MUST NOT be empty"); + if (provider == null) + throw new IllegalArgumentException("provider MUST NOT be null"); + if (initArgs == null) + throw new IllegalArgumentException("Constructor's parameters MUST NOT be null"); + + Enumeration enumer = provider.propertyNames(); + String key = null; + String alias; + int count = 0; + boolean algorithmFound = false; + CPStringBuilder sb = new CPStringBuilder(); + while (enumer.hasMoreElements()) + { + key = (String) enumer.nextElement(); + if (key.equalsIgnoreCase(service + "." + algorithm)) + { + // remove the service portion from the key + algorithm = key.substring(service.length() + 1); + algorithmFound = true; + break; + } + else if (key.equalsIgnoreCase(ALG_ALIAS + service + "." + algorithm)) + { + alias = provider.getProperty(key); + if (! algorithm.equalsIgnoreCase(alias)) // does not refer to itself + { + algorithm = alias; + if (count++ > MAX_ALIASES) + { + sb.append("Algorithm [").append(algorithm) + .append("] of type [").append(service) + .append("] from provider [").append(provider) + .append("] has too many aliases"); + throw new NoSuchAlgorithmException(sb.toString()); + } + // need to reset enumeration to now look for the alias + enumer = provider.propertyNames(); + } + } + } + + if (! algorithmFound) + { + sb.append("Algorithm [").append(algorithm).append("] of type [") + .append(service).append("] from provider [") + .append(provider).append("] is not found"); + throw new NoSuchAlgorithmException(sb.toString()); + } + + // Find and instantiate the implementation + Class clazz = null; + ClassLoader loader = provider.getClass().getClassLoader(); + Constructor constructor = null; + String className = provider.getProperty(key); + sb.append("Class [").append(className).append("] for algorithm [") + .append(algorithm).append("] of type [").append(service) + .append("] from provider [").append(provider).append("] "); + Throwable cause = null; + try + { + if (loader != null) + clazz = loader.loadClass(className); + else + clazz = Class.forName(className); + constructor = getCompatibleConstructor(clazz, initArgs); + return constructor.newInstance(initArgs); + } + catch (ClassNotFoundException x) + { + sb.append("cannot not be found"); + cause = x; + } + catch (IllegalAccessException x) + { + sb.append("cannot be accessed"); + cause = x; + } + catch (InstantiationException x) + { + sb.append("cannot be instantiated"); + cause = x; + } + catch (ExceptionInInitializerError x) + { + sb.append("cannot be initialized"); + cause = x; + } + catch (SecurityException x) + { + sb.append("caused a security violation"); + cause = x; + } + catch (NoSuchMethodException x) + { + sb.append("does not have/expose an appropriate constructor"); + cause = x; + } + + NoSuchAlgorithmException x = new NoSuchAlgorithmException(sb.toString()); + x.initCause(cause); + throw x; + } + + /** + * Find a constructor in the given class that can take the specified + * argument list, allowing any of which to be null. + * + * @param clazz The class from which to get the constructor. + * @param initArgs The argument list to be passed to the constructor. + * @return The constructor. + * @throws NoSuchMethodException If no constructor of the given class + * can take the specified argument array. + */ + private static Constructor getCompatibleConstructor(Class clazz, + Object[] initArgs) + throws NoSuchMethodException + { + Constructor[] c = clazz.getConstructors(); + outer:for (int i = 0; i < c.length; i++) + { + Class[] argTypes = c[i].getParameterTypes(); + if (argTypes.length != initArgs.length) + continue; + for (int j = 0; j < argTypes.length; j++) + { + if (initArgs[j] != null && + !argTypes[j].isAssignableFrom(initArgs[j].getClass())) + continue outer; + } + // If we reach this point, we know this constructor (c[i]) has + // the same number of parameters as the target parameter list, + // and all our parameters are either (1) null, or (2) assignable + // to the target parameter type. + return c[i]; + } + throw new NoSuchMethodException(); + } +} diff --git a/libjava/classpath/gnu/java/security/OID.java b/libjava/classpath/gnu/java/security/OID.java new file mode 100644 index 000000000..c7efe6557 --- /dev/null +++ b/libjava/classpath/gnu/java/security/OID.java @@ -0,0 +1,512 @@ +/* OID.java -- numeric representation of an object identifier + Copyright (C) 2003, 2004, 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.java.security; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.der.DEREncodingException; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.StringTokenizer; + +/** + * This immutable class represents an object identifier, or OID. + * + *

OIDs are represented as a series of hierarchical tokens, each of + * which is usually represented as a single, unsigned integer. The + * hierarchy works so that later tokens are considered within the group + * of earlier tokens. Thus, the OID for the Serpent block cipher, + * 1.3.6.1.4.1.11591.13.2, is maintained by the GNU project, whose OID + * is 1.3.6.1.4.1.11591 (which is, in turn, part of bigger, more general + * bodies; the topmost, 1, stands for the OIDs assigned by the + * International Standards Organization, ISO). + * + *

OIDs can be represented in a variety of ways, including the + * dotted-decimal form we use here. + * + *

OIDs may be relative, in which case the first two elements of the + * OID are omitted. + * + * @author Casey Marshall (csm@gnu.org) + */ +public class OID implements Cloneable, Comparable, java.io.Serializable +{ + + // Fields. + // ------------------------------------------------------------------------ + + /* Serial version id for serialization. */ + static final long serialVersionUID = 5722492029044597779L; + + /** + * The numeric ID structure. + */ + private int[] components; + + /** + * The string representation of this OID, in dotted-decimal format. + */ + private transient String strRep; + + /** + * The DER encoding of this OID. + */ + private transient byte[] der; + + /** + * Whether or not this OID is relative. + */ + private boolean relative; + + // Constructors. + // ------------------------------------------------------------------------ + + /** + * Create a new OID from the given byte array. The argument (which can + * neither be null nor zero-length) is copied to prevent subsequent + * modification. + * + * @param components The numeric IDs. + * @throws IllegalArgumentException If components is null or empty. + */ + public OID(int[] components) + { + this(components, false); + } + + /** + * Create a new OID from the given byte array. The argument (which can + * neither be null nor zero-length) is copied to prevent subsequent + * modification. + * + * @param components The numeric IDs. + * @param relative The relative flag. + * @throws IllegalArgumentException If components is null or empty. + */ + public OID(int[] components, boolean relative) + { + if (components == null || components.length == 0) + throw new IllegalArgumentException(); + this.components = (int[]) components.clone(); + this.relative = relative; + } + + /** + * Create a new OID from the given dotted-decimal representation. + * + * @param strRep The string representation of the OID. + * @throws IllegalArgumentException If the string does not contain at + * least one integer. + * @throws NumberFormatException If the string does not contain only + * numbers and periods ('.'). + */ + public OID(String strRep) + { + this(strRep, false); + } + + /** + * Create a new OID from the given dotted-decimal representation. + * + * @param strRep The string representation of the OID. + * @param relative The relative flag. + * @throws IllegalArgumentException If the string does not contain at + * least one integer. + * @throws NumberFormatException If the string does not contain only + * numbers and periods ('.'). + */ + public OID(String strRep, boolean relative) + { + this.relative = relative; + this.strRep = strRep; + components = fromString(strRep); + } + + /** + * Construct a new OID from the DER bytes in an input stream. This method + * does not read the tag or the length field from the input stream, so + * the caller must supply the number of octets in this OID's encoded + * form. + * + * @param derIn The DER input stream. + * @param len The number of bytes in the encoded form. + * @throws IOException If an error occurs reading the OID. + */ + public OID(InputStream derIn, int len) throws IOException + { + this(derIn, len, false); + } + + /** + * Construct a new OID from the DER bytes in an input stream. This method + * does not read the tag or the length field from the input stream, so + * the caller must supply the number of octets in this OID's encoded + * form. + * + * @param derIn The DER input stream. + * @param len The number of bytes in the encoded form. + * @param relative The relative flag. + * @throws IOException If an error occurs reading the OID. + */ + public OID(InputStream derIn, int len, boolean relative) throws IOException + { + der = new byte[len]; + derIn.read(der); + this.relative = relative; + try + { + components = fromDER(der, relative); + } + catch (ArrayIndexOutOfBoundsException aioobe) + { + aioobe.printStackTrace(); + throw aioobe; + } + } + + /** + * Construct a new OID from the given DER bytes. + * + * @param encoded The DER encoded OID. + * @throws IOException If an error occurs reading the OID. + */ + public OID(byte[] encoded) throws IOException + { + this(encoded, false); + } + + /** + * Construct a new OID from the given DER bytes. + * + * @param encoded The encoded relative OID. + * @param relative The relative flag. + */ + public OID(byte[] encoded, boolean relative) throws IOException + { + der = (byte[]) encoded.clone(); + this.relative = relative; + try + { + components = fromDER(der, relative); + } + catch (ArrayIndexOutOfBoundsException aioobe) + { + aioobe.printStackTrace(); + throw aioobe; + } + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Return the numeric IDs of this OID. The value returned is copied to + * prevent modification. + * + * @return The IDs in a new integer array. + */ + public int[] getIDs() + { + return (int[]) components.clone(); + } + + /** + * Get the DER encoding of this OID, minus the tag and length fields. + * + * @return The DER bytes. + */ + public byte[] getDER() + { + if (der == null) + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + int i = 0; + if (!relative) + { + int b = components[i++] * 40 + (components.length > 1 + ? components[i++] : 0); + encodeSubID(bout, b); + } + for ( ; i < components.length; i++) + encodeSubID(bout, components[i]); + der = bout.toByteArray(); + } + return (byte[]) der.clone(); + } + + /** + * Get the parent OID of this OID. That is, if this OID is "1.2.3.4", + * then the parent OID will be "1.2.3". If this OID is a top-level + * OID, this method returns null. + * + * @return The parent OID, or null. + */ + public OID getParent() + { + if (components.length == 1) + return null; + int[] parent = new int[components.length - 1]; + System.arraycopy(components, 0, parent, 0, parent.length); + return new OID(parent); + } + + public OID getChild(int id) + { + int[] child = new int[components.length + 1]; + System.arraycopy(components, 0, child, 0, components.length); + child[child.length - 1] = id; + return new OID(child); + } + + /** + * Get the root OID of this OID. That is, the first two components. + * + * @return The root OID. + */ + public OID getRoot() + { + if (components.length <= 2) + return this; + int[] root = new int[2]; + root[0] = components[0]; + root[1] = components[1]; + return new OID(root); + } + + public boolean isRelative() + { + return relative; + } + + /** + * Returns a copy of this OID. + * + * @return The copy. + */ + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException cnse) + { + InternalError ie = new InternalError(); + ie.initCause(cnse); + throw ie; + } + } + + /* Nice idea, but possibly too expensive for whatever benefit it + * provides. + + public String getShortName() + { + return OIDTable.getShortName(this); + } + + public String getLongName() + { + return OIDTable.getLongName(this); + } + + */ + + /** + * Returns the value of this OID in dotted-decimal format. + * + * @return The string representation. + */ + public String toString() + { + if (strRep != null) + return strRep; + else + { + CPStringBuilder buf = new CPStringBuilder(); + for (int i = 0; i < components.length; i++) + { + buf.append((long) components[i] & 0xFFFFFFFFL); + if (i < components.length - 1) + buf.append('.'); + } + return (strRep = buf.toString()); + } + } + + /** + * Computes a hash code for this OID. + * + * @return The hash code. + */ + public int hashCode() + { + int ret = 0; + for (int i = 0; i < components.length; i++) + ret += components[i] << (i & 31); + return ret; + } + + /** + * Tests whether or not this OID equals another. + * + * @return Whether or not this OID equals the other. + */ + public boolean equals(Object o) + { + if (!(o instanceof OID)) + return false; + return java.util.Arrays.equals(components, ((OID) o).components); + } + + /** + * Compares this OID to another. The comparison is essentially + * lexicographic, where the two OIDs are compared until their + * first difference, then that difference is returned. If one OID is + * shorter, but all elements equal between the two for the shorter + * length, then the shorter OID is lesser than the longer. + * + * @param o The object to compare. + * @return An integer less than, equal to, or greater than zero if + * this object is less than, equal to, or greater than the + * argument. + * @throws ClassCastException If o is not an OID. + */ + public int compareTo(Object o) + { + if (equals(o)) + return 0; + int[] components2 = ((OID) o).components; + int len = Math.min(components.length, components2.length); + for (int i = 0; i < len; i++) + { + if (components[i] != components2[i]) + return (components[i] < components2[i]) ? -1 : 1; + } + if (components.length == components2.length) + return 0; + return (components.length < components2.length) ? -1 : 1; + } + + // Own methods. + // ------------------------------------------------------------------------ + + private static int[] fromDER(byte[] der, boolean relative) + throws DEREncodingException + { + // cannot be longer than this. + int[] components = new int[der.length + 1]; + int count = 0; + int i = 0; + if (!relative && i < der.length) + { + // Non-relative OIDs have the first two arcs coded as: + // + // i = first_arc * 40 + second_arc; + // + int j = (der[i] & 0xFF); + components[count++] = j / 40; + components[count++] = j % 40; + i++; + } + while (i < der.length) + { + int j = 0; + do + { + j = der[i++] & 0xFF; + components[count] <<= 7; + components[count] |= j & 0x7F; + if (i >= der.length && (j & 0x80) != 0) + throw new DEREncodingException("malformed OID"); + } + while ((j & 0x80) != 0); + count++; + } + if (count == components.length) + return components; + int[] ret = new int[count]; + System.arraycopy(components, 0, ret, 0, count); + return ret; + } + + private static int[] fromString(String strRep) throws NumberFormatException + { + if (strRep.startsWith("OID.") || strRep.startsWith("oid.")) + strRep = strRep.substring(4); + StringTokenizer tok = new StringTokenizer(strRep, "."); + if (tok.countTokens() == 0) + throw new IllegalArgumentException(); + int[] components = new int[tok.countTokens()]; + int i = 0; + while (tok.hasMoreTokens()) + { + components[i++] = Integer.parseInt(tok.nextToken()); + } + return components; + } + + private static void encodeSubID(ByteArrayOutputStream out, int id) + { + if (id < 128) + { + out.write(id); + } + else if (id < 16384) + { + out.write((id >>> 7) | 0x80); + out.write(id & 0x7F); + } + else if (id < 2097152) + { + out.write((id >>> 14) | 0x80); + out.write(((id >>> 7) | 0x80) & 0xFF); + out.write(id & 0x7F); + } + else if (id < 268435456) + { + out.write( (id >>> 21) | 0x80); + out.write(((id >>> 14) | 0x80) & 0xFF); + out.write(((id >>> 7) | 0x80) & 0xFF); + out.write(id & 0x7F); + } + } +} diff --git a/libjava/classpath/gnu/java/security/PolicyFile.java b/libjava/classpath/gnu/java/security/PolicyFile.java new file mode 100644 index 000000000..0560bce07 --- /dev/null +++ b/libjava/classpath/gnu/java/security/PolicyFile.java @@ -0,0 +1,687 @@ +/* PolicyFile.java -- policy file reader + Copyright (C) 2004, 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.java.security; + +import gnu.classpath.debug.Component; +import gnu.classpath.debug.SystemLogger; + +import gnu.java.lang.CPStringBuilder; +import gnu.java.security.action.GetPropertyAction; + +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.StreamTokenizer; +import java.lang.reflect.Constructor; +import java.net.MalformedURLException; +import java.net.URL; +import java.security.AccessController; +import java.security.CodeSource; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.Permission; +import java.security.PermissionCollection; +import java.security.Permissions; +import java.security.Policy; +import java.security.Principal; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.security.Security; +import java.security.UnresolvedPermission; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +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.StringTokenizer; +import java.util.logging.Logger; + +/** + * An implementation of a {@link java.security.Policy} object whose + * permissions are specified by a policy file. + * + *

The approximate syntax of policy files is:

+ * + *
+ * policyFile ::= keystoreOrGrantEntries ;
+ *
+ * keystoreOrGrantEntries ::= keystoreOrGrantEntry |
+ *                            keystoreOrGrantEntries keystoreOrGrantEntry |
+ *                            EMPTY ;
+ *
+ * keystoreOrGrantEntry ::= keystoreEntry | grantEntry ;
+ *
+ * keystoreEntry ::= "keystore" keystoreUrl ';' |
+ *                   "keystore" keystoreUrl ',' keystoreAlgorithm ';' ;
+ *
+ * keystoreUrl ::= URL ;
+ * keystoreAlgorithm ::= STRING ;
+ *
+ * grantEntry ::= "grant" domainParameters '{' permissions '}' ';'
+ *
+ * domainParameters ::= domainParameter |
+ *                      domainParameter ',' domainParameters ;
+ *
+ * domainParameter ::= "signedBy" signerNames |
+ *                     "codeBase" codeBaseUrl |
+ *                     "principal" principalClassName principalName |
+ *                     "principal" principalName ;
+ *
+ * signerNames ::= quotedString ;
+ * codeBaseUrl ::= URL ;
+ * principalClassName ::= STRING ;
+ * principalName ::= quotedString ;
+ *
+ * quotedString ::= quoteChar STRING quoteChar ;
+ * quoteChar ::= '"' | '\'';
+ *
+ * permissions ::= permission | permissions permission ;
+ *
+ * permission ::= "permission" permissionClassName permissionTarget permissionAction |
+ *                "permission" permissionClassName permissionTarget |
+ *                "permission" permissionClassName;
+ * 
+ * + *

Comments are either form of Java comments. Keystore entries only + * affect subsequent grant entries, so if a grant entry preceeds a + * keystore entry, that grant entry is not affected by that keystore + * entry. Certian instances of ${property-name} will be + * replaced with System.getProperty("property-name") in + * quoted strings.

+ * + *

This class will load the following files when created or + * refreshed, in order:

+ * + *
    + *
  1. The file ${java.home}/lib/security/java.policy.
  2. + *
  3. All URLs specified by security properties + * "policy.file.n", for increasing n + * starting from 1. The sequence stops at the first undefined + * property, so you must set "policy.file.1" if you also + * set "policy.file.2", and so on.
  4. + *
  5. The URL specified by the property + * "java.security.policy".
  6. + *
+ * + * @author Casey Marshall (csm@gnu.org) + * @see java.security.Policy + */ +public final class PolicyFile extends Policy +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + protected static final Logger logger = SystemLogger.SYSTEM; + // Added to cut redundant AccessController.doPrivileged calls + private static GetPropertyAction prop = new GetPropertyAction("file.separator"); + private static final String fs = (String) AccessController.doPrivileged(prop); + + private static final String DEFAULT_POLICY = + (String) AccessController.doPrivileged(prop.setParameters("java.home")) + + fs + "lib" + fs + "security" + fs + "java.policy"; + private static final String DEFAULT_USER_POLICY = + (String) AccessController.doPrivileged(prop.setParameters("user.home")) + + fs + ".java.policy"; + + private final Map cs2pc; + + // Constructors. + // ------------------------------------------------------------------------- + + public PolicyFile() + { + cs2pc = new HashMap(); + refresh(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public PermissionCollection getPermissions(CodeSource codeSource) + { + Permissions perms = new Permissions(); + for (Iterator it = cs2pc.entrySet().iterator(); it.hasNext(); ) + { + Map.Entry e = (Map.Entry) it.next(); + CodeSource cs = (CodeSource) e.getKey(); + if (cs.implies(codeSource)) + { + logger.log (Component.POLICY, "{0} -> {1}", new Object[] + { cs, codeSource }); + PermissionCollection pc = (PermissionCollection) e.getValue(); + for (Enumeration ee = pc.elements(); ee.hasMoreElements(); ) + { + perms.add((Permission) ee.nextElement()); + } + } + else + logger.log (Component.POLICY, "{0} !-> {1}", new Object[] + { cs, codeSource }); + } + logger.log (Component.POLICY, "returning permissions {0} for {1}", + new Object[] { perms, codeSource }); + return perms; + } + + public void refresh() + { + cs2pc.clear(); + final List policyFiles = new LinkedList(); + try + { + policyFiles.add (new File (DEFAULT_POLICY).toURL()); + policyFiles.add (new File (DEFAULT_USER_POLICY).toURL ()); + + AccessController.doPrivileged( + new PrivilegedExceptionAction() + { + public Object run() throws Exception + { + String allow = Security.getProperty ("policy.allowSystemProperty"); + if (allow == null || Boolean.getBoolean (allow)) + { + String s = System.getProperty ("java.security.policy"); + logger.log (Component.POLICY, "java.security.policy={0}", s); + if (s != null) + { + boolean only = s.startsWith ("="); + if (only) + s = s.substring (1); + policyFiles.clear (); + policyFiles.add (new URL (s)); + if (only) + return null; + } + } + for (int i = 1; ; i++) + { + String pname = "policy.url." + i; + String s = Security.getProperty (pname); + logger.log (Component.POLICY, "{0}={1}", new Object [] + { pname, s }); + if (s == null) + break; + policyFiles.add (new URL (s)); + } + return null; + } + }); + } + catch (PrivilegedActionException pae) + { + logger.log (Component.POLICY, "reading policy properties", pae); + } + catch (MalformedURLException mue) + { + logger.log (Component.POLICY, "setting default policies", mue); + } + + logger.log (Component.POLICY, "building policy from URLs {0}", + policyFiles); + for (Iterator it = policyFiles.iterator(); it.hasNext(); ) + { + try + { + URL url = (URL) it.next(); + parse(url); + } + catch (IOException ioe) + { + logger.log (Component.POLICY, "reading policy", ioe); + } + } + } + + public String toString() + { + return super.toString() + " [ " + cs2pc.toString() + " ]"; + } + + // Own methods. + // ------------------------------------------------------------------------- + + private static final int STATE_BEGIN = 0; + private static final int STATE_GRANT = 1; + private static final int STATE_PERMS = 2; + + /** + * Parse a policy file, incorporating the permission definitions + * described therein. + * + * @param url The URL of the policy file to read. + * @throws IOException if an I/O error occurs, or if the policy file + * cannot be parsed. + */ + private void parse(final URL url) throws IOException + { + logger.log (Component.POLICY, "reading policy file from {0}", url); + final StreamTokenizer in = new StreamTokenizer(new InputStreamReader(url.openStream())); + in.resetSyntax(); + in.slashSlashComments(true); + in.slashStarComments(true); + in.wordChars('A', 'Z'); + in.wordChars('a', 'z'); + in.wordChars('0', '9'); + in.wordChars('.', '.'); + in.wordChars('_', '_'); + in.wordChars('$', '$'); + in.whitespaceChars(' ', ' '); + in.whitespaceChars('\t', '\t'); + in.whitespaceChars('\f', '\f'); + in.whitespaceChars('\n', '\n'); + in.whitespaceChars('\r', '\r'); + in.quoteChar('\''); + in.quoteChar('"'); + + int tok; + int state = STATE_BEGIN; + List keystores = new LinkedList(); + URL currentBase = null; + List currentCerts = new LinkedList(); + Permissions currentPerms = new Permissions(); + while ((tok = in.nextToken()) != StreamTokenizer.TT_EOF) + { + switch (tok) + { + case '{': + if (state != STATE_GRANT) + error(url, in, "spurious '{'"); + state = STATE_PERMS; + tok = in.nextToken(); + break; + case '}': + if (state != STATE_PERMS) + error(url, in, "spurious '}'"); + state = STATE_BEGIN; + currentPerms.setReadOnly(); + Certificate[] c = null; + if (!currentCerts.isEmpty()) + c = (Certificate[]) currentCerts.toArray(new Certificate[currentCerts.size()]); + cs2pc.put(new CodeSource(currentBase, c), currentPerms); + currentCerts.clear(); + currentPerms = new Permissions(); + currentBase = null; + tok = in.nextToken(); + if (tok != ';') + in.pushBack(); + continue; + } + if (tok != StreamTokenizer.TT_WORD) + { + error(url, in, "expecting word token"); + } + + // keystore "" [',' ""] ';' + if (in.sval.equalsIgnoreCase("keystore")) + { + String alg = KeyStore.getDefaultType(); + tok = in.nextToken(); + if (tok != '"' && tok != '\'') + error(url, in, "expecting key store URL"); + String store = in.sval; + tok = in.nextToken(); + if (tok == ',') + { + tok = in.nextToken(); + if (tok != '"' && tok != '\'') + error(url, in, "expecting key store type"); + alg = in.sval; + tok = in.nextToken(); + } + if (tok != ';') + error(url, in, "expecting semicolon"); + try + { + KeyStore keystore = KeyStore.getInstance(alg); + keystore.load(new URL(url, store).openStream(), null); + keystores.add(keystore); + } + catch (Exception x) + { + error(url, in, x.toString()); + } + } + else if (in.sval.equalsIgnoreCase("grant")) + { + if (state != STATE_BEGIN) + error(url, in, "extraneous grant keyword"); + state = STATE_GRANT; + } + else if (in.sval.equalsIgnoreCase("signedBy")) + { + if (state != STATE_GRANT && state != STATE_PERMS) + error(url, in, "spurious 'signedBy'"); + if (keystores.isEmpty()) + error(url, in, "'signedBy' with no keystores"); + tok = in.nextToken(); + if (tok != '"' && tok != '\'') + error(url, in, "expecting signedBy name"); + StringTokenizer st = new StringTokenizer(in.sval, ","); + while (st.hasMoreTokens()) + { + String alias = st.nextToken(); + for (Iterator it = keystores.iterator(); it.hasNext(); ) + { + KeyStore keystore = (KeyStore) it.next(); + try + { + if (keystore.isCertificateEntry(alias)) + currentCerts.add(keystore.getCertificate(alias)); + } + catch (KeyStoreException kse) + { + error(url, in, kse.toString()); + } + } + } + tok = in.nextToken(); + if (tok != ',') + { + if (state != STATE_GRANT) + error(url, in, "spurious ','"); + in.pushBack(); + } + } + else if (in.sval.equalsIgnoreCase("codeBase")) + { + if (state != STATE_GRANT) + error(url, in, "spurious 'codeBase'"); + tok = in.nextToken(); + if (tok != '"' && tok != '\'') + error(url, in, "expecting code base URL"); + String base = expand(in.sval); + if (File.separatorChar != '/') + base = base.replace(File.separatorChar, '/'); + try + { + currentBase = new URL(base); + } + catch (MalformedURLException mue) + { + error(url, in, mue.toString()); + } + tok = in.nextToken(); + if (tok != ',') + in.pushBack(); + } + else if (in.sval.equalsIgnoreCase("principal")) + { + if (state != STATE_GRANT) + error(url, in, "spurious 'principal'"); + tok = in.nextToken(); + if (tok == StreamTokenizer.TT_WORD) + { + tok = in.nextToken(); + if (tok != '"' && tok != '\'') + error(url, in, "expecting principal name"); + String name = in.sval; + Principal p = null; + try + { + Class pclass = Class.forName(in.sval); + Constructor c = + pclass.getConstructor(new Class[] { String.class }); + p = (Principal) c.newInstance(new Object[] { name }); + } + catch (Exception x) + { + error(url, in, x.toString()); + } + for (Iterator it = keystores.iterator(); it.hasNext(); ) + { + KeyStore ks = (KeyStore) it.next(); + try + { + for (Enumeration e = ks.aliases(); e.hasMoreElements(); ) + { + String alias = (String) e.nextElement(); + if (ks.isCertificateEntry(alias)) + { + Certificate cert = ks.getCertificate(alias); + if (!(cert instanceof X509Certificate)) + continue; + if (p.equals(((X509Certificate) cert).getSubjectDN()) || + p.equals(((X509Certificate) cert).getSubjectX500Principal())) + currentCerts.add(cert); + } + } + } + catch (KeyStoreException kse) + { + error(url, in, kse.toString()); + } + } + } + else if (tok == '"' || tok == '\'') + { + String alias = in.sval; + for (Iterator it = keystores.iterator(); it.hasNext(); ) + { + KeyStore ks = (KeyStore) it.next(); + try + { + if (ks.isCertificateEntry(alias)) + currentCerts.add(ks.getCertificate(alias)); + } + catch (KeyStoreException kse) + { + error(url, in, kse.toString()); + } + } + } + else + error(url, in, "expecting principal"); + tok = in.nextToken(); + if (tok != ',') + in.pushBack(); + } + else if (in.sval.equalsIgnoreCase("permission")) + { + if (state != STATE_PERMS) + error(url, in, "spurious 'permission'"); + tok = in.nextToken(); + if (tok != StreamTokenizer.TT_WORD) + error(url, in, "expecting permission class name"); + String className = in.sval; + Class clazz = null; + try + { + clazz = Class.forName(className); + } + catch (ClassNotFoundException cnfe) + { + } + tok = in.nextToken(); + if (tok == ';') + { + if (clazz == null) + { + currentPerms.add(new UnresolvedPermission(className, + null, null, (Certificate[]) currentCerts.toArray(new Certificate[currentCerts.size()]))); + continue; + } + try + { + currentPerms.add((Permission) clazz.newInstance()); + } + catch (Exception x) + { + error(url, in, x.toString()); + } + continue; + } + if (tok != '"' && tok != '\'') + error(url, in, "expecting permission target"); + String target = expand(in.sval); + tok = in.nextToken(); + if (tok == ';') + { + if (clazz == null) + { + currentPerms.add(new UnresolvedPermission(className, + target, null, (Certificate[]) currentCerts.toArray(new Certificate[currentCerts.size()]))); + continue; + } + try + { + Constructor c = + clazz.getConstructor(new Class[] { String.class }); + currentPerms.add((Permission) c.newInstance( + new Object[] { target })); + } + catch (Exception x) + { + error(url, in, x.toString()); + } + continue; + } + if (tok != ',') + error(url, in, "expecting ','"); + tok = in.nextToken(); + if (tok == StreamTokenizer.TT_WORD) + { + if (!in.sval.equalsIgnoreCase("signedBy")) + error(url, in, "expecting 'signedBy'"); + try + { + Constructor c = + clazz.getConstructor(new Class[] { String.class }); + currentPerms.add((Permission) c.newInstance( + new Object[] { target })); + } + catch (Exception x) + { + error(url, in, x.toString()); + } + in.pushBack(); + continue; + } + if (tok != '"' && tok != '\'') + error(url, in, "expecting permission action"); + String action = in.sval; + if (clazz == null) + { + currentPerms.add(new UnresolvedPermission(className, + target, action, (Certificate[]) currentCerts.toArray(new Certificate[currentCerts.size()]))); + continue; + } + else + { + try + { + Constructor c = clazz.getConstructor( + new Class[] { String.class, String.class }); + currentPerms.add((Permission) c.newInstance( + new Object[] { target, action })); + } + catch (Exception x) + { + error(url, in, x.toString()); + } + } + tok = in.nextToken(); + if (tok != ';' && tok != ',') + error(url, in, "expecting ';' or ','"); + } + } + } + + /** + * Expand all instances of "${property-name}" into + * System.getProperty("property-name"). + */ + private static String expand(final String s) + { + final CPStringBuilder result = new CPStringBuilder(); + final CPStringBuilder prop = new CPStringBuilder(); + int state = 0; + for (int i = 0; i < s.length(); i++) + { + switch (state) + { + case 0: + if (s.charAt(i) == '$') + state = 1; + else + result.append(s.charAt(i)); + break; + case 1: + if (s.charAt(i) == '{') + state = 2; + else + { + state = 0; + result.append('$').append(s.charAt(i)); + } + break; + case 2: + if (s.charAt(i) == '}') + { + String p = prop.toString(); + if (p.equals("/")) + p = "file.separator"; + p = System.getProperty(p); + if (p == null) + p = ""; + result.append(p); + prop.setLength(0); + state = 0; + } + else + prop.append(s.charAt(i)); + break; + } + } + if (state != 0) + result.append('$').append('{').append(prop); + return result.toString(); + } + + /** + * I miss macros. + */ + private static void error(URL base, StreamTokenizer in, String msg) + throws IOException + { + throw new IOException(base+":"+in.lineno()+": "+msg); + } +} diff --git a/libjava/classpath/gnu/java/security/Properties.java b/libjava/classpath/gnu/java/security/Properties.java new file mode 100644 index 000000000..2213bde06 --- /dev/null +++ b/libjava/classpath/gnu/java/security/Properties.java @@ -0,0 +1,348 @@ +/* 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 gnu.java.security.Configuration; + +import java.io.FileInputStream; +import java.io.IOException; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.HashMap; +import java.util.PropertyPermission; +import java.util.logging.Logger; + +/** + * A global object containing build-specific properties that affect the + * behaviour of the generated binaries from this library. + */ +public final class Properties +{ + private static final Logger log = Logger.getLogger(Properties.class.getName()); + + 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; + + /** Trivial constructor to enforce Singleton pattern. */ + private Properties() + { + super(); + init(); + } + + /** + * 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; + } + + 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 (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("IO error reading " + propFile + ": " + ioe.getMessage()); + } + catch (SecurityException se) + { + if (Configuration.DEBUG) + log.fine("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 = Boolean.valueOf((String) props.get(REPRODUCIBLE_PRNG)).booleanValue(); + checkForWeakKeys = Boolean.valueOf((String) props.get(CHECK_WEAK_KEYS)).booleanValue(); + doRSABlinding = Boolean.valueOf((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 (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("Setting " + name + " to '" + s + "'"); + props.put(name, s); + } + else + { + if (Configuration.DEBUG) + log.fine("Invalid value for -D" + name + ": " + s + ". Ignored"); + } + } + } +} diff --git a/libjava/classpath/gnu/java/security/Registry.java b/libjava/classpath/gnu/java/security/Registry.java new file mode 100644 index 000000000..4ce5044ab --- /dev/null +++ b/libjava/classpath/gnu/java/security/Registry.java @@ -0,0 +1,465 @@ +/* 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 +{ + /** 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"; + + // Key Wrapping Algorithm names and synonyms ............................... + + String KWA_PREFIX = "kw-"; + String AES_KWA = KWA_PREFIX + AES_CIPHER; + String AES128_KWA = AES_KWA + "128"; + String AES192_KWA = AES_KWA + "192"; + String AES256_KWA = AES_KWA + "256"; + String RIJNDAEL_KWA = KWA_PREFIX + RIJNDAEL_CIPHER; + + String TRIPLEDES_KWA = KWA_PREFIX + TRIPLEDES_CIPHER; + String DESEDE_KWA = KWA_PREFIX + DESEDE_CIPHER; + + // 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#5 padding scheme. */ + String PKCS5_PAD = "pkcs5"; + + /** 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"; + + /** ISO 10126-2 padding scheme. */ + String ISO10126_PAD = "iso10126"; + + // 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; +} diff --git a/libjava/classpath/gnu/java/security/Requires.java b/libjava/classpath/gnu/java/security/Requires.java new file mode 100644 index 000000000..6b52bd168 --- /dev/null +++ b/libjava/classpath/gnu/java/security/Requires.java @@ -0,0 +1,59 @@ +/* Requires.java -- mark methods as requiring permission. + 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.java.security; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.CLASS; +import java.security.Permission; + +/** + * + * + * @author Casey Marshall (csm@gnu.org) + */ +@Documented @Retention(CLASS) @Target(METHOD) +public @interface Requires +{ + Class permissionClass(); + String target(); + String action(); +} diff --git a/libjava/classpath/gnu/java/security/action/GetPropertyAction.java b/libjava/classpath/gnu/java/security/action/GetPropertyAction.java new file mode 100644 index 000000000..7295d8d5a --- /dev/null +++ b/libjava/classpath/gnu/java/security/action/GetPropertyAction.java @@ -0,0 +1,89 @@ +/* GetPropertyAction.java + 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.security.action; + +import java.security.PrivilegedAction; + +/** + * PrivilegedAction implementation that calls System.getProperty() with + * the property name passed to its constructor. + * + * Example of use: + * + * GetPropertyAction action = new GetPropertyAction("http.proxyPort"); + * String port = AccessController.doPrivileged(action); + * + */ +public class GetPropertyAction implements PrivilegedAction +{ + String name; + String value = null; + + public GetPropertyAction() + { + } + + public GetPropertyAction(String propName) + { + setParameters(propName); + } + + public GetPropertyAction(String propName, String defaultValue) + { + setParameters(propName, defaultValue); + } + + public String run() + { + return System.getProperty(name, value); + } + + public GetPropertyAction setParameters(String propName) + { + this.name = propName; + this.value = null; + return this; + } + + public GetPropertyAction setParameters(String propName, String defaultValue) + { + this.name = propName; + this.value = defaultValue; + return this; + } +} diff --git a/libjava/classpath/gnu/java/security/action/GetSecurityPropertyAction.java b/libjava/classpath/gnu/java/security/action/GetSecurityPropertyAction.java new file mode 100644 index 000000000..ac928ca33 --- /dev/null +++ b/libjava/classpath/gnu/java/security/action/GetSecurityPropertyAction.java @@ -0,0 +1,93 @@ +/* GetSecurityPropertyAction.java + 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.security.action; + +import java.security.PrivilegedAction; +import java.security.Security; + +/** + * PrivilegedAction implementation that calls Security.getProperty() + * with the property name passed to its constructor. + * + * Example of use: + * + * GetSecurityPropertyAction action = new GetSecurityPropertyAction("javax.net.ssl.trustStorePassword"); + * String passwd = AccessController.doPrivileged(action); + * + */ +public class GetSecurityPropertyAction implements PrivilegedAction +{ + private String name; + private String value; + + public GetSecurityPropertyAction() + { + } + + public GetSecurityPropertyAction(String propName) + { + setParameters(propName); + } + + public GetSecurityPropertyAction(String propName, String defaultValue) + { + setParameters(propName, defaultValue); + } + + public GetSecurityPropertyAction setParameters(String propName) + { + this.name = propName; + this.value = null; + return this; + } + + public GetSecurityPropertyAction setParameters(String propName, String defaultValue) + { + this.name = propName; + this.value = defaultValue; + return this; + } + + public String run() + { + String val = Security.getProperty(name); + if (val == null) + val = value; + return val; + } +} diff --git a/libjava/classpath/gnu/java/security/action/SetAccessibleAction.java b/libjava/classpath/gnu/java/security/action/SetAccessibleAction.java new file mode 100644 index 000000000..d3e3c0f90 --- /dev/null +++ b/libjava/classpath/gnu/java/security/action/SetAccessibleAction.java @@ -0,0 +1,77 @@ +/* SetAccessibleAction.java + 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.security.action; + +import java.lang.reflect.AccessibleObject; +import java.security.PrivilegedAction; + +/** + * PrivilegedAction implementation that calls setAccessible(true) on the + * AccessibleObject passed to its constructor. + * + * Example of use: + * + * Field dataField = cl.getDeclaredField("data"); + * AccessController.doPrivileged(new SetAccessibleAction(dataField)); + * + */ +public class SetAccessibleAction implements PrivilegedAction +{ + AccessibleObject member; + + public SetAccessibleAction() + { + } + + public SetAccessibleAction(AccessibleObject member) + { + this.member = member; + } + + public Object run() + { + member.setAccessible(true); + return null; + } + + public SetAccessibleAction setMember(AccessibleObject member) + { + this.member = member; + return this; + } +} diff --git a/libjava/classpath/gnu/java/security/action/package.html b/libjava/classpath/gnu/java/security/action/package.html new file mode 100644 index 000000000..fc3dfa229 --- /dev/null +++ b/libjava/classpath/gnu/java/security/action/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.security.action + + +

+ + + diff --git a/libjava/classpath/gnu/java/security/ber/BER.java b/libjava/classpath/gnu/java/security/ber/BER.java new file mode 100644 index 000000000..7efb1bf90 --- /dev/null +++ b/libjava/classpath/gnu/java/security/ber/BER.java @@ -0,0 +1,46 @@ +/* BER.java -- basic encoding rules (BER) constants. + 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.security.ber; + +import gnu.java.security.der.DER; + +public interface BER extends DER +{ + BERValue END_OF_SEQUENCE = new BERValue(0, null); +} diff --git a/libjava/classpath/gnu/java/security/ber/BEREncodingException.java b/libjava/classpath/gnu/java/security/ber/BEREncodingException.java new file mode 100644 index 000000000..aad10932c --- /dev/null +++ b/libjava/classpath/gnu/java/security/ber/BEREncodingException.java @@ -0,0 +1,54 @@ +/* BEREncodingException.java --- BER Encoding Exception + 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.security.ber; + +import gnu.java.security.der.DEREncodingException; + +public class BEREncodingException extends DEREncodingException +{ + public BEREncodingException() + { + super (); + } + + public BEREncodingException (String msg) + { + super (msg); + } +} diff --git a/libjava/classpath/gnu/java/security/ber/BERReader.java b/libjava/classpath/gnu/java/security/ber/BERReader.java new file mode 100644 index 000000000..53a3f3ee9 --- /dev/null +++ b/libjava/classpath/gnu/java/security/ber/BERReader.java @@ -0,0 +1,103 @@ +/* BERReader.java -- basic encoding rules (BER) reader. + 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.security.ber; + +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; + +public class BERReader extends DERReader implements BER +{ + + /** + * Create a new DER reader from a byte array. + * + * @param in The encoded bytes. + */ + public BERReader(byte[] in) + { + super(in); + } + + public BERReader (byte[] in, int off, int len) + { + super(in, off, len); + } + + /** + * Create a new DER readed from an input stream. + * + * @param in The encoded bytes. + */ + public BERReader(InputStream in) + { + super(in); + } + + public DERValue read() throws IOException + { + in.mark(2); + int tag = in.read(); + if (tag == -1) + throw new EOFException(); + int length = in.read(); + if (length == 0) + { + if (tag == 0) + return END_OF_SEQUENCE; + return new BERValue(tag, CONSTRUCTED_VALUE, new byte[] { (byte) tag, 0 }); + } + else + { + in.reset(); + return super.read(); + } + } + + public int peek() throws IOException + { + in.mark(1); + int ret = in.read(); + in.reset(); + return ret; + } +} diff --git a/libjava/classpath/gnu/java/security/ber/BERValue.java b/libjava/classpath/gnu/java/security/ber/BERValue.java new file mode 100644 index 000000000..aeaef39bf --- /dev/null +++ b/libjava/classpath/gnu/java/security/ber/BERValue.java @@ -0,0 +1,82 @@ +/* BERReader.java -- basic encoding rules (BER) value. + 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.security.ber; + +import gnu.java.security.der.DERValue; + +public class BERValue extends DERValue +{ + + private boolean indefinite; + + public BERValue(int tag, Object value, byte[] encoded) + { + super(tag, 0, value, encoded); + indefinite = true; + } + + public BERValue(int tag, int length, Object value, byte[] encoded) + { + super(tag, length, value, encoded); + } + + public BERValue(int tag, Object value) + { + super(tag, 0, value, null); + } + + public static boolean isIndefinite(DERValue value) + { + if (value instanceof BERValue) + return ((BERValue) value).getIndefinite(); + return false; + } + + public boolean getIndefinite() + { + return indefinite; + } + + public int getLength() + { + if (indefinite) + return 0; + return super.getLength(); + } +} diff --git a/libjava/classpath/gnu/java/security/ber/package.html b/libjava/classpath/gnu/java/security/ber/package.html new file mode 100644 index 000000000..348a83c20 --- /dev/null +++ b/libjava/classpath/gnu/java/security/ber/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.security.ber + + +

+ + + diff --git a/libjava/classpath/gnu/java/security/der/BitString.java b/libjava/classpath/gnu/java/security/der/BitString.java new file mode 100644 index 000000000..ac10be22e --- /dev/null +++ b/libjava/classpath/gnu/java/security/der/BitString.java @@ -0,0 +1,332 @@ +/* BitString.java -- Java representation of the BIT STRING type. + Copyright (C) 2003 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.der; + +import gnu.java.lang.CPStringBuilder; + +import java.math.BigInteger; +import java.util.Arrays; + +/** + * Immutable representation of a bit string, which is equivalent to a + * byte array except some number of the rightmost bits are ignored. For + * example, this could be the bit string: + * + *
   00010101 11101101 11010xxx
+ * + *

Where the "xxx" represents three bits that should be ignored, and + * can have any value. + * + * @author Casey Marshall (csm@gnu.org) + */ +public class BitString implements Cloneable, Comparable +{ + + // Fields. + // ------------------------------------------------------------------------ + + /** The bits themselves. */ + private final byte[] bytes; + + /** + * The exportable byte array. This array has the ignored bits + * removed. + */ + private transient byte[] externBytes; + + /** The number of bits ignored at the end of the byte array. */ + private final int ignoredBits; + + /** This bit string as a boolean array. */ + private transient boolean[] boolVal; + + // Constructors. + // ------------------------------------------------------------------------ + + /** + * Create a new bit string, shifting the given byte array if needed. + * + * @param bytes The byte array holding the bit string. + * @param ignoredBits The number of bits to ignore. + * @param doShift Pass true in this parameter if the byte array has + * not yet been shifted left by ignoredBits. + * @throws IllegalArgumentException If ignoredBits is negative + * or greater than 7. + * @throws NullPointerException If bytes is null. + */ + public BitString(byte[] bytes, int ignoredBits, boolean doShift) + { + this(bytes, 0, bytes.length, ignoredBits, doShift); + } + + /** + * Create a new bit string, shifting the given byte array if needed. + * + * @param bytes The byte array holding the bit string. + * @param offset The offset where the meaningful bytes begin. + * @param length The number of meaningful bytes. + * @param ignoredBits The number of bits to ignore. + * @param doShift Pass true in this parameter if the byte array has + * not yet been shifted left by ignoredBits. + * @throws IllegalArgumentException If ignoredBits is negative + * or greater than 7. + * @throws NullPointerException If bytes is null. + */ + public BitString(byte[] bytes, int offset, int length, + int ignoredBits, boolean doShift) + { + if (ignoredBits < 0 || ignoredBits > 7) + throw new IllegalArgumentException(); + if (bytes == null) + throw new NullPointerException(); + if (doShift && ignoredBits > 0) + { + this.externBytes = new byte[length]; + System.arraycopy(bytes, offset, externBytes, 0, length); + this.bytes = new BigInteger(externBytes).shiftLeft(ignoredBits) + .toByteArray(); + } + else + { + this.bytes = new byte[length]; + System.arraycopy(bytes, offset, this.bytes, 0, length); + } + this.ignoredBits = ignoredBits; + } + + /** + * Create a new bit string. + * + * @param bytes The byte array holding the bit string. + * @param offset The offset where the meaningful bytes begin. + * @param length The number of meaningful bytes. + * @param ignoredBits The number of bits to ignore. + * @throws IllegalArgumentException If ignoredBits is negative + * or greater than 7. + * @throws NullPointerException If bytes is null. + */ + public BitString(byte[] bytes, int offset, int length, int ignoredBits) + { + this(bytes, offset, length, ignoredBits, false); + } + + /** + * Create a new bit string. + * + * @param bytes The byte array holding the bit string. + * @param ignoredBits The number of bits to ignore. + * @throws IllegalArgumentException If ignoredBits is negative + * or greater than 7. + * @throws NullPointerException If bytes is null. + */ + public BitString(byte[] bytes, int ignoredBits) + { + this(bytes, 0, bytes.length, ignoredBits, false); + } + + /** + * Create a new bit string. + * + * @param bytes The byte array holding the bit string. + * @param offset The offset where the meaningful bytes begin. + * @param length The number of meaningful bytes. + * @throws NullPointerException If bytes is null. + */ + public BitString(byte[] bytes, int offset, int length) + { + this(bytes, offset, length, 0, false); + } + + /** + * Create a new bit string. + * + * @param bytes The byte array holding the bit string. + * @throws NullPointerException If bytes is null. + */ + public BitString(byte[] bytes) + { + this(bytes, 0, bytes.length, 0, false); + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Return this bit string as a byte array, with the ignored bits + * trimmed off. The byte array is cloned every time this method is + * called to prevent modification. + * + * @return The trimmed byte array. + */ + public byte[] toByteArray() + { + if (ignoredBits == 0) + return (byte[]) bytes.clone(); + if (externBytes == null) + externBytes = new BigInteger(bytes).shiftRight(ignoredBits).toByteArray(); + return (byte[]) externBytes.clone(); + } + + /** + * Returns this bit string as a byte array, with the ignored bits + * present. The byte array is cloned every time this method is + * called to prevent modification. + * + * @return The byte array. + */ + public byte[] getShiftedByteArray() + { + return (byte[]) bytes.clone(); + } + + /** + * Returns the number of ignored bits. + * + * @return The number of ignored bits. + */ + public int getIgnoredBits() + { + return ignoredBits; + } + + /** + * Returns the size, in bits, of this bit string. + * + * @return The size of this bit string. + */ + public int size() + { + return (bytes.length << 3) - ignoredBits; + } + + /** + * Return this bit string as a boolean array. The value returned is of + * size {@link #size()}, and each true value + * corresponding to each "1" in this bit string. The boolean array is + * cloned before it is returned. + * + * @return The boolean array. + */ + public boolean[] toBooleanArray() + { + if (boolVal == null) + { + boolVal = new boolean[size()]; + for (int i = 0, j = 7, k = 0; i < boolVal.length; i++) + { + boolVal[i] = (bytes[k] & 1 << j--) != 0; + if (j < 0) + { + j = 7; + k++; + } + } + } + return (boolean[]) boolVal.clone(); + } + + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException cce) + { + throw new InternalError(cce.getMessage()); + } + } + + public int compareTo(Object o) + { + BitString that = (BitString) o; + if (this.equals(that)) + return 0; + if (this.bytes.length != that.bytes.length) + return (this.bytes.length < that.bytes.length) ? -1 : 1; + if (this.ignoredBits != that.ignoredBits) + return (this.ignoredBits < that.ignoredBits) ? -1 : 1; + for (int i = 0; i < this.bytes.length; i++) + if (this.bytes[i] != that.bytes[i]) + return (this.bytes[i] < that.bytes[i]) ? -1 : 1; + return 0; // not reached. + } + + public int hashCode() + { + int result = 0; + for (int i = 0; i < bytes.length - 1; ++i) + result = result * 31 + bytes[i]; + if (bytes.length > 0) + { + int lastByte = bytes[bytes.length - 1] & ~ ((1 << ignoredBits) - 1); + result = result * 31 + lastByte; + } + return result; + } + + public boolean equals(Object o) + { + if (!(o instanceof BitString)) + return false; + BitString that = (BitString) o; + // True for cloned instances. + if (this.bytes == that.bytes && this.ignoredBits == that.ignoredBits) + return true; + if (this.ignoredBits == that.ignoredBits) + return Arrays.equals(this.bytes, that.bytes); + return false; + } + + public String toString() + { + CPStringBuilder sb = new CPStringBuilder(); + for (int i = 0, j = 7, k = 0; i < size(); i++) + { + sb.append((bytes[k] & 1 << j) != 0 ? "1" : "0"); + j--; + if (j < 0) + { + j = 7; + k++; + } + } + return sb.toString(); + } +} diff --git a/libjava/classpath/gnu/java/security/der/DER.java b/libjava/classpath/gnu/java/security/der/DER.java new file mode 100644 index 000000000..a7eb4a689 --- /dev/null +++ b/libjava/classpath/gnu/java/security/der/DER.java @@ -0,0 +1,86 @@ +/* DER.java -- Basic constants in DER sequences. + Copyright (C) 2003 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.der; + +/** + * The set of tags for DER types. + * + * @author Casey Marshall (csm@gnu.org) + */ +public interface DER +{ + int UNIVERSAL = 0x00; + int APPLICATION = 0x40; + int CONTEXT = 0x80; + int PRIVATE = 0xC0; + + int CONSTRUCTED = 0x20; + + int ANY = 0x00; + int BOOLEAN = 0x01; + int INTEGER = 0x02; + int BIT_STRING = 0x03; + int OCTET_STRING = 0x04; + int NULL = 0x05; + int OBJECT_IDENTIFIER = 0x06; + int REAL = 0x09; + int ENUMERATED = 0x0a; + int RELATIVE_OID = 0x0d; + + int SEQUENCE = 0x10; + int SET = 0x11; + + Object CONSTRUCTED_VALUE = new Object(); + + int NUMERIC_STRING = 0x12; + int PRINTABLE_STRING = 0x13; + int T61_STRING = 0x14; + int VIDEOTEX_STRING = 0x15; + int IA5_STRING = 0x16; + int GRAPHIC_STRING = 0x19; + int ISO646_STRING = 0x1A; + int GENERAL_STRING = 0x1B; + + int UTF8_STRING = 0x0C; + int UNIVERSAL_STRING = 0x1C; + int BMP_STRING = 0x1E; + + int UTC_TIME = 0x17; + int GENERALIZED_TIME = 0x18; +} diff --git a/libjava/classpath/gnu/java/security/der/DEREncodingException.java b/libjava/classpath/gnu/java/security/der/DEREncodingException.java new file mode 100644 index 000000000..90042a3fc --- /dev/null +++ b/libjava/classpath/gnu/java/security/der/DEREncodingException.java @@ -0,0 +1,54 @@ +/* DEREncodingException.java --- DER Encoding Exception + Copyright (C) 1999,2003 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.der; + +import java.io.IOException; + +public class DEREncodingException extends IOException +{ + public DEREncodingException() + { + super (); + } + + public DEREncodingException (String msg) + { + super (msg); + } +} diff --git a/libjava/classpath/gnu/java/security/der/DERReader.java b/libjava/classpath/gnu/java/security/der/DERReader.java new file mode 100644 index 000000000..cd552c8be --- /dev/null +++ b/libjava/classpath/gnu/java/security/der/DERReader.java @@ -0,0 +1,439 @@ +/* DERReader.java -- parses ASN.1 DER sequences + Copyright (C) 2003 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.der; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.OID; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigInteger; +import java.util.Calendar; +import java.util.Date; +import java.util.TimeZone; + +/** + * This class decodes DER sequences into Java objects. The methods of + * this class do not have knowledge of higher-levels of structure in the + * DER stream -- such as ASN.1 constructions -- and it is therefore up + * to the calling application to determine if the data are structured + * properly by inspecting the {@link DERValue} that is returned. + * + * @author Casey Marshall (csm@gnu.org) + */ +public class DERReader implements DER +{ + + // Fields. + // ------------------------------------------------------------------------ + + protected InputStream in; + + protected final ByteArrayOutputStream encBuf; + + // Constructor. + // ------------------------------------------------------------------------ + + /** + * Create a new DER reader from a byte array. + * + * @param in The encoded bytes. + */ + public DERReader(byte[] in) + { + this(new ByteArrayInputStream(in)); + } + + public DERReader (byte[] in, int off, int len) + { + this (new ByteArrayInputStream (in, off, len)); + } + + /** + * Create a new DER readed from an input stream. + * + * @param in The encoded bytes. + */ + public DERReader(InputStream in) + { + if (!in.markSupported()) + this.in = new BufferedInputStream(in, 16384); + else + this.in = in; + encBuf = new ByteArrayOutputStream(2048); + } + + // Class methods. + // ------------------------------------------------------------------------ + + /** + * Convenience method for reading a single primitive value from the + * given byte array. + * + * @param encoded The encoded bytes. + * @throws IOException If the bytes do not represent an encoded + * object. + */ + public static DERValue read(byte[] encoded) throws IOException + { + return new DERReader(encoded).read(); + } + + // Instance methods. + // ------------------------------------------------------------------------ + + public void skip (int bytes) throws IOException + { + in.skip (bytes); + } + + /** + * Decode a single value from the input stream, returning it in a new + * {@link DERValue}. By "single value" we mean any single type in its + * entirety -- including constructed types such as SEQUENCE and all + * the values they contain. Usually it is sufficient to call this + * method once to parse and return the top-level structure, then to + * inspect the returned value for the proper contents. + * + * @return The parsed DER structure. + * @throws IOException If an error occurs reading from the input + * stream. + * @throws DEREncodingException If the input does not represent a + * valid DER stream. + */ + public DERValue read() throws IOException + { + int tag = in.read(); + if (tag == -1) + throw new EOFException(); + encBuf.write(tag); + int len = readLength(); + DERValue value = null; + if ((tag & CONSTRUCTED) == CONSTRUCTED) + { + in.mark(2048); + byte[] encoded = new byte[len]; + in.read(encoded); + encBuf.write(encoded); + value = new DERValue(tag, len, CONSTRUCTED_VALUE, encBuf.toByteArray()); + in.reset(); + encBuf.reset(); + return value; + } + switch (tag & 0xC0) + { + case UNIVERSAL: + value = new DERValue(tag, len, readUniversal(tag, len), + encBuf.toByteArray()); + encBuf.reset(); + break; + case CONTEXT: + byte[] encoded = new byte[len]; + in.read(encoded); + encBuf.write(encoded); + value = new DERValue(tag, len, encoded, encBuf.toByteArray()); + encBuf.reset(); + break; + case APPLICATION: + // This should not be reached, since (I think) APPLICATION is + // always constructed. + throw new DEREncodingException("non-constructed APPLICATION data"); + default: + throw new DEREncodingException("PRIVATE class not supported"); + } + return value; + } + + protected int readLength() throws IOException + { + int i = in.read(); + if (i == -1) + throw new EOFException(); + encBuf.write(i); + if ((i & ~0x7F) == 0) + { + return i; + } + else if (i < 0xFF) + { + byte[] octets = new byte[i & 0x7F]; + in.read(octets); + encBuf.write(octets); + return new BigInteger(1, octets).intValue(); + } + throw new DEREncodingException(); + } + + // Own methods. + // ------------------------------------------------------------------------ + + private Object readUniversal(int tag, int len) throws IOException + { + byte[] value = new byte[len]; + in.read(value); + encBuf.write(value); + switch (tag & 0x1F) + { + case BOOLEAN: + if (value.length != 1) + throw new DEREncodingException(); + return Boolean.valueOf(value[0] != 0); + case NULL: + if (len != 0) + throw new DEREncodingException(); + return null; + case INTEGER: + case ENUMERATED: + return new BigInteger(value); + case BIT_STRING: + byte[] bits = new byte[len - 1]; + System.arraycopy(value, 1, bits, 0, bits.length); + return new BitString(bits, value[0] & 0xFF); + case OCTET_STRING: + return value; + case NUMERIC_STRING: + case PRINTABLE_STRING: + case T61_STRING: + case VIDEOTEX_STRING: + case IA5_STRING: + case GRAPHIC_STRING: + case ISO646_STRING: + case GENERAL_STRING: + case UNIVERSAL_STRING: + case BMP_STRING: + case UTF8_STRING: + return makeString(tag, value); + case UTC_TIME: + case GENERALIZED_TIME: + return makeTime(tag, value); + case OBJECT_IDENTIFIER: + return new OID(value); + case RELATIVE_OID: + return new OID(value, true); + default: + throw new DEREncodingException("unknown tag " + tag); + } + } + + private static String makeString(int tag, byte[] value) + throws IOException + { + switch (tag & 0x1F) + { + case NUMERIC_STRING: + case PRINTABLE_STRING: + case T61_STRING: + case VIDEOTEX_STRING: + case IA5_STRING: + case GRAPHIC_STRING: + case ISO646_STRING: + case GENERAL_STRING: + return fromIso88591(value); + + case UNIVERSAL_STRING: + // XXX The docs say UniversalString is encoded in four bytes + // per character, but Java has no support (yet) for UTF-32. + //return new String(buf, "UTF-32"); + case BMP_STRING: + return fromUtf16Be(value); + + case UTF8_STRING: + return fromUtf8(value); + + default: + throw new DEREncodingException("unknown string tag"); + } + } + + private static String fromIso88591(byte[] bytes) + { + CPStringBuilder str = new CPStringBuilder(bytes.length); + for (int i = 0; i < bytes.length; i++) + str.append((char) (bytes[i] & 0xFF)); + return str.toString(); + } + + private static String fromUtf16Be(byte[] bytes) throws IOException + { + if ((bytes.length & 0x01) != 0) + throw new IOException("UTF-16 bytes are odd in length"); + CPStringBuilder str = new CPStringBuilder(bytes.length / 2); + for (int i = 0; i < bytes.length; i += 2) + { + char c = (char) ((bytes[i] << 8) & 0xFF); + c |= (char) (bytes[i+1] & 0xFF); + str.append(c); + } + return str.toString(); + } + + private static String fromUtf8(byte[] bytes) throws IOException + { + CPStringBuilder str = new CPStringBuilder((int)(bytes.length / 1.5)); + for (int i = 0; i < bytes.length; ) + { + char c = 0; + if ((bytes[i] & 0xE0) == 0xE0) + { + if ((i + 2) >= bytes.length) + throw new IOException("short UTF-8 input"); + c = (char) ((bytes[i++] & 0x0F) << 12); + if ((bytes[i] & 0x80) != 0x80) + throw new IOException("malformed UTF-8 input"); + c |= (char) ((bytes[i++] & 0x3F) << 6); + if ((bytes[i] & 0x80) != 0x80) + throw new IOException("malformed UTF-8 input"); + c |= (char) (bytes[i++] & 0x3F); + } + else if ((bytes[i] & 0xC0) == 0xC0) + { + if ((i + 1) >= bytes.length) + throw new IOException("short input"); + c = (char) ((bytes[i++] & 0x1F) << 6); + if ((bytes[i] & 0x80) != 0x80) + throw new IOException("malformed UTF-8 input"); + c |= (char) (bytes[i++] & 0x3F); + } + else if ((bytes[i] & 0xFF) < 0x80) + { + c = (char) (bytes[i++] & 0xFF); + } + else + throw new IOException("badly formed UTF-8 sequence"); + str.append(c); + } + return str.toString(); + } + + private Date makeTime(int tag, byte[] value) throws IOException + { + Calendar calendar = Calendar.getInstance(); + String str = makeString(PRINTABLE_STRING, value); + + // Classpath's SimpleDateFormat does not work for parsing these + // types of times, so we do this by hand. + String date = str; + String tz = ""; + if (str.indexOf("+") > 0) + { + date = str.substring(0, str.indexOf("+")); + tz = str.substring(str.indexOf("+")); + } + else if (str.indexOf("-") > 0) + { + date = str.substring(0, str.indexOf("-")); + tz = str.substring(str.indexOf("-")); + } + else if (str.endsWith("Z")) + { + date = str.substring(0, str.length()-2); + tz = "Z"; + } + if (!tz.equals("Z") && tz.length() > 0) + calendar.setTimeZone(TimeZone.getTimeZone(tz)); + else + calendar.setTimeZone(TimeZone.getTimeZone("UTC")); + if ((tag & 0x1F) == UTC_TIME) + { + if (date.length() < 10) // must be at least 10 chars long + throw new DEREncodingException("cannot parse date"); + // UTCTime is of the form "yyMMddHHmm[ss](Z|(+|-)hhmm)" + try + { + int year = Integer.parseInt(str.substring(0, 2)); + if (year < 50) + year += 2000; + else + year += 1900; + calendar.set(year, + Integer.parseInt(str.substring( 2, 4))-1, // month + Integer.parseInt(str.substring( 4, 6)), // day + Integer.parseInt(str.substring( 6, 8)), // hour + Integer.parseInt(str.substring( 8, 10))); // minute + if (date.length() == 12) + calendar.set(Calendar.SECOND, + Integer.parseInt(str.substring(10, 12))); + } + catch (NumberFormatException nfe) + { + throw new DEREncodingException("cannot parse date"); + } + } + else + { + if (date.length() < 10) // must be at least 10 chars long + throw new DEREncodingException("cannot parse date"); + // GeneralTime is of the form "yyyyMMddHH[mm[ss[(.|,)SSSS]]]" + // followed by "Z" or "(+|-)hh[mm]" + try + { + calendar.set( + Integer.parseInt(date.substring(0, 4)), // year + Integer.parseInt(date.substring(4, 6))-1, // month + Integer.parseInt(date.substring(6, 8)), // day + Integer.parseInt(date.substring(8, 10)), 0); // hour, min + switch (date.length()) + { + case 19: + case 18: + case 17: + case 16: + calendar.set(Calendar.MILLISECOND, + Integer.parseInt(date.substring(15))); + case 14: + calendar.set(Calendar.SECOND, + Integer.parseInt(date.substring(12, 14))); + case 12: + calendar.set(Calendar.MINUTE, + Integer.parseInt(date.substring(10, 12))); + } + } + catch (NumberFormatException nfe) + { + throw new DEREncodingException("cannot parse date"); + } + } + return calendar.getTime(); + } +} diff --git a/libjava/classpath/gnu/java/security/der/DERValue.java b/libjava/classpath/gnu/java/security/der/DERValue.java new file mode 100644 index 000000000..2cbe34573 --- /dev/null +++ b/libjava/classpath/gnu/java/security/der/DERValue.java @@ -0,0 +1,189 @@ +/* DERValue.java -- a value read or written to a DER encoding. + Copyright (C) 2003 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.der; + +import gnu.java.security.x509.Util; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +public class DERValue implements DER +{ + + // Fields. + // ------------------------------------------------------------------------ + + private final int tagClass; + private final boolean constructed; + private final int tag; + private int length; + private final Object value; + private byte[] encoded; + + // Constructor. + // ------------------------------------------------------------------------ + + public DERValue(int tag, int length, Object value, byte[] encoded) + { + tagClass = tag & 0xC0; + this.tag = tag & 0x1F; + constructed = (tag & CONSTRUCTED) == CONSTRUCTED; + this.length = length; + this.value = value; + if (encoded != null) + this.encoded = (byte[]) encoded.clone(); + } + + public DERValue(int tag, Object value) + { + this(tag, 0, value, null); + } + + // Instance methods. + // ------------------------------------------------------------------------ + + public int getExternalTag() + { + return tagClass | tag | (constructed ? 0x20 : 0x00); + } + + public int getTag() + { + return tag; + } + + public int getTagClass() + { + return tagClass; + } + + public boolean isConstructed() + { + return constructed; + } + + public int getLength() + { + if (encoded == null) + { + try + { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + length = DERWriter.write(out, this); + encoded = out.toByteArray(); + } + catch (IOException ioe) + { + IllegalArgumentException iae = new IllegalArgumentException (); + iae.initCause (ioe); + throw iae; + } + } + return length; + } + + public Object getValue() + { + return value; + } + + public Object getValueAs (final int derType) throws IOException + { + byte[] encoded = getEncoded (); + encoded[0] = (byte) derType; + return DERReader.read (encoded).getValue (); + } + + public byte[] getEncoded() + { + if (encoded == null) + { + try + { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + length = DERWriter.write(out, this); + encoded = out.toByteArray(); + } + catch (IOException ioe) + { + IllegalArgumentException iae = new IllegalArgumentException (); + iae.initCause (ioe); + throw iae; + } + } + return (byte[]) encoded.clone(); + } + + public int getEncodedLength() + { + if (encoded == null) + { + try + { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + length = DERWriter.write(out, this); + encoded = out.toByteArray(); + } + catch (IOException ioe) + { + IllegalArgumentException iae = new IllegalArgumentException (); + iae.initCause (ioe); + throw iae; + } + } + return encoded.length; + } + + public String toString() + { + 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/libjava/classpath/gnu/java/security/der/DERWriter.java b/libjava/classpath/gnu/java/security/der/DERWriter.java new file mode 100644 index 000000000..0c2633605 --- /dev/null +++ b/libjava/classpath/gnu/java/security/der/DERWriter.java @@ -0,0 +1,355 @@ +/* DERWriter.java -- write Java types in DER format. + Copyright (C) 2003, 2004, 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.java.security.der; + +import gnu.java.security.OID; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import java.math.BigInteger; + +import java.text.SimpleDateFormat; + +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.TimeZone; + +/** + * Methods that allow various Java types to be written as a DER + * (Distinguished Encoding Rules) stream to the specified output stream. + * DER is used to encode ASN.1 constructions, but this class provides no + * methods for interacting with ASN.1. Rather, callers should construct + * their output objects properly for whatever ASN.1 construct is being + * output. + * + *

This class only defines static methods; there are no instance + * variables needed. + * + * @author Casey Marshall (csm@gnu.org) + */ +public class DERWriter implements DER +{ + + // Constructors. + // ------------------------------------------------------------------------ + + /** This class only has static methods. */ + private DERWriter() + { + } + + // Class methods. + // ------------------------------------------------------------------------ + + 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) + { + writeLength(out, 0); + return 0; + } + if (value instanceof Boolean) + return writeBoolean(out, (Boolean) value); + else if (value instanceof BigInteger) + return writeInteger(out, (BigInteger) value); + else if (value instanceof Date) + return writeDate(out, object.getExternalTag(), (Date) value); + else if (value instanceof String) + return writeString(out, object.getExternalTag(), (String) value); + else if (value instanceof List) + return writeSequence(out, (List) value); + else if (value instanceof Set) + return writeSet(out, (Set) value); + else if (value instanceof BitString) + return writeBitString(out, (BitString) value); + else if (value instanceof OID) + return writeOID(out, (OID) value); + else if (value instanceof byte[]) + { + writeLength(out, ((byte[]) value).length); + out.write((byte[]) value); + return ((byte[]) value).length; + } + else if (value instanceof DERValue) + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + write(bout, (DERValue) value); + byte[] buf = bout.toByteArray(); + writeLength(out, buf.length); + out.write(buf); + return buf.length; + } + else + throw new DEREncodingException("cannot encode " + value.getClass().getName()); + } + + public static int definiteEncodingSize(int length) + { + if (length < 128) + return 1; + else if (length < 256) + return 2; + else if (length < 65536) + return 3; + else if (length < 16777216) + return 4; + else + return 5; + } + + // Own methods. + // ------------------------------------------------------------------------ + + /** + * Write a BOOLEAN type to the given output stream. + * + * @param out The sink output stream. + * @param b The boolean value to write. + */ + private static int writeBoolean(OutputStream out, Boolean b) + throws IOException + { + writeLength(out, 1); + if (b.booleanValue()) + out.write(0xFF); + else + out.write(0); + return 1; + } + + /** + * Write an INTEGER type to the given output stream. + * + * @param out The sink output stream. + * @param integer The integer to write. + */ + private static int writeInteger(OutputStream out, BigInteger integer) + throws IOException + { + byte[] bytes = integer.toByteArray(); + writeLength(out, bytes.length); + out.write(bytes); + return bytes.length; + } + + private static int writeSequence(OutputStream out, List sequence) + throws IOException + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + for (Iterator i = sequence.iterator(); i.hasNext(); ) + { + write(bout, (DERValue) i.next()); + } + byte[] buf = bout.toByteArray(); + writeLength(out, buf.length); + out.write(buf); + return buf.length; + } + + private static int writeSet(OutputStream out, Set set) + throws IOException + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + for (Iterator i = set.iterator(); i.hasNext(); ) + { + write(bout, (DERValue) i.next()); + } + byte[] buf = bout.toByteArray(); + writeLength(out, buf.length); + out.write(buf); + return buf.length; + } + + private static int writeOID(OutputStream out, OID oid) + throws IOException + { + byte[] der = oid.getDER(); + writeLength(out, der.length); + out.write(der); + return der.length; + } + + private static int writeBitString(OutputStream out, BitString bs) + throws IOException + { + byte[] buf = bs.getShiftedByteArray(); + writeLength(out, buf.length + 1); + out.write(bs.getIgnoredBits()); + out.write(buf); + return buf.length + 1; + } + + private static int writeString(OutputStream out, int tag, String str) + throws IOException + { + byte[] b = null; + switch (tag & 0x1F) + { + case NUMERIC_STRING: + case PRINTABLE_STRING: + case T61_STRING: + case VIDEOTEX_STRING: + case IA5_STRING: + case GRAPHIC_STRING: + case ISO646_STRING: + case GENERAL_STRING: + b = toIso88591(str); + break; + + case UNIVERSAL_STRING: + case BMP_STRING: + b = toUtf16Be(str); + break; + + case UTF8_STRING: + default: + b = toUtf8(str); + break; + } + writeLength(out, b.length); + out.write(b); + return b.length; + } + + private static byte[] toIso88591(String string) + { + byte[] result = new byte[string.length()]; + for (int i = 0; i < string.length(); i++) + result[i] = (byte) string.charAt(i); + return result; + } + + private static byte[] toUtf16Be(String string) + { + byte[] result = new byte[string.length() * 2]; + for (int i = 0; i < string.length(); i++) + { + result[i*2 ] = (byte) ((string.charAt(i) >>> 8) & 0xFF); + result[i*2+1] = (byte) (string.charAt(i) & 0xFF); + } + return result; + } + + private static byte[] toUtf8(String string) + { + ByteArrayOutputStream buf = + new ByteArrayOutputStream((int)(string.length() * 1.5)); + for (int i = 0; i < string.length(); i++) + { + char c = string.charAt(i); + if (c < 0x0080) + buf.write(c & 0xFF); + else if (c < 0x0800) + { + buf.write(0xC0 | ((c >>> 6) & 0x3F)); + buf.write(0x80 | (c & 0x3F)); + } + else + { + buf.write(0xE0 | ((c >>> 12) & 0x0F)); + buf.write(0x80 | ((c >>> 6) & 0x3F)); + buf.write(0x80 | (c & 0x3F)); + } + } + return buf.toByteArray(); + } + + private static int writeDate(OutputStream out, int tag, Date date) + throws IOException + { + SimpleDateFormat sdf = null; + if ((tag & 0x1F) == UTC_TIME) + sdf = new SimpleDateFormat("yyMMddHHmmss'Z'"); + else + sdf = new SimpleDateFormat("yyyyMMddHHmmss'.'SSS'Z'"); + sdf.setTimeZone(TimeZone.getTimeZone("UTC")); + byte[] b = sdf.format(date).getBytes("ISO-8859-1"); + writeLength(out, b.length); + out.write(b); + return b.length; + } + + // Package method. + // ------------------------------------------------------------------------ + + static void writeLength(OutputStream out, int len) throws IOException + { + if (len < 128) + out.write(len); + else if (len < 256) + { + out.write(0x81); + out.write(len); + } + else if (len < 65536) + { + out.write(0x82); + out.write(len >> 8); + out.write(len); + } + else if (len < 16777216) + { + out.write(0x83); + out.write(len >> 16); + out.write(len >> 8); + out.write(len); + } + else + { + out.write(0x84); + out.write(len >> 24); + out.write(len >> 16); + out.write(len >> 8); + out.write(len); + } + } +} diff --git a/libjava/classpath/gnu/java/security/der/package.html b/libjava/classpath/gnu/java/security/der/package.html new file mode 100644 index 000000000..e74b0db4e --- /dev/null +++ b/libjava/classpath/gnu/java/security/der/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.security.der + + +

+ + + diff --git a/libjava/classpath/gnu/java/security/hash/BaseHash.java b/libjava/classpath/gnu/java/security/hash/BaseHash.java new file mode 100644 index 000000000..bab930f28 --- /dev/null +++ b/libjava/classpath/gnu/java/security/hash/BaseHash.java @@ -0,0 +1,183 @@ +/* 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 +{ + /** 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; + + /** + * 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(); + } + + 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(); + } + + 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/libjava/classpath/gnu/java/security/hash/HashFactory.java b/libjava/classpath/gnu/java/security/hash/HashFactory.java new file mode 100644 index 000000000..1210ff4db --- /dev/null +++ b/libjava/classpath/gnu/java/security/hash/HashFactory.java @@ -0,0 +1,135 @@ +/* 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 +{ + /** Trivial constructor to enforce Singleton pattern. */ + private HashFactory() + { + super(); + } + + /** + * 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); + } +} diff --git a/libjava/classpath/gnu/java/security/hash/Haval.java b/libjava/classpath/gnu/java/security/hash/Haval.java new file mode 100644 index 000000000..15c303934 --- /dev/null +++ b/libjava/classpath/gnu/java/security/hash/Haval.java @@ -0,0 +1,807 @@ +/* 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 +{ + 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; + + /** + * 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(); + } + + public Object clone() + { + return new Haval(this); + } + + 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; + int sigByte = (bl & 0x03) << 6; + sigByte |= (rounds & 0x07) << 3; + sigByte |= HAVAL_VERSION & 0x07; + result[padding++] = (byte) sigByte; + 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) + { + String d = Util.toString(new Haval().digest()); + valid = Boolean.valueOf(DIGEST0.equals(d)); + } + return valid.booleanValue(); + } + + /** 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/libjava/classpath/gnu/java/security/hash/IMessageDigest.java b/libjava/classpath/gnu/java/security/hash/IMessageDigest.java new file mode 100644 index 000000000..9b716e596 --- /dev/null +++ b/libjava/classpath/gnu/java/security/hash/IMessageDigest.java @@ -0,0 +1,127 @@ +/* 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 +{ + /** + * 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/libjava/classpath/gnu/java/security/hash/MD2.java b/libjava/classpath/gnu/java/security/hash/MD2.java new file mode 100644 index 000000000..d78af93fa --- /dev/null +++ b/libjava/classpath/gnu/java/security/hash/MD2.java @@ -0,0 +1,256 @@ +/* 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 +{ + /** 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; + + /** 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(); + } + + public Object clone() + { + return new MD2(this); + } + + 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) + { + String d = Util.toString(new MD2().digest()); + valid = Boolean.valueOf(DIGEST0.equals(d)); + } + 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) + { + updateCheckSumAndEncryptBlock(in, off); + } + + /** + * 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] ^ PI[t & 0xFF]); + work[j] = t; + } + 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] ^ b); + 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] ^ PI[t & 0xFF]); + work[j] = t; + } + t = (byte)(t + i); + } + } +} diff --git a/libjava/classpath/gnu/java/security/hash/MD4.java b/libjava/classpath/gnu/java/security/hash/MD4.java new file mode 100644 index 000000000..e6ac11bc8 --- /dev/null +++ b/libjava/classpath/gnu/java/security/hash/MD4.java @@ -0,0 +1,337 @@ +/* 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.java.security.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 +{ + /** 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; + + /** + * 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(); + } + + public Object clone() + { + return new MD4(this); + } + + protected byte[] getResult() + { + return new byte[] { + (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) }; + } + + protected void resetContext() + { + a = A; + b = B; + c = C; + d = D; + } + + public boolean selfTest() + { + if (valid == null) + { + String d = Util.toString(new MD4().digest()); + valid = Boolean.valueOf(DIGEST0.equals(d)); + } + 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/libjava/classpath/gnu/java/security/hash/MD5.java b/libjava/classpath/gnu/java/security/hash/MD5.java new file mode 100644 index 000000000..dfffd3c80 --- /dev/null +++ b/libjava/classpath/gnu/java/security/hash/MD5.java @@ -0,0 +1,371 @@ +/* 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 +{ + 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; + + /** 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(); + } + + public Object clone() + { + return new MD5(this); + } + + 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() + { + return 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) }; + } + + protected void resetContext() + { + // magic MD5/RIPEMD128 initialisation constants + h0 = 0x67452301; + h1 = 0xEFCDAB89; + h2 = 0x98BADCFE; + h3 = 0x10325476; + } + + public boolean selfTest() + { + if (valid == null) + { + String d = Util.toString(new MD5().digest()); + valid = Boolean.valueOf(DIGEST0.equals(d)); + } + return valid.booleanValue(); + } +} diff --git a/libjava/classpath/gnu/java/security/hash/RipeMD128.java b/libjava/classpath/gnu/java/security/hash/RipeMD128.java new file mode 100644 index 000000000..bd0adc5e0 --- /dev/null +++ b/libjava/classpath/gnu/java/security/hash/RipeMD128.java @@ -0,0 +1,257 @@ +/* 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 +{ + 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]; + + /** 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(); + } + + public Object clone() + { + return new RipeMD128(this); + } + + 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() + { + return 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) + }; + } + + protected void resetContext() + { + // magic RIPEMD128 initialisation constants + h0 = 0x67452301; + h1 = 0xEFCDAB89; + h2 = 0x98BADCFE; + h3 = 0x10325476; + } + + public boolean selfTest() + { + if (valid == null) + { + String d = Util.toString(new RipeMD128().digest()); + valid = Boolean.valueOf(DIGEST0.equals(d)); + } + return valid.booleanValue(); + } +} diff --git a/libjava/classpath/gnu/java/security/hash/RipeMD160.java b/libjava/classpath/gnu/java/security/hash/RipeMD160.java new file mode 100644 index 000000000..795f5a4b0 --- /dev/null +++ b/libjava/classpath/gnu/java/security/hash/RipeMD160.java @@ -0,0 +1,291 @@ +/* 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 +{ + 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]; + + /** 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(); + } + + public Object clone() + { + return (new RipeMD160(this)); + } + + 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() + { + return 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) + }; + } + + protected void resetContext() + { + // magic RIPEMD160 initialisation constants + h0 = 0x67452301; + h1 = 0xEFCDAB89; + h2 = 0x98BADCFE; + h3 = 0x10325476; + h4 = 0xC3D2E1F0; + } + + public boolean selfTest() + { + if (valid == null) + { + String d = Util.toString(new RipeMD160().digest()); + valid = Boolean.valueOf(DIGEST0.equals(d)); + } + return valid.booleanValue(); + } +} diff --git a/libjava/classpath/gnu/java/security/hash/Sha160.java b/libjava/classpath/gnu/java/security/hash/Sha160.java new file mode 100644 index 000000000..88bf0e405 --- /dev/null +++ b/libjava/classpath/gnu/java/security/hash/Sha160.java @@ -0,0 +1,241 @@ +/* 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 +{ + 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; + + /** 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(); + } + + public static final int[] G(int hh0, int hh1, int hh2, int hh3, int hh4, + byte[] in, int offset) + { + return sha(hh0, hh1, hh2, hh3, hh4, in, offset); + } + + public Object clone() + { + return new Sha160(this); + } + + protected void transform(byte[] in, int offset) + { + 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() + { + 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 }; + } + + 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 = Boolean.valueOf(DIGEST0.equals(result)); + } + return valid.booleanValue(); + } + + private static synchronized final int[] 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; + } + for (r = 0; r < 20; r++) // rounds 0-19 + { + 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; + } + for (r = 20; r < 40; r++) // rounds 20-39 + { + 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; + } + for (r = 40; r < 60; r++) // rounds 40-59 + { + 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; + } + for (r = 60; r < 80; r++) // rounds 60-79 + { + 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/libjava/classpath/gnu/java/security/hash/Sha256.java b/libjava/classpath/gnu/java/security/hash/Sha256.java new file mode 100644 index 000000000..76e28d4e0 --- /dev/null +++ b/libjava/classpath/gnu/java/security/hash/Sha256.java @@ -0,0 +1,252 @@ +/* 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 +{ + 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; + + /** 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(); + } + + 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); + } + + public Object clone() + { + return new Sha256(this); + } + + 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 = Boolean.valueOf(DIGEST0.equals(result)); + } + return valid.booleanValue(); + } + + private static synchronized final 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/libjava/classpath/gnu/java/security/hash/Sha384.java b/libjava/classpath/gnu/java/security/hash/Sha384.java new file mode 100644 index 000000000..5fea4f3b1 --- /dev/null +++ b/libjava/classpath/gnu/java/security/hash/Sha384.java @@ -0,0 +1,279 @@ +/* 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 +{ + 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; + + /** 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(); + } + + 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); + } + + public Object clone() + { + return new Sha384(this); + } + + 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 }; + } + + 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 = Boolean.valueOf(DIGEST0.equals(result)); + } + return valid.booleanValue(); + } + + private static synchronized final 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/libjava/classpath/gnu/java/security/hash/Sha512.java b/libjava/classpath/gnu/java/security/hash/Sha512.java new file mode 100644 index 000000000..17c4323fa --- /dev/null +++ b/libjava/classpath/gnu/java/security/hash/Sha512.java @@ -0,0 +1,281 @@ +/* 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 +{ + 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; + + /** 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(); + } + + 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); + } + + public Object clone() + { + return new Sha512(this); + } + + 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 = Boolean.valueOf(DIGEST0.equals(result)); + } + return valid.booleanValue(); + } + + private static synchronized final 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/libjava/classpath/gnu/java/security/hash/Tiger.java b/libjava/classpath/gnu/java/security/hash/Tiger.java new file mode 100644 index 000000000..d2993db9f --- /dev/null +++ b/libjava/classpath/gnu/java/security/hash/Tiger.java @@ -0,0 +1,864 @@ +/* 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 +{ + 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; + + /** + * 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; + } + + public Object clone() + { + return new Tiger(this); + } + + public boolean selfTest() + { + if (valid == null) + { + String d = Util.toString(new Tiger().digest()); + valid = Boolean.valueOf(DIGEST0.equals(d)); + } + 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/libjava/classpath/gnu/java/security/hash/Whirlpool.java b/libjava/classpath/gnu/java/security/hash/Whirlpool.java new file mode 100644 index 000000000..574104074 --- /dev/null +++ b/libjava/classpath/gnu/java/security/hash/Whirlpool.java @@ -0,0 +1,608 @@ +/* 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.lang.CPStringBuilder; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import java.util.logging.Logger; + +/** + * 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. + *

+ * This implementation is of Whirlpool Version 3, described in [1] last revised + * on May 24th, 2003. + *

+ * 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 +{ + private static final Logger log = Logger.getLogger(Whirlpool.class.getName()); + 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 = + "19FA61D75522A4669B44E39C1D2E1726C530232130D407F89AFEE0964997F7A7" + + "3E83BE698B288FEBCF88E3E03C4F0757EA8964E59B63D93708B138CC42A66EB3"; + + /** Default number of rounds. */ + private static final int R = 10; + + /** Whirlpool S-box; p. 19. */ + private static final String S_box = // 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"; + + /** The 64-bit lookup tables; section 7.1 p. 13. */ + 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]; + + /** The round constants. */ + 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 + { + long time = System.currentTimeMillis(); + int ROOT = 0x11D; // para. 2.1 [WHIRLPOOL] + int i, r, j; + long s1, s2, s4, s5, s8, s9, t; + char c; + final byte[] S = new byte[256]; + for (i = 0; i < 256; i++) + { + c = S_box.charAt(i >>> 1); + + s1 = ((i & 1) == 0 ? c >>> 8 : c) & 0xFFL; + s2 = s1 << 1; + if (s2 > 0xFFL) + s2 ^= ROOT; + + s4 = s2 << 1; + if (s4 > 0xFFL) + s4 ^= ROOT; + + s5 = s4 ^ s1; + s8 = s4 << 1; + if (s8 > 0xFFL) + s8 ^= ROOT; + + s9 = s8 ^ s1; + + T0[i] = t = s1 << 56 | s1 << 48 | s4 << 40 | s1 << 32 + | s8 << 24 | s5 << 16 | s2 << 8 | s9; + 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 = 0, i = 0; r < R; ) + rc[r++] = (T0[i++] & 0xFF00000000000000L) + ^ (T1[i++] & 0x00FF000000000000L) + ^ (T2[i++] & 0x0000FF0000000000L) + ^ (T3[i++] & 0x000000FF00000000L) + ^ (T4[i++] & 0x00000000FF000000L) + ^ (T5[i++] & 0x0000000000FF0000L) + ^ (T6[i++] & 0x000000000000FF00L) + ^ (T7[i++] & 0x00000000000000FFL); + time = System.currentTimeMillis() - time; + if (Configuration.DEBUG) + { + log.fine("Static data"); + log.fine("T0[]:"); + CPStringBuilder sb; + for (i = 0; i < 64; i++) + { + sb = new CPStringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T0[i * 4 + j])).append(", "); + + log.fine(sb.toString()); + } + log.fine("T1[]:"); + for (i = 0; i < 64; i++) + { + sb = new CPStringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T1[i * 4 + j])).append(", "); + + log.fine(sb.toString()); + } + log.fine("T2[]:"); + for (i = 0; i < 64; i++) + { + sb = new CPStringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T2[i * 4 + j])).append(", "); + + log.fine(sb.toString()); + } + log.fine("T3[]:"); + for (i = 0; i < 64; i++) + { + sb = new CPStringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T3[i * 4 + j])).append(", "); + + log.fine(sb.toString()); + } + log.fine("\nT4[]:"); + for (i = 0; i < 64; i++) + { + sb = new CPStringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T4[i * 4 + j])).append(", "); + + log.fine(sb.toString()); + } + log.fine("T5[]:"); + for (i = 0; i < 64; i++) + { + sb = new CPStringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T5[i * 4 + j])).append(", "); + + log.fine(sb.toString()); + } + log.fine("T6[]:"); + for (i = 0; i < 64; i++) + { + sb = new CPStringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T5[i * 4 + j])).append(", "); + + log.fine(sb.toString()); + } + log.fine("T7[]:"); + for (i = 0; i < 64; i++) + { + sb = new CPStringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T5[i * 4 + j])).append(", "); + + log.fine(sb.toString()); + } + log.fine("rc[]:"); + for (i = 0; i < R; i++) + log.fine("0x" + Util.toString(rc[i])); + + log.fine("Total initialization time: " + time + " ms."); + } + } + + /** 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(); + } + + public Object clone() + { + return (new Whirlpool(this)); + } + + 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 + 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() + { + H0 = H1 = H2 = H3 = H4 = H5 = H6 = H7 = 0L; + } + + public boolean selfTest() + { + if (valid == null) + { + String d = Util.toString(new Whirlpool().digest()); + valid = Boolean.valueOf(DIGEST0.equals(d)); + } + return valid.booleanValue(); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/hash/HavalSpi.java b/libjava/classpath/gnu/java/security/jce/hash/HavalSpi.java new file mode 100644 index 000000000..7c0a6027b --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/hash/HavalSpi.java @@ -0,0 +1,54 @@ +/* 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. + */ +public class HavalSpi + extends MessageDigestAdapter +{ + public HavalSpi() + { + super(Registry.HAVAL_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/hash/MD2Spi.java b/libjava/classpath/gnu/java/security/jce/hash/MD2Spi.java new file mode 100644 index 000000000..76def7acb --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/hash/MD2Spi.java @@ -0,0 +1,55 @@ +/* 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. + */ +public class MD2Spi + extends MessageDigestAdapter +{ + /** Trivial 0-arguments constructor. */ + public MD2Spi() + { + super(Registry.MD2_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/hash/MD4Spi.java b/libjava/classpath/gnu/java/security/jce/hash/MD4Spi.java new file mode 100644 index 000000000..125943d30 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/hash/MD4Spi.java @@ -0,0 +1,55 @@ +/* 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. + */ +public class MD4Spi + extends MessageDigestAdapter +{ + /** Trivial 0-arguments constructor. */ + public MD4Spi() + { + super(Registry.MD4_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/hash/MD5Spi.java b/libjava/classpath/gnu/java/security/jce/hash/MD5Spi.java new file mode 100644 index 000000000..25d9240b4 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/hash/MD5Spi.java @@ -0,0 +1,54 @@ +/* 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. + */ +public class MD5Spi + extends MessageDigestAdapter +{ + public MD5Spi() + { + super(Registry.MD5_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/hash/MessageDigestAdapter.java b/libjava/classpath/gnu/java/security/jce/hash/MessageDigestAdapter.java new file mode 100644 index 000000000..2651ecf92 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/hash/MessageDigestAdapter.java @@ -0,0 +1,133 @@ +/* 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 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 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 provider implement the {@link Cloneable} interface. + */ +class MessageDigestAdapter + extends MessageDigestSpi + implements Cloneable +{ + /** Our underlying hash instance. */ + private IMessageDigest adaptee; + + /** + * 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; + } + + 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/libjava/classpath/gnu/java/security/jce/hash/RipeMD128Spi.java b/libjava/classpath/gnu/java/security/jce/hash/RipeMD128Spi.java new file mode 100644 index 000000000..499996c02 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/hash/RipeMD128Spi.java @@ -0,0 +1,54 @@ +/* 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. + */ +public class RipeMD128Spi + extends MessageDigestAdapter +{ + public RipeMD128Spi() + { + super(Registry.RIPEMD128_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/hash/RipeMD160Spi.java b/libjava/classpath/gnu/java/security/jce/hash/RipeMD160Spi.java new file mode 100644 index 000000000..a62bea6c0 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/hash/RipeMD160Spi.java @@ -0,0 +1,54 @@ +/* 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. + */ +public class RipeMD160Spi + extends MessageDigestAdapter +{ + public RipeMD160Spi() + { + super(Registry.RIPEMD160_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/hash/Sha160Spi.java b/libjava/classpath/gnu/java/security/jce/hash/Sha160Spi.java new file mode 100644 index 000000000..ea2dfe24c --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/hash/Sha160Spi.java @@ -0,0 +1,54 @@ +/* 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. + */ +public class Sha160Spi + extends MessageDigestAdapter +{ + public Sha160Spi() + { + super(Registry.SHA160_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/hash/Sha256Spi.java b/libjava/classpath/gnu/java/security/jce/hash/Sha256Spi.java new file mode 100644 index 000000000..39d31d07b --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/hash/Sha256Spi.java @@ -0,0 +1,54 @@ +/* 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. + */ +public class Sha256Spi + extends MessageDigestAdapter +{ + public Sha256Spi() + { + super(Registry.SHA256_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/hash/Sha384Spi.java b/libjava/classpath/gnu/java/security/jce/hash/Sha384Spi.java new file mode 100644 index 000000000..fa1e3f948 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/hash/Sha384Spi.java @@ -0,0 +1,54 @@ +/* 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. + */ +public class Sha384Spi + extends MessageDigestAdapter +{ + public Sha384Spi() + { + super(Registry.SHA384_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/hash/Sha512Spi.java b/libjava/classpath/gnu/java/security/jce/hash/Sha512Spi.java new file mode 100644 index 000000000..4bd39daed --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/hash/Sha512Spi.java @@ -0,0 +1,54 @@ +/* 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. + */ +public class Sha512Spi + extends MessageDigestAdapter +{ + public Sha512Spi() + { + super(Registry.SHA512_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/hash/TigerSpi.java b/libjava/classpath/gnu/java/security/jce/hash/TigerSpi.java new file mode 100644 index 000000000..3d38c847f --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/hash/TigerSpi.java @@ -0,0 +1,55 @@ +/* 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. + */ +public class TigerSpi + extends MessageDigestAdapter +{ + /** Trivial 0-arguments constructor. */ + public TigerSpi() + { + super(Registry.TIGER_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/hash/WhirlpoolSpi.java b/libjava/classpath/gnu/java/security/jce/hash/WhirlpoolSpi.java new file mode 100644 index 000000000..68a3a7059 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/hash/WhirlpoolSpi.java @@ -0,0 +1,54 @@ +/* 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. + */ +public class WhirlpoolSpi + extends MessageDigestAdapter +{ + public WhirlpoolSpi() + { + super(Registry.WHIRLPOOL_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/prng/HavalRandomSpi.java b/libjava/classpath/gnu/java/security/jce/prng/HavalRandomSpi.java new file mode 100644 index 000000000..ebf80f2d7 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/prng/HavalRandomSpi.java @@ -0,0 +1,54 @@ +/* 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 +{ + public HavalRandomSpi() + { + super(Registry.HAVAL_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/prng/MD2RandomSpi.java b/libjava/classpath/gnu/java/security/jce/prng/MD2RandomSpi.java new file mode 100644 index 000000000..8b9abe4e9 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/prng/MD2RandomSpi.java @@ -0,0 +1,54 @@ +/* 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 +{ + public MD2RandomSpi() + { + super(Registry.MD2_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/prng/MD4RandomSpi.java b/libjava/classpath/gnu/java/security/jce/prng/MD4RandomSpi.java new file mode 100644 index 000000000..2a71d6a0d --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/prng/MD4RandomSpi.java @@ -0,0 +1,54 @@ +/* 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 +{ + public MD4RandomSpi() + { + super(Registry.MD4_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/prng/MD5RandomSpi.java b/libjava/classpath/gnu/java/security/jce/prng/MD5RandomSpi.java new file mode 100644 index 000000000..8fb50e16f --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/prng/MD5RandomSpi.java @@ -0,0 +1,54 @@ +/* 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 +{ + public MD5RandomSpi() + { + super(Registry.MD5_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/prng/RipeMD128RandomSpi.java b/libjava/classpath/gnu/java/security/jce/prng/RipeMD128RandomSpi.java new file mode 100644 index 000000000..6f8dde0e0 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/prng/RipeMD128RandomSpi.java @@ -0,0 +1,54 @@ +/* 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 +{ + public RipeMD128RandomSpi() + { + super(Registry.RIPEMD128_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/prng/RipeMD160RandomSpi.java b/libjava/classpath/gnu/java/security/jce/prng/RipeMD160RandomSpi.java new file mode 100644 index 000000000..6bb4e2b50 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/prng/RipeMD160RandomSpi.java @@ -0,0 +1,54 @@ +/* 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 +{ + public RipeMD160RandomSpi() + { + super(Registry.RIPEMD160_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/prng/SecureRandomAdapter.java b/libjava/classpath/gnu/java/security/jce/prng/SecureRandomAdapter.java new file mode 100644 index 000000000..9307cfa7f --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/prng/SecureRandomAdapter.java @@ -0,0 +1,184 @@ +/* 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.action.GetSecurityPropertyAction; +import gnu.classpath.SystemProperties; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.prng.MDGenerator; + +import java.security.AccessController; +import java.security.SecureRandom; +import java.security.SecureRandomSpi; + +import java.util.Collections; +import java.util.logging.Level; +import java.util.logging.Logger; + +import java.io.InputStream; +import java.io.IOException; + +import java.net.MalformedURLException; +import java.net.URL; + +/** + *

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.

+ */ +public abstract class SecureRandomAdapter + extends SecureRandomSpi +{ + + private boolean isSeeded = false; + + /** Our underlying prng instance. */ + private MDGenerator adaptee = new MDGenerator(); + + /** The name of the message digest algorithm used by the adaptee. */ + private String mdName; + + private static final Logger logger = + Logger.getLogger(SecureRandom.class.getName()); + + private static final String SECURERANDOM_SOURCE = "securerandom.source"; + private static final String JAVA_SECURITY_EGD = "java.security.egd"; + + /** + *

Trivial protected constructor.

+ * + * @param mdName the canonical name of the underlying hash algorithm. + */ + protected SecureRandomAdapter(String mdName) + { + super(); + + this.mdName = mdName; + adaptee.init (Collections.singletonMap (MDGenerator.MD_NAME, mdName)); + } + + public static final byte[] getSeed(int numBytes) + { + URL sourceUrl = null; + String urlStr = null; + + byte[] buffer = new byte[numBytes]; + + GetSecurityPropertyAction action = + new GetSecurityPropertyAction(SECURERANDOM_SOURCE); + try + { + urlStr = (String) AccessController.doPrivileged(action); + if (urlStr != null) + sourceUrl = new URL(urlStr); + } + catch (MalformedURLException ignored) + { + logger.log(Level.WARNING, + SECURERANDOM_SOURCE + " property is malformed: {0}", + urlStr); + } + + if (sourceUrl == null) + { + try + { + urlStr = SystemProperties.getProperty(JAVA_SECURITY_EGD); + if (urlStr != null) + sourceUrl = new URL(urlStr); + } + catch (MalformedURLException mue) + { + logger.log(Level.WARNING, + JAVA_SECURITY_EGD + " property is malformed: {0}", + urlStr); + } + } + + if (sourceUrl != null) + { + try + { + InputStream in = sourceUrl.openStream(); + in.read(buffer); + return buffer; + } + catch (IOException ioe) + { + logger.log(Level.FINE, "error reading random bytes", ioe); + } + } + + // If we get here, we did not get any seed from a property URL. + VMSecureRandom.generateSeed(buffer, 0, buffer.length); + return buffer; + } + + public byte[] engineGenerateSeed(int numBytes) + { + return getSeed(numBytes); + } + + public void engineNextBytes(byte[] bytes) + { + if (!isSeeded) + { + engineSetSeed(engineGenerateSeed(32)); + } + try + { + adaptee.nextBytes(bytes, 0, bytes.length); + } + catch (LimitReachedException ignored) + { + } + } + + public void engineSetSeed(byte[] seed) + { + adaptee.addRandomBytes (seed); + isSeeded = true; + } +} diff --git a/libjava/classpath/gnu/java/security/jce/prng/Sha160RandomSpi.java b/libjava/classpath/gnu/java/security/jce/prng/Sha160RandomSpi.java new file mode 100644 index 000000000..ba4d22265 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/prng/Sha160RandomSpi.java @@ -0,0 +1,54 @@ +/* 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 +{ + public Sha160RandomSpi() + { + super(Registry.SHA160_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/prng/Sha256RandomSpi.java b/libjava/classpath/gnu/java/security/jce/prng/Sha256RandomSpi.java new file mode 100644 index 000000000..a6ddb70af --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/prng/Sha256RandomSpi.java @@ -0,0 +1,54 @@ +/* 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 +{ + public Sha256RandomSpi() + { + super(Registry.SHA256_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/prng/Sha384RandomSpi.java b/libjava/classpath/gnu/java/security/jce/prng/Sha384RandomSpi.java new file mode 100644 index 000000000..4954b1be7 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/prng/Sha384RandomSpi.java @@ -0,0 +1,54 @@ +/* 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 +{ + public Sha384RandomSpi() + { + super(Registry.SHA384_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/prng/Sha512RandomSpi.java b/libjava/classpath/gnu/java/security/jce/prng/Sha512RandomSpi.java new file mode 100644 index 000000000..27de7f319 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/prng/Sha512RandomSpi.java @@ -0,0 +1,54 @@ +/* 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 +{ + public Sha512RandomSpi() + { + super(Registry.SHA512_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/prng/TigerRandomSpi.java b/libjava/classpath/gnu/java/security/jce/prng/TigerRandomSpi.java new file mode 100644 index 000000000..722ab3279 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/prng/TigerRandomSpi.java @@ -0,0 +1,54 @@ +/* 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 +{ + public TigerRandomSpi() + { + super(Registry.TIGER_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/prng/WhirlpoolRandomSpi.java b/libjava/classpath/gnu/java/security/jce/prng/WhirlpoolRandomSpi.java new file mode 100644 index 000000000..5da43d77e --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/prng/WhirlpoolRandomSpi.java @@ -0,0 +1,54 @@ +/* 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 +{ + public WhirlpoolRandomSpi() + { + super(Registry.WHIRLPOOL_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/sig/DSSKeyFactory.java b/libjava/classpath/gnu/java/security/jce/sig/DSSKeyFactory.java new file mode 100644 index 000000000..ec993432c --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/sig/DSSKeyFactory.java @@ -0,0 +1,221 @@ +/* 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) + { + throw new InvalidKeySpecException(x.getMessage(), x); + } + } + 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) + { + throw new InvalidKeySpecException(x.getMessage(), x); + } + } + 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/libjava/classpath/gnu/java/security/jce/sig/DSSKeyPairGeneratorSpi.java b/libjava/classpath/gnu/java/security/jce/sig/DSSKeyPairGeneratorSpi.java new file mode 100644 index 000000000..2d33e1621 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/sig/DSSKeyPairGeneratorSpi.java @@ -0,0 +1,146 @@ +/* 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 DSS keypair generator instances. + *

+ * In case the client does not explicitly initialize the KeyPairGenerator (via a + * call to an initialize() method), the GNU provider uses a + * default modulus size (keysize) of 1024 bits. + */ +public class DSSKeyPairGeneratorSpi + extends KeyPairGeneratorAdapter + implements DSAKeyPairGenerator +{ + public DSSKeyPairGeneratorSpi() + { + super(Registry.DSS_KPG); + } + + 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, + Integer.valueOf(Registry.ASN1_ENCODING_ID)); + try + { + adaptee.setup(attributes); + } + catch (IllegalArgumentException x) + { + throw new InvalidAlgorithmParameterException(x.getMessage(), x); + } + } + + 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(x.getMessage()); + 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, Integer.valueOf(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, + Integer.valueOf(Registry.ASN1_ENCODING_ID)); + try + { + adaptee.setup(attributes); + } + catch (IllegalArgumentException x) + { + InvalidParameterException y = new InvalidParameterException(x.getMessage()); + y.initCause(x); + throw y; + } + } +} diff --git a/libjava/classpath/gnu/java/security/jce/sig/DSSParameters.java b/libjava/classpath/gnu/java/security/jce/sig/DSSParameters.java new file mode 100644 index 000000000..fbf778dae --- /dev/null +++ b/libjava/classpath/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.lang.CPStringBuilder; + +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() + { + CPStringBuilder sb = new CPStringBuilder("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/libjava/classpath/gnu/java/security/jce/sig/DSSParametersGenerator.java b/libjava/classpath/gnu/java/security/jce/sig/DSSParametersGenerator.java new file mode 100644 index 000000000..09c138610 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/java/security/jce/sig/DSSRawSignatureSpi.java b/libjava/classpath/gnu/java/security/jce/sig/DSSRawSignatureSpi.java new file mode 100644 index 000000000..edee4e577 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/sig/DSSRawSignatureSpi.java @@ -0,0 +1,56 @@ +/* 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. + */ +public class DSSRawSignatureSpi + extends SignatureAdapter +{ + public DSSRawSignatureSpi() + { + super(Registry.DSS_SIG, new DSSSignatureRawCodec()); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/sig/EncodedKeyFactory.java b/libjava/classpath/gnu/java/security/jce/sig/EncodedKeyFactory.java new file mode 100644 index 000000000..19ec088c5 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/sig/EncodedKeyFactory.java @@ -0,0 +1,430 @@ +/* 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.Configuration; +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 java.util.logging.Level; +import java.util.logging.Logger; + +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 +{ + private static final Logger log = Logger.getLogger(EncodedKeyFactory.class.getName()); + + 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) + { + throw new InvalidKeySpecException(x.getMessage(), x); + } + catch (IllegalAccessException x) + { + throw new InvalidKeySpecException(x.getMessage(), x); + } + catch (InvocationTargetException x) + { + throw new InvalidKeySpecException(x.getMessage(), x); + } + } + + private static Class getConcreteClass(String className) + throws InvalidKeySpecException + { + try + { + Class result = Class.forName(className); + return result; + } + catch (ClassNotFoundException x) + { + throw new InvalidKeySpecException(x.getMessage(), x); + } + } + + 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) + { + throw new InvalidKeySpecException(x.getMessage(), x); + } + } + + 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) + { + throw new InvalidKeySpecException(x.getMessage(), x); + } + catch (InvocationTargetException x) + { + throw new InvalidKeySpecException(x.getMessage(), x); + } + } + + private static Method getValueOfMethod(Class clazz) + throws InvalidKeySpecException + { + try + { + Method result = clazz.getMethod("valueOf", new Class[] {byte[].class}); + return result; + } + catch (NoSuchMethodException x) + { + throw new InvalidKeySpecException(x.getMessage(), x); + } + } + + protected PublicKey engineGeneratePublic(KeySpec keySpec) + throws InvalidKeySpecException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineGeneratePublic()", keySpec); + PublicKey result = null; + if (keySpec instanceof DSAPublicKeySpec) + result = decodeDSSPublicKey((DSAPublicKeySpec) keySpec); + else if (keySpec instanceof RSAPublicKeySpec) + result = decodeRSAPublicKey((RSAPublicKeySpec) keySpec); + else if (keySpec instanceof DHPublicKeySpec) + result = decodeDHPublicKey((DHPublicKeySpec) keySpec); + else + { + if (! (keySpec instanceof X509EncodedKeySpec)) + throw new InvalidKeySpecException("Unsupported key specification"); + + byte[] input = ((X509EncodedKeySpec) keySpec).getEncoded(); + boolean ok = false; + // try DSS + try + { + result = DSSPublicKey.valueOf(input); + ok = true; + } + catch (InvalidParameterException ignored) + { + if (Configuration.DEBUG) + log.log(Level.FINE, "Exception in DSSPublicKey.valueOf(). Ignore", + ignored); + } + if (! ok) // try RSA + try + { + result = GnuRSAPublicKey.valueOf(input); + ok = true; + } + catch (InvalidParameterException ignored) + { + if (Configuration.DEBUG) + log.log(Level.FINE, + "Exception in GnuRSAPublicKey.valueOf(). Ignore", + ignored); + } + if (! ok) // try DH + result = decodeDHPublicKey(input); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineGeneratePublic()", result); + return result; + } + + protected PrivateKey engineGeneratePrivate(KeySpec keySpec) + throws InvalidKeySpecException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineGeneratePrivate()", keySpec); + PrivateKey result = null; + if (keySpec instanceof DSAPrivateKeySpec) + result = decodeDSSPrivateKey((DSAPrivateKeySpec) keySpec); + else if (keySpec instanceof RSAPrivateCrtKeySpec) + result = decodeRSAPrivateKey((RSAPrivateCrtKeySpec) keySpec); + else if (keySpec instanceof DHPrivateKeySpec) + result = decodeDHPrivateKey((DHPrivateKeySpec) keySpec); + else + { + if (! (keySpec instanceof PKCS8EncodedKeySpec)) + throw new InvalidKeySpecException("Unsupported key specification"); + + byte[] input = ((PKCS8EncodedKeySpec) keySpec).getEncoded(); + boolean ok = false; + // try DSS + try + { + result = DSSPrivateKey.valueOf(input); + ok = true; + } + catch (InvalidParameterException ignored) + { + if (Configuration.DEBUG) + log.log(Level.FINE, "Exception in DSSPrivateKey.valueOf(). Ignore", + ignored); + } + if (! ok) // try RSA + try + { + result = GnuRSAPrivateKey.valueOf(input); + ok = true; + } + catch (InvalidParameterException ignored) + { + if (Configuration.DEBUG) + log.log(Level.FINE, + "Exception in GnuRSAPrivateKey.valueOf(). Ignore", + ignored); + } + if (! ok) // try DH + result = decodeDHPrivateKey(input); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineGeneratePrivate()", result); + return result; + } + + 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[] {Integer.valueOf(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[] {Integer.valueOf(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/libjava/classpath/gnu/java/security/jce/sig/KeyPairGeneratorAdapter.java b/libjava/classpath/gnu/java/security/jce/sig/KeyPairGeneratorAdapter.java new file mode 100644 index 000000000..9d3e5efdd --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/sig/KeyPairGeneratorAdapter.java @@ -0,0 +1,95 @@ +/* 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 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 provider supplies + * (and document) default values to be used. For example, the GNU provider uses + * a default modulus size (keysize) of 1024 bits for the DSS (Digital + * Signature Standard) a.k.a DSA. + */ +public abstract class KeyPairGeneratorAdapter + extends KeyPairGenerator +{ + /** Our underlying keypair instance. */ + protected IKeyPairGenerator adaptee; + + /** + * Trivial protected constructor. + * + * @param kpgName the canonical name of the keypair generator algorithm. + */ + protected KeyPairGeneratorAdapter(String kpgName) + { + super(kpgName); + + this.adaptee = KeyPairGeneratorFactory.getInstance(kpgName); + } + + 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/libjava/classpath/gnu/java/security/jce/sig/MD2withRSA.java b/libjava/classpath/gnu/java/security/jce/sig/MD2withRSA.java new file mode 100644 index 000000000..353be2185 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/java/security/jce/sig/MD5withRSA.java b/libjava/classpath/gnu/java/security/jce/sig/MD5withRSA.java new file mode 100644 index 000000000..42c481b0a --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/java/security/jce/sig/RSAKeyFactory.java b/libjava/classpath/gnu/java/security/jce/sig/RSAKeyFactory.java new file mode 100644 index 000000000..3ba49edc2 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/sig/RSAKeyFactory.java @@ -0,0 +1,231 @@ +/* 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 + { + return new RSAKeyPairX509Codec().decodePublicKey(encoded); + } + catch (RuntimeException x) + { + throw new InvalidKeySpecException(x.getMessage(), x); + } + } + 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 PKCS8EncodedKeySpec) + { + PKCS8EncodedKeySpec spec = (PKCS8EncodedKeySpec) keySpec; + byte[] encoded = spec.getEncoded(); + PrivateKey result; + try + { + return new RSAKeyPairPKCS8Codec().decodePrivateKey(encoded); + } + catch (RuntimeException x) + { + throw new InvalidKeySpecException(x.getMessage(), x); + } + } + 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); + } + throw new InvalidKeyException("Unsupported key type"); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/sig/RSAKeyPairGeneratorSpi.java b/libjava/classpath/gnu/java/security/jce/sig/RSAKeyPairGeneratorSpi.java new file mode 100644 index 000000000..ef53b8115 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/sig/RSAKeyPairGeneratorSpi.java @@ -0,0 +1,96 @@ +/* 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 RSA keypair generator instances. + *

+ * In case the client does not explicitly initialize the KeyPairGenerator (via a + * call to an initialize() method), the GNU provider uses a + * default modulus size (keysize) of 1024 bits. + */ +public class RSAKeyPairGeneratorSpi + extends KeyPairGeneratorAdapter +{ + public RSAKeyPairGeneratorSpi() + { + super(Registry.RSA_KPG); + } + + public void initialize(int keysize, SecureRandom random) + { + HashMap attributes = new HashMap(); + attributes.put(RSAKeyPairGenerator.MODULUS_LENGTH, Integer.valueOf(keysize)); + if (random != null) + attributes.put(RSAKeyPairGenerator.SOURCE_OF_RANDOMNESS, random); + + attributes.put(RSAKeyPairGenerator.PREFERRED_ENCODING_FORMAT, + Integer.valueOf(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, + Integer.valueOf(Registry.ASN1_ENCODING_ID)); + adaptee.setup(attributes); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/sig/RSAPSSRawSignatureSpi.java b/libjava/classpath/gnu/java/security/jce/sig/RSAPSSRawSignatureSpi.java new file mode 100644 index 000000000..496c9caa6 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/sig/RSAPSSRawSignatureSpi.java @@ -0,0 +1,56 @@ +/* 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. + */ +public class RSAPSSRawSignatureSpi + extends SignatureAdapter +{ + public RSAPSSRawSignatureSpi() + { + super(Registry.RSA_PSS_SIG, new RSAPSSSignatureRawCodec()); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/sig/SHA160withDSS.java b/libjava/classpath/gnu/java/security/jce/sig/SHA160withDSS.java new file mode 100644 index 000000000..c55139f46 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/java/security/jce/sig/SHA160withRSA.java b/libjava/classpath/gnu/java/security/jce/sig/SHA160withRSA.java new file mode 100644 index 000000000..d3b2054e0 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/java/security/jce/sig/SHA256withRSA.java b/libjava/classpath/gnu/java/security/jce/sig/SHA256withRSA.java new file mode 100644 index 000000000..d21888b59 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/java/security/jce/sig/SHA384withRSA.java b/libjava/classpath/gnu/java/security/jce/sig/SHA384withRSA.java new file mode 100644 index 000000000..5495ec1ca --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/java/security/jce/sig/SHA512withRSA.java b/libjava/classpath/gnu/java/security/jce/sig/SHA512withRSA.java new file mode 100644 index 000000000..f7632290a --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/java/security/jce/sig/SignatureAdapter.java b/libjava/classpath/gnu/java/security/jce/sig/SignatureAdapter.java new file mode 100644 index 000000000..0ed1e2f41 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/sig/SignatureAdapter.java @@ -0,0 +1,250 @@ +/* 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.Configuration; +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; +import java.util.logging.Logger; + +/** + * The implementation of a generic {@link java.security.Signature} adapter class + * to wrap GNU 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 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 provider implement the {@link Cloneable} interface. + */ +class SignatureAdapter + extends SignatureSpi + implements Cloneable +{ + private static final Logger log = Logger.getLogger(SignatureAdapter.class.getName()); + + /** Our underlying signature instance. */ + private ISignature adaptee; + + /** Our underlying signature encoder/decoder engine. */ + private ISignatureCodec codec; + + /** + * 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; + } + + 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(x.getMessage(), 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(x.getMessage(), 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(x.getMessage(), x); + } + } + + public void engineUpdate(byte b) throws SignatureException + { + try + { + adaptee.update(b); + } + catch (IllegalStateException x) + { + throw new SignatureException(x.getMessage(), x); + } + } + + public void engineUpdate(byte[] b, int off, int len) + throws SignatureException + { + try + { + adaptee.update(b, off, len); + } + catch (IllegalStateException x) + { + throw new SignatureException(x.getMessage(), x); + } + } + + public byte[] engineSign() throws SignatureException + { + Object signature = null; + try + { + signature = adaptee.sign(); + } + catch (IllegalStateException x) + { + throw new SignatureException(x.getMessage(), 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("Not enough room to store signature"); + + System.arraycopy(signature, 0, outbuf, offset, result); + return result; + } + + public boolean engineVerify(byte[] sigBytes) throws SignatureException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineVerify"); + Object signature = codec.decodeSignature(sigBytes); + boolean result = false; + try + { + result = adaptee.verify(signature); + } + catch (IllegalStateException x) + { + throw new SignatureException(x.getMessage(), x); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineVerify", + Boolean.valueOf(result)); + 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/libjava/classpath/gnu/java/security/key/IKeyPairCodec.java b/libjava/classpath/gnu/java/security/key/IKeyPairCodec.java new file mode 100644 index 000000000..5c88c86ca --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/IKeyPairCodec.java @@ -0,0 +1,124 @@ +/* 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. + */ +public interface IKeyPairCodec +{ + /** 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; + + /** + * 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/libjava/classpath/gnu/java/security/key/IKeyPairGenerator.java b/libjava/classpath/gnu/java/security/key/IKeyPairGenerator.java new file mode 100644 index 000000000..72aac2463 --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/IKeyPairGenerator.java @@ -0,0 +1,73 @@ +/* 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. + */ +public interface IKeyPairGenerator +{ + /** + * 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/libjava/classpath/gnu/java/security/key/KeyPairCodecFactory.java b/libjava/classpath/gnu/java/security/key/KeyPairCodecFactory.java new file mode 100644 index 000000000..d42866423 --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/KeyPairCodecFactory.java @@ -0,0 +1,360 @@ +/* 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/libjava/classpath/gnu/java/security/key/KeyPairGeneratorFactory.java b/libjava/classpath/gnu/java/security/key/KeyPairGeneratorFactory.java new file mode 100644 index 000000000..151cace39 --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/KeyPairGeneratorFactory.java @@ -0,0 +1,120 @@ +/* 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. + */ +public class KeyPairGeneratorFactory +{ + /** Trivial constructor to enforce Singleton pattern. */ + private KeyPairGeneratorFactory() + { + super(); + } + + /** + * 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.equalsIgnoreCase(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.DSA_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) + { + throw new IllegalArgumentException( + "strong crypto key pair generator not available: " + clazz, x); + } + } +} diff --git a/libjava/classpath/gnu/java/security/key/dss/DSSKey.java b/libjava/classpath/gnu/java/security/key/dss/DSSKey.java new file mode 100644 index 000000000..49f229f7b --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/dss/DSSKey.java @@ -0,0 +1,213 @@ +/* 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.lang.CPStringBuilder; + +import gnu.java.security.Registry; +import gnu.java.security.action.GetPropertyAction; +import gnu.java.security.util.FormatUtil; + +import java.math.BigInteger; +import java.security.AccessController; +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. + *

+ * IMPORTANT: Under certain circumstances (e.g. in an X.509 certificate + * with inherited AlgorithmIdentifier's parameters of a SubjectPublicKeyInfo + * element) these three MPIs may be null. + * + * @see DSSPrivateKey#getEncoded + * @see DSSPublicKey#getEncoded + */ +public abstract class DSSKey + implements Key, DSAKey +{ + /** + * 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; + + /** String representation of this key. Cached for speed. */ + private transient String str; + + /** + * 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; + } + + public DSAParams getParams() + { + return new DSAParameterSpec(p, q, g); + } + + public String getAlgorithm() + { + return Registry.DSS_KPG; + } + + /** @deprecated see getEncoded(int). */ + public byte[] getEncoded() + { + return getEncoded(defaultFormat); + } + + public String getFormat() + { + return FormatUtil.getEncodingShortName(defaultFormat); + } + + /** + * 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. + *

+ * Always returns false if the MPIs of this key are + * inherited. This may be the case when the key is re-constructed from + * an X.509 certificate with absent or NULL AlgorithmIdentifier's parameters + * field. + * + * @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 (hasInheritedParameters()) + return false; + + 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()); + } + + public String toString() + { + if (str == null) + { + String ls = (String) AccessController.doPrivileged(new GetPropertyAction("line.separator")); + CPStringBuilder sb = new CPStringBuilder(ls) + .append("defaultFormat=").append(defaultFormat).append(",") + .append(ls); + if (hasInheritedParameters()) + sb.append("p=inherited,").append(ls) + .append("q=inherited,").append(ls) + .append("g=inherited"); + else + sb.append("p=0x").append(p.toString(16)).append(",").append(ls) + .append("q=0x").append(q.toString(16)).append(",").append(ls) + .append("g=0x").append(g.toString(16)); + str = sb.toString(); + } + return str; + } + + public abstract byte[] getEncoded(int format); + + /** + * @return true if p, q and + * g are all null. Returns + * false otherwise. + */ + public boolean hasInheritedParameters() + { + return p == null && q == null && g == null; + } +} diff --git a/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairGenerator.java b/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairGenerator.java new file mode 100644 index 000000000..6bda4e88e --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairGenerator.java @@ -0,0 +1,382 @@ +/* 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.Configuration; +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.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; +import java.util.logging.Logger; + +/** + * 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 +{ + private static final Logger log = Logger.getLogger(DSSKeyPairGenerator.class.getName()); + + /** The BigInteger constant 2. */ + private static final BigInteger TWO = BigInteger.valueOf(2L); + + /** 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; + + 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 (Configuration.DEBUG) + { + log.fine("seed: " + seed.toString(16)); + log.fine("counter: " + counter.intValue()); + log.fine("q: " + q.toString(16)); + log.fine("p: " + p.toString(16)); + log.fine("e: " + e.toString(16)); + log.fine("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); + } + + /** + * 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/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairPKCS8Codec.java b/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairPKCS8Codec.java new file mode 100644 index 000000000..a59ca3cee --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairPKCS8Codec.java @@ -0,0 +1,249 @@ +/* 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.Configuration; +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; +import java.util.logging.Logger; + +/** + * 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 Logger log = Logger.getLogger(DSSKeyPairPKCS8Codec.class.getName()); + 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); + + // The OCTET STRING is the DER encoding of an INTEGER. + DERValue derX = new DERValue(DER.INTEGER, x); + DERValue derPrivateKey = new DERValue(DER.OCTET_STRING, derX.getEncoded()); + + 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(e.getMessage()); + 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 (Configuration.DEBUG) + log.entering(this.getClass().getName(), "decodePrivateKey"); + 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(); + if (Configuration.DEBUG) + log.fine("val = " + val); + byte[] xBytes = (byte[]) val.getValue(); + if (Configuration.DEBUG) + log.fine(Util.dumpString(xBytes, "xBytes: ")); + DERReader der2 = new DERReader(xBytes); + val = der2.read(); + DerUtil.checkIsBigInteger(val, "Wrong X field"); + x = (BigInteger) val.getValue(); + } + catch (IOException e) + { + InvalidParameterException y = new InvalidParameterException(e.getMessage()); + y.initCause(e); + throw y; + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "decodePrivateKey"); + return new DSSPrivateKey(Registry.PKCS8_ENCODING_ID, p, q, g, x); + } +} diff --git a/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairRawCodec.java b/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairRawCodec.java new file mode 100644 index 000000000..5b93c6b1e --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairRawCodec.java @@ -0,0 +1,347 @@ +/* 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. + */ +public class DSSKeyPairRawCodec + implements IKeyPairCodec +{ + // implicit 0-arguments constructor + + 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/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairX509Codec.java b/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairX509Codec.java new file mode 100644 index 000000000..8c26910f1 --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairX509Codec.java @@ -0,0 +1,276 @@ +/* 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
+   *   }
+   * 
+ *

+ * Note that RFC-3280 (page 79) implies that some certificates MAY have an + * absent, or NULL, parameters field in their AlgorithmIdentifier element, + * implying that those parameters MUST be inherited from another + * certificate. This implementation, encodes a NULL element as the DER + * value of the parameters field when such is the case. + *

+ * 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; + DERValue derParams; + if (dssKey.hasInheritedParameters()) + derParams = new DERValue(DER.NULL, null); + else + { + BigInteger p = dssKey.getParams().getP(); + BigInteger q = dssKey.getParams().getQ(); + BigInteger g = dssKey.getParams().getG(); + + 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); + 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); + + BigInteger y = dssKey.getY(); + 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(x.getMessage()); + 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 = null; + BigInteger g = null; + BigInteger q = null; + BigInteger 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 val = der.read(); + // RFC-3280, page 79 states: "If the subjectPublicKeyInfo field of the + // certificate contains an algorithm field with null parameters or + // parameters are omitted, compare the certificate subjectPublicKey + // algorithm to the working_public_key_algorithm. If the certificate + // subjectPublicKey algorithm and the working_public_key_algorithm are + // different, set the working_public_key_parameters to null." + // in other words, the parameters field of an AlgorithmIdentifier + // element MAY NOT be present at all, or if present MAY be NULL! + // the Mauve test ValidDSAParameterInheritenceTest5, in + // gnu.testlet.java.security.cert.pkix.pkits, is/was failing because + // of this. + if (val.getTag() == DER.NULL) + val = der.read(); + else if (val.isConstructed()) + { + 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(x.getMessage()); + 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/libjava/classpath/gnu/java/security/key/dss/DSSPrivateKey.java b/libjava/classpath/gnu/java/security/key/dss/DSSPrivateKey.java new file mode 100644 index 000000000..de3668c01 --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/dss/DSSPrivateKey.java @@ -0,0 +1,205 @@ +/* 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.lang.CPStringBuilder; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.action.GetPropertyAction; +import gnu.java.security.key.IKeyPairCodec; + +import java.math.BigInteger; +import java.security.AccessController; +import java.security.PrivateKey; +import java.security.interfaces.DSAPrivateKey; + +/** + * An object that embodies a DSS (Digital Signature Standard) private key. + * + * @see #getEncoded + */ +public class DSSPrivateKey + extends DSSKey + implements PrivateKey, DSAPrivateKey +{ + /** + * A randomly or pseudorandomly generated integer with 0 < x < + * q. + */ + private final BigInteger x; + + /** String representation of this key. Cached for speed. */ + private transient String str; + + /** + * 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; + } + + /** + * 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); + } + + public BigInteger getX() + { + return x; + } + + /** + * 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()); + } + + public String toString() + { + if (str == null) + { + String ls = (String) AccessController.doPrivileged + (new GetPropertyAction("line.separator")); + str = new CPStringBuilder(this.getClass().getName()).append("(") + .append(super.toString()).append(",").append(ls) + .append("x=0x").append(Configuration.DEBUG ? x.toString(16) + : "**...*").append(ls) + .append(")") + .toString(); + } + return str; + } +} diff --git a/libjava/classpath/gnu/java/security/key/dss/DSSPublicKey.java b/libjava/classpath/gnu/java/security/key/dss/DSSPublicKey.java new file mode 100644 index 000000000..d7c1afe15 --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/dss/DSSPublicKey.java @@ -0,0 +1,203 @@ +/* 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.lang.CPStringBuilder; + +import gnu.java.security.Registry; +import gnu.java.security.action.GetPropertyAction; +import gnu.java.security.key.IKeyPairCodec; + +import java.math.BigInteger; +import java.security.AccessController; +import java.security.PublicKey; +import java.security.interfaces.DSAPublicKey; + +/** + * An object that embodies a DSS (Digital Signature Standard) public key. + * + * @see #getEncoded + */ +public class DSSPublicKey + extends DSSKey + implements PublicKey, DSAPublicKey +{ + /** + * y = gx mod p where x is the + * private part of the DSA key. + */ + private final BigInteger y; + + /** String representation of this key. Cached for speed. */ + private transient String str; + + /** + * 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; + } + + /** + * 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); + } + + public BigInteger getY() + { + return y; + } + + /** + * 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()); + } + + public String toString() + { + if (str == null) + { + String ls = (String) AccessController.doPrivileged + (new GetPropertyAction("line.separator")); + str = new CPStringBuilder(this.getClass().getName()).append("(") + .append(super.toString()).append(",").append(ls) + .append("y=0x").append(y.toString(16)).append(ls) + .append(")") + .toString(); + } + return str; + } +} diff --git a/libjava/classpath/gnu/java/security/key/dss/FIPS186.java b/libjava/classpath/gnu/java/security/key/dss/FIPS186.java new file mode 100644 index 000000000..5d371e10c --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/dss/FIPS186.java @@ -0,0 +1,262 @@ +/* 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 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. + */ +public class FIPS186 +{ + 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 = BigInteger.valueOf(2L); + + 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; + + public FIPS186(int L, SecureRandom rnd) + { + super(); + + this.L = L; + this.rnd = rnd; + } + + /** + * 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 (q.isProbablePrime(80)) + break step1; + } // step1 + // 6. Let counter = 0 and offset = 2. + counter = 0; + offset = 2; + 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 (p.isProbablePrime(80)) + 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 }; + } + + /** + * 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/libjava/classpath/gnu/java/security/key/rsa/GnuRSAKey.java b/libjava/classpath/gnu/java/security/key/rsa/GnuRSAKey.java new file mode 100644 index 000000000..38530ee4c --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/rsa/GnuRSAKey.java @@ -0,0 +1,178 @@ +/* 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.lang.CPStringBuilder; + +import gnu.java.security.Registry; +import gnu.java.security.action.GetPropertyAction; +import gnu.java.security.util.FormatUtil; + +import java.math.BigInteger; +import java.security.AccessController; +import java.security.Key; +import java.security.interfaces.RSAKey; + +/** + * A base asbtract class for both public and private RSA keys. + */ +public abstract class GnuRSAKey + implements Key, RSAKey +{ + /** 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; + + /** String representation of this key. Cached for speed. */ + private transient String str; + + /** + * 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; + } + + public BigInteger getModulus() + { + return getN(); + } + + public String getAlgorithm() + { + return Registry.RSA_KPG; + } + + /** @deprecated see getEncoded(int). */ + public byte[] getEncoded() + { + return getEncoded(defaultFormat); + } + + public String getFormat() + { + return FormatUtil.getEncodingShortName(defaultFormat); + } + + /** + * 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()); + } + + public String toString() + { + if (str == null) + { + String ls = (String) AccessController.doPrivileged + (new GetPropertyAction("line.separator")); + str = new CPStringBuilder(ls) + .append("defaultFormat=").append(defaultFormat).append(",").append(ls) + .append("n=0x").append(n.toString(16)).append(",").append(ls) + .append("e=0x").append(e.toString(16)) + .toString(); + } + return str; + } + + public abstract byte[] getEncoded(int format); +} diff --git a/libjava/classpath/gnu/java/security/key/rsa/GnuRSAPrivateKey.java b/libjava/classpath/gnu/java/security/key/rsa/GnuRSAPrivateKey.java new file mode 100644 index 000000000..39f91cbe4 --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/rsa/GnuRSAPrivateKey.java @@ -0,0 +1,313 @@ +/* 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.lang.CPStringBuilder; + +import gnu.java.security.Configuration; +import gnu.java.security.action.GetPropertyAction; +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairCodec; + +import java.math.BigInteger; +import java.security.AccessController; +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. + *
+ */ +public class GnuRSAPrivateKey + extends GnuRSAKey + implements PrivateKey, RSAPrivateCrtKey +{ + /** The first prime divisor of the modulus. */ + private final BigInteger p; + + /** The second prime divisor of the modulus. */ + private final BigInteger q; + + /** 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; + + /** String representation of this key. Cached for speed. */ + private transient String str; + + /** + * 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; + } + + /** + * 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); + } + + 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; + } + + public BigInteger getPrivateExponent() + { + return d; + } + + /** + * 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; + } + + public String toString() + { + if (str == null) + { + String ls = (String) AccessController.doPrivileged + (new GetPropertyAction("line.separator")); + str = new CPStringBuilder(this.getClass().getName()).append("(") + .append(super.toString()).append(",").append(ls) + .append("d=0x").append(Configuration.DEBUG ? d.toString(16) + : "**...*").append(ls) + .append("p=0x").append(Configuration.DEBUG ? p.toString(16) + : "**...*").append(ls) + .append("q=0x").append(Configuration.DEBUG ? q.toString(16) + : "**...*").append(ls) + .append("dP=0x").append(Configuration.DEBUG ? dP.toString(16) + : "**...*").append(ls) + .append("dQ=0x").append(Configuration.DEBUG ? dQ.toString(16) + : "**...*").append(ls) + .append("qInv=0x").append(Configuration.DEBUG ? qInv.toString(16) + : "**...*").append(ls) + .append(")") + .toString(); + } + return str; + } +} diff --git a/libjava/classpath/gnu/java/security/key/rsa/GnuRSAPublicKey.java b/libjava/classpath/gnu/java/security/key/rsa/GnuRSAPublicKey.java new file mode 100644 index 000000000..0bad92881 --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/rsa/GnuRSAPublicKey.java @@ -0,0 +1,190 @@ +/* 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.lang.CPStringBuilder; + +import gnu.java.security.Registry; +import gnu.java.security.action.GetPropertyAction; +import gnu.java.security.key.IKeyPairCodec; + +import java.math.BigInteger; +import java.security.AccessController; +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. + *
+ */ +public class GnuRSAPublicKey + extends GnuRSAKey + implements PublicKey, RSAPublicKey +{ + /** String representation of this key. Cached for speed. */ + private transient String str; + + /** + * 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); + } + + /** + * 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); + } + + /** + * 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()); + } + + public String toString() + { + if (str == null) + { + String ls = (String) AccessController.doPrivileged + (new GetPropertyAction("line.separator")); + str = new CPStringBuilder(this.getClass().getName()).append("(") + .append(super.toString()).append(",").append(ls) + .append(")") + .toString(); + } + return str; + } +} diff --git a/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairGenerator.java b/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairGenerator.java new file mode 100644 index 000000000..bec60d350 --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairGenerator.java @@ -0,0 +1,246 @@ +/* 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.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairGenerator; +import gnu.java.security.util.PRNG; + +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; +import java.util.logging.Logger; + +/** + * 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 +{ + private static final Logger log = Logger.getLogger(RSAKeyPairGenerator.class.getName()); + + /** 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; + + // implicit 0-arguments constructor + + 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) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "setup", 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(); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "setup"); + } + + /** + *

+ * 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() + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "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 + && p.isProbablePrime(80) && 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 && q.isProbablePrime(80) && 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); + KeyPair result = new KeyPair(pubK, secK); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "generate", result); + 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/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairPKCS8Codec.java b/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairPKCS8Codec.java new file mode 100644 index 000000000..2785f02c8 --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairPKCS8Codec.java @@ -0,0 +1,299 @@ +/* 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 gnu.java.security.Configuration; +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 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 java.util.logging.Logger; + +/** + * 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 Logger log = Logger.getLogger(RSAKeyPairPKCS8Codec.class.getName()); + 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
+   *   }
+   * 
+ *

+ * As indicated in RFC-2459: "The parameters field shall have ASN.1 type NULL + * for this algorithm identifier.". + *

+ * 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 (Configuration.DEBUG) + log.entering(this.getClass().getName(), "encodePrivateKey()", 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(2); + algorithmID.add(derOID); + algorithmID.add(new DERValue(DER.NULL, null)); + 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; + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "encodePrivateKey()", result); + 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 (Configuration.DEBUG) + log.entering(this.getClass().getName(), "decodePrivateKey()", 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); + + // rfc-2459 states that this field is OPTIONAL but NULL if/when present + DERValue val = der.read(); + if (val.getTag() == DER.NULL) + 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; + } + PrivateKey result = new GnuRSAPrivateKey(Registry.PKCS8_ENCODING_ID, + n, e, d, p, q, dP, dQ, qInv); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "decodePrivateKey()", result); + return result; + } +} diff --git a/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairRawCodec.java b/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairRawCodec.java new file mode 100644 index 000000000..f088e794e --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairRawCodec.java @@ -0,0 +1,300 @@ +/* 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. + */ +public class RSAKeyPairRawCodec + implements IKeyPairCodec +{ + // implicit 0-arguments constructor + + 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/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairX509Codec.java b/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairX509Codec.java new file mode 100644 index 000000000..9ad6ae029 --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairX509Codec.java @@ -0,0 +1,250 @@ +/* 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.Configuration; +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; +import java.util.logging.Logger; + +/** + * 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 Logger log = Logger.getLogger(RSAKeyPairX509Codec.class.getName()); + 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
+   *   }
+   * 
+ *

+ * As indicated in RFC-2459: "The parameters field shall have ASN.1 type NULL + * for this algorithm identifier.". + *

+ * 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 (Configuration.DEBUG) + log.entering(this.getClass().getName(), "encodePublicKey()", 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(2); + algorithmID.add(derOID); + algorithmID.add(new DERValue(DER.NULL, null)); + 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(x.getMessage()); + y.initCause(x); + throw y; + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "encodePublicKey()", result); + 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 (Configuration.DEBUG) + log.entering(this.getClass().getName(), "decodePublicKey()", 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); + + // rfc-2459 states that this field is OPTIONAL but NULL if/when present + DERValue val = der.read(); + if (val.getTag() == DER.NULL) + 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(x.getMessage()); + y.initCause(x); + throw y; + } + PublicKey result = new GnuRSAPublicKey(Registry.X509_ENCODING_ID, n, e); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "decodePublicKey()", result); + return result; + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public PrivateKey decodePrivateKey(byte[] input) + { + throw new InvalidParameterException("Wrong format for private keys"); + } +} diff --git a/libjava/classpath/gnu/java/security/package.html b/libjava/classpath/gnu/java/security/package.html new file mode 100644 index 000000000..bb6e91d61 --- /dev/null +++ b/libjava/classpath/gnu/java/security/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.security + + +

+ + + diff --git a/libjava/classpath/gnu/java/security/pkcs/PKCS7Data.java b/libjava/classpath/gnu/java/security/pkcs/PKCS7Data.java new file mode 100644 index 000000000..c6474f081 --- /dev/null +++ b/libjava/classpath/gnu/java/security/pkcs/PKCS7Data.java @@ -0,0 +1,69 @@ +/* PKCS7Data.java -- Reader/writer for PKCS#7 Data objects + 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.pkcs; + +import gnu.java.security.OID; + +/** + * A read/write helper class for PKCS#7 Data ASN.1 structures. + */ +public class PKCS7Data +{ + public static final OID PKCS7_DATA = new OID("1.2.840.113549.1.7.1"); + + private byte[] content; + + /** + * Constructs a new instance of PKCS7Data with the possibly + * null (implicetly referenced) content data. + * + * @param data the raw bytes of the data to use in a PKCS#7 framework. + */ + public PKCS7Data(byte[] data) + { + super(); + + this.content = data; + } + + public byte[] getEncoded() + { + return content; + } +} diff --git a/libjava/classpath/gnu/java/security/pkcs/PKCS7SignedData.java b/libjava/classpath/gnu/java/security/pkcs/PKCS7SignedData.java new file mode 100644 index 000000000..adb00a3be --- /dev/null +++ b/libjava/classpath/gnu/java/security/pkcs/PKCS7SignedData.java @@ -0,0 +1,485 @@ +/* PKCS7SignedData.java -- reader/writer for PKCS#7 signedData objects + Copyright (C) 2004, 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.java.security.pkcs; + +import gnu.java.security.Configuration; +import gnu.java.security.OID; +import gnu.java.security.ber.BER; +import gnu.java.security.ber.BEREncodingException; +import gnu.java.security.ber.BERReader; +import gnu.java.security.ber.BERValue; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERValue; +import gnu.java.security.der.DERWriter; +import gnu.java.security.util.Util; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.math.BigInteger; +import java.security.cert.CRL; +import java.security.cert.CRLException; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509CRL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.logging.Logger; + +/** + * The SignedData object in PKCS #7. This is a read-only implementation of + * this format, and is used to provide signed Jar file support. + * + * @author Casey Marshall (csm@gnu.org) + */ +public class PKCS7SignedData +{ + private static final Logger log = Logger.getLogger(PKCS7SignedData.class.getName()); + + public static final OID PKCS7_SIGNED_DATA = new OID("1.2.840.113549.1.7.2"); + + private BigInteger version; + private Set digestAlgorithms; + private OID contentType; + private byte[] content; + private Certificate[] certificates; + private CRL[] crls; + private Set signerInfos; + + public PKCS7SignedData(InputStream in) + throws CRLException, CertificateException, IOException + { + this(new BERReader(in)); + } + + /** + * Parse an encoded PKCS#7 SignedData object. The ASN.1 format of this + * object is: + * + *
+   * SignedData ::= SEQUENCE {
+   *   version           Version, -- always 1 for PKCS7 v1.5
+   *   digestAlgorithms  DigestAlgorithmIdentifiers,
+   *   contentInfo       ContentInfo,
+   *   certificates  [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL,
+   *   crls          [1] IMPLICIT CertificateRevocationLists OPTIONAL,
+   *   signerInfos       SignerInfos }
+   *
+   * Version ::= INTEGER
+   *
+   * DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
+   *
+   * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+   *
+   * ContentInfo ::= SEQUENCE {
+   *   contentType   ContentType,
+   *   content   [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
+   *
+   * ContentType ::= OBJECT IDENTIFIER
+   *
+   * ExtendedCertificatesAndCertificates ::=
+   *   SET OF ExtendedCertificatesAndCertificate
+   *
+   * ExtendedCertificatesAndCertificate ::= CHOICE {
+   *   certificate             Certificate, -- from X.509
+   *   extendedCertificate [0] IMPLICIT ExtendedCertificate }
+   *
+   * CertificateRevocationLists ::= SET OF CertificateRevocationList
+   *   -- from X.509
+   *
+   * SignerInfos ::= SET OF SignerInfo
+   *
+   * SignerInfo ::= SEQUENCE {
+   *   version                       Version, -- always 1 for PKCS7 v1.5
+   *   issuerAndSerialNumber         IssuerAndSerialNumber,
+   *   digestAlgorithm               DigestAlgorithmIdentifier,
+   *   authenticatedAttributes   [0] IMPLICIT Attributes OPTIONAL,
+   *   digestEncryptionAlgorithm     DigestEncryptionAlgorithmIdentifier,
+   *   encryptedDigest               EncryptedDigest,
+   *   unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL }
+   *
+   * EncryptedDigest ::= OCTET STRING
+   * 
+ * + *

(Readers who are confused as to why it takes 40 levels of indirection + * to specify "data with a signature", rest assured that the present author + * is as confused as you are).

+ */ + public PKCS7SignedData(BERReader ber) + throws CRLException, CertificateException, IOException + { + CertificateFactory x509 = CertificateFactory.getInstance("X509"); + DERValue val = ber.read(); + if (!val.isConstructed()) + throw new BEREncodingException("malformed ContentInfo"); + + val = ber.read(); + if (val.getTag() != BER.OBJECT_IDENTIFIER) + throw new BEREncodingException("malformed ContentType"); + + if (!PKCS7_SIGNED_DATA.equals(val.getValue())) + throw new BEREncodingException("content is not SignedData"); + + val = ber.read(); + if (val.getTag() != 0) + throw new BEREncodingException("malformed Content"); + + val = ber.read(); + if (!val.isConstructed()) + throw new BEREncodingException("malformed SignedData"); + + if (Configuration.DEBUG) + log.fine("SignedData: " + val); + + val = ber.read(); + if (val.getTag() != BER.INTEGER) + throw new BEREncodingException("expecting Version"); + version = (BigInteger) val.getValue(); + if (Configuration.DEBUG) + log.fine(" Version: " + version); + + digestAlgorithms = new HashSet(); + val = ber.read(); + if (!val.isConstructed()) + throw new BEREncodingException("malformed DigestAlgorithmIdentifiers"); + if (Configuration.DEBUG) + log.fine(" DigestAlgorithmIdentifiers: " + val); + int count = 0; + DERValue val2 = ber.read(); + while (val2 != BER.END_OF_SEQUENCE && + (val.getLength() > 0 && val.getLength() > count)) + { + if (!val2.isConstructed()) + throw new BEREncodingException("malformed AlgorithmIdentifier"); + if (Configuration.DEBUG) + log.fine(" AlgorithmIdentifier: " + val2); + count += val2.getEncodedLength(); + val2 = ber.read(); + if (val2.getTag() != BER.OBJECT_IDENTIFIER) + throw new BEREncodingException("malformed AlgorithmIdentifier"); + if (Configuration.DEBUG) + log.fine(" digestAlgorithmIdentifiers OID: " + val2.getValue()); + List algId = new ArrayList(2); + algId.add(val2.getValue()); + val2 = ber.read(); + if (val2 != BER.END_OF_SEQUENCE) + { + count += val2.getEncodedLength(); + if (val2.getTag() == BER.NULL) + algId.add(null); + else + algId.add(val2.getEncoded()); + + if (val2.isConstructed()) + ber.skip(val2.getLength()); + + if (BERValue.isIndefinite(val)) + val2 = ber.read(); + } + else + algId.add(null); + + if (Configuration.DEBUG) + { + log.fine(" digestAlgorithmIdentifiers params: "); + log.fine(Util.dumpString((byte[]) algId.get(1), + " digestAlgorithmIdentifiers params: ")); + } + digestAlgorithms.add(algId); + } + + val = ber.read(); + if (!val.isConstructed()) + throw new BEREncodingException("malformed ContentInfo"); + if (Configuration.DEBUG) + log.fine(" ContentInfo: " + val); + val2 = ber.read(); + if (val2.getTag() != BER.OBJECT_IDENTIFIER) + throw new BEREncodingException("malformed ContentType"); + + contentType = (OID) val2.getValue(); + if (Configuration.DEBUG) + log.fine(" ContentType OID: " + contentType); + if (BERValue.isIndefinite(val) + || (val.getLength() > 0 && val.getLength() > val2.getEncodedLength())) + { + val2 = ber.read(); + if (val2 != BER.END_OF_SEQUENCE) + { + content = val2.getEncoded(); + if (BERValue.isIndefinite(val)) + val2 = ber.read(); + } + } + if (Configuration.DEBUG) + { + log.fine(" Content: "); + log.fine(Util.dumpString(content, " Content: ")); + } + val = ber.read(); + if (val.getTag() == 0) + { + if (!val.isConstructed()) + throw new BEREncodingException("malformed ExtendedCertificatesAndCertificates"); + if (Configuration.DEBUG) + log.fine(" ExtendedCertificatesAndCertificates: " + val); + count = 0; + val2 = ber.read(); + List certs = new LinkedList(); + while (val2 != BER.END_OF_SEQUENCE && + (val.getLength() > 0 && val.getLength() > count)) + { + Certificate cert = + x509.generateCertificate(new ByteArrayInputStream(val2.getEncoded())); + if (Configuration.DEBUG) + log.fine(" Certificate: " + cert); + certs.add(cert); + count += val2.getEncodedLength(); + ber.skip(val2.getLength()); + if (BERValue.isIndefinite(val) || val.getLength() > count) + val2 = ber.read(); + } + certificates = (Certificate[]) certs.toArray(new Certificate[certs.size()]); + val = ber.read(); + } + + if (val.getTag() == 1) + { + if (!val.isConstructed()) + throw new BEREncodingException("malformed CertificateRevocationLists"); + if (Configuration.DEBUG) + log.fine(" CertificateRevocationLists: " + val); + count = 0; + val2 = ber.read(); + List crls = new LinkedList(); + while (val2 != BER.END_OF_SEQUENCE && + (val.getLength() > 0 && val.getLength() > count)) + { + CRL crl = x509.generateCRL(new ByteArrayInputStream(val2.getEncoded())); + if (Configuration.DEBUG) + log.fine(" CRL: " + crl); + crls.add(crl); + count += val2.getEncodedLength(); + ber.skip(val2.getLength()); + if (BERValue.isIndefinite(val) || val.getLength() > count) + val2 = ber.read(); + } + this.crls = (CRL[]) crls.toArray(new CRL[crls.size()]); + val = ber.read(); + } + + signerInfos = new HashSet(); + if (!val.isConstructed()) + throw new BEREncodingException("malformed SignerInfos"); + if (Configuration.DEBUG) + log.fine(" SignerInfos: " + val); + + // FIXME read this more carefully. + // Since we are just reading a file (probably) we just read until we + // reach the end. + while (true) + { + int i = ber.peek(); + if (i == 0 || i == -1) + break; + signerInfos.add(new SignerInfo(ber)); + } + } + + /** + * Constructs a new instance of PKCS7SignedData given a + * designated set of fields. + * + * @param digestAlgorithms the collection of DigestAlgorithm elements. Each + * DigestAlgorithm is a {@link List} of two elements, the first is an + * OID while the second is dependent on the value of the OID element. + * @param data an instance of a PKCS#7 (non-signed) data. In its simplest form + * such an ASN.1 structure would consist of just the OID of a + * non-signed PKCS#7 Data. + * @param certificates the array of Certificates used to authenticate the + * enclosed (or referenced, in case the content is null) data. + * @param crls the array of certificate-revocation lists of the used + * certificates. + * @param signerInfos a set of {@link SignerInfo} elements, one per signer of + * the data referenced by this PKCS7SignedData + * instance. + */ + public PKCS7SignedData(Set digestAlgorithms, PKCS7Data data, + Certificate[] certificates, X509CRL[] crls, + Set signerInfos) + { + super(); + + this.version = BigInteger.ONE; + this.digestAlgorithms = digestAlgorithms; + this.contentType = PKCS7_SIGNED_DATA; + this.content = data == null ? null : data.getEncoded(); + this.certificates = certificates; + this.crls = crls; + this.signerInfos = signerInfos; + } + + public BigInteger getVersion() + { + return version; + } + + public Certificate[] getCertificates() + { + return (certificates != null ? (Certificate[]) certificates.clone() + : null); + } + + public OID getContentType() + { + return contentType; + } + + public byte[] getContent() + { + return (content != null ? (byte[]) content.clone() : null); + } + + public Set getDigestAlgorithms() + { + // FIXME copy contents too, they are mutable!!! + return Collections.unmodifiableSet(digestAlgorithms); + } + + public Set getSignerInfos() + { + Set copy = new HashSet(); + for (Iterator it = signerInfos.iterator(); it.hasNext(); ) + copy.add(it.next()); + return Collections.unmodifiableSet(copy); + } + + /** + * Writes to the designated output stream the DER encoding of the current + * contents of this instance. + * + * @param out the destination output stream. + * @throws IOException if an I/O related exception occurs during the process. + * @throws CRLException if an exception occurs while encoding the certificate + * revocation lists associated with this instance. + * @throws CertificateEncodingException if an exception occurs while encoding + * the certificate chains associated with this instance. + */ + public void encode(OutputStream out) throws IOException, CRLException, + CertificateEncodingException + { + DERValue derVersion = new DERValue(DER.INTEGER, version); + + DERValue derDigestAlgorithms = new DERValue(DER.CONSTRUCTED | DER.SET, + digestAlgorithms); + + DERValue derContentType = new DERValue(DER.OBJECT_IDENTIFIER, + PKCS7Data.PKCS7_DATA); + ArrayList contentInfo = new ArrayList(2); + contentInfo.add(derContentType); + if (content == null) + contentInfo.add(new DERValue(DER.NULL, null)); + else + contentInfo.add(content); + + DERValue derContentInfo = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + contentInfo); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(4096); + for (int i = 0; i < certificates.length; i++) + baos.write(certificates[i].getEncoded()); + + baos.flush(); + byte[] b = baos.toByteArray(); + DERValue derExtendedCertificatesAndCertificates = + new DERValue(DER.CONSTRUCTED | DER.CONTEXT | 0, b.length, b, null); + + DERValue derCertificateRevocationLists = null; + if (crls != null && crls.length > 0) + { + baos.reset(); + for (int i = 0; i < crls.length; i++) + baos.write(((X509CRL) crls[i]).getEncoded()); + + baos.flush(); + byte[] b2 = baos.toByteArray(); + derCertificateRevocationLists = + new DERValue(DER.CONSTRUCTED | DER.CONTEXT | 1, b2.length, b2, null); + } + + baos.reset(); + for (Iterator it = signerInfos.iterator(); it.hasNext();) + { + SignerInfo signerInfo = (SignerInfo) it.next(); + signerInfo.encode(baos); + } + baos.flush(); + byte[] b3 = baos.toByteArray(); + DERValue derSignerInfos = new DERValue(DER.CONSTRUCTED | DER.SET, + b3.length, b3, null); + + ArrayList signedData = new ArrayList(6); + signedData.add(derVersion); + signedData.add(derDigestAlgorithms); + signedData.add(derContentInfo); + signedData.add(derExtendedCertificatesAndCertificates); + if (derCertificateRevocationLists != null) + signedData.add(derCertificateRevocationLists); + + signedData.add(derSignerInfos); + DERValue derSignedData = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + signedData); + // now the outer contents + ArrayList outer = new ArrayList(3); + outer.add(new DERValue(DER.OBJECT_IDENTIFIER, PKCS7_SIGNED_DATA)); + outer.add(new DERValue(DER.CONTEXT | 0, null)); + outer.add(derSignedData); + DERValue derOuter = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, outer); + + DERWriter.write(out, derOuter); + } +} diff --git a/libjava/classpath/gnu/java/security/pkcs/SignerInfo.java b/libjava/classpath/gnu/java/security/pkcs/SignerInfo.java new file mode 100644 index 000000000..645ed67bb --- /dev/null +++ b/libjava/classpath/gnu/java/security/pkcs/SignerInfo.java @@ -0,0 +1,429 @@ +/* SignerInfo.java -- a SignerInfo object, from PKCS #7 + Copyright (C) 2004, 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.java.security.pkcs; + +import gnu.java.security.Configuration; +import gnu.java.security.OID; +import gnu.java.security.ber.BER; +import gnu.java.security.ber.BEREncodingException; +import gnu.java.security.ber.BERReader; +import gnu.java.security.ber.BERValue; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERValue; +import gnu.java.security.der.DERWriter; +import gnu.java.security.util.Util; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.logging.Logger; + +import javax.security.auth.x500.X500Principal; + +public class SignerInfo +{ + private static final Logger log = Logger.getLogger(SignerInfo.class.getName()); + + private final BigInteger version; + private final BigInteger serialNumber; + private final X500Principal issuer; + private final OID digestAlgorithmId; + private final byte[] digestAlgorithmParams; + private final byte[] authenticatedAttributes; + private final OID digestEncryptionAlgorithmId; + private final byte[] digestEncryptionAlgorithmParams; + private final byte[] encryptedDigest; + private final byte[] unauthenticatedAttributes; + + /** + * Parse a SignerInfo object. + *

+ * A SignerInfo is a structure with the following ASN.1 syntax: + *

+   * SignerInfo ::= SEQUENCE {
+   *   version                       Version, -- always 1 for PKCS7 v1.5
+   *   issuerAndSerialNumber         IssuerAndSerialNumber, -- an INTEGER
+   *   digestAlgorithm               DigestAlgorithmIdentifier,
+   *   authenticatedAttributes   [0] IMPLICIT Attributes OPTIONAL,
+   *   digestEncryptionAlgorithm     DigestEncryptionAlgorithmIdentifier,
+   *   encryptedDigest               EncryptedDigest,
+   *   unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL }
+   *
+   * IssuerAndSerialNumber ::= SEQUENCE {
+   *   issuer       Name,
+   *   serialNumber CertificateSerialNumber
+   * }
+   *
+   * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+   *
+   * DigestEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
+   *
+   * EncryptedDigest ::= OCTET STRING
+   * 
+ */ + public SignerInfo(BERReader ber) throws IOException + { + DERValue val = ber.read(); + if (Configuration.DEBUG) + log.fine("SignerInfo: " + val); + if (!val.isConstructed()) + throw new BEREncodingException("malformed SignerInfo"); + + val = ber.read(); + if (val.getTag() != BER.INTEGER) + throw new BEREncodingException("malformed Version"); + + version = (BigInteger) val.getValue(); + log.fine(" Version: " + version); + + val = ber.read(); + if (!val.isConstructed()) + throw new BEREncodingException("malformed IssuerAndSerialNumber"); + if (Configuration.DEBUG) + log.fine(" IssuerAndSerialNumber: " + val); + + val = ber.read(); + if (!val.isConstructed()) + throw new BEREncodingException("malformed Issuer"); + + issuer = new X500Principal(val.getEncoded()); + ber.skip(val.getLength()); + if (Configuration.DEBUG) + log.fine(" Issuer: " + issuer); + + val = ber.read(); + if (val.getTag() != BER.INTEGER) + throw new BEREncodingException("malformed SerialNumber"); + + serialNumber = (BigInteger) val.getValue(); + if (Configuration.DEBUG) + log.fine(" SerialNumber: " + serialNumber); + + val = ber.read(); + if (!val.isConstructed()) + throw new BEREncodingException("malformed DigestAlgorithmIdentifier"); + if (Configuration.DEBUG) + log.fine(" DigestAlgorithmIdentifier: " + val); + + int count = 0; + DERValue val2 = ber.read(); + if (val2.getTag() != BER.OBJECT_IDENTIFIER) + throw new BEREncodingException("malformed AlgorithmIdentifier"); + + digestAlgorithmId = (OID) val2.getValue(); + if (Configuration.DEBUG) + log.fine(" digestAlgorithm OID: " + digestAlgorithmId); + + if (BERValue.isIndefinite(val)) + { + val2 = ber.read(); + if (val2 != BER.END_OF_SEQUENCE) + { + digestAlgorithmParams = val2.getEncoded(); + val2 = ber.read(); + if (val2 != BER.END_OF_SEQUENCE) + throw new BEREncodingException("expecting BER end-of-sequence"); + } + else + digestAlgorithmParams = null; + } + else if (val2.getEncodedLength() < val.getLength()) + { + val2 = ber.read(); + digestAlgorithmParams = val2.getEncoded(); + if (val2.isConstructed()) + ber.skip(val2.getLength()); + } + else + digestAlgorithmParams = null; + + if (Configuration.DEBUG) + { + log.fine(" digestAlgorithm params: "); + log.fine(Util.dumpString(digestAlgorithmParams, + " digestAlgorithm params: ")); + } + val = ber.read(); + if (val.getTag() == 0) + { + authenticatedAttributes = val.getEncoded(); + val = ber.read(); + if (val.isConstructed()) + ber.skip(val.getLength()); + + val = ber.read(); + } + else + authenticatedAttributes = null; + + if (Configuration.DEBUG) + { + log.fine(" AuthenticatedAttributes: "); + log.fine(Util.dumpString(authenticatedAttributes, + " AuthenticatedAttributes: ")); + } + if (!val.isConstructed()) + throw new BEREncodingException("malformed DigestEncryptionAlgorithmIdentifier"); + if (Configuration.DEBUG) + log.fine(" DigestEncryptionAlgorithmIdentifier: " + val); + count = 0; + val2 = ber.read(); + if (val2.getTag() != BER.OBJECT_IDENTIFIER) + throw new BEREncodingException("malformed AlgorithmIdentifier"); + + digestEncryptionAlgorithmId = (OID) val2.getValue(); + if (Configuration.DEBUG) + log.fine(" digestEncryptionAlgorithm OID: " + digestEncryptionAlgorithmId); + + if (BERValue.isIndefinite(val)) + { + val2 = ber.read(); + if (val2 != BER.END_OF_SEQUENCE) + { + digestEncryptionAlgorithmParams = val2.getEncoded(); + val2 = ber.read(); + if (val2 != BER.END_OF_SEQUENCE) + throw new BEREncodingException("expecting BER end-of-sequence"); + } + else + digestEncryptionAlgorithmParams = null; + } + else if (val2.getEncodedLength() < val.getLength()) + { + val2 = ber.read(); + digestEncryptionAlgorithmParams = val2.getEncoded(); + if (val2.isConstructed()) + ber.skip(val2.getLength()); + } + else + digestEncryptionAlgorithmParams = null; + + if (Configuration.DEBUG) + { + log.fine(" digestEncryptionAlgorithm params: "); + log.fine(Util.dumpString(digestEncryptionAlgorithmParams, + " digestEncryptionAlgorithm params: ")); + } + val = ber.read(); + if (val.getTag() != BER.OCTET_STRING) + throw new BEREncodingException("malformed EncryptedDigest"); + + encryptedDigest = (byte[]) val.getValue(); + if (Configuration.DEBUG) + { + log.fine(" EncryptedDigest: "); + log.fine(Util.dumpString(encryptedDigest, " EncryptedDigest: ")); + } + if (ber.peek() == 1) + unauthenticatedAttributes = ber.read().getEncoded(); + else + unauthenticatedAttributes = null; + + if (Configuration.DEBUG) + { + log.fine(" UnauthenticatedAttributes: "); + log.fine(Util.dumpString(unauthenticatedAttributes, + " UnauthenticatedAttributes: ")); + } + if (ber.peek() == 0) + ber.read(); + } + + /** + * Constructs a new instance of SignerInfo given a designated + * set of fields. + * + * @param issuer the X.500 Principal name of the signer referenced by this + * instance. + * @param serialNumber the serial number of the certificate being used. Both + * this and the previous arguments are gleaned from the signer's + * certificate. + * @param digestAlgorithmOID the OID of the digest algorithm. When + * constructing the DigestAlgorithmIdentifier with this OID, the + * parameters part will be NULL. + * @param authenticatedAttributes the encoding of the set of authenticated + * attributes to use. + * @param digestEncryptionAlgorithmOID the OID of the digest encryption + * algorithm. When constructing the + * DigestEncryptionAlgorithmIdentifier with this OID, the parameters + * part will be NULL. + * @param encryptedDigest the encrypted hash generated with this signer's + * private key. + * @param unauthenticatedAttributes the encoding of the set of + * unauthencticated attributes. + */ + public SignerInfo(X500Principal issuer, BigInteger serialNumber, + OID digestAlgorithmOID, byte[] authenticatedAttributes, + OID digestEncryptionAlgorithmOID, + byte[] encryptedDigest, byte[] unauthenticatedAttributes) + { + super(); + + this.version = BigInteger.ONE; + this.issuer = issuer; + this.serialNumber = serialNumber; + this.digestAlgorithmId = digestAlgorithmOID; + this.digestAlgorithmParams = null; + this.authenticatedAttributes = authenticatedAttributes; + this.digestEncryptionAlgorithmId = digestEncryptionAlgorithmOID; + this.digestEncryptionAlgorithmParams = null; + this.encryptedDigest = encryptedDigest; + this.unauthenticatedAttributes = unauthenticatedAttributes; + } + + public BigInteger getVersion() + { + return version; + } + + public BigInteger getSerialNumber() + { + return serialNumber; + } + + public X500Principal getIssuer() + { + return issuer; + } + + public OID getDigestAlgorithmId() + { + return digestAlgorithmId; + } + + public byte[] getDigestAlgorithmParams() + { + return (digestAlgorithmParams != null + ? (byte[]) digestAlgorithmParams.clone() + : null); + } + + public byte[] getAuthenticatedAttributes() + { + return (authenticatedAttributes != null + ? (byte[]) authenticatedAttributes.clone() + : null); + } + + public OID getDigestEncryptionAlgorithmId() + { + return digestEncryptionAlgorithmId; + } + + public byte[] getDigestEncryptionAlgorithmParams() + { + return (digestEncryptionAlgorithmParams != null + ? (byte[]) digestEncryptionAlgorithmParams.clone() + : null); + } + + public byte[] getEncryptedDigest() + { + return (encryptedDigest != null ? (byte[]) encryptedDigest.clone() : null); + } + + public byte[] getUnauthenticatedAttributes() + { + return (unauthenticatedAttributes != null + ? (byte[]) unauthenticatedAttributes.clone() + : null); + } + + /** + * Writes to the designated output stream the DER encoding of the current + * contents of this instance. + * + * @param out the destination output stream. + * @throws IOException if an I/O related exception occurs during the process. + */ + public void encode(OutputStream out) throws IOException + { + DERValue derVersion = new DERValue(DER.INTEGER, version); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(4096); + baos.write(issuer.getEncoded()); + DERValue derSerialNumber = new DERValue(DER.INTEGER, serialNumber); + DERWriter.write(baos, derSerialNumber); + baos.flush(); + byte[] b = baos.toByteArray(); + DERValue derIssuerAndSerialNumber = + new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, b.length, b, null); + + DERValue derDigestAlgorithmOID = new DERValue(DER.OBJECT_IDENTIFIER, + digestAlgorithmId); + ArrayList digestAlgorithmIdentifier = new ArrayList(1); + digestAlgorithmIdentifier.add(derDigestAlgorithmOID); + DERValue derDigestAlgorithmIdentifier = + new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, digestAlgorithmIdentifier); + + DERValue derAuthenticatedAttributes; + if (authenticatedAttributes == null) + derAuthenticatedAttributes = new DERValue(DER.NULL, null); + else + derAuthenticatedAttributes = new DERValue(DER.CONSTRUCTED | DER.SET, + authenticatedAttributes); + + DERValue derDigestEncryptionAlgorithmOID = + new DERValue(DER.OBJECT_IDENTIFIER, digestEncryptionAlgorithmId); + ArrayList digestEncryptionAlgorithmIdentifier = new ArrayList(1); + digestEncryptionAlgorithmIdentifier.add(derDigestEncryptionAlgorithmOID); + DERValue derDigestEncryptionAlgorithmIdentifier = + new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, digestEncryptionAlgorithmIdentifier); + + DERValue derEncryptedDigest = new DERValue(DER.OCTET_STRING, encryptedDigest); + + DERValue derUnauthenticatedAttributes; + if (unauthenticatedAttributes == null) + derUnauthenticatedAttributes = new DERValue(DER.NULL, null); + else + derUnauthenticatedAttributes = new DERValue(DER.CONSTRUCTED | DER.SET, + unauthenticatedAttributes); + + ArrayList signerInfo = new ArrayList(5); + signerInfo.add(derVersion); + signerInfo.add(derIssuerAndSerialNumber); + signerInfo.add(derDigestAlgorithmIdentifier); + signerInfo.add(derDigestEncryptionAlgorithmIdentifier); + signerInfo.add(derEncryptedDigest); + DERValue derSignerInfo = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + signerInfo); + DERWriter.write(out, derSignerInfo); + } +} diff --git a/libjava/classpath/gnu/java/security/pkcs/package.html b/libjava/classpath/gnu/java/security/pkcs/package.html new file mode 100644 index 000000000..60d658f8e --- /dev/null +++ b/libjava/classpath/gnu/java/security/pkcs/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.security.pkcs + + +

+ + + diff --git a/libjava/classpath/gnu/java/security/prng/BasePRNG.java b/libjava/classpath/gnu/java/security/prng/BasePRNG.java new file mode 100644 index 000000000..eb5ada71c --- /dev/null +++ b/libjava/classpath/gnu/java/security/prng/BasePRNG.java @@ -0,0 +1,178 @@ +/* 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 +{ + /** 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; + + /** + * 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]; + } + + 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"); + } + + public boolean isInitialised() + { + return initialised; + } + + private byte nextByteInternal() throws LimitReachedException + { + if (ndx >= buffer.length) + { + this.fillBlock(); + ndx = 0; + } + + return buffer[ndx++]; + } + + 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/libjava/classpath/gnu/java/security/prng/EntropySource.java b/libjava/classpath/gnu/java/security/prng/EntropySource.java new file mode 100644 index 000000000..a7173d3b1 --- /dev/null +++ b/libjava/classpath/gnu/java/security/prng/EntropySource.java @@ -0,0 +1,61 @@ +/* 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(); +} diff --git a/libjava/classpath/gnu/java/security/prng/IRandom.java b/libjava/classpath/gnu/java/security/prng/IRandom.java new file mode 100644 index 000000000..eb1495dd8 --- /dev/null +++ b/libjava/classpath/gnu/java/security/prng/IRandom.java @@ -0,0 +1,174 @@ +/* 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 greater 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 underlying + * 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 an + * 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 +{ + /** + * 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; +} diff --git a/libjava/classpath/gnu/java/security/prng/LimitReachedException.java b/libjava/classpath/gnu/java/security/prng/LimitReachedException.java new file mode 100644 index 000000000..028c74553 --- /dev/null +++ b/libjava/classpath/gnu/java/security/prng/LimitReachedException.java @@ -0,0 +1,57 @@ +/* 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 +{ + public LimitReachedException() + { + super(); + } + + public LimitReachedException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/gnu/java/security/prng/MDGenerator.java b/libjava/classpath/gnu/java/security/prng/MDGenerator.java new file mode 100644 index 000000000..b110486f4 --- /dev/null +++ b/libjava/classpath/gnu/java/security/prng/MDGenerator.java @@ -0,0 +1,127 @@ +/* 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 +{ + /** 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; + + /** Trivial 0-arguments constructor. */ + public MDGenerator() + { + super(Registry.MD_PRNG); + } + + 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); + } + + public void addRandomByte(final byte b) + { + if (md == null) + throw new IllegalStateException("not initialized"); + md.update(b); + } + + public void addRandomBytes(final byte[] buf, final int off, final int len) + { + if (md == null) + throw new IllegalStateException("not initialized"); + md.update(buf, off, len); + } + + 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/libjava/classpath/gnu/java/security/prng/PRNGFactory.java b/libjava/classpath/gnu/java/security/prng/PRNGFactory.java new file mode 100644 index 000000000..b57d7c7bb --- /dev/null +++ b/libjava/classpath/gnu/java/security/prng/PRNGFactory.java @@ -0,0 +1,92 @@ +/* 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.Set; + +/** + * A Factory to instantiate pseudo random number generators. + */ +public class PRNGFactory + implements Registry +{ + /** Trivial constructor to enforce Singleton pattern. */ + protected PRNGFactory() + { + } + + /** + * 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); + } +} diff --git a/libjava/classpath/gnu/java/security/prng/RandomEvent.java b/libjava/classpath/gnu/java/security/prng/RandomEvent.java new file mode 100644 index 000000000..fc4607a8a --- /dev/null +++ b/libjava/classpath/gnu/java/security/prng/RandomEvent.java @@ -0,0 +1,81 @@ +/* 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; + +/** + * A type 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; + } +} diff --git a/libjava/classpath/gnu/java/security/prng/RandomEventListener.java b/libjava/classpath/gnu/java/security/prng/RandomEventListener.java new file mode 100644 index 000000000..720f2afe4 --- /dev/null +++ b/libjava/classpath/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); +} diff --git a/libjava/classpath/gnu/java/security/provider/CollectionCertStoreImpl.java b/libjava/classpath/gnu/java/security/provider/CollectionCertStoreImpl.java new file mode 100644 index 000000000..4bf3d5434 --- /dev/null +++ b/libjava/classpath/gnu/java/security/provider/CollectionCertStoreImpl.java @@ -0,0 +1,102 @@ +/* CollectionCertStore.java -- Collection-based cert store. + 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.security.provider; + +import java.security.InvalidAlgorithmParameterException; +import java.security.cert.CRL; +import java.security.cert.CRLSelector; +import java.security.cert.CertSelector; +import java.security.cert.CertStoreException; +import java.security.cert.CertStoreParameters; +import java.security.cert.CertStoreSpi; +import java.security.cert.Certificate; +import java.security.cert.CollectionCertStoreParameters; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; + +public final class CollectionCertStoreImpl extends CertStoreSpi +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final Collection store; + + // Constructors. + // ------------------------------------------------------------------------- + + public CollectionCertStoreImpl(CertStoreParameters params) + throws InvalidAlgorithmParameterException + { + super(params); + if (! (params instanceof CollectionCertStoreParameters)) + throw new InvalidAlgorithmParameterException("not a CollectionCertStoreParameters object"); + store = ((CollectionCertStoreParameters) params).getCollection(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public Collection engineGetCertificates(CertSelector selector) + throws CertStoreException + { + LinkedList result = new LinkedList(); + for (Iterator it = store.iterator(); it.hasNext(); ) + { + Object o = it.next(); + if ((o instanceof Certificate) && selector.match((Certificate) o)) + result.add(o); + } + return result; + } + + public Collection engineGetCRLs(CRLSelector selector) + throws CertStoreException + { + LinkedList result = new LinkedList(); + for (Iterator it = store.iterator(); it.hasNext(); ) + { + Object o = it.next(); + if ((o instanceof CRL) && selector.match((CRL) o)) + result.add(o); + } + return result; + } +} diff --git a/libjava/classpath/gnu/java/security/provider/DefaultPolicy.java b/libjava/classpath/gnu/java/security/provider/DefaultPolicy.java new file mode 100644 index 000000000..566c949da --- /dev/null +++ b/libjava/classpath/gnu/java/security/provider/DefaultPolicy.java @@ -0,0 +1,68 @@ +/* DefaultPolicy.java -- + Copyright (C) 2001, 2002 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.provider; + +import java.security.AllPermission; +import java.security.CodeSource; +import java.security.Permission; +import java.security.PermissionCollection; +import java.security.Permissions; +import java.security.Policy; + +/** + * This is just a stub policy implementation which grants all permissions + * to any code source. FIXME: This should be replaced with a real + * implementation that reads the policy configuration from a file, like + * $JAVA_HOME/jre/lib/security/java.security. + */ +public class DefaultPolicy extends Policy +{ + static Permission allPermission = new AllPermission(); + + public PermissionCollection getPermissions(CodeSource codesource) + { + Permissions perms = new Permissions(); + perms.add(allPermission); + return perms; + } + + public void refresh() + { + // Nothing. + } +} diff --git a/libjava/classpath/gnu/java/security/provider/Gnu.java b/libjava/classpath/gnu/java/security/provider/Gnu.java new file mode 100644 index 000000000..62bb0a29e --- /dev/null +++ b/libjava/classpath/gnu/java/security/provider/Gnu.java @@ -0,0 +1,306 @@ +/* Gnu.java --- Gnu provider main class + Copyright (C) 1999, 2002, 2003, 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.java.security.provider; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.Provider; + +public final class Gnu + extends Provider +{ + public Gnu() + { + super("GNU", 1.0, + "GNU provider v1.0 implementing SHA-1, MD5, DSA, RSA, X.509 " + + "Certificates and CRLs, PKIX certificate path validators, " + + "Collection cert stores, Diffie-Hellman key agreement and " + + "key pair generator"); + AccessController.doPrivileged (new PrivilegedAction() + { + public Object run() + { + // Note that all implementation class names are referenced by using + // Class.getName(). That way when we staticly link the Gnu provider + // we automatically get all the implementation classes. + + // Signature + put("Signature.SHA160withDSS", + gnu.java.security.jce.sig.SHA160withDSS.class.getName()); + put("Alg.Alias.Signature.SHA1withDSA", "SHA160withDSS"); + put("Alg.Alias.Signature.DSS", "SHA160withDSS"); + put("Alg.Alias.Signature.DSA", "SHA160withDSS"); + put("Alg.Alias.Signature.SHAwithDSA", "SHA160withDSS"); + put("Alg.Alias.Signature.DSAwithSHA", "SHA160withDSS"); + put("Alg.Alias.Signature.DSAwithSHA1", "SHA160withDSS"); + put("Alg.Alias.Signature.SHA/DSA", "SHA160withDSS"); + put("Alg.Alias.Signature.SHA-1/DSA", "SHA160withDSS"); + put("Alg.Alias.Signature.SHA1/DSA", "SHA160withDSS"); + put("Alg.Alias.Signature.OID.1.2.840.10040.4.3", "SHA160withDSS"); + put("Alg.Alias.Signature.1.2.840.10040.4.3", "SHA160withDSS"); + put("Alg.Alias.Signature.1.3.14.3.2.13", "SHA160withDSS"); + put("Alg.Alias.Signature.1.3.14.3.2.27", "SHA160withDSS"); + + put("Signature.MD2withRSA", + gnu.java.security.jce.sig.MD2withRSA.class.getName()); + put("Signature.MD2withRSA ImplementedIn", "Software"); + put("Alg.Alias.Signature.md2WithRSAEncryption", "MD2withRSA"); + put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.2", "MD2withRSA"); + put("Alg.Alias.Signature.1.2.840.113549.1.1.2", "MD2withRSA"); + + put("Signature.MD5withRSA", + gnu.java.security.jce.sig.MD5withRSA.class.getName()); + put("Signature.MD5withRSA ImplementedIn", "Software"); + put("Alg.Alias.Signature.md5WithRSAEncryption", "MD5withRSA"); + put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.4", "MD5withRSA"); + put("Alg.Alias.Signature.1.2.840.113549.1.1.4", "MD5withRSA"); + put("Alg.Alias.Signature.RSA", "MD5withRSA"); + + put("Signature.SHA160withRSA", + gnu.java.security.jce.sig.SHA160withRSA.class.getName()); + put("Signature.SHA160withRSA ImplementedIn", "Software"); + put("Alg.Alias.Signature.sha-1WithRSAEncryption", "SHA160withRSA"); + put("Alg.Alias.Signature.sha-160WithRSAEncryption", "SHA160withRSA"); + put("Alg.Alias.Signature.sha1WithRSAEncryption", "SHA160withRSA"); + put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.5", "SHA160withRSA"); + put("Alg.Alias.Signature.1.2.840.113549.1.1.5", "SHA160withRSA"); + put("Alg.Alias.Signature.SHA1withRSA", "SHA160withRSA"); + + put("Signature.SHA256withRSA", + gnu.java.security.jce.sig.SHA256withRSA.class.getName()); + put("Signature.SHA160withRSA ImplementedIn", "Software"); + put("Alg.Alias.Signature.sha256WithRSAEncryption", "SHA256withRSA"); + put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.11", "SHA256withRSA"); + put("Alg.Alias.Signature.1.2.840.113549.1.1.11", "SHA256withRSA"); + + put("Signature.SHA384withRSA", + gnu.java.security.jce.sig.SHA384withRSA.class.getName()); + put("Signature.SHA160withRSA ImplementedIn", "Software"); + put("Alg.Alias.Signature.sha384WithRSAEncryption", "SHA384withRSA"); + put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.12", "SHA384withRSA"); + put("Alg.Alias.Signature.1.2.840.113549.1.1.12", "SHA384withRSA"); + + put("Signature.SHA512withRSA", + gnu.java.security.jce.sig.SHA512withRSA.class.getName()); + put("Signature.SHA160withRSA ImplementedIn", "Software"); + put("Alg.Alias.Signature.sha512WithRSAEncryption", "SHA512withRSA"); + put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.13", "SHA512withRSA"); + put("Alg.Alias.Signature.1.2.840.113549.1.1.13", "SHA512withRSA"); + + 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.DSS", + gnu.java.security.jce.sig.DSSKeyPairGeneratorSpi.class.getName()); + put("KeyPairGenerator.DSS KeySize", "1024"); + put("KeyPairGenerator.DSS ImplementedIn", "Software"); + put("Alg.Alias.KeyPairGenerator.DSA", "DSS"); + put("Alg.Alias.KeyPairGenerator.OID.1.2.840.10040.4.1", "DSS"); + put("Alg.Alias.KeyPairGenerator.1.2.840.10040.4.1", "DSS"); + put("Alg.Alias.KeyPairGenerator.1.3.14.3.2.12", "DSS"); + + put("KeyPairGenerator.RSA", + gnu.java.security.jce.sig.RSAKeyPairGeneratorSpi.class.getName()); + put("KeyPairGenerator.RSA KeySize", "1024"); + put("KeyPairGenerator.RSA ImplementedIn", "Software"); + + // Key Factory + put("KeyFactory.DSS", + gnu.java.security.jce.sig.DSSKeyFactory.class.getName()); + put("Alg.Alias.KeyFactory.DSA", "DSS"); + put("Alg.Alias.KeyFactory.OID.1.2.840.10040.4.1", "DSS"); + put("Alg.Alias.KeyFactory.1.2.840.10040.4.1", "DSS"); + put("Alg.Alias.KeyFactory.1.3.14.3.2.12", "DSS"); + + put("KeyFactory.RSA", + gnu.java.security.jce.sig.RSAKeyFactory.class.getName()); + + put("KeyFactory.Encoded", + gnu.java.security.jce.sig.EncodedKeyFactory.class.getName()); + put("KeyFactory.Encoded ImplementedIn", "Software"); + put("Alg.Alias.KeyFactory.X.509", "Encoded"); + put("Alg.Alias.KeyFactory.X509", "Encoded"); + put("Alg.Alias.KeyFactory.PKCS#8", "Encoded"); + put("Alg.Alias.KeyFactory.PKCS8", "Encoded"); + + 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.DSS", + gnu.java.security.jce.sig.DSSParameters.class.getName()); + put("Alg.Alias.AlgorithmParameters.DSA", "DSS"); + put("Alg.Alias.AlgorithmParameters.SHAwithDSA", "DSS"); + put("Alg.Alias.AlgorithmParameters.OID.1.2.840.10040.4.3", "DSS"); + put("Alg.Alias.AlgorithmParameters.1.2.840.10040.4.3", "DSS"); + + // Algorithm Parameter Generator + put("AlgorithmParameterGenerator.DSA", + gnu.java.security.jce.sig.DSSParametersGenerator.class.getName()); + put("Alg.Alias.AlgorithmParameterGenerator.DSA", "DSS"); + + // SecureRandom + put("SecureRandom.SHA1PRNG", + gnu.java.security.jce.prng.Sha160RandomSpi.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()); + put("CertificateFactory.X509 ImplementedIn", "Software"); + put("Alg.Alias.CertificateFactory.X.509", "X509"); + + // CertPathValidator + put("CertPathValidator.PKIX", PKIXCertPathValidatorImpl.class.getName()); + put("CertPathValidator.PKIX ImplementedIn", "Software"); + + // CertStore + put("CertStore.Collection", CollectionCertStoreImpl.class.getName()); + + return null; + } + }); + } +} diff --git a/libjava/classpath/gnu/java/security/provider/PKIXCertPathValidatorImpl.java b/libjava/classpath/gnu/java/security/provider/PKIXCertPathValidatorImpl.java new file mode 100644 index 000000000..d4ce4aeb4 --- /dev/null +++ b/libjava/classpath/gnu/java/security/provider/PKIXCertPathValidatorImpl.java @@ -0,0 +1,693 @@ +/* PKIXCertPathValidatorImpl.java -- PKIX certificate path validator. + Copyright (C) 2004, 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.java.security.provider; + +import gnu.java.security.Configuration; +import gnu.java.security.OID; +import gnu.java.security.Registry; +import gnu.java.security.key.dss.DSSPublicKey; +import gnu.java.security.x509.GnuPKIExtension; +import gnu.java.security.x509.PolicyNodeImpl; +import gnu.java.security.x509.X509CRLSelectorImpl; +import gnu.java.security.x509.X509CertSelectorImpl; +import gnu.java.security.x509.ext.BasicConstraints; +import gnu.java.security.x509.ext.CertificatePolicies; +import gnu.java.security.x509.ext.Extension; +import gnu.java.security.x509.ext.KeyUsage; +import gnu.java.security.x509.ext.PolicyConstraint; + +import java.io.IOException; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.PublicKey; +import java.security.cert.CRL; +import java.security.cert.CertPath; +import java.security.cert.CertPathParameters; +import java.security.cert.CertPathValidatorException; +import java.security.cert.CertPathValidatorResult; +import java.security.cert.CertPathValidatorSpi; +import java.security.cert.CertStore; +import java.security.cert.CertStoreException; +import java.security.cert.CertificateException; +import java.security.cert.PKIXCertPathChecker; +import java.security.cert.PKIXCertPathValidatorResult; +import java.security.cert.PKIXParameters; +import java.security.cert.TrustAnchor; +import java.security.cert.X509CRL; +import java.security.cert.X509Certificate; +import java.security.interfaces.DSAParams; +import java.security.interfaces.DSAPublicKey; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.logging.Logger; + +/** + * An implementation of the Public Key Infrastructure's X.509 certificate path + * validation algorithm. + *

+ * See RFC 3280: Internet X.509 + * Public Key Infrastructure Certificate and Certificate Revocation List (CRL) + * Profile. + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +public class PKIXCertPathValidatorImpl + extends CertPathValidatorSpi +{ + private static final Logger log = Logger.getLogger(PKIXCertPathValidatorImpl.class.getName()); + + public static final String ANY_POLICY = "2.5.29.32.0"; + + public PKIXCertPathValidatorImpl() + { + super(); + } + + public CertPathValidatorResult engineValidate(CertPath path, + CertPathParameters params) + throws CertPathValidatorException, InvalidAlgorithmParameterException + { + if (! (params instanceof PKIXParameters)) + throw new InvalidAlgorithmParameterException("not a PKIXParameters object"); + // First check if the certificate path is valid. + // + // This means that: + // + // (a) for all x in {1, ..., n-1}, the subject of certificate x is + // the issuer of certificate x+1; + // + // (b) for all x in {1, ..., n}, the certificate was valid at the + // time in question. + // + // Because this is the X.509 algorithm, we also check if all + // cerificates are of type X509Certificate. + PolicyNodeImpl rootNode = new PolicyNodeImpl(); + Set initPolicies = ((PKIXParameters) params).getInitialPolicies(); + rootNode.setValidPolicy(ANY_POLICY); + rootNode.setCritical(false); + rootNode.setDepth(0); + if (initPolicies != null) + rootNode.addAllExpectedPolicies(initPolicies); + else + rootNode.addExpectedPolicy(ANY_POLICY); + List checks = ((PKIXParameters) params).getCertPathCheckers(); + List l = path.getCertificates(); + if (l == null || l.size() == 0) + throw new CertPathValidatorException(); + X509Certificate[] p = null; + try + { + p = (X509Certificate[]) l.toArray(new X509Certificate[l.size()]); + } + catch (ClassCastException cce) + { + throw new CertPathValidatorException("invalid certificate path"); + } + String sigProvider = ((PKIXParameters) params).getSigProvider(); + PublicKey prevKey = null; + Date now = ((PKIXParameters) params).getDate(); + if (now == null) + now = new Date(); + LinkedList policyConstraints = new LinkedList(); + for (int i = p.length - 1; i >= 0; i--) + { + try + { + p[i].checkValidity(now); + } + catch (CertificateException ce) + { + throw new CertPathValidatorException(ce.toString()); + } + Set uce = getCritExts(p[i]); + for (Iterator check = checks.iterator(); check.hasNext();) + { + try + { + ((PKIXCertPathChecker) check.next()).check(p[i], uce); + } + catch (Exception x) + { + } + } + PolicyConstraint constr = null; + if (p[i] instanceof GnuPKIExtension) + { + Extension pcx = ((GnuPKIExtension) p[i]).getExtension(PolicyConstraint.ID); + if (pcx != null) + constr = (PolicyConstraint) pcx.getValue(); + } + else + { + byte[] pcx = p[i].getExtensionValue(PolicyConstraint.ID.toString()); + if (pcx != null) + { + try + { + constr = new PolicyConstraint(pcx); + } + catch (Exception x) + { + } + } + } + if (constr != null && constr.getRequireExplicitPolicy() >= 0) + policyConstraints.add(new int[] { p.length - i, + constr.getRequireExplicitPolicy() }); + updatePolicyTree(p[i], rootNode, p.length - i, (PKIXParameters) params, + checkExplicitPolicy(p.length - i, policyConstraints)); + // The rest of the tests involve this cert's relationship with the + // next in the path. If this cert is the end entity, we can stop. + if (i == 0) + break; + + basicSanity(p, i); + PublicKey pubKey = null; + try + { + pubKey = p[i].getPublicKey(); + if (pubKey instanceof DSAPublicKey) + { + DSAParams dsa = ((DSAPublicKey) pubKey).getParams(); + // If the DSA public key is missing its parameters, use those + // from the previous cert's key. + if (dsa == null || dsa.getP() == null || dsa.getG() == null + || dsa.getQ() == null) + { + if (prevKey == null) + throw new InvalidKeyException("DSA keys not chainable"); + if (! (prevKey instanceof DSAPublicKey)) + throw new InvalidKeyException("DSA keys not chainable"); + dsa = ((DSAPublicKey) prevKey).getParams(); + pubKey = new DSSPublicKey(Registry.X509_ENCODING_ID, + dsa.getP(), dsa.getQ(), + dsa.getG(), + ((DSAPublicKey) pubKey).getY()); + } + } + if (sigProvider == null) + p[i - 1].verify(pubKey); + else + p[i - 1].verify(pubKey, sigProvider); + prevKey = pubKey; + } + catch (Exception e) + { + throw new CertPathValidatorException(e.toString()); + } + if (! p[i].getSubjectDN().equals(p[i - 1].getIssuerDN())) + throw new CertPathValidatorException("issuer DN mismatch"); + boolean[] issuerUid = p[i - 1].getIssuerUniqueID(); + boolean[] subjectUid = p[i].getSubjectUniqueID(); + if (issuerUid != null && subjectUid != null) + if (! Arrays.equals(issuerUid, subjectUid)) + throw new CertPathValidatorException("UID mismatch"); + + // Check the certificate against the revocation lists. + if (((PKIXParameters) params).isRevocationEnabled()) + { + X509CRLSelectorImpl selector = new X509CRLSelectorImpl(); + try + { + selector.addIssuerName(p[i].getSubjectDN()); + } + catch (IOException ioe) + { + throw new CertPathValidatorException("error selecting CRLs"); + } + List certStores = ((PKIXParameters) params).getCertStores(); + List crls = new LinkedList(); + for (Iterator it = certStores.iterator(); it.hasNext();) + { + CertStore cs = (CertStore) it.next(); + try + { + Collection c = cs.getCRLs(selector); + crls.addAll(c); + } + catch (CertStoreException cse) + { + } + } + if (crls.isEmpty()) + throw new CertPathValidatorException("no CRLs for issuer"); + boolean certOk = false; + for (Iterator it = crls.iterator(); it.hasNext();) + { + CRL crl = (CRL) it.next(); + if (! (crl instanceof X509CRL)) + continue; + X509CRL xcrl = (X509CRL) crl; + if (! checkCRL(xcrl, p, now, p[i], pubKey, certStores)) + continue; + if (xcrl.isRevoked(p[i - 1])) + throw new CertPathValidatorException("certificate is revoked"); + else + certOk = true; + } + if (! certOk) + throw new CertPathValidatorException( + "certificate's validity could not be determined"); + } + } + rootNode.setReadOnly(); + // Now ensure that the first certificate in the chain was issued + // by a trust anchor. + Exception cause = null; + Set anchors = ((PKIXParameters) params).getTrustAnchors(); + for (Iterator i = anchors.iterator(); i.hasNext();) + { + TrustAnchor anchor = (TrustAnchor) i.next(); + X509Certificate anchorCert = null; + PublicKey anchorKey = null; + if (anchor.getTrustedCert() != null) + { + anchorCert = anchor.getTrustedCert(); + anchorKey = anchorCert.getPublicKey(); + } + else + anchorKey = anchor.getCAPublicKey(); + if (anchorKey == null) + continue; + try + { + if (anchorCert != null) + anchorCert.checkValidity(now); + p[p.length - 1].verify(anchorKey); + if (anchorCert != null && anchorCert.getBasicConstraints() >= 0 + && anchorCert.getBasicConstraints() < p.length) + continue; + + if (((PKIXParameters) params).isRevocationEnabled()) + { + X509CRLSelectorImpl selector = new X509CRLSelectorImpl(); + if (anchorCert != null) + try + { + selector.addIssuerName(anchorCert.getSubjectDN()); + } + catch (IOException ioe) + { + } + else + selector.addIssuerName(anchor.getCAName()); + List certStores = ((PKIXParameters) params).getCertStores(); + List crls = new LinkedList(); + for (Iterator it = certStores.iterator(); it.hasNext();) + { + CertStore cs = (CertStore) it.next(); + try + { + Collection c = cs.getCRLs(selector); + crls.addAll(c); + } + catch (CertStoreException cse) + { + } + } + if (crls.isEmpty()) + continue; + for (Iterator it = crls.iterator(); it.hasNext();) + { + CRL crl = (CRL) it.next(); + if (! (crl instanceof X509CRL)) + continue; + X509CRL xcrl = (X509CRL) crl; + try + { + xcrl.verify(anchorKey); + } + catch (Exception x) + { + continue; + } + Date nextUpdate = xcrl.getNextUpdate(); + if (nextUpdate != null && nextUpdate.compareTo(now) < 0) + continue; + if (xcrl.isRevoked(p[p.length - 1])) + throw new CertPathValidatorException("certificate is revoked"); + } + } + // The chain is valid; return the result. + return new PKIXCertPathValidatorResult(anchor, rootNode, + p[0].getPublicKey()); + } + catch (Exception ignored) + { + cause = ignored; + continue; + } + } + // The path is not valid. + CertPathValidatorException cpve = + new CertPathValidatorException("path validation failed"); + if (cause != null) + cpve.initCause(cause); + throw cpve; + } + + /** + * Check if a given CRL is acceptable for checking the revocation status of + * certificates in the path being checked. + *

+ * The CRL is accepted iff: + *

    + *
  1. The nextUpdate field (if present) is in the future.
  2. + *
  3. The CRL does not contain any unsupported critical extensions.
  4. + *
  5. The CRL is signed by one of the certificates in the path, or,
  6. + *
  7. The CRL is signed by the given public key and was issued by the public + * key's subject, or,
  8. + *
  9. The CRL is signed by a certificate in the given cert stores, and that + * cert is signed by one of the certificates in the path.
  10. + *
+ * + * @param crl The CRL being checked. + * @param path The path this CRL is being checked against. + * @param now The value to use as 'now'. + * @param pubKeyCert The certificate authenticating the public key. + * @param pubKey The public key to check. + * @return True if the CRL is acceptable. + */ + private static boolean checkCRL(X509CRL crl, X509Certificate[] path, + Date now, X509Certificate pubKeyCert, + PublicKey pubKey, List certStores) + { + Date nextUpdate = crl.getNextUpdate(); + if (nextUpdate != null && nextUpdate.compareTo(now) < 0) + return false; + if (crl.hasUnsupportedCriticalExtension()) + return false; + for (int i = 0; i < path.length; i++) + { + if (! path[i].getSubjectDN().equals(crl.getIssuerDN())) + continue; + boolean[] keyUsage = path[i].getKeyUsage(); + if (keyUsage != null) + { + if (! keyUsage[KeyUsage.CRL_SIGN]) + continue; + } + try + { + crl.verify(path[i].getPublicKey()); + return true; + } + catch (Exception x) + { + } + } + if (crl.getIssuerDN().equals(pubKeyCert.getSubjectDN())) + { + try + { + boolean[] keyUsage = pubKeyCert.getKeyUsage(); + if (keyUsage != null) + { + if (! keyUsage[KeyUsage.CRL_SIGN]) + throw new Exception(); + } + crl.verify(pubKey); + return true; + } + catch (Exception x) + { + } + } + try + { + X509CertSelectorImpl select = new X509CertSelectorImpl(); + select.addSubjectName(crl.getIssuerDN()); + List certs = new LinkedList(); + for (Iterator it = certStores.iterator(); it.hasNext();) + { + CertStore cs = (CertStore) it.next(); + try + { + certs.addAll(cs.getCertificates(select)); + } + catch (CertStoreException cse) + { + } + } + for (Iterator it = certs.iterator(); it.hasNext();) + { + X509Certificate c = (X509Certificate) it.next(); + for (int i = 0; i < path.length; i++) + { + if (! c.getIssuerDN().equals(path[i].getSubjectDN())) + continue; + boolean[] keyUsage = c.getKeyUsage(); + if (keyUsage != null) + { + if (! keyUsage[KeyUsage.CRL_SIGN]) + continue; + } + try + { + c.verify(path[i].getPublicKey()); + crl.verify(c.getPublicKey()); + return true; + } + catch (Exception x) + { + } + } + if (c.getIssuerDN().equals(pubKeyCert.getSubjectDN())) + { + c.verify(pubKey); + crl.verify(c.getPublicKey()); + } + } + } + catch (Exception x) + { + } + return false; + } + + private static Set getCritExts(X509Certificate cert) + { + HashSet s = new HashSet(); + if (cert instanceof GnuPKIExtension) + { + Collection exts = ((GnuPKIExtension) cert).getExtensions(); + for (Iterator it = exts.iterator(); it.hasNext();) + { + Extension ext = (Extension) it.next(); + if (ext.isCritical() && ! ext.isSupported()) + s.add(ext.getOid().toString()); + } + } + else + s.addAll(cert.getCriticalExtensionOIDs()); + return s; + } + + /** + * Perform a basic sanity check on the CA certificate at index. + */ + private static void basicSanity(X509Certificate[] path, int index) + throws CertPathValidatorException + { + X509Certificate cert = path[index]; + int pathLen = 0; + for (int i = index - 1; i > 0; i--) + { + if (! path[i].getIssuerDN().equals(path[i].getSubjectDN())) + pathLen++; + } + Extension e = null; + if (cert instanceof GnuPKIExtension) + { + e = ((GnuPKIExtension) cert).getExtension(BasicConstraints.ID); + } + else + { + try + { + e = new Extension(cert.getExtensionValue(BasicConstraints.ID.toString())); + } + catch (Exception x) + { + } + } + if (e == null) + throw new CertPathValidatorException("no basicConstraints"); + BasicConstraints bc = (BasicConstraints) e.getValue(); + if (! bc.isCA()) + throw new CertPathValidatorException( + "certificate cannot be used to verify signatures"); + if (bc.getPathLengthConstraint() >= 0 + && bc.getPathLengthConstraint() < pathLen) + throw new CertPathValidatorException("path is too long"); + + boolean[] keyUsage = cert.getKeyUsage(); + if (keyUsage != null) + { + if (! keyUsage[KeyUsage.KEY_CERT_SIGN]) + throw new CertPathValidatorException( + "certificate cannot be used to sign certificates"); + } + } + + private static void updatePolicyTree(X509Certificate cert, + PolicyNodeImpl root, int depth, + PKIXParameters params, + boolean explicitPolicy) + throws CertPathValidatorException + { + if (Configuration.DEBUG) + log.fine("updatePolicyTree depth == " + depth); + Set nodes = new HashSet(); + LinkedList stack = new LinkedList(); + Iterator current = null; + stack.addLast(Collections.singleton(root).iterator()); + do + { + current = (Iterator) stack.removeLast(); + while (current.hasNext()) + { + PolicyNodeImpl p = (PolicyNodeImpl) current.next(); + if (Configuration.DEBUG) + log.fine("visiting node == " + p); + if (p.getDepth() == depth - 1) + { + if (Configuration.DEBUG) + log.fine("added node"); + nodes.add(p); + } + else + { + if (Configuration.DEBUG) + log.fine("skipped node"); + stack.addLast(current); + current = p.getChildren(); + } + } + } + while (! stack.isEmpty()); + + Extension e = null; + CertificatePolicies policies = null; + List qualifierInfos = null; + if (cert instanceof GnuPKIExtension) + { + e = ((GnuPKIExtension) cert).getExtension(CertificatePolicies.ID); + if (e != null) + policies = (CertificatePolicies) e.getValue(); + } + + List cp = null; + if (policies != null) + cp = policies.getPolicies(); + else + cp = Collections.EMPTY_LIST; + boolean match = false; + if (Configuration.DEBUG) + { + log.fine("nodes are == " + nodes); + log.fine("cert policies are == " + cp); + } + for (Iterator it = nodes.iterator(); it.hasNext();) + { + PolicyNodeImpl parent = (PolicyNodeImpl) it.next(); + if (Configuration.DEBUG) + log.fine("adding policies to " + parent); + for (Iterator it2 = cp.iterator(); it2.hasNext();) + { + OID policy = (OID) it2.next(); + if (Configuration.DEBUG) + log.fine("trying to add policy == " + policy); + if (policy.toString().equals(ANY_POLICY) + && params.isAnyPolicyInhibited()) + continue; + PolicyNodeImpl child = new PolicyNodeImpl(); + child.setValidPolicy(policy.toString()); + child.addExpectedPolicy(policy.toString()); + if (parent.getExpectedPolicies().contains(policy.toString())) + { + parent.addChild(child); + match = true; + } + else if (parent.getExpectedPolicies().contains(ANY_POLICY)) + { + parent.addChild(child); + match = true; + } + else if (ANY_POLICY.equals(policy.toString())) + { + parent.addChild(child); + match = true; + } + if (match && policies != null) + { + List qualifiers = policies.getPolicyQualifierInfos(policy); + if (qualifiers != null) + child.addAllPolicyQualifiers(qualifiers); + } + } + } + if (! match && (params.isExplicitPolicyRequired() || explicitPolicy)) + throw new CertPathValidatorException("policy tree building failed"); + } + + private boolean checkExplicitPolicy(int depth, List explicitPolicies) + { + if (Configuration.DEBUG) + log.fine("checkExplicitPolicy depth=" + depth); + for (Iterator it = explicitPolicies.iterator(); it.hasNext();) + { + int[] i = (int[]) it.next(); + int caDepth = i[0]; + int limit = i[1]; + if (Configuration.DEBUG) + log.fine(" caDepth=" + caDepth + " limit=" + limit); + if (depth - caDepth >= limit) + return true; + } + return false; + } +} diff --git a/libjava/classpath/gnu/java/security/provider/X509CertificateFactory.java b/libjava/classpath/gnu/java/security/provider/X509CertificateFactory.java new file mode 100644 index 000000000..644033156 --- /dev/null +++ b/libjava/classpath/gnu/java/security/provider/X509CertificateFactory.java @@ -0,0 +1,295 @@ +/* X509CertificateFactory.java -- generates X.509 certificates. + Copyright (C) 2003 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.provider; + +import gnu.java.io.Base64InputStream; +import gnu.java.lang.CPStringBuilder; +import gnu.java.security.x509.X509CRL; +import gnu.java.security.x509.X509CertPath; +import gnu.java.security.x509.X509Certificate; + +import java.io.BufferedInputStream; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.security.cert.CRL; +import java.security.cert.CRLException; +import java.security.cert.CertPath; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactorySpi; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +public class X509CertificateFactory + extends CertificateFactorySpi +{ + public static final String BEGIN_CERTIFICATE = "-----BEGIN CERTIFICATE-----"; + + public static final String END_CERTIFICATE = "-----END CERTIFICATE-----"; + + public static final String BEGIN_X509_CRL = "-----BEGIN X509 CRL-----"; + + public static final String END_X509_CRL = "-----END X509 CRL-----"; + + public X509CertificateFactory() + { + super(); + } + + public Certificate engineGenerateCertificate(InputStream inStream) + throws CertificateException + { + try + { + return generateCert(inStream); + } + catch (IOException ioe) + { + CertificateException ce = new CertificateException(ioe.getMessage()); + ce.initCause(ioe); + throw ce; + } + } + + public Collection engineGenerateCertificates(InputStream inStream) + throws CertificateException + { + LinkedList certs = new LinkedList(); + while (true) + { + try + { + certs.add(generateCert(inStream)); + } + catch (EOFException eof) + { + break; + } + catch (IOException ioe) + { + CertificateException ce = new CertificateException(ioe.getMessage()); + ce.initCause(ioe); + throw ce; + } + } + return certs; + } + + public CRL engineGenerateCRL(InputStream inStream) throws CRLException + { + try + { + return generateCRL(inStream); + } + catch (IOException ioe) + { + CRLException crle = new CRLException(ioe.getMessage()); + crle.initCause(ioe); + throw crle; + } + } + + public Collection engineGenerateCRLs(InputStream inStream) + throws CRLException + { + LinkedList crls = new LinkedList(); + while (true) + { + try + { + crls.add(generateCRL(inStream)); + } + catch (EOFException eof) + { + break; + } + catch (IOException ioe) + { + CRLException crle = new CRLException(ioe.getMessage()); + crle.initCause(ioe); + throw crle; + } + } + return crls; + } + + public CertPath engineGenerateCertPath(List certs) + { + return new X509CertPath(certs); + } + + public CertPath engineGenerateCertPath(InputStream in) + throws CertificateEncodingException + { + return new X509CertPath(in); + } + + public CertPath engineGenerateCertPath(InputStream in, String encoding) + throws CertificateEncodingException + { + return new X509CertPath(in, encoding); + } + + public Iterator engineGetCertPathEncodings() + { + return X509CertPath.ENCODINGS.iterator(); + } + + private X509Certificate generateCert(InputStream inStream) + throws IOException, CertificateException + { + if (inStream == null) + throw new CertificateException("missing input stream"); + if (! inStream.markSupported()) + inStream = new BufferedInputStream(inStream, 8192); + inStream.mark(20); + int i = inStream.read(); + if (i == -1) + throw new EOFException(); + // If the input is in binary DER format, the first byte MUST be + // 0x30, which stands for the ASN.1 [UNIVERSAL 16], which is the + // UNIVERSAL SEQUENCE, with the CONSTRUCTED bit (0x20) set. + // + // So if we do not see 0x30 here we will assume it is in Base-64. + if (i != 0x30) + { + inStream.reset(); + CPStringBuilder line = new CPStringBuilder(80); + do + { + line.setLength(0); + do + { + i = inStream.read(); + if (i == -1) + throw new EOFException(); + if (i != '\n' && i != '\r') + line.append((char) i); + } + while (i != '\n' && i != '\r'); + } + while (! line.toString().equals(BEGIN_CERTIFICATE)); + X509Certificate ret = new X509Certificate( + new BufferedInputStream(new Base64InputStream(inStream), 8192)); + line.setLength(0); + line.append('-'); // Base64InputStream will eat this. + do + { + i = inStream.read(); + if (i == -1) + throw new EOFException(); + if (i != '\n' && i != '\r') + line.append((char) i); + } + while (i != '\n' && i != '\r'); + // XXX ??? + if (! line.toString().equals(END_CERTIFICATE)) + throw new CertificateException("no end-of-certificate marker"); + return ret; + } + else + { + inStream.reset(); + return new X509Certificate(inStream); + } + } + + private X509CRL generateCRL(InputStream inStream) throws IOException, + CRLException + { + if (inStream == null) + throw new CRLException("missing input stream"); + if (! inStream.markSupported()) + inStream = new BufferedInputStream(inStream, 8192); + inStream.mark(20); + int i = inStream.read(); + if (i == -1) + throw new EOFException(); + // If the input is in binary DER format, the first byte MUST be + // 0x30, which stands for the ASN.1 [UNIVERSAL 16], which is the + // UNIVERSAL SEQUENCE, with the CONSTRUCTED bit (0x20) set. + // + // So if we do not see 0x30 here we will assume it is in Base-64. + if (i != 0x30) + { + inStream.reset(); + CPStringBuilder line = new CPStringBuilder(80); + do + { + line.setLength(0); + do + { + i = inStream.read(); + if (i == -1) + throw new EOFException(); + if (i != '\n' && i != '\r') + line.append((char) i); + } + while (i != '\n' && i != '\r'); + } + while (! line.toString().startsWith(BEGIN_X509_CRL)); + X509CRL ret = new X509CRL( + new BufferedInputStream(new Base64InputStream(inStream), 8192)); + line.setLength(0); + line.append('-'); // Base64InputStream will eat this. + do + { + i = inStream.read(); + if (i == -1) + throw new EOFException(); + if (i != '\n' && i != '\r') + line.append((char) i); + } + while (i != '\n' && i != '\r'); + // XXX ??? + if (! line.toString().startsWith(END_X509_CRL)) + throw new CRLException("no end-of-CRL marker"); + return ret; + } + else + { + inStream.reset(); + return new X509CRL(inStream); + } + } +} diff --git a/libjava/classpath/gnu/java/security/provider/package.html b/libjava/classpath/gnu/java/security/provider/package.html new file mode 100644 index 000000000..641a22aff --- /dev/null +++ b/libjava/classpath/gnu/java/security/provider/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.security.provider + + +

+ + + diff --git a/libjava/classpath/gnu/java/security/sig/BaseSignature.java b/libjava/classpath/gnu/java/security/sig/BaseSignature.java new file mode 100644 index 000000000..ef4d87f26 --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/BaseSignature.java @@ -0,0 +1,219 @@ +/* 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 +{ + /** 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; + + /** + * 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; + } + + 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); + } + + 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; + + /** 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(): " + x); + } + catch (LimitReachedException x) + { + throw new RuntimeException("nextRandomBytes(): " + 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/libjava/classpath/gnu/java/security/sig/ISignature.java b/libjava/classpath/gnu/java/security/sig/ISignature.java new file mode 100644 index 000000000..be98f9a9b --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/ISignature.java @@ -0,0 +1,160 @@ +/* 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. + *
+ */ +public interface ISignature + extends Cloneable +{ + /** 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.java.security.prng.IRandom} + * instance to use. The default is to use a classloader singleton from + * {@link gnu.java.security.util.PRNG}. + */ + public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.sig.prng"; + + /** + * 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/libjava/classpath/gnu/java/security/sig/ISignatureCodec.java b/libjava/classpath/gnu/java/security/sig/ISignatureCodec.java new file mode 100644 index 000000000..f8b147361 --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/ISignatureCodec.java @@ -0,0 +1,59 @@ +/* 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. + */ +public interface ISignatureCodec +{ + /** Constant identifying the Raw encoding format. */ + int RAW_FORMAT = Registry.RAW_ENCODING_ID; + + int getFormatID(); + + byte[] encodeSignature(Object signature); + + Object decodeSignature(byte[] input); +} diff --git a/libjava/classpath/gnu/java/security/sig/SignatureCodecFactory.java b/libjava/classpath/gnu/java/security/sig/SignatureCodecFactory.java new file mode 100644 index 000000000..0026ad164 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/java/security/sig/SignatureFactory.java b/libjava/classpath/gnu/java/security/sig/SignatureFactory.java new file mode 100644 index 000000000..6cdaf6544 --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/SignatureFactory.java @@ -0,0 +1,101 @@ +/* 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; + + /** Trivial constructor to enforce Singleton pattern. */ + private SignatureFactory() + { + super(); + } + + /** + * 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/libjava/classpath/gnu/java/security/sig/dss/DSSSignature.java b/libjava/classpath/gnu/java/security/sig/dss/DSSSignature.java new file mode 100644 index 000000000..024521ba4 --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/dss/DSSSignature.java @@ -0,0 +1,275 @@ +/* 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. + *
+ */ +public class DSSSignature + extends BaseSignature +{ + /** 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(); + } + + 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); + } + + 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 + { + final BigInteger[] rs = computeRS(md.digest()); + return encodeSignature(rs[0], rs[1]); + } + + protected boolean verifySignature(Object sig) throws IllegalStateException + { + final BigInteger[] rs = decodeSignature(sig); + return checkRS(rs, md.digest()); + } + + /** + * 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/libjava/classpath/gnu/java/security/sig/dss/DSSSignatureRawCodec.java b/libjava/classpath/gnu/java/security/sig/dss/DSSSignatureRawCodec.java new file mode 100644 index 000000000..169f84bd1 --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/dss/DSSSignatureRawCodec.java @@ -0,0 +1,164 @@ +/* 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. + */ +public class DSSSignatureRawCodec + implements ISignatureCodec +{ + 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 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("signature"); + } + 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/libjava/classpath/gnu/java/security/sig/dss/DSSSignatureX509Codec.java b/libjava/classpath/gnu/java/security/sig/dss/DSSSignatureX509Codec.java new file mode 100644 index 000000000..d0a0188fb --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/dss/DSSSignatureX509Codec.java @@ -0,0 +1,193 @@ +/* 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.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 raw bytes which would constitute a 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 raw bytes of such a BIT STRING; i.e. not the DER-encoded + * form itself. + *

+ * 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
+ *   }
+ * 
+ *

+ * Client code that needs to build a DER BIT STRING MUST construct such + * an ASN.1 value. The following is an example of how to do this: + *

+ *

+ * ...
+ * import gnu.java.security.der.BitString;
+ * import gnu.java.security.der.DER;
+ * import gnu.java.security.der.DERValue;
+ * ...
+ * DERValue bitString = new DERValue(DER.BIT_STRING, new BitString(sigBytes));
+ * ...
+ * 
+ */ +public class DSSSignatureX509Codec + implements ISignatureCodec +{ + // implicit 0-arguments constructor + + public int getFormatID() + { + return Registry.X509_ENCODING_ID; + } + + /** + * Encodes a DSS Signature output as the signature raw bytes which can + * be used to construct an ASN.1 DER-encoded 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 raw bytes of a DSS signature which could be then used as the + * contents of a BIT STRING as per 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(); + } + catch (IOException x) + { + InvalidParameterException y = new InvalidParameterException(); + y.initCause(x); + throw y; + } + + return result; + } + + /** + * Decodes a signature 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 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/libjava/classpath/gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java b/libjava/classpath/gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java new file mode 100644 index 000000000..329ca8ed6 --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java @@ -0,0 +1,274 @@ +/* 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 +{ + private int k; + + private ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + /** Our default source of randomness. */ + private PRNG prng = PRNG.getInstance(); + + private EME_PKCS1_V1_5(final int k) + { + super(); + + this.k = k; + } + + 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); + } + + /** + * 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; + } + + 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/libjava/classpath/gnu/java/security/sig/rsa/EMSA_PKCS1_V1_5.java b/libjava/classpath/gnu/java/security/sig/rsa/EMSA_PKCS1_V1_5.java new file mode 100644 index 000000000..3cddab4aa --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/rsa/EMSA_PKCS1_V1_5.java @@ -0,0 +1,243 @@ +/* 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. + *
+ */ +public class EMSA_PKCS1_V1_5 + implements Cloneable +{ + /* 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; + + /** + * 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 + } + + /** + * 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); + } + + public Object clone() + { + return getInstance(hash.name()); + } + + /** + * 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/libjava/classpath/gnu/java/security/sig/rsa/EMSA_PSS.java b/libjava/classpath/gnu/java/security/sig/rsa/EMSA_PSS.java new file mode 100644 index 000000000..917d96323 --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/rsa/EMSA_PSS.java @@ -0,0 +1,371 @@ +/* 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.Configuration; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.util.Util; + +import java.util.Arrays; +import java.util.logging.Logger; + +/** + * 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. + *
+ */ +public class EMSA_PSS + implements Cloneable +{ + private static final Logger log = Logger.getLogger(EMSA_PSS.class.getName()); + + /** The underlying hash function to use with this instance. */ + private IMessageDigest hash; + + /** The output size of the hash function in octets. */ + private int hLen; + + /** + * 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(); + } + + /** + * 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); + } + + public Object clone() + { + return getInstance(hash.name()); + } + + /** + * 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 (Configuration.DEBUG) + { + log.fine("dbMask (encode): " + Util.toString(dbMask)); + log.fine("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 (Configuration.DEBUG) + { + log.fine("mHash: " + Util.toString(mHash)); + log.fine("EM: " + Util.toString(EM)); + log.fine("emBits: " + String.valueOf(emBits)); + log.fine("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 (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + { + log.fine("dbMask (decode): " + Util.toString(dbMask)); + log.fine("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 (Configuration.DEBUG) + log.fine("DB[" + String.valueOf(i) + "] != 0x00"); + return false; + } + } + if (DB[i] != 0x01) + { // i == emLen -hLen -sLen -2 + if (Configuration.DEBUG) + log.fine("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); + } + + /** + * 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/libjava/classpath/gnu/java/security/sig/rsa/RSA.java b/libjava/classpath/gnu/java/security/sig/rsa/RSA.java new file mode 100644 index 000000000..343b2cf65 --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/rsa/RSA.java @@ -0,0 +1,324 @@ +/* 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 +{ + 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(); + + /** Trivial private constructor to enforce Singleton pattern. */ + private RSA() + { + super(); + } + + /** + * 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"); + } + } + + /** + * 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"); + } + } + + /** + * 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; + } + + 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/libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5Signature.java b/libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5Signature.java new file mode 100644 index 000000000..1420331de --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5Signature.java @@ -0,0 +1,224 @@ +/* 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. + *
+ */ +public class RSAPKCS1V1_5Signature + extends BaseSignature +{ + /** The underlying EMSA-PKCS1-v1.5 instance for this object. */ + private EMSA_PKCS1_V1_5 pkcs1; + + /** + * 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(); + } + + 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/libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureRawCodec.java b/libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureRawCodec.java new file mode 100644 index 000000000..548dc3deb --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureX509Codec.java b/libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureX509Codec.java new file mode 100644 index 000000000..ee8586f7d --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureX509Codec.java @@ -0,0 +1,128 @@ +/* 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.sig.ISignatureCodec; + +import java.security.InvalidParameterException; + +/** + * An implementation of an {@link ISignatureCodec} that knows to encode and + * decode RSA PKCS1 (v1.5) signatures into the raw bytes which would constitute + * a 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 raw bytes of such a BIT STRING; i.e. not the DER-encoded + * form itself. + *

+ * 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 pass through + * such a byte array. + *

+ * Client code that needs to build a DER BIT STRING MUST construct such + * an ASN.1 value. The following is an example of how to do this: + *

+ *

+ * ...
+ * import gnu.java.security.der.BitString;
+ * import gnu.java.security.der.DER;
+ * import gnu.java.security.der.DERValue;
+ * ...
+ * DERValue bitString = new DERValue(DER.BIT_STRING, new BitString(sigBytes));
+ * ...
+ * 
+ */ +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 raw bytes of an RSA signature which could be then used as the + * contents of a BIT STRING as per rfc-2459. + */ + public byte[] encodeSignature(Object signature) + { + byte[] result = (byte[]) signature; + return result; + } + + /** + * Decodes a signature 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. a byte array. MUST NOT be null. + * @return an array of raw bytes decoded from the designated input. In the + * case of RSA PKCS1 (v1.5) this is the same as the input. + * @throw InvalidParameterException if the input array is null. + */ + public Object decodeSignature(byte[] input) + { + if (input == null) + throw new InvalidParameterException("Input bytes MUST NOT be null"); + + return input; + } +} diff --git a/libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignature.java b/libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignature.java new file mode 100644 index 000000000..d8f8327f1 --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignature.java @@ -0,0 +1,255 @@ +/* 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.Configuration; +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.math.BigInteger; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.util.logging.Logger; + +/** + * 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. + *
+ */ +public class RSAPSSSignature + extends BaseSignature +{ + private static final Logger log = Logger.getLogger(RSAPSSSignature.class.getName()); + + /** 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; + + /** + * 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(); + } + + 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 (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("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; + } +} diff --git a/libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignatureRawCodec.java b/libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignatureRawCodec.java new file mode 100644 index 000000000..b147ea3ea --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignatureRawCodec.java @@ -0,0 +1,134 @@ +/* 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 ISignatureCodec} operations for the + * Raw format to use with RSA-PSS signatures. + */ +public class RSAPSSSignatureRawCodec + implements ISignatureCodec +{ + // implicit 0-arguments constructor + + 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("signature"); + } + 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/libjava/classpath/gnu/java/security/sig/rsa/RSASignatureFactory.java b/libjava/classpath/gnu/java/security/sig/rsa/RSASignatureFactory.java new file mode 100644 index 000000000..ba5121b46 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/java/security/util/ByteArray.java b/libjava/classpath/gnu/java/security/util/ByteArray.java new file mode 100644 index 000000000..a9b9e5d00 --- /dev/null +++ b/libjava/classpath/gnu/java/security/util/ByteArray.java @@ -0,0 +1,111 @@ +/* ByteArray.java -- wrapper around a byte array, with nice toString output. + 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.java.security.util; + +import gnu.java.lang.CPStringBuilder; + +import java.io.PrintWriter; +import java.io.StringWriter; + +public final class ByteArray +{ + private final byte[] value; + + public ByteArray (final byte[] value) + { + this.value = value; + } + + public byte[] getValue () + { + return value; + } + + public String toString () + { + StringWriter str = new StringWriter (); + PrintWriter out = new PrintWriter (str); + int i = 0; + int len = value.length; + while (i < len) + { + out.print (formatInt (i, 16, 8)); + out.print (" "); + int l = Math.min (16, len - i); + String s = toHexString (value, i, l, ' '); + out.print (s); + for (int j = 56 - (56 - s.length ()); j < 56; j++) + out.print (" "); + for (int j = 0; j < l; j++) + { + byte b = value[i+j]; + if ((b & 0xFF) < 0x20 || (b & 0xFF) > 0x7E) + out.print ("."); + else + out.print ((char) (b & 0xFF)); + } + out.println (); + i += 16; + } + return str.toString (); + } + + public static String toHexString (byte[] buf, int off, int len, char sep) + { + CPStringBuilder str = new CPStringBuilder(); + for (int i = 0; i < len; i++) + { + str.append (Character.forDigit (buf[i+off] >>> 4 & 0x0F, 16)); + str.append (Character.forDigit (buf[i+off] & 0x0F, 16)); + if (i < len - 1) + str.append(sep); + } + return str.toString(); + } + + public static String formatInt (int value, int radix, int len) + { + String s = Integer.toString (value, radix); + CPStringBuilder buf = new CPStringBuilder (); + for (int j = 0; j < len - s.length(); j++) + buf.append ("0"); + buf.append (s); + return buf.toString(); + } +} diff --git a/libjava/classpath/gnu/java/security/util/ByteBufferOutputStream.java b/libjava/classpath/gnu/java/security/util/ByteBufferOutputStream.java new file mode 100644 index 000000000..642ccdf68 --- /dev/null +++ b/libjava/classpath/gnu/java/security/util/ByteBufferOutputStream.java @@ -0,0 +1,118 @@ +/* ByteBufferOutputStream.java -- output stream with a growable underlying + byte buffer. + 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.java.security.util; + +import java.io.IOException; +import java.io.OutputStream; + +import java.nio.ByteBuffer; + +/** + * An output stream that writes bytes to a ByteBuffer, which will be resized + * if more space is needed. + * + * @author Casey Marshall (csm@gnu.org) + */ +public class ByteBufferOutputStream extends OutputStream +{ + private ByteBuffer buffer; + + public ByteBufferOutputStream() + { + this(256); + } + + public ByteBufferOutputStream(int initialCapacity) + { + buffer = ByteBuffer.allocate(initialCapacity); + } + + /* (non-Javadoc) + * @see java.io.OutputStream#write(int) + */ + public @Override synchronized void write(int b) throws IOException + { + if (!buffer.hasRemaining()) + growBuffer(); + buffer.put((byte) b); + } + + public @Override synchronized void write(byte[] b, int offset, int length) + { + if (buffer.remaining() < length) + growBuffer(); + buffer.put(b, offset, length); + } + + public @Override void write(byte[] b) + { + write(b, 0, b.length); + } + + /** + * Get the current state of the buffer. The returned buffer will have + * its position set to zero, its capacity set to the current limit, + * and its limit set to its capacity. + * + * @return The buffer. + */ + public ByteBuffer buffer() + { + return ((ByteBuffer) buffer.duplicate().flip()).slice(); + } + + public String toString() + { + return super.toString() + " [ buffer: " + buffer + " ]"; + } + + private void growBuffer() + { + int newCapacity = buffer.capacity(); + if (newCapacity < 16384) // If the buffer isn't huge yet, double its size + newCapacity = newCapacity << 1; + else // Otherwize, increment by a bit. + newCapacity += 4096; + ByteBuffer newBuffer = ByteBuffer.allocate(newCapacity); + buffer.flip(); + newBuffer.put(buffer); + buffer = newBuffer; + } +} diff --git a/libjava/classpath/gnu/java/security/util/DerUtil.java b/libjava/classpath/gnu/java/security/util/DerUtil.java new file mode 100644 index 000000000..26232ba98 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/java/security/util/ExpirableObject.java b/libjava/classpath/gnu/java/security/util/ExpirableObject.java new file mode 100644 index 000000000..e24af249a --- /dev/null +++ b/libjava/classpath/gnu/java/security/util/ExpirableObject.java @@ -0,0 +1,150 @@ +/* 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 +{ + /** + * 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; + + /** + * 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); + } + + /** + * 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; + + /** + * The task that destroys the target when the timeout elapses. + */ + private final class Destroyer + extends TimerTask + { + private final ExpirableObject target; + + Destroyer(final ExpirableObject target) + { + super(); + this.target = target; + } + + public void run() + { + try + { + if (! target.isDestroyed()) + target.doDestroy(); + } + catch (DestroyFailedException dfe) + { + } + } + } +} diff --git a/libjava/classpath/gnu/java/security/util/FormatUtil.java b/libjava/classpath/gnu/java/security/util/FormatUtil.java new file mode 100644 index 000000000..35da322b8 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/java/security/util/IntegerUtil.java b/libjava/classpath/gnu/java/security/util/IntegerUtil.java new file mode 100644 index 000000000..106dc4d66 --- /dev/null +++ b/libjava/classpath/gnu/java/security/util/IntegerUtil.java @@ -0,0 +1,109 @@ +/* IntegerUtil.java -- JDK 5 Integer methods with 1.4 API + 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.LinkedHashMap; +import java.util.Map; + +/** + * Utility class which offers Integer related methods found in RI's version 5 + * but written with RI's 1.4 API. + */ +public abstract class IntegerUtil +{ + /** Maximum size of our cache of constructed Integers. */ + private static final int CACHE_SIZE = 100; + /** LRU (Least Recently Used) cache, of the last accessed 100 Integers. */ + private static final Map cache = new LinkedHashMap(CACHE_SIZE + 1, 0.75F, true) + { + public boolean removeEldestEntry(Map.Entry entry) + { + return size() > CACHE_SIZE; + } + }; + + /** Trivial private constructor to enforce Singleton usage. */ + private IntegerUtil() + { + super(); + } + + /** + * Similar to {@link Integer#valueOf(String)} except it caches the result in + * a local LRU cache of 100 elements, organized by access order. + *

+ * This method MUST be used in the gnu.java.security and gnu.javax.crypto + * packages to ensure they would work with a version 1.4 only of the Java + * class library API. + * + * @param aString a string representation of an integer. + * @return the {@link Integer} object representing the designated string. + */ + public static final Integer valueOf(String aString) + { + Integer result; + synchronized (cache) + { + result = (Integer) cache.get(aString); + if (result == null) + { + result = Integer.valueOf(aString); + cache.put(aString, result); + } + } + return result; + } + + /** + * Simulates the valueOf(int) method found in {@link Integer} of + * the RI's version 1.5 using a local LRU cache of 100 elements, organized by + * access order. + *

+ * This method MUST be used in the gnu.java.security and gnu.javax.crypto + * packages to ensure they would work with a version 1.4 only of the Java + * class library API. + * + * @param anInt a decimal integer. + * @return the {@link Integer} object representing the designated primitive. + */ + public static final Integer valueOf(int anInt) + { + return valueOf(Integer.toString(anInt, 10)); + } +} diff --git a/libjava/classpath/gnu/java/security/util/PRNG.java b/libjava/classpath/gnu/java/security/util/PRNG.java new file mode 100644 index 000000000..1bed04dcd --- /dev/null +++ b/libjava/classpath/gnu/java/security/util/PRNG.java @@ -0,0 +1,141 @@ +/* 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 +{ + /** The underlying {@link IRandom}. */ + private IRandom delegate; + + /** + * Private constructor to enforce using the Factory method. + * + * @param delegate the undelying {@link IRandom} object used. + */ + private PRNG(IRandom delegate) + { + super(); + + this.delegate = delegate; + } + + 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); + } + + /** + * 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/libjava/classpath/gnu/java/security/util/Prime.java b/libjava/classpath/gnu/java/security/util/Prime.java new file mode 100644 index 000000000..82c584ff4 --- /dev/null +++ b/libjava/classpath/gnu/java/security/util/Prime.java @@ -0,0 +1,164 @@ +/* Prime.java --- Prime number generation utilities + Copyright (C) 1999, 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.security.util; +import java.math.BigInteger; +import java.util.Random; +//import java.security.SecureRandom; + +public final class Prime +{ + + /* + See IEEE P1363 A.15.4 (10/05/98 Draft) + */ + public static BigInteger generateRandomPrime( int pmin, int pmax, BigInteger f ) + { + BigInteger d; + + //Step 1 - generate prime + BigInteger p = new BigInteger( (pmax + pmin)/2, new Random() ); + if( p.compareTo( BigInteger.valueOf( 1 ).shiftLeft( pmin ) ) <= 0 ) + { + p = p.add( BigInteger.valueOf( 1 ).shiftLeft( pmin ).subtract( p ) ); + } + + //Step 2 - test for even + if( p.mod( BigInteger.valueOf(2) ).compareTo( BigInteger.valueOf( 0 )) == 0) + p = p.add( BigInteger.valueOf( 1 ) ); + + for(;;) + { + //Step 3 + if( p.compareTo( BigInteger.valueOf( 1 ).shiftLeft( pmax)) > 0) + { + //Step 3.1 + p = p.subtract( BigInteger.valueOf( 1 ).shiftLeft( pmax) ); + p = p.add( BigInteger.valueOf( 1 ).shiftLeft( pmin) ); + p = p.subtract( BigInteger.valueOf( 1 ) ); + + //Step 3.2 + // put step 2 code here so looping code is cleaner + //Step 2 - test for even + if( p.mod( BigInteger.valueOf(2) ).compareTo( BigInteger.valueOf( 0 )) == 0) + p = p.add( BigInteger.valueOf( 1 ) ); + continue; + } + + //Step 4 - compute GCD + d = p.subtract( BigInteger.valueOf(1) ); + d = d.gcd( f ); + + //Step 5 - test d + if( d.compareTo( BigInteger.valueOf( 1 ) ) == 0) + { + //Step 5.1 - test primality + if( p.isProbablePrime( 1 ) == true ) + { + //Step 5.2; + return p; + } + } + //Step 6 + p = p.add( BigInteger.valueOf( 2 ) ); + + //Step 7 + } + } + + + /* + See IEEE P1363 A.15.5 (10/05/98 Draft) + */ + public static BigInteger generateRandomPrime( BigInteger r, BigInteger a, int pmin, int pmax, BigInteger f ) + { + BigInteger d, w; + + //Step 1 - generate prime + BigInteger p = new BigInteger( (pmax + pmin)/2, new Random() ); + + steptwo:{ //Step 2 + w = p.mod( r.multiply( BigInteger.valueOf(2) )); + + //Step 3 + p = p.add( r.multiply( BigInteger.valueOf(2) ) ); + p = p.subtract( w ); + p = p.add(a); + + //Step 4 - test for even + if( p.mod( BigInteger.valueOf(2) ).compareTo( BigInteger.valueOf( 0 )) == 0) + p = p.add( r ); + + for(;;) + { + //Step 5 + if( p.compareTo( BigInteger.valueOf( 1 ).shiftLeft( pmax)) > 0) + { + //Step 5.1 + p = p.subtract( BigInteger.valueOf( 1 ).shiftLeft( pmax) ); + p = p.add( BigInteger.valueOf( 1 ).shiftLeft( pmin) ); + p = p.subtract( BigInteger.valueOf( 1 ) ); + + //Step 5.2 - goto to Step 2 + break steptwo; + } + + //Step 6 + d = p.subtract( BigInteger.valueOf(1) ); + d = d.gcd( f ); + + //Step 7 - test d + if( d.compareTo( BigInteger.valueOf( 1 ) ) == 0) + { + //Step 7.1 - test primality + if( p.isProbablePrime( 1 ) == true ) + { + //Step 7.2; + return p; + } + } + //Step 8 + p = p.add( r.multiply( BigInteger.valueOf(2) ) ); + + //Step 9 + } + } + //Should never reach here but makes the compiler happy + return BigInteger.valueOf(0); + } +} diff --git a/libjava/classpath/gnu/java/security/util/Sequence.java b/libjava/classpath/gnu/java/security/util/Sequence.java new file mode 100644 index 000000000..63086d2bd --- /dev/null +++ b/libjava/classpath/gnu/java/security/util/Sequence.java @@ -0,0 +1,133 @@ +/* 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 +{ + private final Integer[] sequence; + + /** + * 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[] { Integer.valueOf(start), + Integer.valueOf(end) }; + else + sequence = new Integer[] { Integer.valueOf(start) }; + } + else + { + LinkedList l = new LinkedList(); + for (int i = start; i != end; i += span) + l.add(Integer.valueOf(i)); + + l.add(Integer.valueOf(end)); + sequence = (Integer[]) l.toArray(new Integer[l.size()]); + } + } + + 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/libjava/classpath/gnu/java/security/util/SimpleList.java b/libjava/classpath/gnu/java/security/util/SimpleList.java new file mode 100644 index 000000000..15d54c988 --- /dev/null +++ b/libjava/classpath/gnu/java/security/util/SimpleList.java @@ -0,0 +1,155 @@ +/* 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 +{ + private final Object[] elements; + + /** + * Create a singleton list. + * + * @param element 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(); + } + + 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/libjava/classpath/gnu/java/security/util/Util.java b/libjava/classpath/gnu/java/security/util/Util.java new file mode 100644 index 000000000..ef3d480a0 --- /dev/null +++ b/libjava/classpath/gnu/java/security/util/Util.java @@ -0,0 +1,629 @@ +/* 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 gnu.java.lang.CPStringBuilder; + +import java.math.BigInteger; + +/** + * A collection of utility methods used throughout this project. + */ +public class Util +{ + // 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(); + + /** Trivial constructor to enforce Singleton pattern. */ + private Util() + { + super(); + } + + /** + * 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) + { + CPStringBuilder sb = new CPStringBuilder(); + 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) + { + CPStringBuilder sb = new CPStringBuilder(); + 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"; + CPStringBuilder sb = new CPStringBuilder(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; + } + CPStringBuilder sb = new CPStringBuilder(); + 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/libjava/classpath/gnu/java/security/util/package.html b/libjava/classpath/gnu/java/security/util/package.html new file mode 100644 index 000000000..36dd33b79 --- /dev/null +++ b/libjava/classpath/gnu/java/security/util/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.security.util + + +

+ + + diff --git a/libjava/classpath/gnu/java/security/x509/GnuPKIExtension.java b/libjava/classpath/gnu/java/security/x509/GnuPKIExtension.java new file mode 100644 index 000000000..8e74b8b24 --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/GnuPKIExtension.java @@ -0,0 +1,59 @@ +/* GnuPKIExtension.java -- interface for GNU PKI extensions. + 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.security.x509; + +import gnu.java.security.OID; +import gnu.java.security.x509.ext.Extension; + +import java.security.cert.X509Extension; +import java.util.Collection; + +public interface GnuPKIExtension extends X509Extension +{ + + /** + * Returns the extension object for the given object identifier. + * + * @param oid The OID of the extension to get. + * @return The extension, or null if there is no such extension. + */ + Extension getExtension(OID oid); + + Collection getExtensions(); +} diff --git a/libjava/classpath/gnu/java/security/x509/PolicyNodeImpl.java b/libjava/classpath/gnu/java/security/x509/PolicyNodeImpl.java new file mode 100644 index 000000000..60d35574d --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/PolicyNodeImpl.java @@ -0,0 +1,216 @@ +/* PolicyNodeImpl.java -- An implementation of a policy tree node. + 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.security.x509; + +import gnu.java.lang.CPStringBuilder; + +import java.security.cert.PolicyNode; +import java.security.cert.PolicyQualifierInfo; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +public final class PolicyNodeImpl implements PolicyNode +{ + + // Fields. + // ------------------------------------------------------------------------- + + private String policy; + private final Set expectedPolicies; + private final Set qualifiers; + private final Set children; + private PolicyNodeImpl parent; + private int depth; + private boolean critical; + private boolean readOnly; + + // Constructors. + // ------------------------------------------------------------------------- + + public PolicyNodeImpl() + { + expectedPolicies = new HashSet(); + qualifiers = new HashSet(); + children = new HashSet(); + readOnly = false; + critical = false; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void addChild(PolicyNodeImpl node) + { + if (readOnly) + throw new IllegalStateException("read only"); + if (node.getParent() != null) + throw new IllegalStateException("already a child node"); + node.parent = this; + node.setDepth(depth + 1); + children.add(node); + } + + public Iterator getChildren() + { + return Collections.unmodifiableSet(children).iterator(); + } + + public int getDepth() + { + return depth; + } + + public void setDepth(int depth) + { + if (readOnly) + throw new IllegalStateException("read only"); + this.depth = depth; + } + + public void addAllExpectedPolicies(Set policies) + { + if (readOnly) + throw new IllegalStateException("read only"); + expectedPolicies.addAll(policies); + } + + public void addExpectedPolicy(String policy) + { + if (readOnly) + throw new IllegalStateException("read only"); + expectedPolicies.add(policy); + } + + public Set getExpectedPolicies() + { + return Collections.unmodifiableSet(expectedPolicies); + } + + public PolicyNode getParent() + { + return parent; + } + + public void addAllPolicyQualifiers (Collection qualifiers) + { + for (Iterator it = qualifiers.iterator(); it.hasNext(); ) + { + if (!(it.next() instanceof PolicyQualifierInfo)) + throw new IllegalArgumentException ("can only add PolicyQualifierInfos"); + } + qualifiers.addAll (qualifiers); + } + + public void addPolicyQualifier (PolicyQualifierInfo qualifier) + { + if (readOnly) + throw new IllegalStateException("read only"); + qualifiers.add(qualifier); + } + + public Set getPolicyQualifiers() + { + return Collections.unmodifiableSet(qualifiers); + } + + public String getValidPolicy() + { + return policy; + } + + public void setValidPolicy(String policy) + { + if (readOnly) + throw new IllegalStateException("read only"); + this.policy = policy; + } + + public boolean isCritical() + { + return critical; + } + + public void setCritical(boolean critical) + { + if (readOnly) + throw new IllegalStateException("read only"); + this.critical = critical; + } + + public void setReadOnly() + { + if (readOnly) + return; + readOnly = true; + for (Iterator it = getChildren(); it.hasNext(); ) + ((PolicyNodeImpl) it.next()).setReadOnly(); + } + + public String toString() + { + CPStringBuilder buf = new CPStringBuilder(); + for (int i = 0; i < depth; i++) + buf.append(" "); + buf.append("("); + buf.append(PolicyNodeImpl.class.getName()); + buf.append(" (oid "); + buf.append(policy); + buf.append(") (depth "); + buf.append(depth); + buf.append(") (qualifiers "); + buf.append(qualifiers); + buf.append(") (critical "); + buf.append(critical); + buf.append(") (expectedPolicies "); + buf.append(expectedPolicies); + buf.append(") (children ("); + final String nl = System.getProperty("line.separator"); + for (Iterator it = getChildren(); it.hasNext(); ) + { + buf.append(nl); + buf.append(it.next().toString()); + } + buf.append(")))"); + return buf.toString(); + } +} diff --git a/libjava/classpath/gnu/java/security/x509/Util.java b/libjava/classpath/gnu/java/security/x509/Util.java new file mode 100644 index 000000000..7b6c89f6a --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/Util.java @@ -0,0 +1,204 @@ +/* Util.java -- Miscellaneous utility methods. + 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.security.x509; + +import gnu.java.lang.CPStringBuilder; + +/** + * A collection of useful class methods. + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +public final class Util +{ + + // Constants. + // ------------------------------------------------------------------------- + + public static final String HEX = "0123456789abcdef"; + + // Class methods. + // ------------------------------------------------------------------------- + + /** + * 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. + */ + public static String toHexString(byte[] buf, int off, int len) + { + CPStringBuilder str = new CPStringBuilder(); + 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)}. + */ + public 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. + */ + public static String toHexString(byte[] buf, int off, int len, char sep) + { + CPStringBuilder str = new CPStringBuilder(); + 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)}. + */ + public 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. + * @return The formatted string. + */ + public static String hexDump(byte[] buf, int off, int len, String prefix) + { + String nl = System.getProperty("line.separator"); + CPStringBuilder str = new CPStringBuilder(); + int i = 0; + while (i < len) + { + 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)}. + */ + public static String hexDump(byte[] buf, String prefix) + { + return hexDump(buf, 0, buf.length, prefix); + } + + /** + * 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. + */ + public static String formatInt(int i, int radix, int len) + { + String s = Integer.toString(i, radix); + CPStringBuilder buf = new CPStringBuilder(); + for (int j = 0; j < len - s.length(); j++) + buf.append("0"); + buf.append(s); + return buf.toString(); + } + + /** + * Convert a hexadecimal string into its byte representation. + * + * @param hex The hexadecimal string. + * @return The converted bytes. + */ + public 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; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/X500DistinguishedName.java b/libjava/classpath/gnu/java/security/x509/X500DistinguishedName.java new file mode 100644 index 000000000..e2e05c57e --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/X500DistinguishedName.java @@ -0,0 +1,558 @@ +/* X500DistinguishedName.java -- X.500 distinguished name. + 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.security.x509; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.io.StringReader; +import java.security.Principal; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class X500DistinguishedName implements Principal +{ + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID CN = new OID("2.5.4.3"); + public static final OID C = new OID("2.5.4.6"); + public static final OID L = new OID("2.5.4.7"); + public static final OID ST = new OID("2.5.4.8"); + public static final OID STREET = new OID("2.5.4.9"); + public static final OID O = new OID("2.5.4.10"); + public static final OID OU = new OID("2.5.4.11"); + public static final OID T = new OID("2.5.4.12"); + public static final OID DNQ = new OID("2.5.4.46"); + public static final OID NAME = new OID("2.5.4.41"); + public static final OID GIVENNAME = new OID("2.5.4.42"); + public static final OID INITIALS = new OID("2.5.4.43"); + public static final OID GENERATION = new OID("2.5.4.44"); + public static final OID EMAIL = new OID("1.2.840.113549.1.9.1"); + public static final OID DC = new OID("0.9.2342.19200300.100.1.25"); + public static final OID UID = new OID("0.9.2342.19200300.100.1.1"); + + private List components; + private Map currentRdn; + private boolean fixed; + private String stringRep; + private byte[] encoded; + + // Constructors. + // ------------------------------------------------------------------------- + + public X500DistinguishedName() + { + components = new LinkedList(); + currentRdn = new LinkedHashMap(); + components.add(currentRdn); + } + + public X500DistinguishedName(String name) + { + this(); + try + { + parseString(name); + } + catch (IOException ioe) + { + throw new IllegalArgumentException(ioe.toString()); + } + } + + public X500DistinguishedName(byte[] encoded) throws IOException + { + this(); + parseDer(new DERReader(encoded)); + } + + public X500DistinguishedName(InputStream encoded) throws IOException + { + this(); + parseDer(new DERReader(encoded)); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public String getName() + { + return toString(); + } + + public void newRelativeDistinguishedName() + { + if (fixed || currentRdn.isEmpty()) return; + currentRdn = new LinkedHashMap(); + components.add(currentRdn); + } + + public int size() + { + return components.size(); + } + + public int countComponents() + { + int count = 0; + for (Iterator it = components.iterator(); it.hasNext(); ) + { + count += ((Map) it.next()).size(); + } + return count; + } + + public boolean containsComponent(OID oid, String value) + { + for (Iterator it = components.iterator(); it.hasNext(); ) + { + Map rdn = (Map) it.next(); + String s = (String) rdn.get(oid); + if (s == null) + continue; + if (compressWS(value).equalsIgnoreCase(compressWS(s))) + return true; + } + return false; + } + + public String getComponent(OID oid) + { + for (Iterator it = components.iterator(); it.hasNext(); ) + { + Map rdn = (Map) it.next(); + if (rdn.containsKey(oid)) + return (String) rdn.get(oid); + } + return null; + } + + public String getComponent(OID oid, int rdn) + { + if (rdn >= size()) + return null; + return (String) ((Map) components.get(rdn)).get(oid); + } + + public void putComponent(OID oid, String value) + { + currentRdn.put(oid, value); + } + + public void putComponent(String name, String value) + { + name = name.trim().toLowerCase(); + if (name.equals("cn")) + putComponent(CN, value); + else if (name.equals("c")) + putComponent(C, value); + else if (name.equals("l")) + putComponent(L, value); + else if (name.equals("street")) + putComponent(STREET, value); + else if (name.equals("st")) + putComponent(ST, value); + else if (name.equals("t")) + putComponent(T, value); + else if (name.equals("dnq")) + putComponent(DNQ, value); + else if (name.equals("name")) + putComponent(NAME, value); + else if (name.equals("givenname")) + putComponent(GIVENNAME, value); + else if (name.equals("initials")) + putComponent(INITIALS, value); + else if (name.equals("generation")) + putComponent(GENERATION, value); + else if (name.equals("email")) + putComponent(EMAIL, value); + else if (name.equals("dc")) + putComponent(DC, value); + else if (name.equals("uid")) + putComponent(UID, value); + else if (name.equals("o")) + putComponent(O, value); + else if (name.equals("ou")) + putComponent(OU, value); + else + putComponent(new OID(name), value); + } + + public void setUnmodifiable() + { + if (fixed) return; + fixed = true; + List newComps = new ArrayList(components.size()); + for (Iterator it = components.iterator(); it.hasNext(); ) + { + Map rdn = (Map) it.next(); + rdn = Collections.unmodifiableMap(rdn); + newComps.add(rdn); + } + components = Collections.unmodifiableList(newComps); + currentRdn = Collections.EMPTY_MAP; + } + + public int hashCode() + { + int sum = 0; + for (Iterator it = components.iterator(); it.hasNext(); ) + { + Map m = (Map) it.next(); + for (Iterator it2 = m.entrySet().iterator(); it2.hasNext(); ) + { + Map.Entry e = (Map.Entry) it2.next(); + sum += e.getKey().hashCode(); + sum += e.getValue().hashCode(); + } + } + return sum; + } + + public boolean equals(Object o) + { + if (!(o instanceof X500DistinguishedName)) + return false; + if (size() != ((X500DistinguishedName) o).size()) + return false; + for (int i = 0; i < size(); i++) + { + Map m = (Map) components.get(i); + for (Iterator it2 = m.entrySet().iterator(); it2.hasNext(); ) + { + Map.Entry e = (Map.Entry) it2.next(); + OID oid = (OID) e.getKey(); + String v1 = (String) e.getValue(); + String v2 = ((X500DistinguishedName) o).getComponent(oid, i); + if (!compressWS(v1).equalsIgnoreCase(compressWS(v2))) + return false; + } + } + return true; + } + + public String toString() + { + if (fixed && stringRep != null) + return stringRep; + CPStringBuilder str = new CPStringBuilder(); + for (Iterator it = components.iterator(); it.hasNext(); ) + { + Map m = (Map) it.next(); + for (Iterator it2 = m.entrySet().iterator(); it2.hasNext(); ) + { + Map.Entry entry = (Map.Entry) it2.next(); + OID oid = (OID) entry.getKey(); + String value = (String) entry.getValue(); + if (oid.equals(CN)) + str.append("CN"); + else if (oid.equals(C)) + str.append("C"); + else if (oid.equals(L)) + str.append("L"); + else if (oid.equals(ST)) + str.append("ST"); + else if (oid.equals(STREET)) + str.append("STREET"); + else if (oid.equals(O)) + str.append("O"); + else if (oid.equals(OU)) + str.append("OU"); + else if (oid.equals(T)) + str.append("T"); + else if (oid.equals(DNQ)) + str.append("DNQ"); + else if (oid.equals(NAME)) + str.append("NAME"); + else + str.append(oid.toString()); + str.append('='); + str.append(value); + if (it2.hasNext()) + str.append("+"); + } + if (it.hasNext()) + str.append(','); + } + return (stringRep = str.toString()); + } + + public byte[] getDer() + { + if (fixed && encoded != null) + return (byte[]) encoded.clone(); + + ArrayList name = new ArrayList(components.size()); + for (Iterator it = components.iterator(); it.hasNext(); ) + { + Map m = (Map) it.next(); + if (m.isEmpty()) + continue; + + Set rdn = new HashSet(); + for (Iterator it2 = m.entrySet().iterator(); it2.hasNext(); ) + { + Map.Entry e = (Map.Entry) it2.next(); + ArrayList atav = new ArrayList(2); + atav.add(new DERValue(DER.OBJECT_IDENTIFIER, e.getKey())); + atav.add(new DERValue(DER.UTF8_STRING, e.getValue())); + rdn.add(new DERValue(DER.SEQUENCE|DER.CONSTRUCTED, atav)); + } + name.add(new DERValue(DER.SET|DER.CONSTRUCTED, rdn)); + } + DERValue val = new DERValue(DER.SEQUENCE|DER.CONSTRUCTED, name); + return (byte[]) (encoded = val.getEncoded()).clone(); + } + + // Own methods. + // ------------------------------------------------------------------------- + + private int sep; + + private void parseString(String str) throws IOException + { + Reader in = new StringReader(str); + while (true) + { + String key = readAttributeType(in); + if (key == null) + break; + String value = readAttributeValue(in); + putComponent(key, value); + if (sep == ',') + newRelativeDistinguishedName(); + } + setUnmodifiable(); + } + + private String readAttributeType(Reader in) throws IOException + { + CPStringBuilder buf = new CPStringBuilder(); + int ch; + while ((ch = in.read()) != '=') + { + if (ch == -1) + { + if (buf.length() > 0) + throw new EOFException(); + return null; + } + if (ch > 127) + throw new IOException("Invalid char: " + (char) ch); + if (Character.isLetterOrDigit((char) ch) || ch == '-' || ch == '.') + buf.append((char) ch); + else + throw new IOException("Invalid char: " + (char) ch); + } + return buf.toString(); + } + + private String readAttributeValue(Reader in) throws IOException + { + CPStringBuilder buf = new CPStringBuilder(); + int ch = in.read(); + if (ch == '#') + { + while (true) + { + ch = in.read(); + if (('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F') + || Character.isDigit((char) ch)) + buf.append((char) ch); + else if (ch == '+' || ch == ',') + { + sep = ch; + String hex = buf.toString(); + return new String(Util.toByteArray(hex)); + } + else + throw new IOException("illegal character: " + (char) ch); + } + } + else if (ch == '"') + { + while (true) + { + ch = in.read(); + if (ch == '"') + break; + else if (ch == '\\') + { + ch = in.read(); + if (ch == -1) + throw new EOFException(); + if (('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F') + || Character.isDigit((char) ch)) + { + int i = Character.digit((char) ch, 16) << 4; + ch = in.read(); + if (!(('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F') + || Character.isDigit((char) ch))) + throw new IOException("illegal hex char"); + i |= Character.digit((char) ch, 16); + buf.append((char) i); + } + else + buf.append((char) ch); + } + else + buf.append((char) ch); + } + sep = in.read(); + if (sep != '+' || sep != ',') + throw new IOException("illegal character: " + (char) ch); + return buf.toString(); + } + else + { + while (true) + { + switch (ch) + { + case '+': + case ',': + sep = ch; + return buf.toString(); + case '\\': + ch = in.read(); + if (ch == -1) + throw new EOFException(); + if (('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F') + || Character.isDigit((char) ch)) + { + int i = Character.digit((char) ch, 16) << 4; + ch = in.read(); + if (!(('a' <= ch && ch <= 'f') || ('A' <= ch && ch <= 'F') + || Character.isDigit((char) ch))) + throw new IOException("illegal hex char"); + i |= Character.digit((char) ch, 16); + buf.append((char) i); + } + else + buf.append((char) ch); + break; + case '=': + case '<': + case '>': + case '#': + case ';': + throw new IOException("illegal character: " + (char) ch); + case -1: + throw new EOFException(); + default: + buf.append((char) ch); + ch = in.read(); + if (ch == -1) + return buf.toString(); + } + } + } + } + + private void parseDer(DERReader der) throws IOException + { + DERValue name = der.read(); + if (!name.isConstructed()) + throw new IOException("malformed Name"); + encoded = name.getEncoded(); + int len = 0; + while (len < name.getLength()) + { + DERValue rdn = der.read(); + if (!rdn.isConstructed()) + throw new IOException("badly formed RDNSequence"); + int len2 = 0; + while (len2 < rdn.getLength()) + { + DERValue atav = der.read(); + if (!atav.isConstructed()) + throw new IOException("badly formed AttributeTypeAndValue"); + DERValue val = der.read(); + if (val.getTag() != DER.OBJECT_IDENTIFIER) + throw new IOException("badly formed AttributeTypeAndValue"); + OID oid = (OID) val.getValue(); + val = der.read(); + if (!(val.getValue() instanceof String)) + throw new IOException("badly formed AttributeTypeAndValue"); + String value = (String) val.getValue(); + putComponent(oid, value); + len2 += atav.getEncodedLength(); + } + len += rdn.getEncodedLength(); + if (len < name.getLength()) + newRelativeDistinguishedName(); + } + setUnmodifiable(); + } + + private static String compressWS(String str) + { + CPStringBuilder buf = new CPStringBuilder(); + char lastChar = 0; + for (int i = 0; i < str.length(); i++) + { + char c = str.charAt(i); + if (Character.isWhitespace(c)) + { + if (!Character.isWhitespace(lastChar)) + buf.append(' '); + } + else + buf.append(c); + lastChar = c; + } + return buf.toString().trim(); + } +} diff --git a/libjava/classpath/gnu/java/security/x509/X509CRL.java b/libjava/classpath/gnu/java/security/x509/X509CRL.java new file mode 100644 index 000000000..7c471c972 --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/X509CRL.java @@ -0,0 +1,485 @@ +/* X509CRL.java -- X.509 certificate revocation list. + Copyright (C) 2003, 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.security.x509; + +import gnu.java.security.Configuration; +import gnu.java.security.OID; +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.x509.ext.Extension; + +import java.io.IOException; +import java.io.InputStream; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Principal; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; +import java.security.cert.CRLException; +import java.security.cert.Certificate; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.logging.Logger; + +import javax.security.auth.x500.X500Principal; + +/** + * X.509 certificate revocation lists. + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +public class X509CRL extends java.security.cert.X509CRL + implements GnuPKIExtension +{ + private static final Logger log = Logger.getLogger(X509CRL.class.getName()); + private static final OID ID_DSA = new OID("1.2.840.10040.4.1"); + private static final OID ID_DSA_WITH_SHA1 = new OID("1.2.840.10040.4.3"); + private static final OID ID_RSA = new OID("1.2.840.113549.1.1.1"); + private static final OID ID_RSA_WITH_MD2 = new OID("1.2.840.113549.1.1.2"); + private static final OID ID_RSA_WITH_MD5 = new OID("1.2.840.113549.1.1.4"); + private static final OID ID_RSA_WITH_SHA1 = new OID("1.2.840.113549.1.1.5"); + + private byte[] encoded; + + private byte[] tbsCRLBytes; + private int version; + private OID algId; + private byte[] algParams; + private Date thisUpdate; + private Date nextUpdate; + private X500DistinguishedName issuerDN; + private HashMap revokedCerts; + private HashMap extensions; + + private OID sigAlg; + private byte[] sigAlgParams; + private byte[] rawSig; + private byte[] signature; + + // Constructors. + // ------------------------------------------------------------------------ + + /** + * Create a new X.509 CRL. + * + * @param encoded The DER encoded CRL. + * @throws CRLException If the input bytes are incorrect. + * @throws IOException If the input bytes cannot be read. + */ + public X509CRL(InputStream encoded) throws CRLException, IOException + { + super(); + revokedCerts = new HashMap(); + extensions = new HashMap(); + try + { + parse(encoded); + } + catch (IOException ioe) + { + ioe.printStackTrace(); + throw ioe; + } + catch (Exception x) + { + x.printStackTrace(); + throw new CRLException(x.toString()); + } + } + + // X509CRL methods. + // ------------------------------------------------------------------------ + + public boolean equals(Object o) + { + if (!(o instanceof X509CRL)) + return false; + return ((X509CRL) o).getRevokedCertificates().equals(revokedCerts.values()); + } + + public int hashCode() + { + return revokedCerts.hashCode(); + } + + public byte[] getEncoded() throws CRLException + { + return (byte[]) encoded.clone(); + } + + public void verify(PublicKey key) + throws CRLException, NoSuchAlgorithmException, InvalidKeyException, + NoSuchProviderException, SignatureException + { + Signature sig = Signature.getInstance(sigAlg.toString()); + doVerify(sig, key); + } + + public void verify(PublicKey key, String provider) + throws CRLException, NoSuchAlgorithmException, InvalidKeyException, + NoSuchProviderException, SignatureException + { + Signature sig = Signature.getInstance(sigAlg.toString(), provider); + doVerify(sig, key); + } + + public int getVersion() + { + return version; + } + + public Principal getIssuerDN() + { + return issuerDN; + } + + public X500Principal getIssuerX500Principal() + { + return new X500Principal(issuerDN.getDer()); + } + + public Date getThisUpdate() + { + return (Date) thisUpdate.clone(); + } + + public Date getNextUpdate() + { + if (nextUpdate != null) + return (Date) nextUpdate.clone(); + return null; + } + + public java.security.cert.X509CRLEntry getRevokedCertificate(BigInteger serialNo) + { + return (java.security.cert.X509CRLEntry) revokedCerts.get(serialNo); + } + + public Set getRevokedCertificates() + { + return Collections.unmodifiableSet(new HashSet(revokedCerts.values())); + } + + public byte[] getTBSCertList() throws CRLException + { + return (byte[]) tbsCRLBytes.clone(); + } + + public byte[] getSignature() + { + return (byte[]) rawSig.clone(); + } + + public String getSigAlgName() + { + if (sigAlg.equals(ID_DSA_WITH_SHA1)) + return "SHA1withDSA"; + if (sigAlg.equals(ID_RSA_WITH_MD2)) + return "MD2withRSA"; + if (sigAlg.equals(ID_RSA_WITH_MD5)) + return "MD5withRSA"; + if (sigAlg.equals(ID_RSA_WITH_SHA1)) + return "SHA1withRSA"; + return "unknown"; + } + + public String getSigAlgOID() + { + return sigAlg.toString(); + } + + public byte[] getSigAlgParams() + { + if (sigAlgParams != null) + return (byte[]) sigAlgParams.clone(); + return null; + } + + // X509Extension methods. + // ------------------------------------------------------------------------ + + public boolean hasUnsupportedCriticalExtension() + { + for (Iterator it = extensions.values().iterator(); it.hasNext(); ) + { + Extension e = (Extension) it.next(); + if (e.isCritical() && !e.isSupported()) + return true; + } + return false; + } + + public Set getCriticalExtensionOIDs() + { + HashSet s = new HashSet(); + for (Iterator it = extensions.values().iterator(); it.hasNext(); ) + { + Extension e = (Extension) it.next(); + if (e.isCritical()) + s.add(e.getOid().toString()); + } + return Collections.unmodifiableSet(s); + } + + public Set getNonCriticalExtensionOIDs() + { + HashSet s = new HashSet(); + for (Iterator it = extensions.values().iterator(); it.hasNext(); ) + { + Extension e = (Extension) it.next(); + if (!e.isCritical()) + s.add(e.getOid().toString()); + } + return Collections.unmodifiableSet(s); + } + + public byte[] getExtensionValue(String oid) + { + Extension e = getExtension(new OID(oid)); + if (e != null) + { + return e.getValue().getEncoded(); + } + return null; + } + + // GnuPKIExtension method. + // ------------------------------------------------------------------------- + + public Extension getExtension(OID oid) + { + return (Extension) extensions.get(oid); + } + + public Collection getExtensions() + { + return extensions.values(); + } + + // CRL methods. + // ------------------------------------------------------------------------- + + public String toString() + { + return X509CRL.class.getName(); + } + + public boolean isRevoked(Certificate cert) + { + if (!(cert instanceof java.security.cert.X509Certificate)) + throw new IllegalArgumentException("not a X.509 certificate"); + BigInteger certSerial = + ((java.security.cert.X509Certificate) cert).getSerialNumber(); + X509CRLEntry ent = (X509CRLEntry) revokedCerts.get(certSerial); + if (ent == null) + return false; + return ent.getRevocationDate().compareTo(new Date()) < 0; + } + + // Own methods. + // ------------------------------------------------------------------------ + + private void doVerify(Signature sig, PublicKey key) + throws CRLException, InvalidKeyException, SignatureException + { + sig.initVerify(key); + sig.update(tbsCRLBytes); + if (!sig.verify(signature)) + throw new CRLException("signature not verified"); + } + + private void parse(InputStream in) throws Exception + { + // CertificateList ::= SEQUENCE { + DERReader der = new DERReader(in); + DERValue val = der.read(); + if (Configuration.DEBUG) + log.fine("start CertificateList len == " + val.getLength()); + if (!val.isConstructed()) + throw new IOException("malformed CertificateList"); + encoded = val.getEncoded(); + + // tbsCertList ::= SEQUENCE { -- TBSCertList + val = der.read(); + if (!val.isConstructed()) + throw new IOException("malformed TBSCertList"); + if (Configuration.DEBUG) + log.fine("start tbsCertList len == " + val.getLength()); + tbsCRLBytes = val.getEncoded(); + + // version Version OPTIONAL, + // -- If present must be v2 + val = der.read(); + if (val.getValue() instanceof BigInteger) + { + version = ((BigInteger) val.getValue()).intValue() + 1; + val = der.read(); + } + else + version = 1; + if (Configuration.DEBUG) + log.fine("read version == " + version); + + // signature AlgorithmIdentifier, + if (Configuration.DEBUG) + log.fine("start AlgorithmIdentifier len == " + val.getLength()); + if (!val.isConstructed()) + throw new IOException("malformed AlgorithmIdentifier"); + DERValue algIdVal = der.read(); + algId = (OID) algIdVal.getValue(); + if (Configuration.DEBUG) + log.fine("read object identifier == " + algId); + if (val.getLength() > algIdVal.getEncodedLength()) + { + val = der.read(); + if (Configuration.DEBUG) + log.fine("read parameters len == " + val.getEncodedLength()); + algParams = val.getEncoded(); + if (val.isConstructed()) + in.skip(val.getLength()); + } + + // issuer Name, + val = der.read(); + issuerDN = new X500DistinguishedName(val.getEncoded()); + der.skip(val.getLength()); + if (Configuration.DEBUG) + log.fine("read issuer == " + issuerDN); + + // thisUpdate Time, + thisUpdate = (Date) der.read().getValue(); + if (Configuration.DEBUG) + log.fine("read thisUpdate == " + thisUpdate); + + // nextUpdate Time OPTIONAL, + val = der.read(); + if (val.getValue() instanceof Date) + { + nextUpdate = (Date) val.getValue(); + if (Configuration.DEBUG) + log.fine("read nextUpdate == " + nextUpdate); + val = der.read(); + } + + // revokedCertificates SEQUENCE OF SEQUENCE { + // -- X509CRLEntry objects... + // } OPTIONAL, + if (val.getTag() != 0) + { + int len = 0; + while (len < val.getLength()) + { + X509CRLEntry entry = new X509CRLEntry(version, der); + revokedCerts.put(entry.getSerialNumber(), entry); + len += entry.getEncoded().length; + } + val = der.read(); + } + + // crlExtensions [0] EXPLICIT Extensions OPTIONAL + // -- if present MUST be v2 + if (val.getTagClass() != DER.UNIVERSAL && val.getTag() == 0) + { + if (version < 2) + throw new IOException("extra data in CRL"); + DERValue exts = der.read(); + if (!exts.isConstructed()) + throw new IOException("malformed Extensions"); + if (Configuration.DEBUG) + log.fine("start Extensions len == " + exts.getLength()); + int len = 0; + while (len < exts.getLength()) + { + DERValue ext = der.read(); + if (!ext.isConstructed()) + throw new IOException("malformed Extension"); + Extension e = new Extension(ext.getEncoded()); + extensions.put(e.getOid(), e); + der.skip(ext.getLength()); + len += ext.getEncodedLength(); + if (Configuration.DEBUG) + log.fine("current count == " + len); + } + val = der.read(); + } + + if (Configuration.DEBUG) + log.fine("read tag == " + val.getTag()); + if (!val.isConstructed()) + throw new IOException("malformed AlgorithmIdentifier"); + if (Configuration.DEBUG) + log.fine("start AlgorithmIdentifier len == " + val.getLength()); + DERValue sigAlgVal = der.read(); + if (Configuration.DEBUG) + log.fine("read tag == " + sigAlgVal.getTag()); + if (sigAlgVal.getTag() != DER.OBJECT_IDENTIFIER) + throw new IOException("malformed AlgorithmIdentifier"); + sigAlg = (OID) sigAlgVal.getValue(); + if (Configuration.DEBUG) + { + log.fine("signature id == " + sigAlg); + log.fine("sigAlgVal length == " + sigAlgVal.getEncodedLength()); + } + if (val.getLength() > sigAlgVal.getEncodedLength()) + { + val = der.read(); + if (Configuration.DEBUG) + log.fine("sig params tag = " + val.getTag() + " len == " + + val.getEncodedLength()); + sigAlgParams = (byte[]) val.getEncoded(); + if (val.isConstructed()) + in.skip(val.getLength()); + } + val = der.read(); + if (Configuration.DEBUG) + log.fine("read tag = " + val.getTag()); + rawSig = val.getEncoded(); + signature = ((BitString) val.getValue()).toByteArray(); + } +} diff --git a/libjava/classpath/gnu/java/security/x509/X509CRLEntry.java b/libjava/classpath/gnu/java/security/x509/X509CRLEntry.java new file mode 100644 index 000000000..26b40363c --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/X509CRLEntry.java @@ -0,0 +1,273 @@ +/* X509CRLEntry.java -- an entry in a X.509 CRL. + Copyright (C) 2003, 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.security.x509; + +import gnu.java.security.Configuration; +import gnu.java.security.OID; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.x509.ext.Extension; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.cert.CRLException; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.logging.Logger; + +/** + * A single entry in a X.509 certificate revocation list. + * + * @see X509CRL + * @author Casey Marshall + */ +class X509CRLEntry extends java.security.cert.X509CRLEntry + implements GnuPKIExtension +{ + private static final Logger log = Logger.getLogger(X509CRLEntry.class.getName()); + /** The DER encoded form of this CRL entry. */ + private byte[] encoded; + + /** The revoked certificate's serial number. */ + private BigInteger serialNo; + + /** The date the certificate was revoked. */ + private Date revocationDate; + + /** The CRL entry extensions. */ + private HashMap extensions; + + // Constructor. + // ------------------------------------------------------------------------ + + /** + * Create a new X.509 certificate revocation list entry from the given + * input stream and CRL version number. + * + * @param version The CRL version. + * @param encoded The stream of DER bytes. + * @throws CRLException If the ASN.1 structure is invalid. + * @throws IOException If the bytes cannot be read. + */ + X509CRLEntry(int version, DERReader encoded) + throws CRLException, IOException + { + super(); + extensions = new HashMap(); + try + { + parse(version, encoded); + } + catch (IOException ioe) + { + throw ioe; + } + catch (Exception x) + { + throw new CRLException(x.toString()); + } + } + + // X509CRLEntry methods. + // ------------------------------------------------------------------------ + + public boolean equals(Object o) + { + if (!(o instanceof X509CRLEntry)) + return false; + return ((X509CRLEntry) o).getSerialNumber().equals(serialNo) && + ((X509CRLEntry) o).getRevocationDate().equals(revocationDate); + } + + public int hashCode() + { + return serialNo.hashCode(); + } + + public byte[] getEncoded() throws CRLException + { + return (byte[]) encoded.clone(); + } + + public BigInteger getSerialNumber() + { + return serialNo; + } + + public Date getRevocationDate() + { + return (Date) revocationDate.clone(); + } + + public boolean hasExtensions() + { + return ! extensions.isEmpty(); + } + + public String toString() + { + return "X509CRLEntry serial=" + serialNo + " revocation date=" + + revocationDate + " ext=" + extensions; + } + + // X509Extension methods. + // ------------------------------------------------------------------------- + + public boolean hasUnsupportedCriticalExtension() + { + for (Iterator it = extensions.values().iterator(); it.hasNext(); ) + { + Extension e = (Extension) it.next(); + if (e.isCritical() && !e.isSupported()) + return true; + } + return false; + } + + public Set getCriticalExtensionOIDs() + { + HashSet s = new HashSet(); + for (Iterator it = extensions.values().iterator(); it.hasNext(); ) + { + Extension e = (Extension) it.next(); + if (e.isCritical()) + s.add(e.getOid().toString()); + } + return Collections.unmodifiableSet(s); + } + + public Set getNonCriticalExtensionOIDs() + { + HashSet s = new HashSet(); + for (Iterator it = extensions.values().iterator(); it.hasNext(); ) + { + Extension e = (Extension) it.next(); + if (!e.isCritical()) + s.add(e.getOid().toString()); + } + return Collections.unmodifiableSet(s); + } + + public byte[] getExtensionValue(String oid) + { + Extension e = getExtension(new OID(oid)); + if (e != null) + { + return e.getValue().getEncoded(); + } + return null; + } + + // GnuPKIExtension method. + // ------------------------------------------------------------------------- + + public Extension getExtension(OID oid) + { + return (Extension) extensions.get(oid); + } + + public Collection getExtensions() + { + return extensions.values(); + } + + // Own methods. + // ------------------------------------------------------------------------- + + private void parse(int version, DERReader der) throws Exception + { + // RevokedCertificate ::= SEQUENCE { + DERValue entry = der.read(); + if (Configuration.DEBUG) + log.fine("start CRL entry len == " + entry.getLength()); + if (!entry.isConstructed()) + throw new IOException("malformed revokedCertificate"); + encoded = entry.getEncoded(); + int len = 0; + if (Configuration.DEBUG) + log.fine("encoded entry:\n" + Util.hexDump(encoded, ">>>> ")); + + // userCertificate CertificateSerialNumber, + DERValue val = der.read(); + serialNo = (BigInteger) val.getValue(); + len += val.getEncodedLength(); + if (Configuration.DEBUG) + log.fine("userCertificate == " + serialNo + " current count == " + len); + + // revocationDate Time, + val = der.read(); + revocationDate = (Date) val.getValue(); + len += val.getEncodedLength(); + if (Configuration.DEBUG) + log.fine("revocationDate == " + revocationDate + " current count == " + + len); + // crlEntryExtensions Extensions OPTIONAL + // -- if present MUST be v2 + if (len < entry.getLength()) + { + if (version < 2) + throw new IOException("extra data in CRL entry"); + DERValue exts = der.read(); + if (!exts.isConstructed()) + throw new IOException("malformed Extensions"); + if (Configuration.DEBUG) + log.fine("start Extensions len == " + exts.getLength()); + len = 0; + while (len < exts.getLength()) + { + val = der.read(); + if (!val.isConstructed()) + throw new IOException("malformed Extension"); + if (Configuration.DEBUG) + log.fine("start Extension len == " + val.getLength()); + Extension e = new Extension(val.getEncoded()); + extensions.put(e.getOid(), e); + der.skip(val.getLength()); + len += val.getEncodedLength(); + if (Configuration.DEBUG) + log.fine("current count == " + len); + } + } + } +} diff --git a/libjava/classpath/gnu/java/security/x509/X509CRLSelectorImpl.java b/libjava/classpath/gnu/java/security/x509/X509CRLSelectorImpl.java new file mode 100644 index 000000000..582d18583 --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/X509CRLSelectorImpl.java @@ -0,0 +1,137 @@ +/* X509CRLSelectorImpl.java -- implementation of an X509CRLSelector. + 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.security.x509; + +import java.io.IOException; + +import java.security.Principal; +import java.security.cert.CRL; +import java.security.cert.CRLSelector; +import java.security.cert.X509CRL; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import javax.security.auth.x500.X500Principal; + +/** + * Sun's implementation of X509CRLSelector sucks. This one tries to work + * better. + */ +public class X509CRLSelectorImpl implements CRLSelector +{ + + // Fields. + // ------------------------------------------------------------------------- + + private Set issuerNames; + + // Constructor. + // ------------------------------------------------------------------------- + + public X509CRLSelectorImpl() + { + issuerNames = new HashSet(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void addIssuerName(byte[] issuerName) throws IOException + { + issuerNames.add(new X500DistinguishedName(issuerName)); + } + + public void addIssuerName(String issuerName) + { + issuerNames.add(new X500DistinguishedName(issuerName)); + } + + public void addIssuerName(Principal issuerName) throws IOException + { + if (issuerName instanceof X500DistinguishedName) + issuerNames.add(issuerName); + else if (issuerName instanceof X500Principal) + issuerNames.add(new X500DistinguishedName(((X500Principal) issuerName).getEncoded())); + else + issuerNames.add(new X500DistinguishedName(issuerName.getName())); + } + + public Collection getIssuerNames() + { + return Collections.unmodifiableSet(issuerNames); + } + + public Object clone() + { + X509CRLSelectorImpl copy = new X509CRLSelectorImpl(); + copy.issuerNames.addAll(issuerNames); + return copy; + } + + public boolean match(CRL crl) + { + if (!(crl instanceof X509CRL)) + return false; + try + { + Principal p = ((X509CRL) crl).getIssuerDN(); + X500DistinguishedName thisName = null; + if (p instanceof X500DistinguishedName) + thisName = (X500DistinguishedName) p; + else if (p instanceof X500Principal) + thisName = new X500DistinguishedName(((X500Principal) p).getEncoded()); + else + thisName = new X500DistinguishedName(p.getName()); + for (Iterator it = issuerNames.iterator(); it.hasNext(); ) + { + X500DistinguishedName name = (X500DistinguishedName) it.next(); + if (thisName.equals(name)) + return true; + } + } + catch (Exception x) + { + } + return false; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/X509CertPath.java b/libjava/classpath/gnu/java/security/x509/X509CertPath.java new file mode 100644 index 000000000..e8ed6bf35 --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/X509CertPath.java @@ -0,0 +1,303 @@ +/* X509CertPath.java -- an X.509 certificate path. + Copyright (C) 2004 Free Software Fonudation, 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.x509; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DEREncodingException; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigInteger; +import java.security.cert.CertPath; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +/** + * A certificate path (or certificate chain) of X509Certificates. + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +public class X509CertPath extends CertPath +{ + + // Fields. + // ------------------------------------------------------------------------- + + public static final List ENCODINGS = Collections.unmodifiableList( + Arrays.asList(new String[] { "PkiPath", "PKCS7" })); + + private static final OID PKCS7_SIGNED_DATA = new OID("1.2.840.113549.1.7.2"); + private static final OID PKCS7_DATA = new OID("1.2.840.113549.1.7.1"); + + /** The certificate path. */ + private List path; + + /** The cached PKCS #7 encoded bytes. */ + private byte[] pkcs_encoded; + + /** The cached PkiPath encoded bytes. */ + private byte[] pki_encoded; + + // Constructor. + // ------------------------------------------------------------------------- + + public X509CertPath(List path) + { + super("X.509"); + this.path = Collections.unmodifiableList(path); + } + + public X509CertPath(InputStream in) throws CertificateEncodingException + { + this(in, (String) ENCODINGS.get(0)); + } + + public X509CertPath(InputStream in, String encoding) + throws CertificateEncodingException + { + super("X.509"); + try + { + parse(in, encoding); + } + catch (IOException ioe) + { + throw new CertificateEncodingException(); + } + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public List getCertificates() + { + return path; // already unmodifiable + } + + public byte[] getEncoded() throws CertificateEncodingException + { + return getEncoded((String) ENCODINGS.get(0)); + } + + public byte[] getEncoded(String encoding) throws CertificateEncodingException + { + if (encoding.equalsIgnoreCase("PkiPath")) + { + if (pki_encoded == null) + { + try + { + pki_encoded = encodePki(); + } + catch (IOException ioe) + { + throw new CertificateEncodingException(); + } + } + return (byte[]) pki_encoded.clone(); + } + else if (encoding.equalsIgnoreCase("PKCS7")) + { + if (pkcs_encoded == null) + { + try + { + pkcs_encoded = encodePKCS(); + } + catch (IOException ioe) + { + throw new CertificateEncodingException(); + } + } + return (byte[]) pkcs_encoded.clone(); + } + else + throw new CertificateEncodingException("unknown encoding: " + encoding); + } + + public Iterator getEncodings() + { + return ENCODINGS.iterator(); // already unmodifiable + } + + // Own methods. + // ------------------------------------------------------------------------- + + private void parse(InputStream in, String encoding) + throws CertificateEncodingException, IOException + { + DERReader der = new DERReader(in); + DERValue path = null; + if (encoding.equalsIgnoreCase("PkiPath")) + { + // PKI encoding is just a SEQUENCE of X.509 certificates. + path = der.read(); + if (!path.isConstructed()) + throw new DEREncodingException("malformed PkiPath"); + } + else if (encoding.equalsIgnoreCase("PKCS7")) + { + // PKCS #7 encoding means that the certificates are contained in a + // SignedData PKCS #7 type. + // + // ContentInfo ::= SEQUENCE { + // contentType ::= ContentType, + // content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL } + // + // ContentType ::= OBJECT IDENTIFIER + // + // SignedData ::= SEQUENCE { + // version Version, + // digestAlgorithms DigestAlgorithmIdentifiers, + // contentInfo ContentInfo, + // certificates [0] IMPLICIT ExtendedCertificatesAndCertificates + // OPTIONAL, + // crls [1] IMPLICIT CertificateRevocationLists OPTIONAL, + // signerInfos SignerInfos } + // + // Version ::= INTEGER + // + DERValue value = der.read(); + if (!value.isConstructed()) + throw new DEREncodingException("malformed ContentInfo"); + value = der.read(); + if (!(value.getValue() instanceof OID) || + ((OID) value.getValue()).equals(PKCS7_SIGNED_DATA)) + throw new DEREncodingException("not a SignedData"); + value = der.read(); + if (!value.isConstructed() || value.getTag() != 0) + throw new DEREncodingException("malformed content"); + value = der.read(); + if (value.getTag() != DER.INTEGER) + throw new DEREncodingException("malformed Version"); + value = der.read(); + if (!value.isConstructed() || value.getTag() != DER.SET) + throw new DEREncodingException("malformed DigestAlgorithmIdentifiers"); + der.skip(value.getLength()); + value = der.read(); + if (!value.isConstructed()) + throw new DEREncodingException("malformed ContentInfo"); + der.skip(value.getLength()); + path = der.read(); + if (!path.isConstructed() || path.getTag() != 0) + throw new DEREncodingException("no certificates"); + } + else + throw new CertificateEncodingException("unknown encoding: " + encoding); + + LinkedList certs = new LinkedList(); + int len = 0; + while (len < path.getLength()) + { + DERValue cert = der.read(); + try + { + certs.add(new X509Certificate(new ByteArrayInputStream(cert.getEncoded()))); + } + catch (CertificateException ce) + { + throw new CertificateEncodingException(ce.getMessage()); + } + len += cert.getEncodedLength(); + der.skip(cert.getLength()); + } + + this.path = Collections.unmodifiableList(certs); + } + + private byte[] encodePki() + throws CertificateEncodingException, IOException + { + synchronized (path) + { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + for (Iterator i = path.iterator(); i.hasNext(); ) + { + out.write(((Certificate) i.next()).getEncoded()); + } + byte[] b = out.toByteArray(); + DERValue val = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + b.length, b, null); + return val.getEncoded(); + } + } + + private byte[] encodePKCS() + throws CertificateEncodingException, IOException + { + synchronized (path) + { + ArrayList signedData = new ArrayList(5); + signedData.add(new DERValue(DER.INTEGER, BigInteger.ONE)); + signedData.add(new DERValue(DER.CONSTRUCTED | DER.SET, + Collections.EMPTY_SET)); + signedData.add(new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + Collections.singletonList( + new DERValue(DER.OBJECT_IDENTIFIER, PKCS7_DATA)))); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + for (Iterator i = path.iterator(); i.hasNext(); ) + { + out.write(((Certificate) i.next()).getEncoded()); + } + byte[] b = out.toByteArray(); + signedData.add(new DERValue(DER.CONSTRUCTED | DER.CONTEXT, + b.length, b, null)); + DERValue sdValue = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + signedData); + + ArrayList contentInfo = new ArrayList(2); + contentInfo.add(new DERValue(DER.OBJECT_IDENTIFIER, PKCS7_SIGNED_DATA)); + contentInfo.add(new DERValue(DER.CONSTRUCTED | DER.CONTEXT, sdValue)); + return new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + contentInfo).getEncoded(); + } + } +} diff --git a/libjava/classpath/gnu/java/security/x509/X509CertSelectorImpl.java b/libjava/classpath/gnu/java/security/x509/X509CertSelectorImpl.java new file mode 100644 index 000000000..5201a76b9 --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/X509CertSelectorImpl.java @@ -0,0 +1,196 @@ +/* X509CertSelectorImpl.java -- implementation of an X509CertSelector. + 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.security.x509; + +import java.io.IOException; +import java.security.Principal; +import java.security.cert.CertSelector; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import javax.security.auth.x500.X500Principal; + +/** + * Sun's implementation of X509CertSelector sucks. This one tries to work + * better. + */ +public class X509CertSelectorImpl implements CertSelector +{ + + // Fields. + // ------------------------------------------------------------------------- + + private Set issuerNames; + private Set subjectNames; + + // Constructor. + // ------------------------------------------------------------------------- + + public X509CertSelectorImpl() + { + issuerNames = new HashSet(); + subjectNames = new HashSet(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void addIssuerName(byte[] issuerName) throws IOException + { + issuerNames.add(new X500DistinguishedName(issuerName)); + } + + public void addIssuerName(String issuerName) + { + issuerNames.add(new X500DistinguishedName(issuerName)); + } + + public void addIssuerName(Principal issuerName) throws IOException + { + if (issuerName instanceof X500DistinguishedName) + issuerNames.add(issuerName); + else if (issuerName instanceof X500Principal) + issuerNames.add(new X500DistinguishedName(((X500Principal) issuerName).getEncoded())); + else + issuerNames.add(new X500DistinguishedName(issuerName.getName())); + } + + public Collection getIssuerNames() + { + return Collections.unmodifiableSet(issuerNames); + } + + public void addSubjectName(byte[] subjectName) throws IOException + { + subjectNames.add(new X500DistinguishedName(subjectName)); + } + + public void addSubjectName(String subjectName) throws IOException + { + subjectNames.add(new X500DistinguishedName(subjectName)); + } + + public void addSubjectName(Principal subjectName) throws IOException + { + if (subjectName instanceof X500DistinguishedName) + subjectNames.add(subjectName); + else if (subjectName instanceof X500Principal) + subjectNames.add(new X500DistinguishedName(((X500Principal) subjectName).getEncoded())); + else + subjectNames.add(new X500DistinguishedName(subjectName.getName())); + } + + public Collection getSubjectNames() + { + return Collections.unmodifiableSet(subjectNames); + } + + public Object clone() + { + X509CertSelectorImpl copy = new X509CertSelectorImpl(); + copy.issuerNames.addAll(issuerNames); + copy.subjectNames.addAll(subjectNames); + return copy; + } + + public boolean match(Certificate cert) + { + if (!(cert instanceof X509Certificate)) + return false; + boolean matchIssuer = false; + boolean matchSubject = false; + try + { + Principal p = ((X509Certificate) cert).getIssuerDN(); + X500DistinguishedName thisName = null; + if (p instanceof X500DistinguishedName) + thisName = (X500DistinguishedName) p; + else if (p instanceof X500Principal) + thisName = new X500DistinguishedName(((X500Principal) p).getEncoded()); + else + thisName = new X500DistinguishedName(p.getName()); + if (issuerNames.isEmpty()) + matchIssuer = true; + else + { + for (Iterator it = issuerNames.iterator(); it.hasNext(); ) + { + X500DistinguishedName name = (X500DistinguishedName) it.next(); + if (thisName.equals(name)) + { + matchIssuer = true; + break; + } + } + } + + p = ((X509Certificate) cert).getSubjectDN(); + thisName = null; + if (p instanceof X500DistinguishedName) + thisName = (X500DistinguishedName) p; + else if (p instanceof X500Principal) + thisName = new X500DistinguishedName(((X500Principal) p).getEncoded()); + else + thisName = new X500DistinguishedName(p.getName()); + if (subjectNames.isEmpty()) + matchSubject = true; + else + { + for (Iterator it = subjectNames.iterator(); it.hasNext(); ) + { + X500DistinguishedName name = (X500DistinguishedName) it.next(); + if (thisName.equals(name)) + { + matchSubject = true; + break; + } + } + } + } + catch (Exception x) + { + } + return matchIssuer && matchSubject; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/X509Certificate.java b/libjava/classpath/gnu/java/security/x509/X509Certificate.java new file mode 100644 index 000000000..14c565264 --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/X509Certificate.java @@ -0,0 +1,757 @@ +/* X509Certificate.java -- X.509 certificate. + Copyright (C) 2003, 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.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; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.x509.ext.BasicConstraints; +import gnu.java.security.x509.ext.ExtendedKeyUsage; +import gnu.java.security.x509.ext.Extension; +import gnu.java.security.x509.ext.GeneralName; +import gnu.java.security.x509.ext.IssuerAlternativeNames; +import gnu.java.security.x509.ext.KeyUsage; +import gnu.java.security.x509.ext.SubjectAlternativeNames; + +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.io.Serializable; +import java.io.StringWriter; +import java.math.BigInteger; +import java.security.AlgorithmParameters; +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Principal; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateNotYetValidException; +import java.security.cert.CertificateParsingException; +import java.security.interfaces.DSAParams; +import java.security.interfaces.DSAPublicKey; +import java.security.spec.DSAParameterSpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.logging.Logger; + +import javax.security.auth.x500.X500Principal; + +/** + * An implementation of X.509 certificates. + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +public class X509Certificate extends java.security.cert.X509Certificate + implements Serializable, GnuPKIExtension +{ + + // Constants and fields. + // ------------------------------------------------------------------------ + + private static final long serialVersionUID = -2491127588187038216L; + private static final Logger logger = SystemLogger.SYSTEM; + + protected static final OID ID_DSA = new OID ("1.2.840.10040.4.1"); + protected static final OID ID_DSA_WITH_SHA1 = new OID ("1.2.840.10040.4.3"); + protected static final OID ID_RSA = new OID ("1.2.840.113549.1.1.1"); + protected static final OID ID_RSA_WITH_MD2 = new OID ("1.2.840.113549.1.1.2"); + protected static final OID ID_RSA_WITH_MD5 = new OID ("1.2.840.113549.1.1.4"); + protected static final OID ID_RSA_WITH_SHA1 = new OID ("1.2.840.113549.1.1.5"); + protected static final OID ID_ECDSA_WITH_SHA1 = new OID ("1.2.840.10045.4.1"); + + // This object SHOULD be serialized with an instance of + // java.security.cert.Certificate.CertificateRep, thus all fields are + // transient. + + // The encoded certificate. + protected transient byte[] encoded; + + // TBSCertificate part. + protected transient byte[] tbsCertBytes; + protected transient int version; + protected transient BigInteger serialNo; + protected transient OID algId; + protected transient byte[] algVal; + protected transient X500DistinguishedName issuer; + protected transient Date notBefore; + protected transient Date notAfter; + protected transient X500DistinguishedName subject; + protected transient PublicKey subjectKey; + protected transient BitString issuerUniqueId; + protected transient BitString subjectUniqueId; + protected transient Map extensions; + + // Signature. + protected transient OID sigAlgId; + protected transient byte[] sigAlgVal; + protected transient byte[] signature; + + // Constructors. + // ------------------------------------------------------------------------ + + /** + * Create a new X.509 certificate from the encoded data. The input + * data are expected to be the ASN.1 DER encoding of the certificate. + * + * @param encoded The encoded certificate data. + * @throws IOException If the certificate cannot be read, possibly + * from a formatting error. + * @throws CertificateException If the data read is not an X.509 + * certificate. + */ + public X509Certificate(InputStream encoded) + throws CertificateException, IOException + { + super(); + extensions = new HashMap(); + try + { + parse(encoded); + } + catch (IOException ioe) + { + logger.log (Component.X509, "", ioe); + throw ioe; + } + catch (Exception e) + { + logger.log (Component.X509, "", e); + CertificateException ce = new CertificateException(e.getMessage()); + ce.initCause (e); + throw ce; + } + } + + protected X509Certificate() + { + extensions = new HashMap(); + } + + // X509Certificate methods. + // ------------------------------------------------------------------------ + + public void checkValidity() + throws CertificateExpiredException, CertificateNotYetValidException + { + checkValidity(new Date()); + } + + public void checkValidity(Date date) + throws CertificateExpiredException, CertificateNotYetValidException + { + if (date.compareTo(notBefore) < 0) + { + throw new CertificateNotYetValidException(); + } + if (date.compareTo(notAfter) > 0) + { + throw new CertificateExpiredException(); + } + } + + public int getVersion() + { + return version; + } + + public BigInteger getSerialNumber() + { + return serialNo; + } + + public Principal getIssuerDN() + { + return issuer; + } + + public X500Principal getIssuerX500Principal() + { + return new X500Principal(issuer.getDer()); + } + + public Principal getSubjectDN() + { + return subject; + } + + public X500Principal getSubjectX500Principal() + { + return new X500Principal(subject.getDer()); + } + + public Date getNotBefore() + { + return (Date) notBefore.clone(); + } + + public Date getNotAfter() + { + return (Date) notAfter.clone(); + } + + public byte[] getTBSCertificate() throws CertificateEncodingException + { + return (byte[]) tbsCertBytes.clone(); + } + + public byte[] getSignature() + { + return (byte[]) signature.clone(); + } + + public String getSigAlgName() + { + if (sigAlgId.equals(ID_DSA_WITH_SHA1)) + { + return "SHA1withDSA"; + } + if (sigAlgId.equals(ID_RSA_WITH_MD2)) + { + return "MD2withRSA"; + } + if (sigAlgId.equals(ID_RSA_WITH_MD5)) + { + return "MD5withRSA"; + } + if (sigAlgId.equals(ID_RSA_WITH_SHA1)) + { + return "SHA1withRSA"; + } + return "unknown"; + } + + public String getSigAlgOID() + { + return sigAlgId.toString(); + } + + public byte[] getSigAlgParams() + { + return (byte[]) sigAlgVal.clone(); + } + + public boolean[] getIssuerUniqueID() + { + if (issuerUniqueId != null) + { + return issuerUniqueId.toBooleanArray(); + } + return null; + } + + public boolean[] getSubjectUniqueID() + { + if (subjectUniqueId != null) + { + return subjectUniqueId.toBooleanArray(); + } + return null; + } + + public boolean[] getKeyUsage() + { + Extension e = getExtension(KeyUsage.ID); + if (e != null) + { + KeyUsage ku = (KeyUsage) e.getValue(); + boolean[] result = new boolean[9]; + boolean[] b = ku.getKeyUsage().toBooleanArray(); + System.arraycopy(b, 0, result, 0, b.length); + return result; + } + return null; + } + + public List getExtendedKeyUsage() throws CertificateParsingException + { + Extension e = getExtension(ExtendedKeyUsage.ID); + if (e != null) + { + List a = ((ExtendedKeyUsage) e.getValue()).getPurposeIds(); + List b = new ArrayList(a.size()); + for (OID oid : a) + b.add(oid.toString()); + return Collections.unmodifiableList(b); + } + return null; + } + + public int getBasicConstraints() + { + Extension e = getExtension(BasicConstraints.ID); + if (e != null) + { + return ((BasicConstraints) e.getValue()).getPathLengthConstraint(); + } + return -1; + } + + public Collection> getSubjectAlternativeNames() + throws CertificateParsingException + { + Extension e = getExtension(SubjectAlternativeNames.ID); + if (e != null) + { + List names + = ((SubjectAlternativeNames) e.getValue()).getNames(); + List> list = new ArrayList>(names.size()); + for (GeneralName name : names) + { + List n = new ArrayList(2); + n.add(name.kind().tag()); + n.add(name.name()); + list.add(n); + } + return list; + } + return null; + } + + public Collection> getIssuerAlternativeNames() + throws CertificateParsingException + { + Extension e = getExtension(IssuerAlternativeNames.ID); + if (e != null) + { + List names + = ((IssuerAlternativeNames) e.getValue()).getNames(); + List> list = new ArrayList>(names.size()); + for (GeneralName name : names) + { + List n = new ArrayList(2); + n.add(name.kind().tag()); + n.add(name.name()); + list.add(n); + } + return list; + } + return null; + } + + // X509Extension methods. + // ------------------------------------------------------------------------ + + public boolean hasUnsupportedCriticalExtension() + { + for (Iterator it = extensions.values().iterator(); it.hasNext(); ) + { + Extension e = (Extension) it.next(); + if (e.isCritical() && !e.isSupported()) + return true; + } + return false; + } + + public Set getCriticalExtensionOIDs() + { + HashSet s = new HashSet(); + for (Extension e : extensions.values()) + { + if (e.isCritical()) + s.add(e.getOid().toString()); + } + return Collections.unmodifiableSet(s); + } + + public Set getNonCriticalExtensionOIDs() + { + HashSet s = new HashSet(); + for (Extension e : extensions.values()) + { + if (!e.isCritical()) + s.add(e.getOid().toString()); + } + return Collections.unmodifiableSet(s); + } + + public byte[] getExtensionValue(String oid) + { + Extension e = getExtension(new OID(oid)); + if (e != null) + { + return e.getValue().getEncoded(); + } + return null; + } + + // GnuPKIExtension method. + // ------------------------------------------------------------------------- + + public Extension getExtension(OID oid) + { + return (Extension) extensions.get(oid); + } + + public Collection getExtensions() + { + return extensions.values(); + } + + // Certificate methods. + // ------------------------------------------------------------------------- + + public byte[] getEncoded() throws CertificateEncodingException + { + return (byte[]) encoded.clone(); + } + + public void verify(PublicKey key) + throws CertificateException, NoSuchAlgorithmException, + InvalidKeyException, NoSuchProviderException, SignatureException + { + Signature sig = Signature.getInstance(sigAlgId.toString()); + doVerify(sig, key); + } + + public void verify(PublicKey key, String provider) + throws CertificateException, NoSuchAlgorithmException, + InvalidKeyException, NoSuchProviderException, SignatureException + { + Signature sig = Signature.getInstance(sigAlgId.toString(), provider); + doVerify(sig, key); + } + + public String toString() + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + out.println(X509Certificate.class.getName() + " {"); + out.println(" TBSCertificate {"); + out.println(" version = " + version + ";"); + out.println(" serialNo = " + serialNo + ";"); + out.println(" signature = {"); + out.println(" algorithm = " + getSigAlgName() + ";"); + out.print(" parameters ="); + if (sigAlgVal != null) + { + out.println(); + out.print(Util.hexDump(sigAlgVal, " ")); + } + else + { + out.println(" null;"); + } + out.println(" }"); + out.println(" issuer = " + issuer.getName() + ";"); + out.println(" validity = {"); + out.println(" notBefore = " + notBefore + ";"); + out.println(" notAfter = " + notAfter + ";"); + out.println(" }"); + out.println(" subject = " + subject.getName() + ";"); + out.println(" subjectPublicKeyInfo = {"); + out.println(" algorithm = " + subjectKey.getAlgorithm()); + out.println(" key ="); + out.print(Util.hexDump(subjectKey.getEncoded(), " ")); + out.println(" };"); + out.println(" issuerUniqueId = " + issuerUniqueId + ";"); + out.println(" subjectUniqueId = " + subjectUniqueId + ";"); + out.println(" extensions = {"); + for (Iterator it = extensions.values().iterator(); it.hasNext(); ) + { + out.println(" " + it.next()); + } + out.println(" }"); + out.println(" }"); + out.println(" signatureAlgorithm = " + getSigAlgName() + ";"); + out.println(" signatureValue ="); + out.print(Util.hexDump(signature, " ")); + out.println("}"); + return str.toString(); + } + + public PublicKey getPublicKey() + { + return subjectKey; + } + + public boolean equals(Object other) + { + if (!(other instanceof X509Certificate)) + return false; + try + { + if (other instanceof X509Certificate) + return Arrays.equals(encoded, ((X509Certificate) other).encoded); + byte[] enc = ((X509Certificate) other).getEncoded(); + if (enc == null) + return false; + return Arrays.equals(encoded, enc); + } + catch (CertificateEncodingException cee) + { + return false; + } + } + + // Own methods. + // ------------------------------------------------------------------------ + + /** + * Verify this certificate's signature. + */ + private void doVerify(Signature sig, PublicKey key) + throws CertificateException, InvalidKeyException, SignatureException + { + logger.log (Component.X509, "verifying sig={0} key={1}", + new Object[] { sig, key }); + sig.initVerify(key); + sig.update(tbsCertBytes); + if (!sig.verify(signature)) + { + throw new CertificateException("signature not validated"); + } + } + + /** + * Parse a DER stream into an X.509 certificate. + * + * @param encoded The encoded bytes. + */ + private void parse(InputStream encoded) throws Exception + { + DERReader der = new DERReader(encoded); + + // Certificate ::= SEQUENCE { + DERValue cert = der.read(); + logger.log (Component.X509, "start Certificate len == {0}", + Integer.valueOf(cert.getLength())); + + this.encoded = cert.getEncoded(); + if (!cert.isConstructed()) + { + throw new IOException("malformed Certificate"); + } + + // TBSCertificate ::= SEQUENCE { + DERValue tbsCert = der.read(); + if (tbsCert.getValue() != DER.CONSTRUCTED_VALUE) + { + throw new IOException("malformed TBSCertificate"); + } + tbsCertBytes = tbsCert.getEncoded(); + logger.log (Component.X509, "start TBSCertificate len == {0}", + Integer.valueOf(tbsCert.getLength())); + + // Version ::= INTEGER [0] { v1(0), v2(1), v3(2) } + DERValue val = der.read(); + if (val.getTagClass() == DER.CONTEXT && val.getTag() == 0) + { + version = ((BigInteger) der.read().getValue()).intValue() + 1; + val = der.read(); + } + else + { + version = 1; + } + logger.log (Component.X509, "read version == {0}", + Integer.valueOf(version)); + + // SerialNumber ::= INTEGER + serialNo = (BigInteger) val.getValue(); + logger.log (Component.X509, "read serial number == {0}", serialNo); + + // AlgorithmIdentifier ::= SEQUENCE { + val = der.read(); + if (!val.isConstructed()) + { + throw new IOException("malformed AlgorithmIdentifier"); + } + int certAlgLen = val.getLength(); + logger.log (Component.X509, "start AlgorithmIdentifier len == {0}", + Integer.valueOf(certAlgLen)); + val = der.read(); + + // algorithm OBJECT IDENTIFIER, + algId = (OID) val.getValue(); + logger.log (Component.X509, "read algorithm ID == {0}", algId); + + // parameters ANY DEFINED BY algorithm OPTIONAL } + if (certAlgLen > val.getEncodedLength()) + { + val = der.read(); + if (val == null) + { + algVal = null; + } + else + { + algVal = val.getEncoded(); + + if (val.isConstructed()) + encoded.skip(val.getLength()); + } + logger.log (Component.X509, "read algorithm parameters == {0}", algVal); + } + + // issuer Name, + val = der.read(); + issuer = new X500DistinguishedName(val.getEncoded()); + der.skip(val.getLength()); + logger.log (Component.X509, "read issuer == {0}", issuer); + + // Validity ::= SEQUENCE { + // notBefore Time, + // notAfter Time } + if (!der.read().isConstructed()) + { + throw new IOException("malformed Validity"); + } + notBefore = (Date) der.read().getValue(); + logger.log (Component.X509, "read notBefore == {0}", notBefore); + notAfter = (Date) der.read().getValue(); + logger.log (Component.X509, "read notAfter == {0}", notAfter); + + // subject Name, + val = der.read(); + subject = new X500DistinguishedName(val.getEncoded()); + der.skip(val.getLength()); + logger.log (Component.X509, "read subject == {0}", subject); + + // SubjectPublicKeyInfo ::= SEQUENCE { + // algorithm AlgorithmIdentifier, + // subjectPublicKey BIT STRING } + DERValue spki = der.read(); + if (!spki.isConstructed()) + { + throw new IOException("malformed SubjectPublicKeyInfo"); + } + KeyFactory spkFac = KeyFactory.getInstance("X.509"); + subjectKey = spkFac.generatePublic(new X509EncodedKeySpec(spki.getEncoded())); + der.skip(spki.getLength()); + logger.log (Component.X509, "read subjectPublicKey == {0}", subjectKey); + + val = der.read(); + if (version >= 2 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 1) + { + byte[] b = (byte[]) val.getValue(); + issuerUniqueId = new BitString(b, 1, b.length-1, b[0] & 0xFF); + logger.log (Component.X509, "read issuerUniqueId == {0}", issuerUniqueId); + val = der.read(); + } + if (version >= 2 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 2) + { + byte[] b = (byte[]) val.getValue(); + subjectUniqueId = new BitString(b, 1, b.length-1, b[0] & 0xFF); + logger.log (Component.X509, "read subjectUniqueId == {0}", subjectUniqueId); + val = der.read(); + } + if (version >= 3 && val.getTagClass() != DER.UNIVERSAL && val.getTag() == 3) + { + val = der.read(); + logger.log (Component.X509, "start Extensions len == {0}", + Integer.valueOf(val.getLength())); + int len = 0; + while (len < val.getLength()) + { + DERValue ext = der.read(); + logger.log (Component.X509, "start extension len == {0}", + Integer.valueOf(ext.getLength())); + Extension e = new Extension(ext.getEncoded()); + extensions.put(e.getOid(), e); + der.skip(ext.getLength()); + len += ext.getEncodedLength(); + logger.log (Component.X509, "read extension {0} == {1}", + new Object[] { e.getOid (), e }); + logger.log (Component.X509, "count == {0}", Integer.valueOf(len)); + } + + val = der.read (); + } + + logger.log (Component.X509, "read value {0}", val); + if (!val.isConstructed()) + { + throw new CertificateException ("malformed AlgorithmIdentifier"); + } + int sigAlgLen = val.getLength(); + logger.log (Component.X509, "start AlgorithmIdentifier len == {0}", + Integer.valueOf(sigAlgLen)); + val = der.read(); + sigAlgId = (OID) val.getValue(); + logger.log (Component.X509, "read algorithm id == {0}", sigAlgId); + if (sigAlgLen > val.getEncodedLength()) + { + val = der.read(); + if (val.getValue() == null) + { + if (subjectKey instanceof DSAPublicKey) + { + AlgorithmParameters params = + AlgorithmParameters.getInstance("DSA"); + DSAParams dsap = ((DSAPublicKey) subjectKey).getParams(); + DSAParameterSpec spec = + new DSAParameterSpec(dsap.getP(), dsap.getQ(), dsap.getG()); + params.init(spec); + sigAlgVal = params.getEncoded(); + } + } + else + { + sigAlgVal = (byte[]) val.getEncoded(); + } + if (val.isConstructed()) + { + encoded.skip(val.getLength()); + } + logger.log (Component.X509, "read parameters == {0}", sigAlgVal); + } + signature = ((BitString) der.read().getValue()).toByteArray(); + logger.log (Component.X509, "read signature ==\n{0}", Util.hexDump(signature, ">>>> ")); + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/AuthorityKeyIdentifier.java b/libjava/classpath/gnu/java/security/x509/ext/AuthorityKeyIdentifier.java new file mode 100644 index 000000000..a94b76f09 --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/AuthorityKeyIdentifier.java @@ -0,0 +1,133 @@ +/* AuthorityKeyIdentifier.java -- Authority key identifier extension. + 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.security.x509.ext; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.x509.Util; + +import java.io.IOException; +import java.math.BigInteger; + +public class AuthorityKeyIdentifier extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.35"); + + private final byte[] keyIdentifier; + private final GeneralNames authorityCertIssuer; + private final BigInteger authorityCertSerialNumber; + + // Contstructor. + // ------------------------------------------------------------------------- + + public AuthorityKeyIdentifier(final byte[] encoded) throws IOException + { + super(encoded); + DERReader der = new DERReader(encoded); + + // AuthorityKeyIdentifier ::= SEQUENCE { + DERValue val = der.read(); + if (!val.isConstructed()) + throw new IOException("malformed AuthorityKeyIdentifier"); + if (val.getLength() > 0) + val = der.read(); + + // keyIdentifier [0] KeyIdentifier OPTIONAL, + // KeyIdentifier ::= OCTET STRING + if (val.getTagClass() == DER.APPLICATION && val.getTag() == 0) + { + keyIdentifier = (byte[]) val.getValue(); + val = der.read(); + } + else + keyIdentifier = null; + + // authorityCertIssuer [1] GeneralNames OPTIONAL, + if (val.getTagClass() == DER.APPLICATION && val.getTag() == 1) + { + byte[] b = val.getEncoded(); + b[0] = (byte) (DER.CONSTRUCTED|DER.SEQUENCE); + authorityCertIssuer = new GeneralNames(b); + der.skip(val.getLength()); + val = der.read(); + } + else + authorityCertIssuer = null; + + // authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL } + if (val.getTagClass() == DER.APPLICATION && val.getTag() == 2) + { + authorityCertSerialNumber = new BigInteger((byte[]) val.getValue()); + } + else + authorityCertSerialNumber = null; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public byte[] getKeyIdentifier() + { + return keyIdentifier != null ? (byte[]) keyIdentifier.clone() : null; + } + + public GeneralNames getAuthorityCertIssuer() + { + return authorityCertIssuer; + } + + public BigInteger getAuthorityCertSerialNumber() + { + return authorityCertSerialNumber; + } + + public String toString() + { + return AuthorityKeyIdentifier.class.getName() + " [ keyId=" + + (keyIdentifier != null ? Util.toHexString (keyIdentifier, ':') : "nil") + + " authorityCertIssuer=" + authorityCertIssuer + + " authorityCertSerialNumbe=" + authorityCertSerialNumber + " ]"; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/BasicConstraints.java b/libjava/classpath/gnu/java/security/x509/ext/BasicConstraints.java new file mode 100644 index 000000000..d8f5c6158 --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/BasicConstraints.java @@ -0,0 +1,129 @@ +/* BasicConstraints.java -- the basic constraints extension. + 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.security.x509.ext; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +import java.io.IOException; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + +public class BasicConstraints extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.19"); + + private final boolean ca; + private final int pathLenConstraint; + + // Constructor. + // ------------------------------------------------------------------------- + + public BasicConstraints(final byte[] encoded) throws IOException + { + super(encoded); + DERReader der = new DERReader(encoded); + DERValue bc = der.read(); + if (!bc.isConstructed()) + throw new IOException("malformed BasicConstraints"); + DERValue val = bc; + if (bc.getLength() > 0) + val = der.read(); + if (val.getTag() == DER.BOOLEAN) + { + ca = ((Boolean) val.getValue()).booleanValue(); + if (val.getEncodedLength() < bc.getLength()) + val = der.read(); + } + else + ca = false; + if (val.getTag() == DER.INTEGER) + { + pathLenConstraint = ((BigInteger) val.getValue()).intValue(); + } + else + pathLenConstraint = -1; + } + + public BasicConstraints (final boolean ca, final int pathLenConstraint) + { + this.ca = ca; + this.pathLenConstraint = pathLenConstraint; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public boolean isCA() + { + return ca; + } + + public int getPathLengthConstraint() + { + return pathLenConstraint; + } + + public byte[] getEncoded() + { + if (encoded == null) + { + List bc = new ArrayList (2); + bc.add (new DERValue (DER.BOOLEAN, Boolean.valueOf (ca))); + if (pathLenConstraint >= 0) + bc.add (new DERValue (DER.INTEGER, + BigInteger.valueOf ((long) pathLenConstraint))); + encoded = new DERValue (DER.CONSTRUCTED|DER.SEQUENCE, bc).getEncoded(); + } + return (byte[]) encoded.clone(); + } + + public String toString() + { + return BasicConstraints.class.getName() + " [ isCA=" + ca + + " pathLen=" + pathLenConstraint + " ]"; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/CRLNumber.java b/libjava/classpath/gnu/java/security/x509/ext/CRLNumber.java new file mode 100644 index 000000000..36b1c7b5f --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/CRLNumber.java @@ -0,0 +1,97 @@ +/* CRLNumber.java -- CRL number extension. + 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.security.x509.ext; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +import java.io.IOException; +import java.math.BigInteger; + +public class CRLNumber extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.20"); + + private final BigInteger number; + + // Constructor. + // ------------------------------------------------------------------------- + + public CRLNumber(final byte[] encoded) throws IOException + { + super(encoded); + DERValue val = DERReader.read(encoded); + if (val.getTag() != DER.INTEGER) + throw new IOException("malformed CRLNumber"); + number = (BigInteger) val.getValue(); + } + + public CRLNumber (final BigInteger number) + { + this.number = number; + } + + // Instance method. + // ------------------------------------------------------------------------- + + public BigInteger getNumber() + { + return number; + } + + public byte[] getEncoded() + { + if (encoded == null) + { + encoded = new DERValue (DER.INTEGER, number).getEncoded(); + } + return (byte[]) encoded.clone(); + } + + public String toString() + { + return CRLNumber.class.getName() + " [ " + number + " ]"; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/CertificatePolicies.java b/libjava/classpath/gnu/java/security/x509/ext/CertificatePolicies.java new file mode 100644 index 000000000..874b8eeeb --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/CertificatePolicies.java @@ -0,0 +1,205 @@ +/* CertificatePolicies.java -- certificate policy extension. + 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.security.x509.ext; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +import java.io.IOException; +import java.security.cert.PolicyQualifierInfo; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +public class CertificatePolicies extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.32"); + + private final List policies; + private final Map> policyQualifierInfos; + + // Constructor. + // ------------------------------------------------------------------------- + + public CertificatePolicies(final byte[] encoded) throws IOException + { + super(encoded); + DERReader der = new DERReader(encoded); + DERValue pol = der.read(); + if (!pol.isConstructed()) + throw new IOException("malformed CertificatePolicies"); + + int len = 0; + LinkedList policyList = new LinkedList(); + HashMap> qualifierMap + = new HashMap>(); + while (len < pol.getLength()) + { + DERValue policyInfo = der.read(); + if (!policyInfo.isConstructed()) + throw new IOException("malformed PolicyInformation"); + DERValue val = der.read(); + if (val.getTag() != DER.OBJECT_IDENTIFIER) + throw new IOException("malformed CertPolicyId"); + OID policyId = (OID) val.getValue(); + policyList.add(policyId); + if (val.getEncodedLength() < policyInfo.getLength()) + { + DERValue qual = der.read(); + int len2 = 0; + LinkedList quals = new LinkedList(); + while (len2 < qual.getLength()) + { + val = der.read(); + quals.add(new PolicyQualifierInfo(val.getEncoded())); + der.skip(val.getLength()); + len2 += val.getEncodedLength(); + } + qualifierMap.put(policyId, quals); + } + len += policyInfo.getEncodedLength(); + } + + policies = Collections.unmodifiableList(policyList); + policyQualifierInfos = Collections.unmodifiableMap(qualifierMap); + } + + public CertificatePolicies (final List policies, + final Map> policyQualifierInfos) + { + for (Iterator it = policies.iterator(); it.hasNext(); ) + if (!(it.next() instanceof OID)) + throw new IllegalArgumentException ("policies must be OIDs"); + for (Iterator it = policyQualifierInfos.entrySet().iterator(); it.hasNext();) + { + Map.Entry e = (Map.Entry) it.next(); + if (!(e.getKey() instanceof OID) || !policies.contains (e.getKey())) + throw new IllegalArgumentException + ("policyQualifierInfos keys must be OIDs"); + if (!(e.getValue() instanceof List)) + throw new IllegalArgumentException + ("policyQualifierInfos values must be Lists of PolicyQualifierInfos"); + for (Iterator it2 = ((List) e.getValue()).iterator(); it.hasNext(); ) + if (!(it2.next() instanceof PolicyQualifierInfo)) + throw new IllegalArgumentException + ("policyQualifierInfos values must be Lists of PolicyQualifierInfos"); + } + this.policies = Collections.unmodifiableList (new ArrayList(policies)); + this.policyQualifierInfos = Collections.unmodifiableMap + (new HashMap>(policyQualifierInfos)); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public List getPolicies() + { + return policies; + } + + /** + * Returns the list of policy OIDs, formatted as dotted-decimal strings. + * + * @return + */ + public List getPolicyStrings() + { + List l = new ArrayList(policies.size()); + for (OID oid : policies) + { + l.add(oid.toString()); + } + return l; + } + + public List getPolicyQualifierInfos(OID oid) + { + return policyQualifierInfos.get(oid); + } + + public byte[] getEncoded() + { + if (encoded == null) + { + List pol = new ArrayList(policies.size()); + for (Iterator it = policies.iterator(); it.hasNext(); ) + { + OID policy = it.next(); + List qualifiers = getPolicyQualifierInfos(policy); + List l = new ArrayList(qualifiers == null ? 1 : 2); + l.add(new DERValue(DER.OBJECT_IDENTIFIER, policy)); + if (qualifiers != null) + { + List ll = new ArrayList(qualifiers.size()); + for (Iterator it2 = qualifiers.iterator(); it.hasNext(); ) + { + PolicyQualifierInfo info = it2.next(); + try + { + ll.add(DERReader.read(info.getEncoded())); + } + catch (IOException ioe) + { + } + } + l.add(new DERValue(DER.CONSTRUCTED|DER.SEQUENCE, ll)); + } + pol.add(new DERValue(DER.CONSTRUCTED|DER.SEQUENCE, l)); + } + encoded = new DERValue(DER.CONSTRUCTED|DER.SEQUENCE, pol).getEncoded(); + } + return (byte[]) encoded.clone(); + } + + public String toString() + { + return CertificatePolicies.class.getName() + " [ policies=" + policies + + " policyQualifierInfos=" + policyQualifierInfos + " ]"; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/ExtendedKeyUsage.java b/libjava/classpath/gnu/java/security/x509/ext/ExtendedKeyUsage.java new file mode 100644 index 000000000..428013d04 --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/ExtendedKeyUsage.java @@ -0,0 +1,95 @@ +/* ExtendedKeyUsage.java -- the extended key usage extension. + 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.security.x509.ext; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +import java.io.IOException; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +public class ExtendedKeyUsage extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.37"); + + private final List purposeIds; + + // Constructor. + // ------------------------------------------------------------------------- + + public ExtendedKeyUsage(final byte[] encoded) throws IOException + { + super(encoded); + DERReader der = new DERReader(encoded); + DERValue usageList = der.read(); + if (!usageList.isConstructed()) + throw new IOException("malformed ExtKeyUsageSyntax"); + int len = 0; + purposeIds = new LinkedList(); + while (len < usageList.getLength()) + { + DERValue val = der.read(); + if (val.getTag() != DER.OBJECT_IDENTIFIER) + throw new IOException("malformed KeyPurposeId"); + purposeIds.add((OID) val.getValue()); + len += val.getEncodedLength(); + } + } + + // Instance method. + // ------------------------------------------------------------------------- + + public List getPurposeIds() + { + return Collections.unmodifiableList(purposeIds); + } + + public String toString() + { + return ExtendedKeyUsage.class.getName() + " [ " + purposeIds + " ]"; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/Extension.java b/libjava/classpath/gnu/java/security/x509/ext/Extension.java new file mode 100644 index 000000000..2b7e96d5a --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/Extension.java @@ -0,0 +1,297 @@ +/* Extension.java -- an X.509 certificate or CRL extension. + 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.security.x509.ext; + +import gnu.java.security.Configuration; +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.x509.Util; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.logging.Logger; + +public class Extension +{ + private static final Logger log = Logger.getLogger(Extension.class.getName()); + /** + * This extension's object identifier. + */ + protected final OID oid; + + /** + * The criticality flag. + */ + protected final boolean critical; + + /** + * Whether or not this extension is locally supported. + */ + protected boolean isSupported; + + /** + * The extension value. + */ + protected final Value value; + + /** + * The DER encoded form. + */ + protected byte[] encoded; + + // Constructors. + // ------------------------------------------------------------------------- + + public Extension(byte[] encoded) throws IOException + { + this.encoded = (byte[]) encoded.clone(); + DERReader der = new DERReader(encoded); + + // Extension ::= SEQUENCE { + DERValue val = der.read(); + if (Configuration.DEBUG) + log.fine("read val tag == " + val.getTag() + " len == " + val.getLength()); + if (!val.isConstructed()) + throw new IOException("malformed Extension"); + + // extnID OBJECT IDENTIFIER, + val = der.read(); + if (val.getTag() != DER.OBJECT_IDENTIFIER) + throw new IOException("expecting OBJECT IDENTIFIER"); + oid = (OID) val.getValue(); + if (Configuration.DEBUG) + log.fine("read oid == " + oid); + + // critical BOOLEAN DEFAULT FALSE, + val = der.read(); + if (val.getTag() == DER.BOOLEAN) + { + critical = ((Boolean) val.getValue()).booleanValue(); + val = der.read(); + } + else + critical = false; + if (Configuration.DEBUG) + log.fine("is critical == " + critical); + + // extnValue OCTET STRING } + if (val.getTag() != DER.OCTET_STRING) + throw new IOException("expecting OCTET STRING"); + byte[] encval = (byte[]) val.getValue(); + isSupported = true; + if (oid.equals(AuthorityKeyIdentifier.ID)) + { + value = new AuthorityKeyIdentifier(encval); + } + else if (oid.equals(SubjectKeyIdentifier.ID)) + { + value = new SubjectKeyIdentifier(encval); + } + else if (oid.equals(KeyUsage.ID)) + { + value = new KeyUsage(encval); + } + else if (oid.equals(PrivateKeyUsagePeriod.ID)) + { + value = new PrivateKeyUsagePeriod(encval); + } + else if (oid.equals(CertificatePolicies.ID)) + { + value = new CertificatePolicies(encval); + } + else if (oid.equals (PolicyConstraint.ID)) + { + value = new PolicyConstraint (encval); + } + else if (oid.equals(PolicyMappings.ID)) + { + value = new PolicyMappings(encval); + } + else if (oid.equals(SubjectAlternativeNames.ID)) + { + value = new SubjectAlternativeNames(encval); + } + else if (oid.equals(IssuerAlternativeNames.ID)) + { + value = new IssuerAlternativeNames(encval); + } + else if (oid.equals(BasicConstraints.ID)) + { + value = new BasicConstraints(encval); + } + else if (oid.equals(ExtendedKeyUsage.ID)) + { + value = new ExtendedKeyUsage(encval); + } + else if (oid.equals(CRLNumber.ID)) + { + value = new CRLNumber(encval); + } + else if (oid.equals(ReasonCode.ID)) + { + value = new ReasonCode(encval); + } + else if (oid.equals(NameConstraints.ID)) + { + value = new NameConstraints(encval); + } + else + { + value = new Value(encval); + isSupported = false; + } + if (Configuration.DEBUG) + log.fine("read value == " + value); + } + + public Extension (final OID oid, final Value value, final boolean critical) + { + this.oid = oid; + this.value = value; + this.critical = critical; + isSupported = true; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public OID getOid() + { + return oid; + } + + public boolean isCritical() + { + return critical; + } + + public boolean isSupported() + { + return isSupported; + } + + public Value getValue() + { + return value; + } + + public byte[] getEncoded() + { + if (encoded == null) + encode(); + return (byte[]) encoded.clone(); + } + + public String toString() + { + return Extension.class.getName() + " [ id=" + oid + " critical=" + + critical + " value=" + value + " ]"; + } + + public DERValue getDerValue() + { + List ext = new ArrayList(3); + ext.add(new DERValue(DER.OBJECT_IDENTIFIER, oid)); + ext.add(new DERValue(DER.BOOLEAN, Boolean.valueOf(critical))); + ext.add(new DERValue(DER.OCTET_STRING, value.getEncoded())); + return new DERValue(DER.CONSTRUCTED|DER.SEQUENCE, ext); + } + + // Own methods. + // ------------------------------------------------------------------------- + + private void encode() + { + encoded = getDerValue().getEncoded(); + } + + // Inner class. + // ------------------------------------------------------------------------- + + public static class Value + { + + // Fields. + // ----------------------------------------------------------------------- + + protected byte[] encoded; + + // Constructor. + // ----------------------------------------------------------------------- + + public Value(byte[] encoded) + { + this.encoded = (byte[]) encoded.clone(); + } + + protected Value() { } + + // Instance methods. + // ----------------------------------------------------------------------- + + public byte[] getEncoded() + { + return (byte[]) encoded; + } + + public int hashCode() + { + int result = 0; + for (int i = 0; i < encoded.length; ++i) + result = result * 31 + encoded[i]; + return result; + } + + public boolean equals(Object o) + { + if (!(o instanceof Value)) + return false; + return Arrays.equals(encoded, ((Value) o).encoded); + } + + public String toString() + { + return Util.toHexString(encoded, ':'); + } + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/GeneralName.java b/libjava/classpath/gnu/java/security/x509/ext/GeneralName.java new file mode 100644 index 000000000..f399de1b7 --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/GeneralName.java @@ -0,0 +1,232 @@ +/* GeneralName.java -- a GeneralName. + 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.java.security.x509.ext; + +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.x509.Util; + +import java.io.IOException; +import java.util.Arrays; + +/** + * The GeneralName structure from X.509. + * + *
+  GeneralName ::= CHOICE {
+    otherName                       [0]     OtherName,
+    rfc822Name                      [1]     IA5String,
+    dNSName                         [2]     IA5String,
+    x400Address                     [3]     ORAddress,
+    directoryName                   [4]     Name,
+    ediPartyName                    [5]     EDIPartyName,
+    uniformResourceIdentifier       [6]     IA5String,
+    iPAddress                       [7]     OCTET STRING,
+    registeredID                    [8]     OBJECT IDENTIFIER }
+
+  OtherName ::= SEQUENCE {
+    type-id    OBJECT IDENTIFIER,
+    value      [0] EXPLICIT ANY DEFINED BY type-id }
+
+  EDIPartyName ::= SEQUENCE {
+    nameAssigner            [0]     DirectoryString OPTIONAL,
+    partyName               [1]     DirectoryString }
+
+ * + * @author Casey Marshall (csm@gnu.org) + */ +public class GeneralName +{ + public static enum Kind + { + otherName (0), + rfc822Name (1), + dNSName (2), + x400Address (3), + directoryName (4), + ediPartyName (5), + uniformResourceIdentifier (6), + iPAddress (7), + registeredId (8); + + private int tag; + + private Kind(int tag) + { + this.tag = tag; + } + + public static Kind forTag(final int tag) + { + switch (tag) + { + case 0: return otherName; + case 1: return rfc822Name; + case 2: return dNSName; + case 3: return x400Address; + case 4: return directoryName; + case 5: return ediPartyName; + case 6: return uniformResourceIdentifier; + case 7: return iPAddress; + case 8: return registeredId; + } + + throw new IllegalArgumentException("invalid tag: " + tag); + } + + public int tag() + { + return tag; + } + }; + + private final Kind kind; + private final byte[] name; + private final byte[] encoded; + + public GeneralName(byte[] encoded) throws IOException + { + DERReader reader = new DERReader(encoded); + DERValue value = reader.read(); + + if (value.getTagClass() != DER.CONTEXT) + throw new IOException("malformed GeneralName"); + + this.encoded = value.getEncoded(); + + kind = Kind.forTag(value.getTag()); + switch (kind) + { + case otherName: + name = value.getEncoded(); + name[0] = (byte) (DER.CONSTRUCTED | DER.SEQUENCE); + // Skip the two fields of the name. + reader.read(); // OID + reader.read(); // Octet string + break; + + case rfc822Name: + name = (byte[]) value.getValue(); + break; + + case dNSName: + name = (byte[]) value.getValue(); + break; + + case x400Address: + name = (byte[]) value.getValue(); + break; + + case directoryName: + name = value.getEncoded(); + name[0] = (byte) (DER.CONSTRUCTED | DER.SEQUENCE); + break; + + case ediPartyName: + name = value.getEncoded(); + name[0] = (byte) (DER.CONSTRUCTED | DER.SEQUENCE); + break; + + case uniformResourceIdentifier: + name = (byte[]) value.getValue(); + break; + + case iPAddress: + name = (byte[]) value.getValue(); + break; + + case registeredId: + name = value.getEncoded(); + name[0] = DER.OBJECT_IDENTIFIER; + break; + + default: + name = null; // Not reached. + } + } + + public GeneralName(Kind kind, byte[] name) + { + this.kind = kind; + this.name = (byte[]) name.clone(); + this.encoded = null; + } + + public Kind kind() + { + return kind; + } + + public byte[] name() + { + return (byte[]) name.clone(); + } + + public byte[] encoded() + { + try + { + return (byte[]) encoded.clone(); + } + catch (NullPointerException npe) + { + return null; + } + } + + public boolean equals(Object o) + { + try + { + GeneralName that = (GeneralName) o; + return (that.kind() == kind() && Arrays.equals(name, that.name)); + } + catch (ClassCastException cce) + { + return false; + } + } + + public String toString() + { + return (super.toString() + " [ kind=" + kind + "; name=" + + Util.hexDump(name, "") + " ]"); + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/GeneralNames.java b/libjava/classpath/gnu/java/security/x509/ext/GeneralNames.java new file mode 100644 index 000000000..f56ee963b --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/GeneralNames.java @@ -0,0 +1,89 @@ +/* GeneralNames.java -- the GeneralNames object + 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.security.x509.ext; + +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +import java.io.IOException; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +public class GeneralNames +{ + + // Instance methods. + // ------------------------------------------------------------------------- + + private List names; + + // Constructor. + // ------------------------------------------------------------------------- + + public GeneralNames(final byte[] encoded) throws IOException + { + names = new LinkedList(); + DERReader der = new DERReader(encoded); + DERValue nameList = der.read(); + if (!nameList.isConstructed()) + throw new IOException("malformed GeneralNames"); + int len = 0; + while (len < nameList.getLength()) + { + DERValue name = der.read(); + GeneralName generalName = new GeneralName(name.getEncoded()); + names.add(generalName); + len += name.getEncodedLength(); + } + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public List getNames() + { + return Collections.unmodifiableList(names); + } + + public String toString() + { + return GeneralNames.class.getName() + " [ " + names + " ]"; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/GeneralSubtree.java b/libjava/classpath/gnu/java/security/x509/ext/GeneralSubtree.java new file mode 100644 index 000000000..5d688deaa --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/GeneralSubtree.java @@ -0,0 +1,156 @@ +/* GeneralSubtree.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.java.security.x509.ext; + +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +import java.io.IOException; +import java.math.BigInteger; + +/** + * The GeneralSubtree structure, a part of the {@link NameConstraints} + * extension. + * + *
+  GeneralSubtree ::= SEQUENCE {
+    base                    GeneralName,
+    minimum         [0]     BaseDistance DEFAULT 0,
+    maximum         [1]     BaseDistance OPTIONAL }
+
+  BaseDistance ::= INTEGER (0..MAX)
+ * + * @author Casey Marshall (csm@gnu.org) + */ +public class GeneralSubtree +{ + private final GeneralName base; + private final int minimum; + private final int maximum; + + public GeneralSubtree(byte[] encoded) throws IOException + { + DERReader reader = new DERReader(encoded); + DERValue generalSubtree = reader.read(); + + if (!generalSubtree.isConstructed()) + throw new IOException("malformed GeneralSubtree"); + + DERValue generalName = reader.read(); + base = new GeneralName(generalName.getEncoded()); + if (generalName.isConstructed()) + reader.skip(generalName.getLength()); + + int len = generalName.getEncodedLength(); + if (len < generalSubtree.getLength()) + { + DERValue distance = reader.read(); + if (distance.getTag() == 0) + { + minimum = ((BigInteger) distance.getValue()).intValue(); + len += distance.getEncodedLength(); + if (len < generalSubtree.getLength()) + { + distance = reader.read(); + if (distance.getTag() != 1) + throw new IOException("unexpected tag " + + distance.getTag() + + " (expected 1 for GeneralSubtree maximum distance)"); + maximum = ((BigInteger) distance.getValue()).intValue(); + } + else + { + maximum = -1; + } + } + else if (distance.getTag() == 1) + { + minimum = 1; + maximum = ((BigInteger) distance.getValue()).intValue(); + } + else + { + throw new IOException("unexpected tag " + distance.getTag() + + " (expected 0 or 1 for GeneralSubtree distance)"); + } + } + else + { + minimum = 0; + maximum = -1; + } + } + + /** + * Returns the base name. + * + * @return The base name. + */ + public GeneralName base() + { + return base; + } + + /** + * Returns the minimum base distance, possibly zero. + * + * @return The minimum base distance. + */ + public int minimum() + { + return minimum; + } + + /** + * Returns the maximum base distance, or -1 if this value was not specified. + * + * @return The maximum base distance. + */ + public int maximum() + { + return maximum; + } + + public String toString() + { + return (GeneralSubtree.class.getName() + " [ base=" + base + + "; minimum=" + minimum + "; maximim=" + maximum + + " ]"); + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/IssuerAlternativeNames.java b/libjava/classpath/gnu/java/security/x509/ext/IssuerAlternativeNames.java new file mode 100644 index 000000000..080070b98 --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/IssuerAlternativeNames.java @@ -0,0 +1,77 @@ +/* IssuerAlternatuveNames.java -- issuer alternative names extension. + 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.security.x509.ext; + +import gnu.java.security.OID; + +import java.io.IOException; +import java.util.List; + +public class IssuerAlternativeNames extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.18"); + + private final GeneralNames names; + + // Constructor. + // ------------------------------------------------------------------------- + + public IssuerAlternativeNames(final byte[] encoded) throws IOException + { + super(encoded); + names = new GeneralNames(encoded); + } + + // Instance method. + // ------------------------------------------------------------------------- + + public List getNames() + { + return names.getNames(); + } + + public String toString() + { + return IssuerAlternativeNames.class.getName() + " [ " + names + " ]"; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/KeyUsage.java b/libjava/classpath/gnu/java/security/x509/ext/KeyUsage.java new file mode 100644 index 000000000..dcd98181e --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/KeyUsage.java @@ -0,0 +1,92 @@ +/* KeyUsage.java -- the key usage extension. + 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.security.x509.ext; + +import gnu.java.security.OID; +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 java.io.IOException; + +public class KeyUsage extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.15"); + public static final int DIGITAL_SIGNATURE = 0; + public static final int NON_REPUDIATION = 1; + public static final int KEY_ENCIPHERMENT = 2; + public static final int DATA_ENCIPHERMENT = 3; + public static final int KEY_AGREEMENT = 4; + public static final int KEY_CERT_SIGN = 5; + public static final int CRL_SIGN = 6; + public static final int ENCIPHER_ONLY = 7; + public static final int DECIPHER_ONLY = 8; + + private final BitString keyUsage; + + // Constructor. + // ------------------------------------------------------------------------- + + public KeyUsage(final byte[] encoded) throws IOException + { + super(encoded); + DERValue val = DERReader.read(encoded); + if (val.getTag() != DER.BIT_STRING) + throw new IOException("malformed KeyUsage"); + keyUsage = (BitString) val.getValue(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public BitString getKeyUsage() + { + return keyUsage; + } + + public String toString() + { + return KeyUsage.class.getName() + " [ " + keyUsage + " ]"; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/NameConstraints.java b/libjava/classpath/gnu/java/security/x509/ext/NameConstraints.java new file mode 100644 index 000000000..8f374d560 --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/NameConstraints.java @@ -0,0 +1,161 @@ +/* NameConstraints.java -- the NameConstraints X.509 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.java.security.x509.ext; + +import gnu.java.security.OID; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.x509.ext.Extension.Value; + +import java.io.IOException; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +/** + * The NameConstraints extension. From RFC 3280, section 4.2.1.11, this + * extension is defined as: + * + *
+  id-ce-nameConstraints OBJECT IDENTIFIER ::=  { id-ce 30 }
+
+  NameConstraints ::= SEQUENCE {
+    permittedSubtrees       [0]     GeneralSubtrees OPTIONAL,
+    excludedSubtrees        [1]     GeneralSubtrees OPTIONAL }
+
+  GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
+
+  GeneralSubtree ::= SEQUENCE {
+    base                    GeneralName,
+    minimum         [0]     BaseDistance DEFAULT 0,
+    maximum         [1]     BaseDistance OPTIONAL }
+
+  BaseDistance ::= INTEGER (0..MAX)
+  
+ * + * See also the classes {@link GeneralNames} and {@link GeneralSubtree}. + * + * @author csm + */ +public class NameConstraints extends Value +{ + public static final OID ID = new OID("2.5.29.30"); + + private List permittedSubtrees; + private List excludedSubtrees; + + public NameConstraints(byte[] encoded) throws IOException + { + super(encoded); + + DERReader der = new DERReader(encoded); + DERValue value = der.read(); + if (!value.isConstructed()) + { + throw new IOException("malformed NameConstraints"); + } + + permittedSubtrees = new LinkedList(); + excludedSubtrees = new LinkedList(); + int len = 0; + if (len < value.getLength()) + { + DERValue subtrees = der.read(); + if (subtrees.getTag() == 0) + { + int len2 = 0; + while (len2 < subtrees.getLength()) + { + DERValue subtree = der.read(); + permittedSubtrees.add(new GeneralSubtree(subtree.getEncoded())); + der.skip(subtree.getLength()); + len2 += subtree.getEncodedLength(); + } + len += subtrees.getEncodedLength(); + + if (len < value.getLength()) + { + subtrees = der.read(); + if (subtrees.getTag() != 1) + throw new IOException("unexpected tag " + subtrees.getTag() + + " (expecting 1 for excludedSubtrees)"); + len2 = 0; + while (len2 < subtrees.getLength()) + { + DERValue subtree = der.read(); + excludedSubtrees.add(new GeneralSubtree(subtree.getEncoded())); + der.skip(subtree.getLength()); + len2 += subtree.getEncodedLength(); + } + } + } + else if (subtrees.getTag() == 1) + { + int len2 = 0; + while (len2 < subtrees.getLength()) + { + DERValue subtree = der.read(); + excludedSubtrees.add(new GeneralSubtree(subtree.getEncoded())); + der.skip(subtree.getLength()); + len2 += subtree.getEncodedLength(); + } + } + else + throw new IOException("unexpected tag " + subtrees.getTag() + + " (expecting 0 or 1)"); + } + } + + public List permittedSubtrees() + { + return Collections.unmodifiableList(permittedSubtrees); + } + + public List excludedSubtrees() + { + return Collections.unmodifiableList(excludedSubtrees); + } + + public String toString() + { + return NameConstraints.class.getName() + " [ permittedSubtrees=" + + permittedSubtrees + "; excludedSubtrees=" + excludedSubtrees + + " ]"; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/PolicyConstraint.java b/libjava/classpath/gnu/java/security/x509/ext/PolicyConstraint.java new file mode 100644 index 000000000..20cf552a0 --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/PolicyConstraint.java @@ -0,0 +1,107 @@ +/* PolicyConstraint.java -- policyConstraint extension + 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.security.x509.ext; + +import gnu.java.security.OID; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +import java.io.IOException; +import java.math.BigInteger; + +public class PolicyConstraint extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID ("2.5.29.36"); + + private final int requireExplicitPolicy; + private final int inhibitPolicyMapping; + + // Constructors. + // ------------------------------------------------------------------------- + + public PolicyConstraint (final byte[] encoded) throws IOException + { + super (encoded); + int rpc = -1, ipm = -1; + DERReader der = new DERReader(encoded); + DERValue pc = der.read(); + if (!pc.isConstructed()) + throw new IOException("malformed PolicyConstraints"); + DERValue val; + int len = pc.getLength(); + while (len > 0) + { + val = der.read(); + if (val.getTag() == 0) + rpc = new BigInteger ((byte[]) val.getValue()).intValue(); + else if (val.getTag() == 1) + ipm = new BigInteger ((byte[]) val.getValue()).intValue(); + else + throw new IOException ("invalid policy constraint"); + len -= val.getEncodedLength(); + } + + requireExplicitPolicy = rpc; + inhibitPolicyMapping = ipm; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public int getRequireExplicitPolicy() + { + return requireExplicitPolicy; + } + + public int getInhibitPolicyMapping() + { + return inhibitPolicyMapping; + } + + public String toString() + { + return PolicyConstraint.class.getName() + " [ requireExplicitPolicy=" + + requireExplicitPolicy + " inhibitPolicyMapping=" + inhibitPolicyMapping + + " ]"; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/PolicyMappings.java b/libjava/classpath/gnu/java/security/x509/ext/PolicyMappings.java new file mode 100644 index 000000000..0493ed89d --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/PolicyMappings.java @@ -0,0 +1,104 @@ +/* PolicyMappings.java -- policy mappings extension. + 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.security.x509.ext; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class PolicyMappings extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.33"); + + private final Map mappings; + + // Constructor. + // ------------------------------------------------------------------------- + + public PolicyMappings(final byte[] encoded) throws IOException + { + super(encoded); + DERReader der = new DERReader(encoded); + DERValue maps = der.read(); + if (!maps.isConstructed()) + throw new IOException("malformed PolicyMappings"); + int len = 0; + HashMap _mappings = new HashMap(); + while (len < maps.getLength()) + { + DERValue map = der.read(); + if (!map.isConstructed()) + throw new IOException("malformed PolicyMapping"); + DERValue val = der.read(); + if (val.getTag() != DER.OBJECT_IDENTIFIER) + throw new IOException("malformed PolicyMapping"); + OID issuerPolicy = (OID) val.getValue(); + val = der.read(); + if (val.getTag() != DER.OBJECT_IDENTIFIER) + throw new IOException("malformed PolicyMapping"); + OID subjectPolicy = (OID) val.getValue(); + _mappings.put(issuerPolicy, subjectPolicy); + len += map.getEncodedLength(); + } + mappings = Collections.unmodifiableMap(_mappings); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public OID getSubjectDomainPolicy(OID issuerDomainPolicy) + { + return (OID) mappings.get(issuerDomainPolicy); + } + + public String toString() + { + return PolicyMappings.class.getName() + " [ " + mappings + " ]"; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/PrivateKeyUsagePeriod.java b/libjava/classpath/gnu/java/security/x509/ext/PrivateKeyUsagePeriod.java new file mode 100644 index 000000000..3b531c055 --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/PrivateKeyUsagePeriod.java @@ -0,0 +1,105 @@ +/* PrivateKeyUsagePeriod.java -- private key usage period extension. + 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.security.x509.ext; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +import java.io.IOException; +import java.util.Date; + +public class PrivateKeyUsagePeriod extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.16"); + + private final Date notBefore; + private final Date notAfter; + + // Constructor. + // ------------------------------------------------------------------------- + + public PrivateKeyUsagePeriod(final byte[] encoded) throws IOException + { + super(encoded); + DERReader der = new DERReader(encoded); + DERValue val = der.read(); + if (!val.isConstructed()) + throw new IOException("malformed PrivateKeyUsagePeriod"); + if (val.getLength() > 0) + val = der.read(); + if (val.getTagClass() == DER.APPLICATION || val.getTag() == 0) + { + notBefore = (Date) val.getValueAs (DER.GENERALIZED_TIME); + val = der.read(); + } + else + notBefore = null; + if (val.getTagClass() == DER.APPLICATION || val.getTag() == 1) + { + notAfter = (Date) val.getValueAs (DER.GENERALIZED_TIME); + } + else + notAfter = null; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public Date getNotBefore() + { + return notBefore != null ? (Date) notBefore.clone() : null; + } + + public Date getNotAfter() + { + return notAfter != null ? (Date) notAfter.clone() : null; + } + + public String toString() + { + return PrivateKeyUsagePeriod.class.getName() + " [ notBefore=" + notBefore + + " notAfter=" + notAfter + " ]"; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/ReasonCode.java b/libjava/classpath/gnu/java/security/x509/ext/ReasonCode.java new file mode 100644 index 000000000..a6d59e43a --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/ReasonCode.java @@ -0,0 +1,85 @@ +/* ReasonCode.java -- a reason code for a certificate revocation. + 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.security.x509.ext; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +import java.io.IOException; +import java.math.BigInteger; + +public class ReasonCode extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.21"); + + public final int reason; + + // Constructor. + // ------------------------------------------------------------------------- + + public ReasonCode(final byte[] encoded) throws IOException + { + super(encoded); + DERValue val = DERReader.read(encoded); + if (val.getTag() != DER.ENUMERATED) + throw new IOException("malformed CRLReason"); + reason = ((BigInteger) val.getValue()).intValue(); + if (reason < 0 || reason == 7 || reason > 10) + throw new IOException("illegal reason: " + reason); + } + + // Instance method. + // ------------------------------------------------------------------------- + + public int getReasonCode() + { + return reason; + } + + public String toString() + { + return ReasonCode.class.getName() + " [ " + reason + " ]"; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/SubjectAlternativeNames.java b/libjava/classpath/gnu/java/security/x509/ext/SubjectAlternativeNames.java new file mode 100644 index 000000000..8b6347d99 --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/SubjectAlternativeNames.java @@ -0,0 +1,77 @@ +/* SubjectAlternatuveNames.java -- subject alternative names extension. + 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.security.x509.ext; + +import gnu.java.security.OID; + +import java.io.IOException; +import java.util.List; + +public class SubjectAlternativeNames extends Extension.Value +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.17"); + + private final GeneralNames names; + + // Constructor. + // ------------------------------------------------------------------------- + + public SubjectAlternativeNames(final byte[] encoded) throws IOException + { + super(encoded); + names = new GeneralNames(encoded); + } + + // Instance method. + // ------------------------------------------------------------------------- + + public List getNames() + { + return names.getNames(); + } + + public String toString() + { + return SubjectAlternativeNames.class.getName() + " [ " + names + " ]"; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/SubjectKeyIdentifier.java b/libjava/classpath/gnu/java/security/x509/ext/SubjectKeyIdentifier.java new file mode 100644 index 000000000..fc65abe21 --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/SubjectKeyIdentifier.java @@ -0,0 +1,84 @@ +/* SubjectKeyIdentifier.java -- subject key identifier extension. + 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.security.x509.ext; + +import gnu.java.security.OID; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.x509.Util; + +import java.io.IOException; + +public class SubjectKeyIdentifier extends Extension.Value +{ + + // Constant. + // ------------------------------------------------------------------------- + + public static final OID ID = new OID("2.5.29.14"); + + private final byte[] keyIdentifier; + + // Constructor. + // ------------------------------------------------------------------------- + + public SubjectKeyIdentifier(final byte[] encoded) throws IOException + { + super(encoded); + DERValue val = DERReader.read(encoded); + if (val.getTag() != DER.OCTET_STRING) + throw new IOException("malformed SubjectKeyIdentifier"); + keyIdentifier = (byte[]) val.getValue(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public byte[] getKeyIdentifier() + { + return (byte[]) keyIdentifier.clone(); + } + + public String toString() + { + return SubjectKeyIdentifier.class.getName() + " [ " + + Util.toHexString (keyIdentifier, ':') + " ]"; + } +} diff --git a/libjava/classpath/gnu/java/security/x509/ext/package.html b/libjava/classpath/gnu/java/security/x509/ext/package.html new file mode 100644 index 000000000..cc44e55c9 --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/ext/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.security.x509.ext + + +

+ + + diff --git a/libjava/classpath/gnu/java/security/x509/package.html b/libjava/classpath/gnu/java/security/x509/package.html new file mode 100644 index 000000000..8b0ba0084 --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.security.x509 + + +

+ + + diff --git a/libjava/classpath/gnu/java/text/AttributedFormatBuffer.java b/libjava/classpath/gnu/java/text/AttributedFormatBuffer.java new file mode 100644 index 000000000..2a89ae097 --- /dev/null +++ b/libjava/classpath/gnu/java/text/AttributedFormatBuffer.java @@ -0,0 +1,251 @@ +/* AttributedFormatBuffer.java -- Implements an attributed FormatBuffer. + 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.text; + +import gnu.java.lang.CPStringBuilder; + +import java.text.AttributedCharacterIterator; +import java.util.ArrayList; +import java.util.HashMap; + +/** + * This class is an implementation of a FormatBuffer with attributes. + * Note that this class is not thread-safe; external synchronisation + * should be used if an instance is to be accessed from multiple threads. + * + * @author Guilhem Lavaux + * @date April 10, 2004 + */ +public class AttributedFormatBuffer implements FormatBuffer +{ + private final CPStringBuilder buffer; + private final ArrayList ranges; + private final ArrayList attributes; + private int[] a_ranges; + private HashMap[] a_attributes; + private int startingRange; + AttributedCharacterIterator.Attribute defaultAttr; + + /** + * This constructor accepts a StringBuffer. If the buffer contains + * already some characters they will not be attributed. + */ + public AttributedFormatBuffer(CPStringBuilder buffer) + { + this.buffer = new CPStringBuilder(buffer); + this.ranges = new ArrayList(); + this.attributes = new ArrayList(); + this.defaultAttr = null; + if (buffer.length() != 0) + { + this.startingRange = buffer.length(); + addAttribute(buffer.length(), null); + } + else + this.startingRange = -1; + } + + public AttributedFormatBuffer(int prebuffer) + { + this(new CPStringBuilder(prebuffer)); + } + + public AttributedFormatBuffer() + { + this(10); + } + + /** + * This method is a helper function for formatters. Given a set of ranges + * and attributes it adds exactly one attribute for the range of characters + * comprised between the last entry in 'ranges' and the specified new range. + * + * @param new_range A new range to insert in the list. + * @param attr A new attribute to insert in the list. + */ + private final void addAttribute(int new_range, AttributedCharacterIterator.Attribute attr) + { + HashMap map; + + if (attr != null) + { + map = new HashMap(); + map.put(attr, attr); + attributes.add(map); + } + else + attributes.add(null); + + ranges.add(new Integer(new_range)); + } + + public void append(String s) + { + if (startingRange < 0) + startingRange = 0; + buffer.append(s); + } + + public void append(String s, AttributedCharacterIterator.Attribute attr) + { + setDefaultAttribute(attr); + startingRange = buffer.length(); + append(s); + setDefaultAttribute(null); + } + + public void append(String s, int[] ranges, HashMap[] attrs) + { + int curPos = buffer.length(); + + setDefaultAttribute(null); + if (ranges != null) + { + for (int i = 0; i < ranges.length; i++) + { + this.ranges.add(new Integer(ranges[i] + curPos)); + this.attributes.add(attrs[i]); + } + } + startingRange = buffer.length(); + buffer.append(s); + } + + public void append(char c) + { + if (startingRange < 0) + startingRange = buffer.length(); + buffer.append(c); + } + + public void append(char c, AttributedCharacterIterator.Attribute attr) + { + setDefaultAttribute(attr); + buffer.append(c); + setDefaultAttribute(null); + } + + public void setDefaultAttribute(AttributedCharacterIterator.Attribute attr) + { + if (attr == defaultAttr) + return; + + int currentPos = buffer.length(); + + if (startingRange != currentPos && startingRange >= 0) + { + addAttribute(currentPos, defaultAttr); + } + defaultAttr = attr; + startingRange = currentPos; + } + + public AttributedCharacterIterator.Attribute getDefaultAttribute() + { + return defaultAttr; + } + + public void cutTail(int length) + { + buffer.setLength(buffer.length()-length); + } + + public int length() + { + return buffer.length(); + } + + public void clear() + { + buffer.setLength(0); + ranges.clear(); + attributes.clear(); + defaultAttr = null; + startingRange = -1; + } + + /** + * This method synchronizes the state of the attribute array. + * After calling it you may call {@link #getDefaultAttribute()}. + */ + public void sync() + { + if (startingRange < 0 || startingRange == buffer.length()) + return; + + addAttribute(buffer.length(), defaultAttr); + + a_ranges = new int[ranges.size()]; + for (int i = 0; i < a_ranges.length; i++) + a_ranges[i] = ((Integer)(ranges.get (i))).intValue(); + + a_attributes = new HashMap[attributes.size()]; + System.arraycopy(attributes.toArray(), 0, a_attributes, 0, a_attributes.length); + } + + /** + * This method returns the internal CPStringBuilder describing + * the attributed string. + * + * @return An instance of CPStringBuilder which contains the string. + */ + public CPStringBuilder getBuffer() + { + return buffer; + } + + /** + * This method returns the ranges for the attributes. + * + * @return An array of int describing the ranges. + */ + public int[] getRanges() + { + return a_ranges; + } + + /** + * This method returns the array containing the map on the + * attributes. + * + * @return An array of {@link java.util.Map} containing the attributes. + */ + public HashMap[] getAttributes() + { + return a_attributes; + } +} diff --git a/libjava/classpath/gnu/java/text/BaseBreakIterator.java b/libjava/classpath/gnu/java/text/BaseBreakIterator.java new file mode 100644 index 000000000..b69f698a1 --- /dev/null +++ b/libjava/classpath/gnu/java/text/BaseBreakIterator.java @@ -0,0 +1,124 @@ +/* BaseBreakIterator.java -- Base class for default BreakIterators + Copyright (C) 1999, 2001, 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.text; + +import java.text.BreakIterator; +import java.text.CharacterIterator; +import java.text.StringCharacterIterator; + +/** + * @author Tom Tromey + * @date March 22, 1999 + */ + +public abstract class BaseBreakIterator extends BreakIterator +{ + public BaseBreakIterator () + { + // It isn't documented, but break iterators are created in a + // working state; their methods won't throw exceptions before + // setText(). + iter = new StringCharacterIterator(""); + } + + public int current () + { + return iter.getIndex(); + } + + public int first () + { + iter.first(); + return iter.getBeginIndex(); + } + + /** + * Return the first boundary after pos. + * This has the side effect of setting the index of the + * CharacterIterator. + */ + public int following (int pos) + { + iter.setIndex(pos); + int r = next (); + return r; + } + + public CharacterIterator getText () + { + return iter; + } + + public int last () + { + iter.last(); + // Go past the last character. + iter.next(); + return iter.getEndIndex(); + } + + public int next (int n) + { + int r = iter.getIndex (); + if (n > 0) + { + while (n > 0 && r != DONE) + { + r = next (); + --n; + } + } + else if (n < 0) + { + while (n < 0 && r != DONE) + { + r = previous (); + ++n; + } + } + return r; + } + + public void setText (CharacterIterator newText) + { + iter = newText; + } + + protected CharacterIterator iter; +} diff --git a/libjava/classpath/gnu/java/text/CharacterBreakIterator.java b/libjava/classpath/gnu/java/text/CharacterBreakIterator.java new file mode 100644 index 000000000..565eb9b9d --- /dev/null +++ b/libjava/classpath/gnu/java/text/CharacterBreakIterator.java @@ -0,0 +1,213 @@ +/* CharacterBreakIterator.java - Default character BreakIterator. + Copyright (C) 1999, 2001, 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.text; + +import java.text.CharacterIterator; + +/** + * @author Tom Tromey + * @date March 19, 1999 + * Written using The Unicode Standard, Version 2.0. + */ + +public class CharacterBreakIterator extends BaseBreakIterator +{ + // Hangul Jamo constants from Unicode book. + private static final int LBase = 0x1100; + private static final int VBase = 0x1161; + private static final int TBase = 0x11a7; + private static final int LCount = 19; + private static final int VCount = 21; + private static final int TCount = 28; + + // Information about surrogates. + private static final int highSurrogateStart = 0xD800; + private static final int highSurrogateEnd = 0xDBFF; + private static final int lowSurrogateStart = 0xDC00; + private static final int lowSurrogateEnd = 0xDFFF; + + public Object clone () + { + return new CharacterBreakIterator (this); + } + + public CharacterBreakIterator () + { + } + + private CharacterBreakIterator (CharacterBreakIterator other) + { + iter = (CharacterIterator) other.iter.clone(); + } + + // Some methods to tell us different properties of characters. + private final boolean isL (char c) + { + return c >= LBase && c <= LBase + LCount; + } + private final boolean isV (char c) + { + return c >= VBase && c <= VBase + VCount; + } + private final boolean isT (char c) + { + return c >= TBase && c <= TBase + TCount; + } + private final boolean isLVT (char c) + { + return isL (c) || isV (c) || isT (c); + } + private final boolean isHighSurrogate (char c) + { + return c >= highSurrogateStart && c <= highSurrogateEnd; + } + private final boolean isLowSurrogate (char c) + { + return c >= lowSurrogateStart && c <= lowSurrogateEnd; + } + + public int next () + { + int end = iter.getEndIndex(); + if (iter.getIndex() == end) + return DONE; + + char c; + for (char prev = CharacterIterator.DONE; iter.getIndex() < end; prev = c) + { + c = iter.next(); + if (c == CharacterIterator.DONE) + break; + int type = Character.getType(c); + + // Break after paragraph separators. + if (type == Character.PARAGRAPH_SEPARATOR) + break; + + // Now we need some lookahead. + char ahead = iter.next(); + iter.previous(); + if (ahead == CharacterIterator.DONE) + break; + int aheadType = Character.getType(ahead); + + if (aheadType != Character.NON_SPACING_MARK + && ! isLowSurrogate (ahead) + && ! isLVT (ahead)) + break; + if (! isLVT (c) && isLVT (ahead)) + break; + if (isL (c) && ! isLVT (ahead) + && aheadType != Character.NON_SPACING_MARK) + break; + if (isV (c) && ! isV (ahead) && !isT (ahead) + && aheadType != Character.NON_SPACING_MARK) + break; + if (isT (c) && ! isT (ahead) + && aheadType != Character.NON_SPACING_MARK) + break; + + if (! isHighSurrogate (c) && isLowSurrogate (ahead)) + break; + if (isHighSurrogate (c) && ! isLowSurrogate (ahead)) + break; + if (! isHighSurrogate (prev) && isLowSurrogate (c)) + break; + } + + return iter.getIndex(); + } + + public int previous () + { + if (iter.getIndex() == iter.getBeginIndex()) + return DONE; + + while (iter.getIndex() >= iter.getBeginIndex()) + { + char c = iter.previous(); + if (c == CharacterIterator.DONE) + break; + int type = Character.getType(c); + + if (type != Character.NON_SPACING_MARK + && ! isLowSurrogate (c) + && ! isLVT (c)) + break; + + // Now we need some lookahead. + char ahead = iter.previous(); + if (ahead == CharacterIterator.DONE) + { + iter.next(); + break; + } + char ahead2 = iter.previous(); + iter.next(); + iter.next(); + if (ahead2 == CharacterIterator.DONE) + break; + int aheadType = Character.getType(ahead); + + if (aheadType == Character.PARAGRAPH_SEPARATOR) + break; + + if (isLVT (c) && ! isLVT (ahead)) + break; + if (! isLVT (c) && type != Character.NON_SPACING_MARK + && isL (ahead)) + break; + if (! isV (c) && ! isT (c) && type != Character.NON_SPACING_MARK + && isV (ahead)) + break; + if (! isT (c) && type != Character.NON_SPACING_MARK + && isT (ahead)) + break; + + if (isLowSurrogate (c) && ! isHighSurrogate (ahead)) + break; + if (! isLowSurrogate (c) && isHighSurrogate (ahead)) + break; + if (isLowSurrogate (ahead) && ! isHighSurrogate (ahead2)) + break; + } + + return iter.getIndex(); + } +} diff --git a/libjava/classpath/gnu/java/text/FormatBuffer.java b/libjava/classpath/gnu/java/text/FormatBuffer.java new file mode 100644 index 000000000..590b16cce --- /dev/null +++ b/libjava/classpath/gnu/java/text/FormatBuffer.java @@ -0,0 +1,136 @@ +/* FormatBuffer.java -- General interface to build attributed strings. + 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.text; + +import java.text.AttributedCharacterIterator; +import java.util.HashMap; + +/** + * This interface describes a modifiable buffer which contains attributed + * characters. The implementation may or may not implements attributes. It + * aims to greatly simplify and clarify the implementation of java.text + * formatters. The buffer may be appended or have its tail cut. It may also + * be completely cleant up. + * + * @author Guilhem Lavaux + * @date April 10, 2004 + */ +public interface FormatBuffer +{ + /** + * This method appends a simple string to the buffer. This part of + * the buffer will be attributed using the default attribute. + * + * @param s The string to append to the buffer. + */ + public void append(String s); + + /** + * This method appends a simple string to the buffer. This part of + * the buffer will have the specified attribute (and only this one). + * The default attribute may be changed after calling this method. + * + * @param s The string to append to the buffer. + * @param attr Attribute to use for the string in the buffer. + */ + public void append(String s, AttributedCharacterIterator.Attribute attr); + + /** + * This method appends a simple string to the buffer. This part of + * the buffer will be attributed using the specified ranges and attributes. + * To have an example on how to specify ranges see {@link gnu.java.text.FormatCharacterIterator}. + * + * @param s The string to append to the buffer. + * @param ranges The ranges describing how the attributes should be applied + * to the string. + * @param attrs The attributes of the string in the buffer. + */ + public void append(String s, int[] ranges, HashMap[] attrs); + + /** + * This method appends a simple char to the buffer. This part of + * the buffer will be attributed using the default attribute. + * + * @param c The character to append to the buffer. + */ + public void append(char c); + + /** + * This method appends a simple character to the buffer. This part of + * the buffer will have the specified attribute (and only this one). + * The default attribute may be changed after calling this method. + * + * @param c The character to append to the buffer. + * @param attr Attribute to use for the character in the buffer. + */ + public void append(char c, AttributedCharacterIterator.Attribute attr); + + /** + * This method changes the current default attribute for the next string + * or character which will be appended to the buffer. + * + * @param attr The attribute which will be used by default. + */ + public void setDefaultAttribute(AttributedCharacterIterator.Attribute attr); + + /** + * This method returns the current default attribute for the buffer. + * + * @return The default attribute for the buffer. + */ + public AttributedCharacterIterator.Attribute getDefaultAttribute(); + + /** + * This method cuts the last characters of the buffer. The number of + * characters to cut is given by "length". + * + * @param length Number of characters to cut at the end of the buffer. + */ + public void cutTail(int length); + + /** + * This method resets completely the buffer. + */ + public void clear(); + + /** + * This method returns the number of character in the buffer. + * + * @return The number of character in the buffer. + */ + public int length(); +} diff --git a/libjava/classpath/gnu/java/text/FormatCharacterIterator.java b/libjava/classpath/gnu/java/text/FormatCharacterIterator.java new file mode 100644 index 000000000..889394ca4 --- /dev/null +++ b/libjava/classpath/gnu/java/text/FormatCharacterIterator.java @@ -0,0 +1,533 @@ +/* FormatCharacter.java -- Implementation of AttributedCharacterIterator for + formatters. + Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 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.java.text; + +import java.text.AttributedCharacterIterator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.Vector; + +/** + * This class should not be put public and it is only intended to the + * classes of the java.text package. Its aim is to build a segmented + * character iterator by appending strings and adding attributes to + * portions of strings. The code intends to do some optimization + * concerning memory consumption and attribute access but at the + * end it is only an AttributedCharacterIterator. + * + * @author Guilhem Lavaux + * @date November 22, 2003 + */ +public class FormatCharacterIterator implements AttributedCharacterIterator +{ + private String formattedString; + private int charIndex; + private int attributeIndex; + private int[] ranges; + private HashMap[] attributes; + private static final boolean DEBUG = false; + + /** + * This constructor builds an empty iterated strings. The attributes + * are empty and so is the string. However you may append strings + * and attributes to this iterator. + */ + public FormatCharacterIterator() + { + formattedString = ""; + ranges = new int[0]; + attributes = new HashMap[0]; + } + + /** + * This constructor take a string s, a set of ranges + * and the corresponding attributes. This is used to build an iterator. + * The array ranges should be formatted as follow: + * each element of ranges specifies the index in the string + * until which the corresponding map of attributes at the same position + * is applied. For example, if you have: + *
+   *   s = "hello";
+   *   ranges = new int[] { 2, 6 };
+   *   attributes = new HashMap[2];
+   * 
+ * "he" will have the attributes attributes[0], + * "llo" the attributes[1]. + */ + public FormatCharacterIterator (String s, int[] ranges, HashMap[] attributes) + { + formattedString = s; + this.ranges = ranges; + this.attributes = attributes; + } + + /* + * The following methods are inherited from AttributedCharacterIterator, + * and thus are already documented. + */ + + public Set getAllAttributeKeys() + { + if (attributes != null && attributes[attributeIndex] != null) + return attributes[attributeIndex].keySet(); + else + return new HashSet(); + } + + public Map getAttributes() + { + if (attributes != null && attributes[attributeIndex] != null) + return attributes[attributeIndex]; + else + return new HashMap(); + } + + public Object getAttribute (AttributedCharacterIterator.Attribute attrib) + { + if (attributes != null && attributes[attributeIndex] != null) + return attributes[attributeIndex].get (attrib); + else + return null; + } + + public int getRunLimit(Set reqAttrs) + { + if (attributes == null) + return formattedString.length(); + + int currentAttrIndex = attributeIndex; + Set newKeys; + + do + { + currentAttrIndex++; + if (currentAttrIndex == attributes.length) + return formattedString.length(); + if (attributes[currentAttrIndex] == null) + break; + newKeys = attributes[currentAttrIndex].keySet(); + } + while (newKeys.containsAll (reqAttrs)); + + return ranges[currentAttrIndex-1]; + } + + public int getRunLimit (AttributedCharacterIterator.Attribute attribute) + { + Set s = new HashSet(); + + s.add (attribute); + return getRunLimit (s); + } + + public int getRunLimit() + { + if (attributes == null) + return formattedString.length(); + if (attributes[attributeIndex] == null) + { + for (int i=attributeIndex+1;i 0) ? ranges[currentAttrIndex-1] : 0; + } + + public int getRunStart() + { + if (attributes == null) + return 0; + + if (attributes[attributeIndex] == null) + { + for (int i=attributeIndex;i>0;i--) + if (attributes[i] != null) + return ranges[attributeIndex-1]; + return 0; + } + + return getRunStart (attributes[attributeIndex].keySet()); + } + + public int getRunStart (AttributedCharacterIterator.Attribute attribute) + { + Set s = new HashSet(); + + s.add (attribute); + return getRunStart (s); + } + + public Object clone() + { + return new FormatCharacterIterator (formattedString, ranges, attributes); + } + + /* + * The following methods are inherited from CharacterIterator and thus + * are already documented. + */ + + public char current() + { + return formattedString.charAt (charIndex); + } + + public char first() + { + charIndex = 0; + attributeIndex = 0; + return formattedString.charAt (0); + } + + public int getBeginIndex() + { + return 0; + } + + public int getEndIndex() + { + return formattedString.length(); + } + + public int getIndex() + { + return charIndex; + } + + public char last() + { + charIndex = formattedString.length()-1; + if (attributes != null) + attributeIndex = attributes.length-1; + return formattedString.charAt (charIndex); + } + + public char next() + { + charIndex++; + if (charIndex >= formattedString.length()) + { + charIndex = getEndIndex(); + return DONE; + } + if (attributes != null) + { + if (charIndex >= ranges[attributeIndex]) + attributeIndex++; + } + return formattedString.charAt (charIndex); + } + + public char previous() + { + charIndex--; + if (charIndex < 0) + { + charIndex = 0; + return DONE; + } + + if (attributes != null) + { + if (charIndex < ranges[attributeIndex]) + attributeIndex--; + } + return formattedString.charAt (charIndex); + } + + public char setIndex (int position) + { + if (position < 0 || position > formattedString.length()) + throw new IllegalArgumentException ("position is out of range"); + + charIndex = position; + if (attributes != null) + { + for (attributeIndex=0;attributeIndex charIndex) + break; + attributeIndex--; + } + if (charIndex == formattedString.length()) + return DONE; + else + return formattedString.charAt (charIndex); + } + + /** + * This method merge the specified attributes and ranges with the + * internal tables. This method is in charge of the optimization + * of tables. Two following sets of attributes are never the same. + * + * @see #FormatCharacterIterator() + * + * @param attributes the new array attributes to apply to the string. + */ + public void mergeAttributes (HashMap[] attributes, int[] ranges) + { + Vector new_ranges = new Vector(); + Vector new_attributes = new Vector(); + int i = 0, j = 0; + + debug("merging " + attributes.length + " attrs"); + + while (i < this.ranges.length && j < ranges.length) + { + if (this.attributes[i] != null) + { + new_attributes.add (this.attributes[i]); + if (attributes[j] != null) + this.attributes[i].putAll (attributes[j]); + } + else + { + new_attributes.add (attributes[j]); + } + if (this.ranges[i] == ranges[j]) + { + new_ranges.add (new Integer (ranges[j])); + i++; + j++; + } + else if (this.ranges[i] < ranges[j]) + { + new_ranges.add (new Integer (this.ranges[i])); + i++; + } + else + { + new_ranges.add (new Integer (ranges[j])); + j++; + } + } + + if (i != this.ranges.length) + { + for (;inull the string will simply have no + * attributes. + */ + public void append (String text, HashMap local_attributes) + { + int[] new_ranges = new int[ranges.length+1]; + HashMap[] new_attributes = new HashMap[attributes.length+1]; + + formattedString += text; + System.arraycopy (attributes, 0, new_attributes, 0, attributes.length); + System.arraycopy (ranges, 0, new_ranges, 0, ranges.length); + new_ranges[ranges.length] = formattedString.length(); + new_attributes[attributes.length] = local_attributes; + + ranges = new_ranges; + attributes = new_attributes; + } + + /** + * This method appends a string without attributes. It is completely + * equivalent to call {@link #append(String,HashMap)} with local_attributes + * equal to null. + * + * @param text The string to append to the iterator. + */ + public void append (String text) + { + append (text, null); + } + + /** + * This method adds a set of attributes to a range of character. The + * bounds are always inclusive. In the case many attributes have to + * be added it is advised to directly use {@link #mergeAttributes([Ljava.util.HashMap;[I} + * + * @param attributes Attributes to merge into the iterator. + * @param range_start Lower bound of the range of characters which will receive the + * attribute. + * @param range_end Upper bound of the range of characters which will receive the + * attribute. + * + * @throws IllegalArgumentException if ranges are out of bounds. + */ + public void addAttributes(HashMap attributes, int range_start, int range_end) + { + if (range_start == 0) + mergeAttributes(new HashMap[] { attributes }, new int[] { range_end }); + else + mergeAttributes(new HashMap[] { null, attributes }, new int[] { range_start, range_end }); + } + + private void debug(String s) + { + if (DEBUG) + System.out.println(s); + } + + private void dumpTable() + { + int start_range = 0; + + if (!DEBUG) + return; + + System.out.println("Dumping internal table:"); + for (int i = 0; i < ranges.length; i++) + { + System.out.print("\t" + start_range + " => " + ranges[i] + ":"); + if (attributes[i] == null) + System.out.println("null"); + else + { + Set keyset = attributes[i].keySet(); + if (keyset != null) + { + Iterator keys = keyset.iterator(); + + while (keys.hasNext()) + System.out.print(" " + keys.next()); + } + else + System.out.println("keySet null"); + System.out.println(); + } + } + System.out.println(); + System.out.flush(); + } +} diff --git a/libjava/classpath/gnu/java/text/LineBreakIterator.java b/libjava/classpath/gnu/java/text/LineBreakIterator.java new file mode 100644 index 000000000..7e44121b0 --- /dev/null +++ b/libjava/classpath/gnu/java/text/LineBreakIterator.java @@ -0,0 +1,194 @@ +/* LineBreakIterator.java - Default word BreakIterator. + Copyright (C) 1999, 2001, 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.text; + +import java.text.CharacterIterator; + +/** + * @author Tom Tromey + * @date March 22, 1999 + * Written using The Unicode Standard, Version 2.0. + */ + +public class LineBreakIterator extends BaseBreakIterator +{ + public Object clone () + { + return new LineBreakIterator (this); + } + + public LineBreakIterator () + { + } + + private LineBreakIterator (LineBreakIterator other) + { + iter = (CharacterIterator) other.iter.clone(); + } + + // Some methods to tell us different properties of characters. + private final boolean isNb (char c) + { + return (c == 0x00a0 // NO-BREAK SPACE + || c == 0x2011 // NON-BREAKING HYPHEN + || c == 0xfeff); // ZERO WITH NO-BREAK SPACE + } + private final boolean isClose (int type) + { + return (type == Character.END_PUNCTUATION + // Unicode book says "comma, period, ...", which I take to + // mean "Po" class. + || type == Character.OTHER_PUNCTUATION); + } + private final boolean isIdeo (char c) + { + return (c >= 0x3040 && c <= 0x309f // Hiragana + || c >= 0x30a0 && c <= 0x30ff // Katakana + || c >= 0x4e00 && c <= 0x9fff // Han + || c >= 0x3100 && c <= 0x312f); // Bopomofo + } + + public int next () + { + int end = iter.getEndIndex(); + if (iter.getIndex() == end) + return DONE; + + while (iter.getIndex() < end) + { + char c = iter.current(); + int type = Character.getType(c); + + char n = iter.next(); + + if (n == CharacterIterator.DONE + || type == Character.PARAGRAPH_SEPARATOR + || type == Character.LINE_SEPARATOR) + break; + + // Handle two cases where we must scan for non-spacing marks. + int start = iter.getIndex(); + if (type == Character.SPACE_SEPARATOR + || type == Character.START_PUNCTUATION + || isIdeo (c)) + { + while (n != CharacterIterator.DONE + && Character.getType(n) == Character.NON_SPACING_MARK) + n = iter.next(); + if (n == CharacterIterator.DONE) + break; + + if (type == Character.SPACE_SEPARATOR) + { + int nt = Character.getType(n); + if (nt != Character.NON_SPACING_MARK + && nt != Character.SPACE_SEPARATOR + && ! isNb (n)) + break; + } + else if (type == Character.START_PUNCTUATION) + { + if (isIdeo (n)) + { + // Open punctuation followed by non spacing marks + // and then ideograph does not have a break in + // it. So skip all this. + start = iter.getIndex(); + } + } + else + { + // Ideograph preceded this character. + if (isClose (Character.getType(n))) + break; + } + } + iter.setIndex(start); + } + + return iter.getIndex(); + } + + public int previous () + { + int start = iter.getBeginIndex(); + if (iter.getIndex() == start) + return DONE; + + while (iter.getIndex() >= start) + { + char c = iter.previous(); + if (c == CharacterIterator.DONE) + break; + int type = Character.getType(c); + + char n = iter.previous(); + if (n == CharacterIterator.DONE) + break; + iter.next(); + + int nt = Character.getType(n); + // Break after paragraph separators. + if (nt == Character.PARAGRAPH_SEPARATOR + || nt == Character.LINE_SEPARATOR) + break; + + // Skip non-spacing marks. + int init = iter.getIndex(); + while (n != CharacterIterator.DONE && nt == Character.NON_SPACING_MARK) + { + n = iter.previous(); + nt = Character.getType(n); + } + + if (nt == Character.SPACE_SEPARATOR + && type != Character.SPACE_SEPARATOR + && type != Character.NON_SPACING_MARK + && ! isNb (c)) + break; + if (! isClose (type) && isIdeo (n)) + break; + if (isIdeo (c) && nt != Character.START_PUNCTUATION) + break; + iter.setIndex(init); + } + + return iter.getIndex(); + } +} diff --git a/libjava/classpath/gnu/java/text/SentenceBreakIterator.java b/libjava/classpath/gnu/java/text/SentenceBreakIterator.java new file mode 100644 index 000000000..4da9df2ea --- /dev/null +++ b/libjava/classpath/gnu/java/text/SentenceBreakIterator.java @@ -0,0 +1,247 @@ +/* SentenceBreakIterator.java - Default sentence BreakIterator. + Copyright (C) 1999, 2001, 2002, 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.text; + +import java.text.CharacterIterator; + +/** + * @author Tom Tromey + * @date March 23, 1999 + * Written using The Unicode Standard, Version 2.0. + */ + +public class SentenceBreakIterator extends BaseBreakIterator +{ + public Object clone () + { + return new SentenceBreakIterator (this); + } + + public SentenceBreakIterator () + { + } + + private SentenceBreakIterator (SentenceBreakIterator other) + { + iter = (CharacterIterator) other.iter.clone(); + } + + public int next () + { + int end = iter.getEndIndex(); + if (iter.getIndex() == end) + return DONE; + + while (iter.getIndex() < end) + { + char c = iter.current(); + if (c == CharacterIterator.DONE) + break; + int type = Character.getType(c); + + char n = iter.next(); + if (n == CharacterIterator.DONE) + break; + + // Always break after paragraph separator. + if (type == Character.PARAGRAPH_SEPARATOR) + break; + + if (c == '!' || c == '?') + { + // Skip close punctuation. + while (n != CharacterIterator.DONE + && Character.getType(n) == Character.END_PUNCTUATION) + n = iter.next(); + // Skip (java) space, line and paragraph separators. + while (n != CharacterIterator.DONE && Character.isWhitespace(n)) + n = iter.next(); + + // There's always a break somewhere after `!' or `?'. + break; + } + + if (c == '.') + { + int save = iter.getIndex(); + // Skip close punctuation. + while (n != CharacterIterator.DONE + && Character.getType(n) == Character.END_PUNCTUATION) + n = iter.next(); + // Skip (java) space, line and paragraph separators. + // We keep count because we need at least one for this period to + // represent a terminator. + int spcount = 0; + while (n != CharacterIterator.DONE && Character.isWhitespace(n)) + { + n = iter.next(); + ++spcount; + } + if (spcount > 0) + { + int save2 = iter.getIndex(); + // Skip over open puncutation. + while (n != CharacterIterator.DONE + && Character.getType(n) == Character.START_PUNCTUATION) + n = iter.next(); + // Next character must not be lower case. + if (n == CharacterIterator.DONE + || ! Character.isLowerCase(n)) + { + iter.setIndex(save2); + break; + } + } + iter.setIndex(save); + } + } + + return iter.getIndex(); + } + + private final int previous_internal () + { + int start = iter.getBeginIndex(); + if (iter.getIndex() == start) + return DONE; + + while (iter.getIndex() >= start) + { + char c = iter.previous(); + if (c == CharacterIterator.DONE) + break; + + char n = iter.previous(); + if (n == CharacterIterator.DONE) + break; + iter.next(); + int nt = Character.getType(n); + + if (! Character.isLowerCase(c) + && (nt == Character.START_PUNCTUATION + || Character.isWhitespace(n))) + { + int save = iter.getIndex(); + int save_nt = nt; + char save_n = n; + // Skip open punctuation. + while (n != CharacterIterator.DONE + && Character.getType(n) == Character.START_PUNCTUATION) + n = iter.previous(); + if (n == CharacterIterator.DONE) + break; + if (Character.isWhitespace(n)) + { + // Must have at least one (java) space after the `.'. + int save2 = iter.getIndex(); + while (n != CharacterIterator.DONE + && Character.isWhitespace(n)) + n = iter.previous(); + // Skip close punctuation. + while (n != CharacterIterator.DONE + && Character.getType(n) == Character.END_PUNCTUATION) + n = iter.previous(); + if (n == CharacterIterator.DONE || n == '.') + { + // Communicate location of actual end. + period = iter.getIndex(); + iter.setIndex(save2); + break; + } + } + iter.setIndex(save); + nt = save_nt; + n = save_n; + } + + if (nt == Character.PARAGRAPH_SEPARATOR) + { + // Communicate location of actual end. + period = iter.getIndex(); + break; + } + else if (Character.isWhitespace(n) + || nt == Character.END_PUNCTUATION) + { + int save = iter.getIndex(); + // Skip (java) space, line and paragraph separators. + while (n != CharacterIterator.DONE + && Character.isWhitespace(n)) + n = iter.previous(); + // Skip close punctuation. + while (n != CharacterIterator.DONE + && Character.getType(n) == Character.END_PUNCTUATION) + n = iter.previous(); + int here = iter.getIndex(); + iter.setIndex(save); + if (n == CharacterIterator.DONE || n == '!' || n == '?') + { + // Communicate location of actual end. + period = here; + break; + } + } + else if (n == '!' || n == '?') + { + // Communicate location of actual end. + period = iter.getIndex(); + break; + } + } + + return iter.getIndex(); + } + + public int previous () + { + // We want to skip over the first sentence end to the second one. + // However, at the end of the string we want the first end. + int here = iter.getIndex(); + period = here; + int first = previous_internal (); + if (here == iter.getEndIndex() || first == DONE) + return first; + iter.setIndex(period); + return previous_internal (); + } + + // This is used for communication between previous and + // previous_internal. + private int period; +} diff --git a/libjava/classpath/gnu/java/text/StringFormatBuffer.java b/libjava/classpath/gnu/java/text/StringFormatBuffer.java new file mode 100644 index 000000000..2367fccb3 --- /dev/null +++ b/libjava/classpath/gnu/java/text/StringFormatBuffer.java @@ -0,0 +1,127 @@ +/* StringFormatBuffer.java -- Implements FormatBuffer using StringBuffer. + 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.text; + +import java.text.AttributedCharacterIterator; +import java.util.HashMap; + +/** + * This class is an implementation of a FormatBuffer without attributes. + * + * @author Guilhem Lavaux + * @date April 10, 2004 + */ +public class StringFormatBuffer implements FormatBuffer +{ + private final StringBuffer buffer; + private AttributedCharacterIterator.Attribute defaultAttr; + + public StringFormatBuffer(int prebuffer) + { + buffer = new StringBuffer(prebuffer); + } + + public StringFormatBuffer(StringBuffer buffer) + { + this.buffer = buffer; + } + + public void append(String s) + { + buffer.append(s); + } + + public void append(String s, AttributedCharacterIterator.Attribute attr) + { + buffer.append(s); + } + + public void append(String s, int[] ranges, HashMap[] attrs) + { + buffer.append(s); + } + + public void append(char c) + { + buffer.append(c); + } + + public void append(char c, AttributedCharacterIterator.Attribute attr) + { + buffer.append(c); + } + + public void setDefaultAttribute(AttributedCharacterIterator.Attribute attr) + { + defaultAttr = attr; + } + + public AttributedCharacterIterator.Attribute getDefaultAttribute() + { + return defaultAttr; + } + + public void cutTail(int length) + { + buffer.setLength(buffer.length()-length); + } + + public int length() + { + return buffer.length(); + } + + public void clear() + { + buffer.setLength(0); + } + + /** + * This method returns the internal {@link java.lang.StringBuffer} which + * contains the string of character. + */ + public StringBuffer getBuffer() + { + return buffer; + } + + public String toString() + { + return buffer.toString(); + } + +} diff --git a/libjava/classpath/gnu/java/text/WordBreakIterator.java b/libjava/classpath/gnu/java/text/WordBreakIterator.java new file mode 100644 index 000000000..fded4bf26 --- /dev/null +++ b/libjava/classpath/gnu/java/text/WordBreakIterator.java @@ -0,0 +1,250 @@ +/* WordBreakIterator.java - Default word BreakIterator. + Copyright (C) 1999, 2001, 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.text; + +import java.text.CharacterIterator; + +/** + * @author Tom Tromey + * @date March 22, 1999 + * Written using The Unicode Standard, Version 2.0. + */ + +public class WordBreakIterator extends BaseBreakIterator +{ + public Object clone () + { + return new WordBreakIterator (this); + } + + public WordBreakIterator () + { + } + + private WordBreakIterator (WordBreakIterator other) + { + iter = (CharacterIterator) other.iter.clone(); + } + + // Some methods to tell us different properties of characters. + private final boolean isHira (char c) + { + return c >= 0x3040 && c <= 0x309f; + } + private final boolean isKata (char c) + { + return c >= 0x30a0 && c <= 0x30ff; + } + private final boolean isHan (char c) + { + return c >= 0x4e00 && c <= 0x9fff; + } + + public int next () + { + int end = iter.getEndIndex(); + if (iter.getIndex() == end) + return DONE; + + while (iter.getIndex() < end) + { + char c = iter.current(); + if (c == CharacterIterator.DONE) + break; + int type = Character.getType(c); + + char n = iter.next(); + if (n == CharacterIterator.DONE) + break; + + // Break after paragraph separators. + if (type == Character.PARAGRAPH_SEPARATOR + || type == Character.LINE_SEPARATOR) + break; + + // Break between letters and non-letters. + // FIXME: we treat apostrophe as part of a word. This + // is an English-ism. + boolean is_letter = Character.isLetter(c); + if (c != '\'' && ! is_letter && type != Character.NON_SPACING_MARK + && Character.isLetter(n)) + break; + + // Always break after certain symbols, such as punctuation. + // This heuristic is derived from hints in the JCL book and is + // not part of Unicode. It seems to be right, however. + // FIXME: we treat apostrophe as part of a word. This + // is an English-ism. + if (c != '\'' + && (type == Character.DASH_PUNCTUATION + || type == Character.START_PUNCTUATION + || type == Character.END_PUNCTUATION + || type == Character.CONNECTOR_PUNCTUATION + || type == Character.OTHER_PUNCTUATION + || type == Character.MATH_SYMBOL + || type == Character.CURRENCY_SYMBOL + || type == Character.MODIFIER_SYMBOL + || type == Character.OTHER_SYMBOL + || type == Character.FORMAT + || type == Character.CONTROL)) + break; + + boolean is_hira = isHira (c); + boolean is_kata = isKata (c); + boolean is_han = isHan (c); + + // Special case Japanese. + if (! is_hira && ! is_kata && ! is_han + && type != Character.NON_SPACING_MARK + && (isHira (n) || isKata (n) || isHan (n))) + break; + + if (is_hira || is_kata || is_han || is_letter) + { + // Now we need to do some lookahead. We might need to do + // quite a bit of lookahead, so we save our position and + // restore it later. + int save = iter.getIndex(); + // Skip string of non spacing marks. + while (n != CharacterIterator.DONE + && Character.getType(n) == Character.NON_SPACING_MARK) + n = iter.next(); + if (n == CharacterIterator.DONE) + break; + if ((is_hira && ! isHira (n)) + || (is_kata && ! isHira (n) && ! isKata (n)) + || (is_han && ! isHira (n) && ! isHan (n)) + // FIXME: we treat apostrophe as part of a word. This + // is an English-ism. + || (is_letter && ! Character.isLetter(n) && n != '\'')) + break; + iter.setIndex(save); + } + } + + return iter.getIndex(); + } + + public int previous () + { + int start = iter.getBeginIndex(); + if (iter.getIndex() == start) + return DONE; + + while (iter.getIndex() >= start) + { + char c = iter.previous(); + if (c == CharacterIterator.DONE) + break; + + boolean is_hira = isHira (c); + boolean is_kata = isKata (c); + boolean is_han = isHan (c); + boolean is_letter = Character.isLetter(c); + + char n = iter.previous(); + if (n == CharacterIterator.DONE) + break; + iter.next(); + int type = Character.getType(n); + // Break after paragraph separators. + if (type == Character.PARAGRAPH_SEPARATOR + || type == Character.LINE_SEPARATOR) + break; + + // Break between letters and non-letters. + // FIXME: we treat apostrophe as part of a word. This + // is an English-ism. + if (n != '\'' && ! Character.isLetter(n) + && type != Character.NON_SPACING_MARK + && is_letter) + break; + + // Always break after certain symbols, such as punctuation. + // This heuristic is derived from hints in the JCL book and is + // not part of Unicode. It seems to be right, however. + // FIXME: we treat apostrophe as part of a word. This + // is an English-ism. + if (n != '\'' + && (type == Character.DASH_PUNCTUATION + || type == Character.START_PUNCTUATION + || type == Character.END_PUNCTUATION + || type == Character.CONNECTOR_PUNCTUATION + || type == Character.OTHER_PUNCTUATION + || type == Character.MATH_SYMBOL + || type == Character.CURRENCY_SYMBOL + || type == Character.MODIFIER_SYMBOL + || type == Character.OTHER_SYMBOL + || type == Character.FORMAT + || type == Character.CONTROL)) + break; + + // Special case Japanese. + if ((is_hira || is_kata || is_han) + && ! isHira (n) && ! isKata (n) && ! isHan (n) + && type != Character.NON_SPACING_MARK) + break; + + // We might have to skip over non spacing marks to see what's + // on the other side. + if (! is_hira || (! is_letter && c != '\'')) + { + int save = iter.getIndex(); + while (n != CharacterIterator.DONE + && Character.getType(n) == Character.NON_SPACING_MARK) + n = iter.previous(); + iter.setIndex(save); + // This is a strange case: a bunch of non-spacing marks at + // the beginning. We treat the current location as a word + // break. + if (n == CharacterIterator.DONE) + break; + if ((isHira (n) && ! is_hira) + || (isKata (n) && ! is_hira && ! is_kata) + || (isHan (n) && ! is_hira && ! is_han) + // FIXME: we treat apostrophe as part of a word. This + // is an English-ism. + || (! is_letter && c != '\'' && Character.isLetter(n))) + break; + } + } + + return iter.getIndex(); + } +} diff --git a/libjava/classpath/gnu/java/text/package.html b/libjava/classpath/gnu/java/text/package.html new file mode 100644 index 000000000..a1025a8e9 --- /dev/null +++ b/libjava/classpath/gnu/java/text/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.text + + +

+ + + diff --git a/libjava/classpath/gnu/java/util/Base64.java b/libjava/classpath/gnu/java/util/Base64.java new file mode 100644 index 000000000..80b1fcc02 --- /dev/null +++ b/libjava/classpath/gnu/java/util/Base64.java @@ -0,0 +1,342 @@ +/* Base64.java -- Base64 encoding and decoding. + Copyright (C) 2006, 2007 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the 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.java.util; + +import gnu.java.lang.CPStringBuilder; + +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, with no line wrapping. + * + * @param buf The byte array to encode. + * @return buf encoded in Base64. + */ + public static String encode(byte[] buf) + { + return encode(buf, 0); + } + + /** + * 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) + { + return encode(buf, 0, buf.length, tw); + } + + /** + * Base64 encode a byte array, returning the returning string. + * + * @param buf The byte array to encode. + * @param offset The offset in the byte array to start. + * @param length The number of bytes 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 offset, int length, int tw) + { + if (offset < 0 || length < 0 || offset + length > buf.length) + throw new ArrayIndexOutOfBoundsException(buf.length + " " + + offset + " " + + length); + int srcLength = buf.length - offset; + byte[] input = new byte[3]; + int[] output = new int[4]; + CPStringBuilder out = new CPStringBuilder(); + int i = offset; + 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: + i++; + 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))) + { + throw new IOException("malformed Base64 sequence"); + } + } + } + } + else + { + if (state != 0) + { + throw new IOException("malformed Base64 sequence"); + } + } + + return result.toByteArray(); + } +} diff --git a/libjava/classpath/gnu/java/util/DoubleEnumeration.java b/libjava/classpath/gnu/java/util/DoubleEnumeration.java new file mode 100644 index 000000000..852644bc6 --- /dev/null +++ b/libjava/classpath/gnu/java/util/DoubleEnumeration.java @@ -0,0 +1,138 @@ +/* gnu.java.util.DoubleEnumeration + Copyright (C) 1998, 1999, 2001, 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.util; + +import java.util.Enumeration; +import java.util.NoSuchElementException; + + +/** + * This is a helper class that combines two Enumerations. + * It returns the elements of the first Enumeration until it has + * no more elements and then returns the elements of the second + * Enumeration.
+ * + * In the default case: + *
+ * doubleEnum = new DoubleEnumeration(enum1, enum2);
+ * while (doubleEnum.hasMoreElements()) {
+ *    Object o = doubleEnum.nextElement();
+ *    do_something(o);
+ * }
+ * 
+ * it calls hasMoreElements of the Enumerations as few times as + * possible. + * The references to the Enumerations are cleared as soon as they have no + * more elements to help garbage collecting. + * + * @author Jochen Hoenicke + * @author Mark Wielaard (mark@klomp.org) + */ +public class DoubleEnumeration implements Enumeration +{ + /** + * This is true as long as one of the enumerations has more + * elements. + * Only valid when hasChecked is true. + * Set in hasMoreElements() + */ + private boolean hasMore; + /** + * This is true, if it is sure that hasMore indicates wether there are + * more elements. + * Set to true in hasMoreElements(). + * Set to false in getNextElement(). + */ + private boolean hasChecked; + /** + * The first enumeration. + */ + private Enumeration e1; + /** + * The second enumeration. + */ + private Enumeration e2; + + /** + * Creates a new Enumeration combining the given two enumerations. + * The enumerations mustn't be accessed by other classes. + */ + public DoubleEnumeration(Enumeration e1, Enumeration e2) + { + this.e1 = e1; + this.e2 = e2; + hasChecked = false; + } + + /** + * Returns true, if at least one of the two enumerations has more + * elements. + */ + public boolean hasMoreElements() + { + if (hasChecked) + return hasMore; + + hasMore = (e1 != null && e1.hasMoreElements()); + + if (!hasMore) { + e1 = e2; + e2 = null; + hasMore = (e1 != null && e1.hasMoreElements()); + } + + hasChecked = true; + return hasMore; + } + + /** + * Returns the next element. This returns the next element of the + * first enumeration, if it has more elements, otherwise the next + * element of the second enumeration. If both enumeration don't have + * any elements it throws a NoSuchElementException. + */ + public T nextElement() + { + if (!hasMoreElements()) + throw new NoSuchElementException(); + else { + hasChecked = false; + return e1.nextElement(); + } + } +} diff --git a/libjava/classpath/gnu/java/util/EmptyEnumeration.java b/libjava/classpath/gnu/java/util/EmptyEnumeration.java new file mode 100644 index 000000000..30c50d81d --- /dev/null +++ b/libjava/classpath/gnu/java/util/EmptyEnumeration.java @@ -0,0 +1,90 @@ +/* EmptyEnumeration.java -- a constant empty enumeration + Copyright (C) 2001, 2002 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.util; + +import java.io.Serializable; +import java.util.Enumeration; +import java.util.NoSuchElementException; + +/** + * This is a helper class that produces an empty Enumerations. There is only + * one instance of this class that can be used whenever one needs a + * non-null but empty enumeration. Using this class prevents multiple + * small objects and inner classes. getInstance() returns + * the only instance of this class. It can be shared by multiple objects and + * threads. + * + * @author Mark Wielaard (mark@klomp.org) + */ +public final class EmptyEnumeration implements Enumeration, Serializable +{ + /** The only instance of this class */ + private static final EmptyEnumeration instance = + new EmptyEnumeration(); + + /** + * Returns an instance of this class for Object. + * It can be shared by multiple objects and threads. + * + * @return the common empty enumeration + */ + public static EmptyEnumeration getInstance() + { + return instance; + } + + /** + * Returns false, since there are no elements. + * + * @return false + */ + public boolean hasMoreElements() + { + return false; + } + + /** + * Always throws NoSuchElementException, since it is empty. + * + * @throws NoSuchElementException this is empty + */ + public T nextElement() + { + throw new NoSuchElementException(); + } +} diff --git a/libjava/classpath/gnu/java/util/LRUCache.java b/libjava/classpath/gnu/java/util/LRUCache.java new file mode 100644 index 000000000..784a442ab --- /dev/null +++ b/libjava/classpath/gnu/java/util/LRUCache.java @@ -0,0 +1,77 @@ +/* LRUCache.java -- A LRU Cache implementation + Copyright (C) 2007 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.util; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * A least recently used cache, based on LinkedHashMap. + */ +public class LRUCache + extends LinkedHashMap +{ + + /** + * The capacity of the cache. + */ + private int capacity; + + /** + * Creates a new LRUCache instance with the specified capacity. + * + * @param cap the capacity of the new cache + */ + public LRUCache(int cap) + { + super(); + capacity = cap; + } + + /** + * Returns true when the oldest entry should be removed. + * + * @param eldest the entry about to be removed + * + * @return true when the oldest entry should be removed + */ + protected boolean removeEldestEntry(Map.Entry eldest) + { + return size() > capacity; + } +} diff --git a/libjava/classpath/gnu/java/util/WeakIdentityHashMap.java b/libjava/classpath/gnu/java/util/WeakIdentityHashMap.java new file mode 100644 index 000000000..4d9014969 --- /dev/null +++ b/libjava/classpath/gnu/java/util/WeakIdentityHashMap.java @@ -0,0 +1,862 @@ +/* WeakIdentityHashMap -- an identity hashtable that keeps only weak references + to its keys, allowing the virtual machine to reclaim them + Copyright (C) 1999, 2000, 2001, 2002, 2003, 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.util; + +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; +import java.util.AbstractMap; +import java.util.AbstractSet; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; + +/** + * A weak hash map has only weak references to the key. This means that it + * allows the key to be garbage collected if it is not used otherwise. If + * this happens, the entry will eventually disappear from the map, + * asynchronously. + * + *

Other strange behaviors to be aware of: The size of this map may + * spontaneously shrink (even if you use a synchronized map and synchronize + * it); it behaves as if another thread removes entries from this table + * without synchronization. The entry set returned by entrySet + * has similar phenomenons: The size may spontaneously shrink, or an + * entry, that was in the set before, suddenly disappears. + * + *

A weak hash map is not meant for caches; use a normal map, with + * soft references as values instead, or try {@link LinkedHashMap}. + * + *

The weak hash map supports null values and null keys. The null key + * is never deleted from the map (except explictly of course). The + * performance of the methods are similar to that of a hash map. + * + *

The value objects are strongly referenced by this table. So if a + * value object maintains a strong reference to the key (either direct + * or indirect) the key will never be removed from this map. According + * to Sun, this problem may be fixed in a future release. It is not + * possible to do it with the jdk 1.2 reference model, though. + * + * @author Jochen Hoenicke + * @author Eric Blake (ebb9@email.byu.edu) + * @author Jeroen Frijters + * + * @see HashMap + * @see WeakReference + * @see WeakHashMap + * @see IdentityHashMap + * @see LinkedHashMap + */ +public class WeakIdentityHashMap extends AbstractMap implements Map +{ + /** + * The default capacity for an instance of HashMap. + * Sun's documentation mildly suggests that this (11) is the correct + * value. + */ + private static final int DEFAULT_CAPACITY = 11; + + /** + * The default load factor of a HashMap. + */ + private static final float DEFAULT_LOAD_FACTOR = 0.75F; + + /** + * This is used instead of the key value null. It is needed + * to distinguish between an null key and a removed key. + */ + // Package visible for use by nested classes. + static final Object NULL_KEY = new Object(); + + /** + * The reference queue where our buckets (which are WeakReferences) are + * registered to. + */ + private final ReferenceQueue queue; + + /** + * The number of entries in this hash map. + */ + // Package visible for use by nested classes. + int size; + + /** + * The load factor of this WeakIdentityHashMap. This is the maximum ratio of + * size versus number of buckets. If size grows the number of buckets + * must grow, too. + */ + private float loadFactor; + + /** + * The rounded product of the capacity (i.e. number of buckets) and + * the load factor. When the number of elements exceeds the + * threshold, the HashMap calls rehash(). + */ + private int threshold; + + /** + * The number of structural modifications. This is used by + * iterators, to see if they should fail. This doesn't count + * the silent key removals, when a weak reference is cleared + * by the garbage collection. Instead the iterators must make + * sure to have strong references to the entries they rely on. + */ + // Package visible for use by nested classes. + int modCount; + + /** + * The entry set. There is only one instance per hashmap, namely + * theEntrySet. Note that the entry set may silently shrink, just + * like the WeakIdentityHashMap. + */ + private final class WeakEntrySet extends AbstractSet + { + /** + * Non-private constructor to reduce bytecode emitted. + */ + WeakEntrySet() + { + } + + /** + * Returns the size of this set. + * + * @return the set size + */ + public int size() + { + return size; + } + + /** + * Returns an iterator for all entries. + * + * @return an Entry iterator + */ + public Iterator iterator() + { + return new Iterator() + { + /** + * The entry that was returned by the last + * next() call. This is also the entry whose + * bucket should be removed by the remove call.
+ * + * It is null, if the next method wasn't + * called yet, or if the entry was already removed.
+ * + * Remembering this entry here will also prevent it from + * being removed under us, since the entry strongly refers + * to the key. + */ + WeakBucket.WeakEntry lastEntry; + + /** + * The entry that will be returned by the next + * next() call. It is null if there + * is no further entry.
+ * + * Remembering this entry here will also prevent it from + * being removed under us, since the entry strongly refers + * to the key. + */ + WeakBucket.WeakEntry nextEntry = findNext(null); + + /** + * The known number of modification to the list, if it differs + * from the real number, we throw an exception. + */ + int knownMod = modCount; + + /** + * Check the known number of modification to the number of + * modifications of the table. If it differs from the real + * number, we throw an exception. + * @throws ConcurrentModificationException if the number + * of modifications doesn't match. + */ + private void checkMod() + { + // This method will get inlined. + cleanQueue(); + if (knownMod != modCount) + throw new ConcurrentModificationException(knownMod + " != " + + modCount); + } + + /** + * Get a strong reference to the next entry after + * lastBucket. + * @param lastEntry the previous bucket, or null if we should + * get the first entry. + * @return the next entry. + */ + private WeakBucket.WeakEntry findNext(WeakBucket.WeakEntry lastEntry) + { + int slot; + WeakBucket nextBucket; + if (lastEntry != null) + { + nextBucket = lastEntry.getBucket().next; + slot = lastEntry.getBucket().slot; + } + else + { + nextBucket = buckets[0]; + slot = 0; + } + + while (true) + { + while (nextBucket != null) + { + WeakBucket.WeakEntry entry = nextBucket.getEntry(); + if (entry != null) + // This is the next entry. + return entry; + + // Entry was cleared, try next. + nextBucket = nextBucket.next; + } + + slot++; + if (slot == buckets.length) + // No more buckets, we are through. + return null; + + nextBucket = buckets[slot]; + } + } + + /** + * Checks if there are more entries. + * @return true, iff there are more elements. + * @throws ConcurrentModificationException if the hash map was + * modified. + */ + public boolean hasNext() + { + checkMod(); + return nextEntry != null; + } + + /** + * Returns the next entry. + * @return the next entry. + * @throws ConcurrentModificationException if the hash map was + * modified. + * @throws NoSuchElementException if there is no entry. + */ + public Object next() + { + checkMod(); + if (nextEntry == null) + throw new NoSuchElementException(); + lastEntry = nextEntry; + nextEntry = findNext(lastEntry); + return lastEntry; + } + + /** + * Removes the last returned entry from this set. This will + * also remove the bucket of the underlying weak hash map. + * @throws ConcurrentModificationException if the hash map was + * modified. + * @throws IllegalStateException if next() was + * never called or the element was already removed. + */ + public void remove() + { + checkMod(); + if (lastEntry == null) + throw new IllegalStateException(); + modCount++; + internalRemove(lastEntry.getBucket()); + lastEntry = null; + knownMod++; + } + }; + } + } + + /** + * A bucket is a weak reference to the key, that contains a strong + * reference to the value, a pointer to the next bucket and its slot + * number.
+ * + * It would be cleaner to have a WeakReference as field, instead of + * extending it, but if a weak reference gets cleared, we only get + * the weak reference (by queue.poll) and wouldn't know where to + * look for this reference in the hashtable, to remove that entry. + * + * @author Jochen Hoenicke + */ + private static class WeakBucket extends WeakReference + { + /** + * The value of this entry. The key is stored in the weak + * reference that we extend. + */ + Object value; + + /** + * The next bucket describing another entry that uses the same + * slot. + */ + WeakBucket next; + + /** + * The slot of this entry. This should be + * Math.abs(key.hashCode() % buckets.length). + * + * But since the key may be silently removed we have to remember + * the slot number. + * + * If this bucket was removed the slot is -1. This marker will + * prevent the bucket from being removed twice. + */ + int slot; + + /** + * Creates a new bucket for the given key/value pair and the specified + * slot. + * @param key the key + * @param queue the queue the weak reference belongs to + * @param value the value + * @param slot the slot. This must match the slot where this bucket + * will be enqueued. + */ + public WeakBucket(Object key, ReferenceQueue queue, Object value, + int slot) + { + super(key, queue); + this.value = value; + this.slot = slot; + } + + /** + * This class gives the Entry representation of the + * current bucket. It also keeps a strong reference to the + * key; bad things may happen otherwise. + */ + class WeakEntry implements Map.Entry + { + /** + * The strong ref to the key. + */ + Object key; + + /** + * Creates a new entry for the key. + * @param key the key + */ + public WeakEntry(Object key) + { + this.key = key; + } + + /** + * Returns the underlying bucket. + * @return the owning bucket + */ + public WeakBucket getBucket() + { + return WeakBucket.this; + } + + /** + * Returns the key. + * @return the key + */ + public Object getKey() + { + return key == NULL_KEY ? null : key; + } + + /** + * Returns the value. + * @return the value + */ + public Object getValue() + { + return value; + } + + /** + * This changes the value. This change takes place in + * the underlying hash map. + * @param newVal the new value + * @return the old value + */ + public Object setValue(Object newVal) + { + Object oldVal = value; + value = newVal; + return oldVal; + } + + /** + * The hashCode as specified in the Entry interface. + * @return the hash code + */ + public int hashCode() + { + return System.identityHashCode(key) + ^ (value == null ? 0 : value.hashCode()); + } + + /** + * The equals method as specified in the Entry interface. + * @param o the object to compare to + * @return true iff o represents the same key/value pair + */ + public boolean equals(Object o) + { + if (o instanceof Map.Entry) + { + Map.Entry e = (Map.Entry) o; + return getKey() == e.getKey() + && (value == null ? e.getValue() == null + : value.equals(e.getValue())); + } + return false; + } + + public String toString() + { + return getKey() + "=" + value; + } + } + + /** + * This returns the entry stored in this bucket, or null, if the + * bucket got cleared in the mean time. + * @return the Entry for this bucket, if it exists + */ + WeakEntry getEntry() + { + final Object key = this.get(); + if (key == null) + return null; + return new WeakEntry(key); + } + } + + /** + * The entry set returned by entrySet(). + */ + private final WeakEntrySet theEntrySet; + + /** + * The hash buckets. These are linked lists. Package visible for use in + * nested classes. + */ + WeakBucket[] buckets; + + /** + * Creates a new weak hash map with default load factor and default + * capacity. + */ + public WeakIdentityHashMap() + { + this(DEFAULT_CAPACITY, DEFAULT_LOAD_FACTOR); + } + + /** + * Creates a new weak hash map with default load factor and the given + * capacity. + * @param initialCapacity the initial capacity + * @throws IllegalArgumentException if initialCapacity is negative + */ + public WeakIdentityHashMap(int initialCapacity) + { + this(initialCapacity, DEFAULT_LOAD_FACTOR); + } + + /** + * Creates a new weak hash map with the given initial capacity and + * load factor. + * @param initialCapacity the initial capacity. + * @param loadFactor the load factor (see class description of HashMap). + * @throws IllegalArgumentException if initialCapacity is negative, or + * loadFactor is non-positive + */ + public WeakIdentityHashMap(int initialCapacity, float loadFactor) + { + // Check loadFactor for NaN as well. + if (initialCapacity < 0 || ! (loadFactor > 0)) + throw new IllegalArgumentException(); + if (initialCapacity == 0) + initialCapacity = 1; + this.loadFactor = loadFactor; + threshold = (int) (initialCapacity * loadFactor); + theEntrySet = new WeakEntrySet(); + queue = new ReferenceQueue(); + buckets = new WeakBucket[initialCapacity]; + } + + /** + * Construct a new WeakIdentityHashMap with the same mappings as the given map. + * The WeakIdentityHashMap has a default load factor of 0.75. + * + * @param m the map to copy + * @throws NullPointerException if m is null + * @since 1.3 + */ + public WeakIdentityHashMap(Map m) + { + this(m.size(), DEFAULT_LOAD_FACTOR); + putAll(m); + } + + /** + * Simply hashes a non-null Object to its array index. + * @param key the key to hash + * @return its slot number + */ + private int hash(Object key) + { + return Math.abs(System.identityHashCode(key) % buckets.length); + } + + /** + * Cleans the reference queue. This will poll all references (which + * are WeakBuckets) from the queue and remove them from this map. + * This will not change modCount, even if it modifies the map. The + * iterators have to make sure that nothing bad happens.
+ * + * Currently the iterator maintains a strong reference to the key, so + * that is no problem. + */ + // Package visible for use by nested classes. + void cleanQueue() + { + Object bucket = queue.poll(); + while (bucket != null) + { + internalRemove((WeakBucket) bucket); + bucket = queue.poll(); + } + } + + /** + * Rehashes this hashtable. This will be called by the + * add() method if the size grows beyond the threshold. + * It will grow the bucket size at least by factor two and allocates + * new buckets. + */ + private void rehash() + { + WeakBucket[] oldBuckets = buckets; + int newsize = buckets.length * 2 + 1; // XXX should be prime. + threshold = (int) (newsize * loadFactor); + buckets = new WeakBucket[newsize]; + + // Now we have to insert the buckets again. + for (int i = 0; i < oldBuckets.length; i++) + { + WeakBucket bucket = oldBuckets[i]; + WeakBucket nextBucket; + while (bucket != null) + { + nextBucket = bucket.next; + + Object key = bucket.get(); + if (key == null) + { + // This bucket should be removed; it is probably + // already on the reference queue. We don't insert it + // at all, and mark it as cleared. + bucket.slot = -1; + size--; + } + else + { + // Add this bucket to its new slot. + int slot = hash(key); + bucket.slot = slot; + bucket.next = buckets[slot]; + buckets[slot] = bucket; + } + bucket = nextBucket; + } + } + } + + /** + * Finds the entry corresponding to key. Since it returns an Entry + * it will also prevent the key from being removed under us. + * @param key the key, may be null + * @return The WeakBucket.WeakEntry or null, if the key wasn't found. + */ + private WeakBucket.WeakEntry internalGet(Object key) + { + if (key == null) + key = NULL_KEY; + int slot = hash(key); + WeakBucket bucket = buckets[slot]; + while (bucket != null) + { + WeakBucket.WeakEntry entry = bucket.getEntry(); + if (entry != null && key == entry.key) + return entry; + + bucket = bucket.next; + } + return null; + } + + /** + * Adds a new key/value pair to the hash map. + * @param key the key. This mustn't exists in the map. It may be null. + * @param value the value. + */ + private void internalAdd(Object key, Object value) + { + if (key == null) + key = NULL_KEY; + int slot = hash(key); + WeakBucket bucket = new WeakBucket(key, queue, value, slot); + bucket.next = buckets[slot]; + buckets[slot] = bucket; + size++; + } + + /** + * Removes a bucket from this hash map, if it wasn't removed before + * (e.g. one time through rehashing and one time through reference queue). + * Package visible for use in nested classes. + * + * @param bucket the bucket to remove. + */ + void internalRemove(WeakBucket bucket) + { + int slot = bucket.slot; + if (slot == -1) + // This bucket was already removed. + return; + + // Mark the bucket as removed. This is necessary, since the + // bucket may be enqueued later by the garbage collection, and + // internalRemove will be called a second time. + bucket.slot = -1; + + WeakBucket prev = null; + WeakBucket next = buckets[slot]; + while (next != bucket) + { + if (next == null) + throw new InternalError("WeakIdentityHashMap in inconsistent state"); + prev = next; + next = prev.next; + } + if (prev == null) + buckets[slot] = bucket.next; + else + prev.next = bucket.next; + + size--; + } + + /** + * Returns the size of this hash map. Note that the size() may shrink + * spontaneously, if the some of the keys were only weakly reachable. + * @return the number of entries in this hash map. + */ + public int size() + { + cleanQueue(); + return size; + } + + /** + * Tells if the map is empty. Note that the result may change + * spontanously, if all of the keys were only weakly reachable. + * @return true, iff the map is empty. + */ + public boolean isEmpty() + { + cleanQueue(); + return size == 0; + } + + /** + * Tells if the map contains the given key. Note that the result + * may change spontanously, if the key was only weakly + * reachable. + * @param key the key to look for + * @return true, iff the map contains an entry for the given key. + */ + public boolean containsKey(Object key) + { + cleanQueue(); + return internalGet(key) != null; + } + + /** + * Gets the value the key is mapped to. + * @return the value the key was mapped to. It returns null if + * the key wasn't in this map, or if the mapped value was + * explicitly set to null. + */ + public Object get(Object key) + { + cleanQueue(); + WeakBucket.WeakEntry entry = internalGet(key); + return entry == null ? null : entry.getValue(); + } + + /** + * Adds a new key/value mapping to this map. + * @param key the key, may be null + * @param value the value, may be null + * @return the value the key was mapped to previously. It returns + * null if the key wasn't in this map, or if the mapped value + * was explicitly set to null. + */ + public Object put(Object key, Object value) + { + cleanQueue(); + WeakBucket.WeakEntry entry = internalGet(key); + if (entry != null) + return entry.setValue(value); + + modCount++; + if (size >= threshold) + rehash(); + + internalAdd(key, value); + return null; + } + + /** + * Removes the key and the corresponding value from this map. + * @param key the key. This may be null. + * @return the value the key was mapped to previously. It returns + * null if the key wasn't in this map, or if the mapped value was + * explicitly set to null. + */ + public Object remove(Object key) + { + cleanQueue(); + WeakBucket.WeakEntry entry = internalGet(key); + if (entry == null) + return null; + + modCount++; + internalRemove(entry.getBucket()); + return entry.getValue(); + } + + /** + * Returns a set representation of the entries in this map. This + * set will not have strong references to the keys, so they can be + * silently removed. The returned set has therefore the same + * strange behaviour (shrinking size(), disappearing entries) as + * this weak hash map. + * @return a set representation of the entries. + */ + public Set entrySet() + { + cleanQueue(); + return theEntrySet; + } + + /** + * Clears all entries from this map. + */ + public void clear() + { + super.clear(); + } + + /** + * Returns true if the map contains at least one key which points to + * the specified object as a value. Note that the result + * may change spontanously, if its key was only weakly reachable. + * @param value the value to search for + * @return true if it is found in the set. + */ + public boolean containsValue(Object value) + { + cleanQueue(); + return super.containsValue(value); + } + + /** + * Returns a set representation of the keys in this map. This + * set will not have strong references to the keys, so they can be + * silently removed. The returned set has therefore the same + * strange behaviour (shrinking size(), disappearing entries) as + * this weak hash map. + * @return a set representation of the keys. + */ + public Set keySet() + { + cleanQueue(); + return super.keySet(); + } + + /** + * Puts all of the mappings from the given map into this one. If the + * key already exists in this map, its value is replaced. + * @param m the map to copy in + */ + public void putAll(Map m) + { + super.putAll(m); + } + + /** + * Returns a collection representation of the values in this map. This + * collection will not have strong references to the keys, so mappings + * can be silently removed. The returned collection has therefore the same + * strange behaviour (shrinking size(), disappearing entries) as + * this weak hash map. + * @return a collection representation of the values. + */ + public Collection values() + { + cleanQueue(); + return super.values(); + } +} // class WeakIdentityHashMap diff --git a/libjava/classpath/gnu/java/util/ZoneInfo.java b/libjava/classpath/gnu/java/util/ZoneInfo.java new file mode 100644 index 000000000..117ef3cf2 --- /dev/null +++ b/libjava/classpath/gnu/java/util/ZoneInfo.java @@ -0,0 +1,1160 @@ +/* gnu.java.util.ZoneInfo + Copyright (C) 2007 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.util; + +import java.io.BufferedInputStream; +import java.io.DataInputStream; +import java.io.EOFException; +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.SimpleTimeZone; +import java.util.TimeZone; + +/** + * This class represents more advanced variant of java.util.SimpleTimeZone. + * It can handle zic(8) compiled transition dates plus uses a SimpleTimeZone + * for years beyond last precomputed transition. Before first precomputed + * transition it assumes no daylight saving was in effect. + * Timezones that never used daylight saving time should use just + * SimpleTimeZone instead of this class. + * + * This object is tightly bound to the Gregorian calendar. It assumes + * a regular seven days week, and the month lengths are that of the + * Gregorian Calendar. + * + * @see Calendar + * @see GregorianCalendar + * @see SimpleTimeZone + * @author Jakub Jelinek + */ +public class ZoneInfo extends TimeZone +{ + private static final int SECS_SHIFT = 22; + private static final long OFFSET_MASK = (1 << 21) - 1; + private static final int OFFSET_SHIFT = 64 - 21; + private static final long IS_DST = 1 << 21; + + /** + * The raw time zone offset in milliseconds to GMT, ignoring + * daylight savings. + * @serial + */ + private int rawOffset; + + /** + * Cached DST savings for the last transition rule. + */ + private int dstSavings; + + /** + * Cached flag whether last transition rule uses DST saving. + */ + private boolean useDaylight; + + /** + * Array of encoded transitions. + * Transition time in UTC seconds since epoch is in the most + * significant 64 - SECS_SHIFT bits, then one bit flag + * whether DST is active and the least significant bits + * containing offset relative to rawOffset. Both the DST + * flag and relative offset apply to time before the transition + * and after or equal to previous transition if any. + * The array must be sorted. + */ + private long[] transitions; + + /** + * SimpleTimeZone rule which applies on or after the latest + * transition. If the DST changes are not expresible as a + * SimpleTimeZone rule, then the rule should just contain + * the standard time and no DST time. + */ + private SimpleTimeZone lastRule; + + /** + * Cached GMT SimpleTimeZone object for internal use in + * getOffset method. + */ + private static SimpleTimeZone gmtZone = null; + + static final long serialVersionUID = -3740626706860383657L; + + /** + * Create a ZoneInfo with the given time offset + * from GMT and with daylight savings. + * + * @param rawOffset The time offset from GMT in milliseconds. + * @param id The identifier of this time zone. + * @param transitions Array of transition times in UTC seconds since + * Epoch in topmost 42 bits, below that 1 boolean bit whether the time + * before that transition used daylight saving and in bottommost 21 + * bits relative daylight saving offset against rawOffset in seconds + * that applies before this transition. + * @param endRule SimpleTimeZone class describing the daylight saving + * rules after the last transition. + */ + public ZoneInfo(int rawOffset, String id, long[] transitions, + SimpleTimeZone lastRule) + { + if (transitions == null || transitions.length < 1) + throw new IllegalArgumentException("transitions must not be null"); + if (lastRule == null) + throw new IllegalArgumentException("lastRule must not be null"); + this.rawOffset = rawOffset; + this.transitions = transitions; + this.lastRule = lastRule; + setID(id); + computeDSTSavings(); + } + + /** + * Gets the time zone offset, for current date, modified in case of + * daylight savings. This is the offset to add to UTC to get the local + * time. + * + * The day must be a positive number and dayOfWeek must be a positive value + * from Calendar. dayOfWeek is redundant, but must match the other values + * or an inaccurate result may be returned. + * + * @param era the era of the given date + * @param year the year of the given date + * @param month the month of the given date, 0 for January. + * @param day the day of month + * @param dayOfWeek the day of week; this must match the other fields. + * @param millis the millis in the day (in local standard time) + * @return the time zone offset in milliseconds. + * @throws IllegalArgumentException if arguments are incorrect. + */ + public int getOffset(int era, int year, int month, int day, int dayOfWeek, + int millis) + { + if (gmtZone == null) + gmtZone = new SimpleTimeZone(0, "GMT"); + + if (dayOfWeek < Calendar.SUNDAY || dayOfWeek > Calendar.SATURDAY) + throw new IllegalArgumentException("dayOfWeek out of range"); + if (month < Calendar.JANUARY || month > Calendar.DECEMBER) + throw new IllegalArgumentException("month out of range:" + month); + + if (era != GregorianCalendar.AD) + return (int) (((transitions[0] << OFFSET_SHIFT) >> OFFSET_SHIFT) * 1000); + + GregorianCalendar cal = new GregorianCalendar((TimeZone) gmtZone); + cal.set(year, month, day, 0, 0, 0); + if (cal.get(Calendar.DAY_OF_MONTH) != day) + throw new IllegalArgumentException("day out of range"); + + return getOffset(cal.getTimeInMillis() - rawOffset + millis); + } + + private long findTransition(long secs) + { + if (secs < (transitions[0] >> SECS_SHIFT)) + return transitions[0]; + + if (secs >= (transitions[transitions.length-1] >> SECS_SHIFT)) + return Long.MAX_VALUE; + + long val = (secs + 1) << SECS_SHIFT; + int lo = 1; + int hi = transitions.length; + int mid = 1; + while (lo < hi) + { + mid = (lo + hi) / 2; + // secs < (transitions[mid-1] >> SECS_SHIFT) + if (val <= transitions[mid-1]) + hi = mid; + // secs >= (transitions[mid] >> SECS_SHIFT) + else if (val > transitions[mid]) + lo = mid + 1; + else + break; + } + return transitions[mid]; + } + + /** + * Get the time zone offset for the specified date, modified in case of + * daylight savings. This is the offset to add to UTC to get the local + * time. + * @param date the date represented in millisecends + * since January 1, 1970 00:00:00 GMT. + */ + public int getOffset(long date) + { + long d = (date >= 0 ? date / 1000 : (date + 1) / 1000 - 1); + long transition = findTransition(d); + + // For times on or after last transition use lastRule. + if (transition == Long.MAX_VALUE) + return lastRule.getOffset(date); + + return (int) (((transition << OFFSET_SHIFT) >> OFFSET_SHIFT) * 1000); + } + + /** + * Returns the time zone offset to GMT in milliseconds, ignoring + * day light savings. + * @return the time zone offset. + */ + public int getRawOffset() + { + return rawOffset; + } + + /** + * Sets the standard time zone offset to GMT. + * @param rawOffset The time offset from GMT in milliseconds. + */ + public void setRawOffset(int rawOffset) + { + this.rawOffset = rawOffset; + lastRule.setRawOffset(rawOffset); + } + + private void computeDSTSavings() + { + if (lastRule.useDaylightTime()) + { + dstSavings = lastRule.getDSTSavings(); + useDaylight = true; + } + else + { + dstSavings = 0; + useDaylight = false; + // lastRule might say no DST is in effect simply because + // the DST rules are too complex for SimpleTimeZone, say + // for Asia/Jerusalem. + // Look at the last DST offset if it is newer than current time. + long currentSecs = System.currentTimeMillis() / 1000; + int i; + for (i = transitions.length - 1; + i >= 0 && currentSecs < (transitions[i] >> SECS_SHIFT); + i--) + if ((transitions[i] & IS_DST) != 0) + { + dstSavings = (int) (((transitions[i] << OFFSET_SHIFT) + >> OFFSET_SHIFT) * 1000) + - rawOffset; + useDaylight = true; + break; + } + } + } + + /** + * Gets the daylight savings offset. This is a positive offset in + * milliseconds with respect to standard time. Typically this + * is one hour, but for some time zones this may be half an our. + * @return the daylight savings offset in milliseconds. + */ + public int getDSTSavings() + { + return dstSavings; + } + + /** + * Returns if this time zone uses daylight savings time. + * @return true, if we use daylight savings time, false otherwise. + */ + public boolean useDaylightTime() + { + return useDaylight; + } + + /** + * Determines if the given date is in daylight savings time. + * @return true, if it is in daylight savings time, false otherwise. + */ + public boolean inDaylightTime(Date date) + { + long d = date.getTime(); + d = (d >= 0 ? d / 1000 : (d + 1) / 1000 - 1); + long transition = findTransition(d); + + // For times on or after last transition use lastRule. + if (transition == Long.MAX_VALUE) + return lastRule.inDaylightTime(date); + + return (transition & IS_DST) != 0; + } + + /** + * Generates the hashCode for the SimpleDateFormat object. It is + * the rawOffset, possibly, if useDaylightSavings is true, xored + * with startYear, startMonth, startDayOfWeekInMonth, ..., endTime. + */ + public synchronized int hashCode() + { + int hash = lastRule.hashCode(); + // FIXME - hash transitions? + return hash; + } + + public synchronized boolean equals(Object o) + { + if (! hasSameRules((TimeZone) o)) + return false; + + ZoneInfo zone = (ZoneInfo) o; + return getID().equals(zone.getID()); + } + + /** + * Test if the other time zone uses the same rule and only + * possibly differs in ID. This implementation for this particular + * class will return true if the other object is a ZoneInfo, + * the raw offsets and useDaylight are identical and if useDaylight + * is true, also the start and end datas are identical. + * @return true if this zone uses the same rule. + */ + public boolean hasSameRules(TimeZone o) + { + if (this == o) + return true; + if (! (o instanceof ZoneInfo)) + return false; + ZoneInfo zone = (ZoneInfo) o; + if (zone.hashCode() != hashCode() || rawOffset != zone.rawOffset) + return false; + if (! lastRule.equals(zone.lastRule)) + return false; + // FIXME - compare transitions? + return true; + } + + /** + * Returns a string representation of this ZoneInfo object. + * @return a string representation of this ZoneInfo object. + */ + public String toString() + { + return getClass().getName() + "[" + "id=" + getID() + ",offset=" + + rawOffset + ",transitions=" + transitions.length + + ",useDaylight=" + useDaylight + + (useDaylight ? (",dstSavings=" + dstSavings) : "") + + ",lastRule=" + lastRule.toString() + "]"; + } + + /** + * Reads zic(8) compiled timezone data file from file + * and returns a TimeZone class describing it, either + * SimpleTimeZone or ZoneInfo depending on whether + * it can be described by SimpleTimeZone rule or not. + */ + public static TimeZone readTZFile(String id, String file) + { + DataInputStream dis = null; + try + { + FileInputStream fis = new FileInputStream(file); + BufferedInputStream bis = new BufferedInputStream(fis); + dis = new DataInputStream(bis); + + // Make sure we are reading a tzfile. + byte[] tzif = new byte[5]; + dis.readFully(tzif); + int tzif2 = 4; + if (tzif[0] == 'T' && tzif[1] == 'Z' + && tzif[2] == 'i' && tzif[3] == 'f') + { + if (tzif[4] >= '2') + tzif2 = 8; + // Reserved bytes + skipFully(dis, 16 - 1); + } + else + // Darwin has tzdata files that don't start with the TZif marker + skipFully(dis, 16 - 5); + + int ttisgmtcnt = dis.readInt(); + int ttisstdcnt = dis.readInt(); + int leapcnt = dis.readInt(); + int timecnt = dis.readInt(); + int typecnt = dis.readInt(); + int charcnt = dis.readInt(); + if (tzif2 == 8) + { + skipFully(dis, timecnt * (4 + 1) + typecnt * (4 + 1 + 1) + charcnt + + leapcnt * (4 + 4) + ttisgmtcnt + ttisstdcnt); + + dis.readFully(tzif); + if (tzif[0] != 'T' || tzif[1] != 'Z' || tzif[2] != 'i' + || tzif[3] != 'f' || tzif[4] < '2') + return null; + + // Reserved bytes + skipFully(dis, 16 - 1); + ttisgmtcnt = dis.readInt(); + ttisstdcnt = dis.readInt(); + leapcnt = dis.readInt(); + timecnt = dis.readInt(); + typecnt = dis.readInt(); + charcnt = dis.readInt(); + } + + // Sanity checks + if (typecnt <= 0 || timecnt < 0 || charcnt < 0 + || leapcnt < 0 || ttisgmtcnt < 0 || ttisstdcnt < 0 + || ttisgmtcnt > typecnt || ttisstdcnt > typecnt) + return null; + + // Transition times + long[] times = new long[timecnt]; + for (int i = 0; i < timecnt; i++) + if (tzif2 == 8) + times[i] = dis.readLong(); + else + times[i] = (long) dis.readInt(); + + // Transition types + int[] types = new int[timecnt]; + for (int i = 0; i < timecnt; i++) + { + types[i] = dis.readByte(); + if (types[i] < 0) + types[i] += 256; + if (types[i] >= typecnt) + return null; + } + + // Types + int[] offsets = new int[typecnt]; + int[] typeflags = new int[typecnt]; + for (int i = 0; i < typecnt; i++) + { + offsets[i] = dis.readInt(); + if (offsets[i] >= IS_DST / 2 || offsets[i] <= -IS_DST / 2) + return null; + int dst = dis.readByte(); + int abbrind = dis.readByte(); + if (abbrind < 0) + abbrind += 256; + if (abbrind >= charcnt) + return null; + typeflags[i] = (dst != 0 ? (1 << 8) : 0) + abbrind; + } + + // Abbrev names + byte[] names = new byte[charcnt]; + dis.readFully(names); + + // Leap transitions, for now ignore + skipFully(dis, leapcnt * (tzif2 + 4) + ttisstdcnt + ttisgmtcnt); + + // tzIf2 format has optional POSIX TZ env string + String tzstr = null; + if (tzif2 == 8 && dis.readByte() == '\n') + { + tzstr = dis.readLine(); + if (tzstr.length() <= 0) + tzstr = null; + } + + // Get std/dst_offset and dst/non-dst time zone names. + int std_ind = -1; + int dst_ind = -1; + if (timecnt == 0) + std_ind = 0; + else + for (int i = timecnt - 1; i >= 0; i--) + { + if (std_ind == -1 && (typeflags[types[i]] & (1 << 8)) == 0) + std_ind = types[i]; + else if (dst_ind == -1 && (typeflags[types[i]] & (1 << 8)) != 0) + dst_ind = types[i]; + if (dst_ind != -1 && std_ind != -1) + break; + } + + if (std_ind == -1) + return null; + + int j = typeflags[std_ind] & 255; + while (j < charcnt && names[j] != 0) + j++; + String std_zonename = new String(names, typeflags[std_ind] & 255, + j - (typeflags[std_ind] & 255), + "ASCII"); + + String dst_zonename = ""; + if (dst_ind != -1) + { + j = typeflags[dst_ind] & 255; + while (j < charcnt && names[j] != 0) + j++; + dst_zonename = new String(names, typeflags[dst_ind] & 255, + j - (typeflags[dst_ind] & 255), "ASCII"); + } + + // Only use gmt offset when necessary. + // Also special case GMT+/- timezones. + String std_offset_string = ""; + String dst_offset_string = ""; + if (tzstr == null + && (dst_ind != -1 + || (offsets[std_ind] != 0 + && !std_zonename.startsWith("GMT+") + && !std_zonename.startsWith("GMT-")))) + { + std_offset_string = Integer.toString(-offsets[std_ind] / 3600); + int seconds = -offsets[std_ind] % 3600; + if (seconds != 0) + { + if (seconds < 0) + seconds *= -1; + if (seconds < 600) + std_offset_string += ":0" + Integer.toString(seconds / 60); + else + std_offset_string += ":" + Integer.toString(seconds / 60); + seconds = seconds % 60; + if (seconds >= 10) + std_offset_string += ":" + Integer.toString(seconds); + else if (seconds > 0) + std_offset_string += ":0" + Integer.toString(seconds); + } + + if (dst_ind != -1 && offsets[dst_ind] != offsets[std_ind] + 3600) + { + dst_offset_string = Integer.toString(-offsets[dst_ind] / 3600); + seconds = -offsets[dst_ind] % 3600; + if (seconds != 0) + { + if (seconds < 0) + seconds *= -1; + if (seconds < 600) + dst_offset_string + += ":0" + Integer.toString(seconds / 60); + else + dst_offset_string + += ":" + Integer.toString(seconds / 60); + seconds = seconds % 60; + if (seconds >= 10) + dst_offset_string += ":" + Integer.toString(seconds); + else if (seconds > 0) + dst_offset_string += ":0" + Integer.toString(seconds); + } + } + } + + /* + * If no tzIf2 POSIX TZ string is available and the timezone + * uses DST, try to guess the last rule by trying to make + * sense from transitions at 5 years in the future and onwards. + * tzdata actually uses only 3 forms of rules: + * fixed date within a month, e.g. change on April, 5th + * 1st weekday on or after Nth: change on Sun>=15 in April + * last weekday in a month: change on lastSun in April + */ + String[] change_spec = { null, null }; + if (tzstr == null && dst_ind != -1 && timecnt > 10) + { + long nowPlus5y = System.currentTimeMillis() / 1000 + + 5 * 365 * 86400; + int first; + + for (first = timecnt - 1; first >= 0; first--) + if (times[first] < nowPlus5y + || (types[first] != std_ind && types[first] != dst_ind) + || types[first] != types[timecnt - 2 + ((first ^ timecnt) & 1)]) + break; + first++; + + if (timecnt - first >= 10 && types[timecnt - 1] != types[timecnt - 2]) + { + GregorianCalendar cal + = new GregorianCalendar(new SimpleTimeZone(0, "GMT")); + + int[] values = new int[2 * 11]; + int i; + for (i = timecnt - 1; i >= first; i--) + { + int base = (i % 2) * 11; + int offset = offsets[types[i > first ? i - 1 : i + 1]]; + cal.setTimeInMillis((times[i] + offset) * 1000); + if (i >= timecnt - 2) + { + values[base + 0] = cal.get(Calendar.YEAR); + values[base + 1] = cal.get(Calendar.MONTH); + values[base + 2] = cal.get(Calendar.DAY_OF_MONTH); + values[base + 3] + = cal.getActualMaximum(Calendar.DAY_OF_MONTH); + values[base + 4] = cal.get(Calendar.DAY_OF_WEEK); + values[base + 5] = cal.get(Calendar.HOUR_OF_DAY); + values[base + 6] = cal.get(Calendar.MINUTE); + values[base + 7] = cal.get(Calendar.SECOND); + values[base + 8] = values[base + 2]; // Range start + values[base + 9] = values[base + 2]; // Range end + values[base + 10] = 0; // Determined type + } + else + { + int year = cal.get(Calendar.YEAR); + int month = cal.get(Calendar.MONTH); + int day_of_month = cal.get(Calendar.DAY_OF_MONTH); + int month_days + = cal.getActualMaximum(Calendar.DAY_OF_MONTH); + int day_of_week = cal.get(Calendar.DAY_OF_WEEK); + int hour = cal.get(Calendar.HOUR_OF_DAY); + int minute = cal.get(Calendar.MINUTE); + int second = cal.get(Calendar.SECOND); + if (year != values[base + 0] - 1 + || month != values[base + 1] + || hour != values[base + 5] + || minute != values[base + 6] + || second != values[base + 7]) + break; + if (day_of_week == values[base + 4]) + { + // Either a Sun>=8 or lastSun rule. + if (day_of_month < values[base + 8]) + values[base + 8] = day_of_month; + if (day_of_month > values[base + 9]) + values[base + 9] = day_of_month; + if (values[base + 10] < 0) + break; + if (values[base + 10] == 0) + { + values[base + 10] = 1; + // If day of month > 28, this is + // certainly lastSun rule. + if (values[base + 2] > 28) + values[base + 2] = 3; + // If day of month isn't in the last + // week, it can't be lastSun rule. + else if (values[base + 2] + <= values[base + 3] - 7) + values[base + 3] = 2; + } + if (values[base + 10] == 1) + { + // If day of month is > 28, this is + // certainly lastSun rule. + if (day_of_month > 28) + values[base + 10] = 3; + // If day of month isn't in the last + // week, it can't be lastSun rule. + else if (day_of_month <= month_days - 7) + values[base + 10] = 2; + } + else if ((values[base + 10] == 2 + && day_of_month > 28) + || (values[base + 10] == 3 + && day_of_month <= month_days - 7)) + break; + } + else + { + // Must be fixed day in month rule. + if (day_of_month != values[base + 2] + || values[base + 10] > 0) + break; + values[base + 4] = day_of_week; + values[base + 10] = -1; + } + values[base + 0] -= 1; + } + } + + if (i < first) + { + for (i = 0; i < 2; i++) + { + int base = 11 * i; + if (values[base + 10] == 0) + continue; + if (values[base + 10] == -1) + { + int[] dayCount + = { 0, 31, 59, 90, 120, 151, + 181, 212, 243, 273, 304, 334 }; + int d = dayCount[values[base + 1] + - Calendar.JANUARY]; + d += values[base + 2]; + change_spec[i] = ",J" + Integer.toString(d); + } + else if (values[base + 10] == 2) + { + // If we haven't seen all days of the week, + // we can't be sure what the rule really is. + if (values[base + 8] + 6 != values[base + 9]) + continue; + + int d; + d = values[base + 1] - Calendar.JANUARY + 1; + // E.g. Sun >= 5 is not representable in POSIX + // TZ env string, use ",Am.n.d" extension + // where m is month 1 .. 12, n is the date on + // or after which it happens and d is day + // of the week, 0 .. 6. So Sun >= 5 in April + // is ",A4.5.0". + if ((values[base + 8] % 7) == 1) + { + change_spec[i] = ",M" + Integer.toString(d); + d = (values[base + 8] + 6) / 7; + } + else + { + change_spec[i] = ",A" + Integer.toString(d); + d = values[base + 8]; + } + change_spec[i] += "." + Integer.toString(d); + d = values[base + 4] - Calendar.SUNDAY; + change_spec[i] += "." + Integer.toString(d); + } + else + { + // If we don't know whether this is lastSun or + // Sun >= 22 rule. That can be either because + // there was insufficient number of + // transitions, or February, where it is quite + // probable we haven't seen any 29th dates. + // For February, assume lastSun rule, otherwise + // punt. + if (values[base + 10] == 1 + && values[base + 1] != Calendar.FEBRUARY) + continue; + + int d; + d = values[base + 1] - Calendar.JANUARY + 1; + change_spec[i] = ",M" + Integer.toString(d); + d = values[base + 4] - Calendar.SUNDAY; + change_spec[i] += ".5." + Integer.toString(d); + } + + // Don't add time specification if time is + // 02:00:00. + if (values[base + 5] != 2 + || values[base + 6] != 0 + || values[base + 7] != 0) + { + int d = values[base + 5]; + change_spec[i] += "/" + Integer.toString(d); + if (values[base + 6] != 0 || values[base + 7] != 0) + { + d = values[base + 6]; + if (d < 10) + change_spec[i] + += ":0" + Integer.toString(d); + else + change_spec[i] += ":" + Integer.toString(d); + d = values[base + 7]; + if (d >= 10) + change_spec[i] + += ":" + Integer.toString(d); + else if (d > 0) + change_spec[i] + += ":0" + Integer.toString(d); + } + } + } + if (types[(timecnt - 1) & -2] == std_ind) + { + String tmp = change_spec[0]; + change_spec[0] = change_spec[1]; + change_spec[1] = tmp; + } + } + } + } + + if (tzstr == null) + { + tzstr = std_zonename + std_offset_string; + if (change_spec[0] != null && change_spec[1] != null) + tzstr += dst_zonename + dst_offset_string + + change_spec[0] + change_spec[1]; + } + + if (timecnt == 0) + return new SimpleTimeZone(offsets[std_ind] * 1000, + id != null ? id : tzstr); + + SimpleTimeZone endRule = createLastRule(tzstr); + if (endRule == null) + return null; + + /* Finally adjust the times array into the form the constructor + * expects. times[0] is special, the offset and DST flag there + * are for all times before that transition. Use the first non-DST + * type. For all other transitions, the data file has the type + * () for the time interval starting + */ + for (int i = 0; i < typecnt; i++) + if ((typeflags[i] & (1 << 8)) == 0) + { + times[0] = (times[0] << SECS_SHIFT) | (offsets[i] & OFFSET_MASK); + break; + } + + for (int i = 1; i < timecnt; i++) + times[i] = (times[i] << SECS_SHIFT) + | (offsets[types[i - 1]] & OFFSET_MASK) + | ((typeflags[types[i - 1]] & (1 << 8)) != 0 ? IS_DST : 0); + + return new ZoneInfo(offsets[std_ind] * 1000, id != null ? id : tzstr, + times, endRule); + } + catch (IOException ioe) + { + // Parse error, not a proper tzfile. + return null; + } + finally + { + try + { + if (dis != null) + dis.close(); + } + catch(IOException ioe) + { + // Error while close, nothing we can do. + } + } + } + + /** + * Skips the requested number of bytes in the given InputStream. + * Throws EOFException if not enough bytes could be skipped. + * Negative numbers of bytes to skip are ignored. + */ + private static void skipFully(InputStream is, long l) throws IOException + { + while (l > 0) + { + long k = is.skip(l); + if (k <= 0) + throw new EOFException(); + l -= k; + } + } + + /** + * Create a SimpleTimeZone from a POSIX TZ environment string, + * see http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html + * for details. + * It supports also an extension, where Am.n.d rule (m 1 .. 12, n 1 .. 25, d + * 0 .. 6) describes day of week d on or after nth day of month m. + * Say A4.5.0 is Sun>=5 in April. + */ + private static SimpleTimeZone createLastRule(String tzstr) + { + String stdName = null; + int stdOffs; + int dstOffs; + try + { + int idLength = tzstr.length(); + + int index = 0; + int prevIndex; + char c; + + // get std + do + c = tzstr.charAt(index); + while (c != '+' && c != '-' && c != ',' && c != ':' + && ! Character.isDigit(c) && c != '\0' && ++index < idLength); + + if (index >= idLength) + return new SimpleTimeZone(0, tzstr); + + stdName = tzstr.substring(0, index); + prevIndex = index; + + // get the std offset + do + c = tzstr.charAt(index++); + while ((c == '-' || c == '+' || c == ':' || Character.isDigit(c)) + && index < idLength); + if (index < idLength) + index--; + + { // convert the dst string to a millis number + String offset = tzstr.substring(prevIndex, index); + prevIndex = index; + + if (offset.charAt(0) == '+' || offset.charAt(0) == '-') + stdOffs = parseTime(offset.substring(1)); + else + stdOffs = parseTime(offset); + + if (offset.charAt(0) == '-') + stdOffs = -stdOffs; + + // TZ timezone offsets are positive when WEST of the meridian. + stdOffs = -stdOffs; + } + + // Done yet? (Format: std offset) + if (index >= idLength) + return new SimpleTimeZone(stdOffs, stdName); + + // get dst + do + c = tzstr.charAt(index); + while (c != '+' && c != '-' && c != ',' && c != ':' + && ! Character.isDigit(c) && c != '\0' && ++index < idLength); + + // Done yet? (Format: std offset dst) + if (index >= idLength) + return new SimpleTimeZone(stdOffs, stdName); + + // get the dst offset + prevIndex = index; + do + c = tzstr.charAt(index++); + while ((c == '-' || c == '+' || c == ':' || Character.isDigit(c)) + && index < idLength); + if (index < idLength) + index--; + + if (index == prevIndex && (c == ',' || c == ';')) + { + // Missing dst offset defaults to one hour ahead of standard + // time. + dstOffs = stdOffs + 60 * 60 * 1000; + } + else + { // convert the dst string to a millis number + String offset = tzstr.substring(prevIndex, index); + prevIndex = index; + + if (offset.charAt(0) == '+' || offset.charAt(0) == '-') + dstOffs = parseTime(offset.substring(1)); + else + dstOffs = parseTime(offset); + + if (offset.charAt(0) == '-') + dstOffs = -dstOffs; + + // TZ timezone offsets are positive when WEST of the meridian. + dstOffs = -dstOffs; + } + + // Done yet? (Format: std offset dst offset) + if (index >= idLength) + return new SimpleTimeZone(stdOffs, stdName); + + // get the DST rule + if (tzstr.charAt(index) == ',' + || tzstr.charAt(index) == ';') + { + index++; + int offs = index; + while (tzstr.charAt(index) != ',' + && tzstr.charAt(index) != ';') + index++; + String startTime = tzstr.substring(offs, index); + index++; + String endTime = tzstr.substring(index); + + index = startTime.indexOf('/'); + int startMillis; + int endMillis; + String startDate; + String endDate; + if (index != -1) + { + startDate = startTime.substring(0, index); + startMillis = parseTime(startTime.substring(index + 1)); + } + else + { + startDate = startTime; + // if time isn't given, default to 2:00:00 AM. + startMillis = 2 * 60 * 60 * 1000; + } + index = endTime.indexOf('/'); + if (index != -1) + { + endDate = endTime.substring(0, index); + endMillis = parseTime(endTime.substring(index + 1)); + } + else + { + endDate = endTime; + // if time isn't given, default to 2:00:00 AM. + endMillis = 2 * 60 * 60 * 1000; + } + + int[] start = getDateParams(startDate); + int[] end = getDateParams(endDate); + return new SimpleTimeZone(stdOffs, tzstr, start[0], start[1], + start[2], startMillis, end[0], end[1], + end[2], endMillis, (dstOffs - stdOffs)); + } + } + + catch (IndexOutOfBoundsException _) + { + } + catch (NumberFormatException _) + { + } + + return null; + } + + /** + * Parses and returns the params for a POSIX TZ date field, + * in the format int[]{ month, day, dayOfWeek }, following the + * SimpleTimeZone constructor rules. + */ + private static int[] getDateParams(String date) + { + int[] dayCount = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; + int month; + int type = 0; + + if (date.charAt(0) == 'M' || date.charAt(0) == 'm') + type = 1; + else if (date.charAt(0) == 'A' || date.charAt(0) == 'a') + type = 2; + + if (type > 0) + { + int day; + + // Month, week of month, day of week + // "Mm.w.d". d is between 0 (Sunday) and 6. Week w is + // between 1 and 5; Week 1 is the first week in which day d + // occurs and Week 5 specifies the last d day in the month. + // Month m is between 1 and 12. + + // Month, day of month, day of week + // ZoneInfo extension, not in POSIX + // "Am.n.d". d is between 0 (Sunday) and 6. Day of month n is + // between 1 and 25. Month m is between 1 and 12. + + month = Integer.parseInt(date.substring(1, date.indexOf('.'))); + int week = Integer.parseInt(date.substring(date.indexOf('.') + 1, + date.lastIndexOf('.'))); + int dayOfWeek = Integer.parseInt(date.substring(date.lastIndexOf('.') + + 1)); + dayOfWeek++; // Java day of week is one-based, Sunday is first day. + + if (type == 2) + { + day = week; + dayOfWeek = -dayOfWeek; + } + else if (week == 5) + day = -1; // last day of month is -1 in java, 5 in TZ + else + { + // First day of week starting on or after. For example, + // to specify the second Sunday of April, set month to + // APRIL, day-of-month to 8, and day-of-week to -SUNDAY. + day = (week - 1) * 7 + 1; + dayOfWeek = -dayOfWeek; + } + + month--; // Java month is zero-based. + return new int[] { month, day, dayOfWeek }; + } + + // julian day, either zero-based 0<=n<=365 (incl feb 29) + // or one-based 1<=n<=365 (no feb 29) + int julianDay; // Julian day + + if (date.charAt(0) != 'J' || date.charAt(0) != 'j') + { + julianDay = Integer.parseInt(date.substring(1)); + julianDay++; // make 1-based + // Adjust day count to include feb 29. + dayCount = new int[] + { + 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 + }; + } + else + // 1-based julian day + julianDay = Integer.parseInt(date); + + int i = 11; + while (i > 0) + if (dayCount[i] < julianDay) + break; + else + i--; + julianDay -= dayCount[i]; + month = i; + return new int[] { month, julianDay, 0 }; + } + + /** + * Parses a time field hh[:mm[:ss]], returning the result + * in milliseconds. No leading sign. + */ + private static int parseTime(String time) + { + int millis = 0; + int i = 0; + + while (i < time.length()) + if (time.charAt(i) == ':') + break; + else + i++; + millis = 60 * 60 * 1000 * Integer.parseInt(time.substring(0, i)); + if (i >= time.length()) + return millis; + + int iprev = ++i; + while (i < time.length()) + if (time.charAt(i) == ':') + break; + else + i++; + millis += 60 * 1000 * Integer.parseInt(time.substring(iprev, i)); + if (i >= time.length()) + return millis; + + millis += 1000 * Integer.parseInt(time.substring(++i)); + return millis; + } +} diff --git a/libjava/classpath/gnu/java/util/jar/JarUtils.java b/libjava/classpath/gnu/java/util/jar/JarUtils.java new file mode 100644 index 000000000..aa2bc2ea8 --- /dev/null +++ b/libjava/classpath/gnu/java/util/jar/JarUtils.java @@ -0,0 +1,451 @@ +/* JarUtils.java -- Utility methods for reading/writing Manifest[-like] files + Copyright (C) 2006, 2007 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.util.jar; + +import gnu.classpath.SystemProperties; + +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.util.Iterator; +import java.util.Map; +import java.util.jar.Attributes; +import java.util.jar.JarException; +import java.util.jar.Attributes.Name; +import java.util.logging.Logger; + +/** + * Utility methods for reading and writing JAR Manifest and + * Manifest-like files. + *

+ * JAR-related files that resemble Manifest files are Signature files + * (with an .SF extension) found in signed JARs. + */ +public abstract class JarUtils +{ + // We used to log here, but this causes problems during bootstrap, + // and it didn't seem worthwhile to preserve this. Still, this + // might be useful for debugging. + // private static final Logger log = Logger.getLogger(JarUtils.class.getName()); + public static final String META_INF = "META-INF/"; + public static final String DSA_SUFFIX = ".DSA"; + public static final String SF_SUFFIX = ".SF"; + public static final String NAME = "Name"; + + /** + * The original string representation of the manifest version attribute name. + */ + public static final String MANIFEST_VERSION = "Manifest-Version"; + + /** + * The original string representation of the signature version attribute + * name. + */ + public static final String SIGNATURE_VERSION = "Signature-Version"; + + /** Platform-independent line-ending. */ + public static final byte[] CRLF = new byte[] { 0x0D, 0x0A }; + private static final String DEFAULT_MF_VERSION = "1.0"; + private static final String DEFAULT_SF_VERSION = "1.0"; + private static final Name CREATED_BY = new Name("Created-By"); + private static final String CREATOR = SystemProperties.getProperty("java.version") + + " (" + + SystemProperties.getProperty("java.vendor") + + ")"; + + // default 0-arguments constructor + + // Methods for reading Manifest files from InputStream ---------------------- + + public static void + readMFManifest(Attributes attr, Map entries, InputStream in) + throws IOException + { + BufferedReader br = new BufferedReader(new InputStreamReader(in, "UTF-8")); + readMainSection(attr, br); + readIndividualSections(entries, br); + } + + public static void + readSFManifest(Attributes attr, Map entries, InputStream in) + throws IOException + { + BufferedReader br = new BufferedReader(new InputStreamReader(in, "UTF-8")); + String version_header = Name.SIGNATURE_VERSION.toString(); + try + { + String version = expectHeader(version_header, br); + attr.putValue(SIGNATURE_VERSION, version); + // This may cause problems during VM bootstrap. + // if (! DEFAULT_SF_VERSION.equals(version)) + // log.warning("Unexpected version number: " + version + // + ". Continue (but may fail later)"); + } + catch (IOException ioe) + { + throw new JarException("Signature file MUST start with a " + + version_header + ": " + ioe.getMessage()); + } + read_attributes(attr, br); + + // read individual sections + String s = br.readLine(); + while (s != null && s.length() > 0) + { + Attributes eAttr = readSectionName(s, br, entries); + read_attributes(eAttr, br); + s = br.readLine(); + } + } + + private static void readMainSection(Attributes attr, BufferedReader br) + throws IOException + { + // According to the spec we should actually call read_version_info() here. + read_attributes(attr, br); + // Explicitly set Manifest-Version attribute if not set in Main + // attributes of Manifest. + // XXX (rsn): why 0.0 and not 1.0? + if (attr.getValue(Name.MANIFEST_VERSION) == null) + attr.putValue(MANIFEST_VERSION, "0.0"); + } + + private static void readIndividualSections(Map entries, BufferedReader br) + throws IOException + { + String s = br.readLine(); + while (s != null && (! s.equals(""))) + { + Attributes attr = readSectionName(s, br, entries); + read_attributes(attr, br); + s = br.readLine(); + } + } + + /** + * Pedantic method that requires the next attribute in the Manifest to be the + * "Manifest-Version". This follows the Manifest spec closely but reject some + * jar Manifest files out in the wild. + */ + private static void readVersionInfo(Attributes attr, BufferedReader br) + throws IOException + { + String version_header = Name.MANIFEST_VERSION.toString(); + try + { + String value = expectHeader(version_header, br); + attr.putValue(MANIFEST_VERSION, value); + } + catch (IOException ioe) + { + throw new JarException("Manifest should start with a " + version_header + + ": " + ioe.getMessage()); + } + } + + private static String expectHeader(String header, BufferedReader br) + throws IOException + { + String s = br.readLine(); + if (s == null) + throw new JarException("unexpected end of file"); + + return expectHeader(header, br, s); + } + + private static void read_attributes(Attributes attr, BufferedReader br) + throws IOException + { + String s = br.readLine(); + while (s != null && (! s.equals(""))) + { + readAttribute(attr, s, br); + s = br.readLine(); + } + } + + private static void + readAttribute(Attributes attr, String s, BufferedReader br) throws IOException + { + try + { + int colon = s.indexOf(": "); + String name = s.substring(0, colon); + String value_start = s.substring(colon + 2); + String value = readHeaderValue(value_start, br); + attr.putValue(name, value); + } + catch (IndexOutOfBoundsException iobe) + { + throw new JarException("Manifest contains a bad header: " + s); + } + } + + private static String readHeaderValue(String s, BufferedReader br) + throws IOException + { + boolean try_next = true; + while (try_next) + { + // Lets see if there is something on the next line + br.mark(1); + if (br.read() == ' ') + s += br.readLine(); + else + { + br.reset(); + try_next = false; + } + } + return s; + } + + private static Attributes + readSectionName(String s, BufferedReader br, Map entries) throws JarException + { + try + { + String name = expectHeader(NAME, br, s); + Attributes attr = new Attributes(); + entries.put(name, attr); + return attr; + } + catch (IOException ioe) + { + throw new JarException("Section should start with a Name header: " + + ioe.getMessage()); + } + } + + private static String expectHeader(String header, BufferedReader br, String s) + throws IOException + { + try + { + String name = s.substring(0, header.length() + 1); + if (name.equalsIgnoreCase(header + ":")) + { + String value_start = s.substring(header.length() + 2); + return readHeaderValue(value_start, br); + } + } + catch (IndexOutOfBoundsException ignored) + { + } + // If we arrive here, something went wrong + throw new JarException("unexpected '" + s + "'"); + } + + // Methods for writing Manifest files to an OutputStream -------------------- + + public static void + writeMFManifest(Attributes attr, Map entries, OutputStream stream) + throws IOException + { + BufferedOutputStream out = stream instanceof BufferedOutputStream + ? (BufferedOutputStream) stream + : new BufferedOutputStream(stream, 4096); + writeVersionInfo(attr, out); + Iterator i; + Map.Entry e; + for (i = attr.entrySet().iterator(); i.hasNext();) + { + e = (Map.Entry) i.next(); + // Don't print the manifest version again + if (! Name.MANIFEST_VERSION.equals(e.getKey())) + writeAttributeEntry(e, out); + } + out.write(CRLF); + + Iterator j; + for (i = entries.entrySet().iterator(); i.hasNext();) + { + e = (Map.Entry) i.next(); + writeHeader(NAME, e.getKey().toString(), out); + Attributes eAttr = (Attributes) e.getValue(); + for (j = eAttr.entrySet().iterator(); j.hasNext();) + { + Map.Entry e2 = (Map.Entry) j.next(); + writeAttributeEntry(e2, out); + } + out.write(CRLF); + } + + out.flush(); + } + + public static void + writeSFManifest(Attributes attr, Map entries, OutputStream stream) + throws IOException + { + BufferedOutputStream out = stream instanceof BufferedOutputStream + ? (BufferedOutputStream) stream + : new BufferedOutputStream(stream, 4096); + writeHeader(Name.SIGNATURE_VERSION.toString(), DEFAULT_SF_VERSION, out); + writeHeader(CREATED_BY.toString(), CREATOR, out); + Iterator i; + Map.Entry e; + for (i = attr.entrySet().iterator(); i.hasNext();) + { + e = (Map.Entry) i.next(); + Name name = (Name) e.getKey(); + if (Name.SIGNATURE_VERSION.equals(name) || CREATED_BY.equals(name)) + continue; + + writeHeader(name.toString(), (String) e.getValue(), out); + } + out.write(CRLF); + + Iterator j; + for (i = entries.entrySet().iterator(); i.hasNext();) + { + e = (Map.Entry) i.next(); + writeHeader(NAME, e.getKey().toString(), out); + Attributes eAttr = (Attributes) e.getValue(); + for (j = eAttr.entrySet().iterator(); j.hasNext();) + { + Map.Entry e2 = (Map.Entry) j.next(); + writeHeader(e2.getKey().toString(), (String) e2.getValue(), out); + } + out.write(CRLF); + } + + out.flush(); + } + + private static void writeVersionInfo(Attributes attr, OutputStream out) + throws IOException + { + // First check if there is already a version attribute set + String version = attr.getValue(Name.MANIFEST_VERSION); + if (version == null) + version = DEFAULT_MF_VERSION; + + writeHeader(Name.MANIFEST_VERSION.toString(), version, out); + } + + private static void writeAttributeEntry(Map.Entry entry, OutputStream out) + throws IOException + { + String name = entry.getKey().toString(); + String value = entry.getValue().toString(); + if (name.equalsIgnoreCase(NAME)) + throw new JarException("Attributes cannot be called 'Name'"); + + if (name.startsWith("From")) + throw new JarException("Header cannot start with the four letters 'From'" + + name); + + writeHeader(name, value, out); + } + + /** + * The basic method for writing Mainfest attributes. This + * implementation respects the rule stated in the Jar Specification concerning + * the maximum allowed line length; i.e. + * + *

+   * No line may be longer than 72 bytes (not characters), in its UTF8-encoded
+   * form. If a value would make the initial line longer than this, it should
+   * be continued on extra lines (each starting with a single SPACE).
+   * 
+ * + * and + * + *
+   * Because header names cannot be continued, the maximum length of a header
+   * name is 70 bytes (there must be a colon and a SPACE after the name).
+   * 
+ * + * @param name the name of the attribute. + * @param value the value of the attribute. + * @param out the output stream to write the attribute's name/value pair to. + * @throws IOException if an I/O related exception occurs during the process. + */ + private static void writeHeader(String name, String value, OutputStream out) + throws IOException + { + String target = name + ": "; + byte[] b = target.getBytes("UTF-8"); + if (b.length > 72) + throw new IOException("Attribute's name already longer than 70 bytes"); + + if (b.length == 72) + { + out.write(b); + out.write(CRLF); + target = " " + value; + } + else + target = target + value; + + int n; + while (true) + { + b = target.getBytes("UTF-8"); + if (b.length < 73) + { + out.write(b); + break; + } + + // find an appropriate character position to break on + n = 72; + while (true) + { + b = target.substring(0, n).getBytes("UTF-8"); + if (b.length < 73) + break; + + n--; + if (n < 1) + throw new IOException("Header is unbreakable and longer than 72 bytes"); + } + + out.write(b); + out.write(CRLF); + target = " " + target.substring(n); + } + + out.write(CRLF); + } +} diff --git a/libjava/classpath/gnu/java/util/package.html b/libjava/classpath/gnu/java/util/package.html new file mode 100644 index 000000000..d90fa59d4 --- /dev/null +++ b/libjava/classpath/gnu/java/util/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.util + + +

+ + + diff --git a/libjava/classpath/gnu/java/util/prefs/FileBasedFactory.java b/libjava/classpath/gnu/java/util/prefs/FileBasedFactory.java new file mode 100644 index 000000000..91ea861c4 --- /dev/null +++ b/libjava/classpath/gnu/java/util/prefs/FileBasedFactory.java @@ -0,0 +1,65 @@ +/* FileBasedFactory - Default Classpath implementation of a PreferencesFactory + Copyright (C) 2001 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.util.prefs; + +import java.util.prefs.*; + +/** + * Default Classpath implementation of a PreferencesFactory. + * Returns system and user root Preferences nodes that are read from files. + * + * @author Mark Wielaard (mark@klomp.org) + */ +public class FileBasedFactory implements PreferencesFactory { + + // We don't save or read any system preferences for the + // time being. + private static final Preferences systemPreferences + = new MemoryBasedPreferences(null, "", false); + + private static final Preferences userPreferences + = new FileBasedPreferences(); + + public Preferences systemRoot() { + return systemPreferences; + } + + public Preferences userRoot() { + return userPreferences; + } +} diff --git a/libjava/classpath/gnu/java/util/prefs/FileBasedPreferences.java b/libjava/classpath/gnu/java/util/prefs/FileBasedPreferences.java new file mode 100644 index 000000000..f89ed6be2 --- /dev/null +++ b/libjava/classpath/gnu/java/util/prefs/FileBasedPreferences.java @@ -0,0 +1,273 @@ +/* FileBasedPreferences.java -- File-based preference implementation + 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.util.prefs; + +import gnu.classpath.SystemProperties; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FilenameFilter; +import java.io.IOException; +import java.nio.channels.FileChannel; +import java.nio.channels.FileLock; +import java.util.Properties; +import java.util.prefs.AbstractPreferences; +import java.util.prefs.BackingStoreException; + +/** + * This is a simple file-based preference implementation which writes + * the preferences as properties files. A node is represented as a directory + * beneath the user's home directory. The preferences for the node are + * stored in a single properties file in that directory. Sub-nodes are + * stored in subdirectories. This implementation uses file locking to + * mediate access to the properties files. + */ +public class FileBasedPreferences + extends AbstractPreferences +{ + /** + * Name of the property file storing the data in a given directory. + */ + private static final String DATA_FILE = "data.properties"; + + /** + * The directory corresponding to this preference node. + */ + private File directory; + + /** + * The file holding the data for this node. + */ + private File dataFile; + + /** + * The data in this node. + */ + private Properties properties; + + /** + * Create the root node for the file-based preferences. + */ + FileBasedPreferences() + { + super(null, ""); + String home = SystemProperties.getProperty("user.home"); + this.directory = new File(new File(home, ".classpath"), "userPrefs"); + this.dataFile = new File(this.directory, DATA_FILE); + load(); + } + + /** + * Create a new file-based preference object with the given parent + * and the given name. + * @param parent the parent + * @param name the name of this node + */ + FileBasedPreferences(FileBasedPreferences parent, String name) + { + super(parent, name); + this.directory = new File(parent.directory, name); + this.dataFile = new File(this.directory, DATA_FILE); + load(); + } + + private void load() + { + this.properties = new Properties(); + FileInputStream fis = null; + FileLock lock = null; + try + { + fis = new FileInputStream(this.dataFile); + FileChannel channel = fis.getChannel(); + lock = channel.lock(0, Long.MAX_VALUE, true); + this.properties.load(fis); + // We release the lock and close the stream in the 'finally' + // clause. + } + catch (IOException _) + { + // We don't mind; this means we're making a new node. + newNode = true; + } + finally + { + try + { + // Release the lock and close the stream. + if (lock != null) + lock.release(); + } + catch (IOException ignore) + { + // Ignore. + } + try + { + // Close the stream. + if (fis != null) + fis.close(); + } + catch (IOException ignore) + { + // Ignore. + } + } + } + + public boolean isUserNode() + { + // For now file preferences are always user nodes. + return true; + } + + protected String[] childrenNamesSpi() throws BackingStoreException + { + // FIXME: security manager. + String[] result = directory.list(new FilenameFilter() + { + public boolean accept(File dir, String name) + { + return new File(dir, name).isDirectory(); + } + }); + if (result == null) + result = new String[0]; + return result; + } + + protected AbstractPreferences childSpi(String name) + { + return new FileBasedPreferences(this, name); + } + + protected String[] keysSpi() throws BackingStoreException + { + return (String[]) properties.keySet().toArray(new String[0]); + } + + protected String getSpi(String key) + { + return properties.getProperty(key); + } + + protected void putSpi(String key, String value) + { + properties.put(key, value); + } + + protected void removeSpi(String key) + { + properties.remove(key); + } + + protected void flushSpi() throws BackingStoreException + { + // FIXME: security manager. + try + { + if (isRemoved()) + { + // Delete the underlying file. + // FIXME: ideally we would also delete the directory + // if it had no subdirectories. This doesn't matter + // much though. + // FIXME: there's a strange race here if a different VM is + // simultaneously updating this node. + dataFile.delete(); + } + else + { + // Write the underlying file. + directory.mkdirs(); + + FileOutputStream fos = null; + FileLock lock = null; + try + { + // Note that we let IOExceptions from the try clause + // propagate to the outer 'try'. + fos = new FileOutputStream(dataFile); + FileChannel channel = fos.getChannel(); + lock = channel.lock(); + properties.store(fos, "created by GNU Classpath FileBasedPreferences"); + // Lock is released and file closed in the finally clause. + } + finally + { + try + { + if (lock != null) + lock.release(); + } + catch (IOException _) + { + // Ignore. + } + try + { + if (fos != null) + fos.close(); + } + catch (IOException _) + { + // Ignore. + } + } + } + } + catch (IOException ioe) + { + throw new BackingStoreException(ioe); + } + } + + protected void syncSpi() throws BackingStoreException + { + // FIXME: we ought to synchronize but instead we merely flush. + flushSpi(); + } + + protected void removeNodeSpi() throws BackingStoreException + { + // We can simply delegate. + flushSpi(); + } +} diff --git a/libjava/classpath/gnu/java/util/prefs/GConfBasedFactory.java b/libjava/classpath/gnu/java/util/prefs/GConfBasedFactory.java new file mode 100644 index 000000000..f5a189471 --- /dev/null +++ b/libjava/classpath/gnu/java/util/prefs/GConfBasedFactory.java @@ -0,0 +1,78 @@ +/* GConfBasedFactory.java -- GConf based PreferencesFactory implementation + 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.util.prefs; + +import java.util.prefs.Preferences; +import java.util.prefs.PreferencesFactory; + +/** + * Factory object that generates a Preferences nodes that are read from a GConf + * daemon. + * + * @author Mario Torre + */ +public class GConfBasedFactory implements PreferencesFactory +{ + /** System preference root. */ + private static final Preferences systemPreferences + = new GConfBasedPreferences(null, "", false); + + /** User preference root. */ + private static final Preferences userPreferences + = new GConfBasedPreferences(null, "", true); + + /** + * Returns the system root preference node. + * + * @see java.util.prefs.PreferencesFactory#systemRoot() + */ + public Preferences systemRoot() + { + return systemPreferences; + } + + /** + * Returns the user root preference node corresponding to the calling user. + * + * @see java.util.prefs.PreferencesFactory#userRoot() + */ + public Preferences userRoot() + { + return userPreferences; + } +} diff --git a/libjava/classpath/gnu/java/util/prefs/GConfBasedPreferences.java b/libjava/classpath/gnu/java/util/prefs/GConfBasedPreferences.java new file mode 100644 index 000000000..e3374eee9 --- /dev/null +++ b/libjava/classpath/gnu/java/util/prefs/GConfBasedPreferences.java @@ -0,0 +1,419 @@ +/* GConfBasedPreferences.java -- GConf based Preferences implementation + 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.util.prefs; + +import gnu.java.util.prefs.gconf.GConfNativePeer; + +import java.security.Permission; + +import java.util.List; +import java.util.prefs.AbstractPreferences; +import java.util.prefs.BackingStoreException; + +/** + * This is a GConf based preference implementation which writes the preferences + * as GConf key-value pairs. System Root is defined to be the + * "/system" directory of GConf for the current user, while User + * Root is "/apps/java". These defaults can be modified by + * defining two system properties:
+ *
+ * User Root:
+ *
+ * + *
+ * gnu.java.util.prefs.gconf.user_root
+ * 
+ * + *
+ *
+ * and System Root:
+ *
+ * + *
+ * gnu.java.util.prefs.gconf.system_root
+ * 
+ * + *
+ * + * @author Mario Torre + */ +public class GConfBasedPreferences + extends AbstractPreferences +{ + /** Get access to Runtime permission */ + private static final Permission PERMISSION + = new RuntimePermission("preferences"); + + /** CGonf client backend */ + private static GConfNativePeer backend = new GConfNativePeer(); + + /** Default user root path */ + private static final String DEFAULT_USER_ROOT = "/apps/classpath"; + + /** Default system root path */ + private static final String DEFAULT_SYSTEM_ROOT = "/system"; + + /** current node full path */ + private String node = ""; + + /** True if this is a preference node in the user tree, false otherwise. */ + private final boolean isUser; + + /** + * Creates a preference root user node. + */ + public GConfBasedPreferences() + { + this(true); + } + + /** + * Creates a preference root node. When isUser is true it will + * be user node otherwise it will be a system node. + */ + public GConfBasedPreferences(boolean isUser) + { + this(null, "", isUser); + } + + /** + * Creates a new preference node given a parent node and a name, which has to + * be relative to its parent. When isUser is true it will be user + * node otherwise it will be a system node. + * + * @param parent The parent node of this newly created node. + * @param name A name relative to the parent node. + * @param isUser Set to true initializes this node to be + * a user node, false initialize it to be a system node. + */ + public GConfBasedPreferences(AbstractPreferences parent, String name, + boolean isUser) + { + super(parent, name); + this.isUser = isUser; + + // stores the fully qualified name of this node + String absolutePath = this.absolutePath(); + if (absolutePath != null && absolutePath.endsWith("/")) + { + absolutePath = absolutePath.substring(0, absolutePath.length() - 1); + } + + // strip invalid characters + // please, note that all names are unescaped into the native peer + int index = absolutePath.lastIndexOf('/'); + if (index > -1) + { + absolutePath = absolutePath.substring(0, index + 1); + absolutePath = absolutePath + GConfNativePeer.escapeString(name); + } + + this.node = this.getRealRoot(isUser) + absolutePath; + + boolean nodeExist = backend.nodeExist(this.node); + + this.newNode = !nodeExist; + } + + /** + * Returns a child node with the given name. + * If the child node does not exists, it will be created. + * + * @param name The name of the requested node. + * @return A new reference to the node, creating the node if it is necessary. + */ + protected AbstractPreferences childSpi(String name) + { + // we don't check anything here, if the node is a new node this will be + // detected in the constructor, so we simply return a new reference to + // the requested node. + + GConfBasedPreferences preferenceNode + = new GConfBasedPreferences(this, name, this.isUser); + + return preferenceNode; + } + + /** + * Returns an array of names of the children of this preference node. + * If the current node does not have children, the returned array will be + * of size 0 (that is, not null). + * + * @return A String array of names of children of the current + * node. + * @throws BackingStoreException if this operation cannot be completed. + */ + protected String[] childrenNamesSpi() throws BackingStoreException + { + List nodeList = backend.getChildrenNodes(this.node); + String[] nodes = new String[nodeList.size()]; + nodeList.toArray(nodes); + + return nodes; + } + + /** + * Suggest a flush to the backend. Actually, this is only a suggestion as + * GConf handles this for us asynchronously. More over, both sync and flush + * have the same meaning in this class, so calling sync has exactly the same + * effect. + * + * @see #sync + * @throws BackingStoreException if this operation cannot be completed. + */ + public void flush() throws BackingStoreException + { + backend.suggestSync(); + } + + /** + * Request a flush. + * + * @see #flush + * @throws BackingStoreException if this operation cannot be completed. + */ + protected void flushSpi() throws BackingStoreException + { + this.flush(); + } + + /** + * Returns all of the key in this preference node. + * If the current node does not have preferences, the returned array will be + * of size zero. + * + * @return A String array of keys stored under the current + * node. + * @throws BackingStoreException if this operation cannot be completed. + */ + protected String[] keysSpi() throws BackingStoreException + { + List keyList = backend.getKeys(this.node); + String[] keys = new String[keyList.size()]; + keyList.toArray(keys); + + return keys; + } + + /** + * Does a recursive postorder traversal of the preference tree, starting from + * the given directory invalidating every preference found in the node. + * + * @param directory The name of the starting directory (node) + */ + private void postorderRemove(String directory) + { + try + { + // gets the listing of directories in this node + List dirs = backend.getChildrenNodes(directory); + + if (dirs.size() != 0) + { + for (String currentDir : dirs) + { + // recursive search inside this directory + postorderRemove(currentDir); + } + } + + // remove all the keys associated to this directory + List entries = backend.getKeys(directory); + + if (entries.size() != 0) + { + for (String key : entries) + { + this.removeSpi(key); + } + } + } + catch (BackingStoreException ex) + { + /* ignore */ + } + } + + /** + * Stores the given key-value pair into this preference node. + * + * @param key The key of this preference. + * @param value The value of this preference. + */ + protected void putSpi(String key, String value) + { + backend.setString(this.getGConfKey(key), value); + } + + /** + * Removes this preference node, including all its children. + * Also removes the preferences associated. + */ + protected void removeNodeSpi() throws BackingStoreException + { + this.postorderRemove(this.node); + this.flush(); + } + + /** + * Removes the given key from this preference node. + * If the key does not exist, no operation is performed. + * + * @param key The key to remove. + */ + protected void removeSpi(String key) + { + backend.unset(this.getGConfKey(key)); + } + + /** + * Suggest a sync to the backend. Actually, this is only a suggestion as GConf + * handles this for us asynchronously. More over, both sync and flush have the + * same meaning in this class, so calling flush has exactly the same effect. + * + * @see #flush + * @throws BackingStoreException if this operation cannot be completed due to + * a failure in the backing store, or inability to communicate with + * it. + */ + public void sync() throws BackingStoreException + { + this.flush(); + } + + /** + * Request a sync. + * + * @see #sync + * @throws BackingStoreException if this operation cannot be completed due to + * a failure in the backing store, or inability to communicate with + * it. + */ + protected void syncSpi() throws BackingStoreException + { + this.sync(); + } + + /** + * Returns the value of the given key. + * If the keys does not have a value, or there is an error in the backing + * store, null is returned instead. + * + * @param key The key to retrieve. + * @return The value associated with the given key. + */ + protected String getSpi(String key) + { + return backend.getKey(this.getGConfKey(key)); + } + + /** + * Returns true if this preference node is a user node, + * false if is a system preference node. + * + * @return true if this preference node is a user node, + * false if is a system preference node. + */ + public boolean isUserNode() + { + return this.isUser; + } + + /* + * PRIVATE METHODS + */ + + /** + * Builds a GConf key string suitable for operations on the backend. + * + * @param key The key to convert into a valid GConf key. + * @return A valid Gconf key. + */ + private String getGConfKey(String key) + { + String nodeName = ""; + + // strip key + // please, note that all names are unescaped into the native peer + key = GConfNativePeer.escapeString(key); + + if (this.node.endsWith("/")) + { + nodeName = this.node + key; + } + else + { + nodeName = this.node + "/" + key; + } + + return nodeName; + } + + /** + * Builds the root node to use for this preference. + * + * @param isUser Defines if this node is a user (true) or system + * (false) node. + * @return The real root of this preference tree. + */ + private String getRealRoot(boolean isUser) + { + // not sure about this, we should have already these permissions... + SecurityManager security = System.getSecurityManager(); + + if (security != null) + { + security.checkPermission(PERMISSION); + } + + String root = null; + + if (isUser) + { + root = System.getProperty("gnu.java.util.prefs.gconf.user_root", + DEFAULT_USER_ROOT); + } + else + { + root = System.getProperty("gnu.java.util.prefs.gconf.system_root", + DEFAULT_SYSTEM_ROOT); + } + + return root; + } +} diff --git a/libjava/classpath/gnu/java/util/prefs/MemoryBasedFactory.java b/libjava/classpath/gnu/java/util/prefs/MemoryBasedFactory.java new file mode 100644 index 000000000..32ed12fc7 --- /dev/null +++ b/libjava/classpath/gnu/java/util/prefs/MemoryBasedFactory.java @@ -0,0 +1,64 @@ +/* MemoryBasedFactory - Memory based PreferencesFactory usefull for testing + Copyright (C) 2001 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.util.prefs; + +import java.util.prefs.*; + +/** + * Memory based PreferencesFactory useful for testing. + * Returns completely empty Preferences for system and user roots. + * All changes are only backed by the current instances in memory. + * + * @author Mark Wielaard (mark@klomp.org) + */ +public class MemoryBasedFactory implements PreferencesFactory { + + // Static fields containing the preferences root nodes + private static final Preferences systemPreferences + = new MemoryBasedPreferences(null, "", false); + private static final Preferences userPreferences + = new MemoryBasedPreferences(null, "", true); + + public Preferences systemRoot() { + return systemPreferences; + } + + public Preferences userRoot() { + return userPreferences; + } +} diff --git a/libjava/classpath/gnu/java/util/prefs/MemoryBasedPreferences.java b/libjava/classpath/gnu/java/util/prefs/MemoryBasedPreferences.java new file mode 100644 index 000000000..ee184d182 --- /dev/null +++ b/libjava/classpath/gnu/java/util/prefs/MemoryBasedPreferences.java @@ -0,0 +1,144 @@ +/* MemoryBasedPreferences - A Preference node which holds all entries in memory + Copyright (C) 2001, 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.util.prefs; + +import java.util.HashMap; + +import java.util.prefs.*; + +/** + * A Preference node which holds all entries in memory + * + * @author Mark Wielaard (mark@klomp.org) + */ +public class MemoryBasedPreferences extends AbstractPreferences { + + /** True if this is a preference node in the user tree, false otherwise. */ + private final boolean isUser; + + /** Contains all the preference entries of this node. */ + private HashMap entries = new HashMap(); + + /** + * Creates a new preferences node with the given name and parent. + * When isUser is true it will be user node otherwise it will be a system + * node. It will always set the newNode field to true + * since there is no real backing store, so all nodes are new. + */ + public MemoryBasedPreferences(MemoryBasedPreferences parent, + String name, + boolean isUser) { + super(parent, name); + this.isUser = isUser; + + // Since we do not have a real backing store all nodes are new + newNode = true; + } + + /** + * Returns true if this node was created as a user node. + */ + public boolean isUserNode() { + return isUser; + } + + /** + * Returns an empty array since all children names are always already + * cached. + */ + protected String[] childrenNamesSpi() throws BackingStoreException { + return new String[0]; + } + + /** + * Returns a new node with the given name with as parent this node and + * with the isUser flag set to the same value as this node. + */ + protected AbstractPreferences childSpi(String childName) { + return new MemoryBasedPreferences(this, childName, isUser); + } + + /** + * Returns a (possibly empty) array of keys of the preferences entries of + * this node. + */ + protected String[] keysSpi() throws BackingStoreException { + return entries.keySet().toArray(new String[entries.size()]); + } + + /** + * Returns the associated value from this nodes preferences entries or + * null when the key has not been set. + */ + protected String getSpi(String key) { + return entries.get(key); + } + + /** + * Sets the value for the given key. + */ + protected void putSpi(String key, String value) { + entries.put(key, value); + } + + /** + * Removes the entry with the given key. + */ + protected void removeSpi(String key) { + entries.remove(key); + } + + /** + * Does nothing since we do not have any backing store. + */ + protected void flushSpi() { + } + + /** + * Does nothing since we do not have any backing store. + */ + protected void syncSpi() { + } + + /** + * Just removes the entries map of this node. + */ + protected void removeNodeSpi() { + entries = null; + } +} diff --git a/libjava/classpath/gnu/java/util/prefs/NodeReader.java b/libjava/classpath/gnu/java/util/prefs/NodeReader.java new file mode 100644 index 000000000..0a49fc777 --- /dev/null +++ b/libjava/classpath/gnu/java/util/prefs/NodeReader.java @@ -0,0 +1,221 @@ +/* NodeReader - Reads and imports preferences nodes from files + Copyright (C) 2001 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.util.prefs; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.prefs.InvalidPreferencesFormatException; +import java.util.prefs.Preferences; +import java.util.prefs.PreferencesFactory; + +/** + * Reads and imports preferences nodes from files. + * + * @author Mark Wielaard (mark@klomp.org) + */ +public class NodeReader { + + private final BufferedReader br; + private String line = ""; + + private final PreferencesFactory factory; + + public NodeReader(Reader r, PreferencesFactory factory) { + if(r instanceof BufferedReader) { + br = (BufferedReader) r; + } else { + br = new BufferedReader(r); + } + this.factory = factory; + } + + public NodeReader(InputStream is, PreferencesFactory factory) { + this(new InputStreamReader(is), factory); + } + + public void importPreferences() + throws InvalidPreferencesFormatException, IOException + { + readPreferences(); + } + + private void readPreferences() + throws InvalidPreferencesFormatException, IOException + { + // Begin starting tag + skipTill(""); + } + + private void readRoot() + throws InvalidPreferencesFormatException, IOException + { + // Begin starting tag + skipTill(""); + } + + private void readNodes(Preferences node) + throws InvalidPreferencesFormatException, IOException + { + while ("node".equals(nextTag())) { + skipTill(""); + } + + } + + private void readMap(Preferences node) + throws InvalidPreferencesFormatException, IOException + { + // Begin map tag + skipTill("")) { + line = line.substring(2); + return; + } + + // Map entries + readEntries(node); + + // Ending tag + skipTill(""); + } + + private void readEntries(Preferences node) + throws InvalidPreferencesFormatException, IOException + { + while ("entry".equals(nextTag())) { + skipTill(""); + bw.newLine(); + bw.write(""); + bw.newLine(); + bw.newLine(); + bw.write(""); + bw.newLine(); + bw.newLine(); + } + + /** + * Write the preferences tag and the root. + */ + private void writePreferences() throws BackingStoreException, IOException { + bw.write(""); + bw.newLine(); + writeRoot(); + bw.write(""); + bw.newLine(); + } + + private void writeRoot() throws BackingStoreException, IOException { + bw.write(" "); + + writeRootMap(); + writeNode(); + + bw.write(" "); + bw.newLine(); + } + + private void writeRootMap() throws BackingStoreException, IOException { + // Is it a root node? + if(prefs.parent() == null && prefs.keys().length > 0) { + bw.newLine(); + writeMap(prefs, 2); + } else { + bw.write(""); + bw.newLine(); + } + } + + /** + * Writes all the parents of the preferences node without any entries. + * Returns the number of parents written, which has to be used as + * argument to writeCloseParents() after writing the node + * itself. + */ + private int writeParents() throws IOException { + int parents; + String path = prefs.absolutePath(); + int lastslash = path.lastIndexOf("/"); + if (lastslash > 0) { + path = path.substring(1, lastslash); + StringTokenizer st = new StringTokenizer(path); + parents = st.countTokens(); + + for (int i=0; i"); + bw.write(""); + bw.write(""); + bw.newLine(); + } + } else { + parents = 0; + } + + return parents; + } + + private void writeCloseParents(int parents) throws IOException { + while(parents > 0) { + indent(parents+1); + bw.write(""); + bw.newLine(); + parents--; + } + } + + private void writeNode() throws BackingStoreException, IOException { + int parents = writeParents(); + // root? + int indent; + if (prefs.parent() == null) { + indent = parents+1; + } else { + indent = parents+2; + } + writeNode(prefs, indent); + writeCloseParents(parents); + } + + private void writeNode(Preferences node, int indent) + throws BackingStoreException, IOException + { + // not root? + if (node.parent() != null) { + indent(indent); + bw.write(""); + if (node.keys().length > 0) { + bw.newLine(); + } + writeMap(node, indent+1); + } + + if (subtree) { + String[] children = node.childrenNames(); + for (int i=0; i"); + bw.newLine(); + } + } + + private void writeMap(Preferences node, int indent) + throws BackingStoreException, IOException + { + // construct String used for indentation + CPStringBuilder indentBuffer = new CPStringBuilder(2*indent); + for (int i=0; i < indent; i++) + indentBuffer.append(" "); + String indentString = indentBuffer.toString(); + + if (node.keys().length > 0) { + bw.write(indentString); + bw.write(""); + bw.newLine(); + writeEntries(node, indentString + " "); + bw.write(indentString); + bw.write(""); + } else { + bw.write(""); + } + bw.newLine(); + } + + private void writeEntries(Preferences node, String indent) + throws BackingStoreException, IOException + { + String[] keys = node.keys(); + for(int i = 0; i < keys.length; i++) { + String value = node.get(keys[i], null); + if (value == null) { + throw new BackingStoreException("null value for key '" + + keys[i] + "'"); + } + + bw.write(indent); + bw.write(""); + bw.newLine(); + } + } + + private void indent(int x) throws IOException { + for (int i=0; i + */ +public final class GConfNativePeer +{ + /** + * Creates a new instance of GConfNativePeer + */ + public GConfNativePeer() + { + init_class(); + } + + /** + * Queries whether the node node exists in theGConf database. + * Returns true or false. + * + * @param node the node to check. + */ + public boolean nodeExist(String node) + { + return gconf_dir_exists(node); + } + + /** + * Change the value of key to val. Automatically creates the key if it didn't + * exist before (ie it was unset or it only had a default value). + * Key names must be valid GConf key names, that is, there can be more + * restrictions than for normal Preference Backend. + * + * @param key the key to alter (or add). + * @param value the new value for this key. + * @return true if the key was updated, false otherwise. + */ + public boolean setString(String key, String value) + { + return gconf_set_string(key, value); + } + + /** + * Unsets the value of key; if key is already unset, has no effect. Depending + * on the GConf daemon, unsetting a key may have the side effect to remove it + * completely form the database. + * + * @param key the key to unset. + * @return true on success, false if the key was not updated. + */ + public boolean unset(String key) + { + return gconf_unset(key); + } + + /** + * Gets the value of a configuration key. + * + * @param key the configuration key. + * @return the values of this key, null if the key is not valid. + */ + public String getKey(String key) + { + return gconf_get_string(key); + } + + /** + * Lists the key in the given node. Does not list subnodes. Keys names are the + * stripped names (name relative to the current node) of the keys stored in + * this node. + * + * @param node the node where keys are stored. + * @return a java.util.List of keys. If there are no keys in the given node, a + * list of size 0 is returned. + */ + public List getKeys(String node) throws BackingStoreException + { + return gconf_all_keys(node); + } + + /** + * Lists the subnodes in node. The returned list contains + * allocated strings. Each string is the name relative tho the given node. + * + * @param node the node to get subnodes from. If there are no subnodes in the + * given node, a list of size 0 is returned. + */ + public List getChildrenNodes(String node) throws BackingStoreException + { + return gconf_all_nodes(node); + } + + /** + * Escape the given string so the it is a valid GConf name. + */ + public static String escapeString(String plain) + { + return gconf_escape_key(plain); + } + + /** + * Unescape a string escaped with {@link #escapeString}. + */ + public static String unescapeString(String escaped) + { + return gconf_unescape_key(escaped); + } + + /** + * Suggest to the backend GConf daemon to synch with the database. + */ + public void suggestSync() throws BackingStoreException + { + gconf_suggest_sync(); + } + + protected void finalize() throws Throwable + { + try + { + finalize_class(); + } + finally + { + super.finalize(); + } + } + + /* ***** native methods ***** */ + + /* + * Basicly, these are one to one mappings to GConfClient functions. + * GConfClient instances are handled by the native layer, and are hidden from + * the main java class. + */ + + /** + * Initialize the GConf native peer and enable the object cache. + * It is meant to be used by the static initializer. + */ + native synchronized static final private void init_id_cache(); + + /** + * Initialize the GConf native peer. This is meant to be used by the + * class constructor. + */ + native synchronized static final private void init_class(); + + /** + * Class finalizer. + */ + native synchronized static final private void finalize_class(); + + /** + * Queries the GConf database to see if the given node exists, returning + * true if the node exist, false otherwise. + * + * @param node the node to query for existence. + * @return true if the node exist, false otherwise. + */ + native synchronized + static final protected boolean gconf_dir_exists(String node); + + /** + * Sets the given key/value pair into the GConf database. + * The key must be a valid GConf key. + * + * @param key the key to store in the GConf database + * @param value the value to associate to the given key. + * @return true if the change has effect, false otherwise. + */ + native synchronized + static final protected boolean gconf_set_string(String key, String value); + + /** + * Returns the key associated to the given key. Null is returned if the + * key is not valid. + * + * @param key the key to return the value of. + * @return The value associated to the given key, or null. + */ + native synchronized + static final protected String gconf_get_string(String key); + + /** + * Usets the given key, removing the key from the database. + * + * @param key the key to remove. + * @return true if the operation success, false otherwise. + */ + native synchronized static final protected boolean gconf_unset(String key); + + /** + * Suggest to the GConf native peer a sync with the database. + * + */ + native synchronized static final protected void gconf_suggest_sync() + throws BackingStoreException; + + /** + * Returns a list of all nodes under the given node. + * + * @param node the source node. + * @return A list of nodes under the given source node. + */ + native + static synchronized final protected List gconf_all_nodes(String node) + throws BackingStoreException; + + /** + * Returns a list of all keys stored in the given node. + * + * @param node the source node. + * @return A list of all keys stored in the given node. + */ + native synchronized + static final protected List gconf_all_keys(String node) + throws BackingStoreException; + + /** + * Escape the input String so that it's a valid element for GConf. + * + * @param plain the String to escape. + * @return An escaped String for use with GConf. + */ + native synchronized + static final protected String gconf_escape_key(String plain); + + /** + * Converts a string escaped with gconf_escape_key back into its + * original form. + * + * @param escaped key as returned by gconf_escape_key + * @return An unescaped key. + */ + native synchronized + static final protected String gconf_unescape_key(String escaped); + + static + { + System.loadLibrary("gconfpeer"); + init_id_cache(); + } +} diff --git a/libjava/classpath/gnu/java/util/prefs/package.html b/libjava/classpath/gnu/java/util/prefs/package.html new file mode 100644 index 000000000..ee5d67f72 --- /dev/null +++ b/libjava/classpath/gnu/java/util/prefs/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.util.prefs + + +

+ + + diff --git a/libjava/classpath/gnu/java/util/regex/BacktrackStack.java b/libjava/classpath/gnu/java/util/regex/BacktrackStack.java new file mode 100644 index 000000000..b03fb8707 --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/BacktrackStack.java @@ -0,0 +1,124 @@ +/* gnu/regexp/BacktrackStack.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.java.util.regex; + +/** + * An instance of this class represents a stack + * used for backtracking. + * + * @author Ito Kazumitsu + */ +final class BacktrackStack +{ + + /** A set of data to be used for backtracking. */ + static class Backtrack + { + /** REToken to which to go back */ + REToken token; + /** CharIndexed on which matches are being searched for. */ + CharIndexed input; + /** REMatch to be used by the REToken token. */ + REMatch match; + /** Some parameter used by the token's backtrack method. */ + Object param; + Backtrack (REToken token, CharIndexed input, REMatch match, + Object param) + { + this.token = token; + this.input = input; + // REMatch may change before backtracking is needed. So we + // keep a clone of it. + this.match = (REMatch) match.clone (); + this.param = param; + } + } + + Backtrack[] stack; + private int size; + private int capacity; + private static final int INITIAL_CAPACITY = 32; + private static final int CAPACITY_INCREMENT = 16; + + BacktrackStack () + { + stack = new Backtrack[INITIAL_CAPACITY]; + size = 0; + capacity = INITIAL_CAPACITY; + } + + boolean empty () + { + return size == 0; + } + + Backtrack peek () + { + return stack[size - 1]; + } + + Backtrack pop () + { + Backtrack bt = stack[--size]; + stack[size] = null; + return bt; + } + + void clear () + { + for (int i = 0; i < size; i++) + { + stack[i] = null; + } + size = 0; + } + + void push (Backtrack bt) + { + if (size >= capacity) + { + capacity += CAPACITY_INCREMENT; + Backtrack[]newStack = new Backtrack[capacity]; + System.arraycopy (stack, 0, newStack, 0, size); + stack = newStack; + } + stack[size++] = bt; + } + +} diff --git a/libjava/classpath/gnu/java/util/regex/CharIndexed.java b/libjava/classpath/gnu/java/util/regex/CharIndexed.java new file mode 100644 index 000000000..de4b1667f --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/CharIndexed.java @@ -0,0 +1,134 @@ +/* gnu/regexp/CharIndexed.java + Copyright (C) 1998-2001, 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.util.regex; + +/** + * Defines the interface used internally so that different types of source + * text can be accessed in the same way. Built-in concrete classes provide + * support for String, StringBuffer, InputStream and char[] types. + * A class that is CharIndexed supports the notion of a cursor within a + * block of text. The cursor must be able to be advanced via the move() + * method. The charAt() method returns the character at the cursor position + * plus a given offset. + * + * @author Wes Biggs + */ +public interface CharIndexed +{ + /** + * Defines a constant (0xFFFF was somewhat arbitrarily chosen) + * that can be returned by the charAt() function indicating that + * the specified index is out of range. + */ + char OUT_OF_BOUNDS = '\uFFFF'; + + /** + * Returns the character at the given offset past the current cursor + * position in the input. The index of the current position is zero. + * It is possible for this method to be called with a negative index. + * This happens when using the '^' operator in multiline matching mode + * or the '\b' or '\<' word boundary operators. In any case, the lower + * bound is currently fixed at -2 (for '^' with a two-character newline). + * + * @param index the offset position in the character field to examine + * @return the character at the specified index, or the OUT_OF_BOUNDS + * character defined by this interface. + */ + char charAt (int index); + + /** + * Shifts the input buffer by a given number of positions. Returns + * true if the new cursor position is valid. + */ + boolean move (int index); + + /** + * Shifts the input buffer by a given number of positions. Returns + * true if the new cursor position is valid or cursor position is at + * the end of input. + */ + boolean move1 (int index); // I cannot think of a better name for this. + + /** + * Returns true if the most recent move() operation placed the cursor + * 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 (); + + /** + * Sets the REMatch last found on this input. + */ + void setLastMatch (REMatch match); + + /** + * Returns the REMatch last found on this input. + */ + REMatch getLastMatch (); + + /** + * Sets the information used for hitEnd(). + */ + void setHitEnd (REMatch match); + + /** + * Returns whether the matcher has hit the end of input. + */ + boolean hitEnd (); + + /** + * Returns the anchor. + */ + int getAnchor (); + + /** + * Sets the anchor. + */ + void setAnchor (int anchor); +} diff --git a/libjava/classpath/gnu/java/util/regex/CharIndexedCharArray.java b/libjava/classpath/gnu/java/util/regex/CharIndexedCharArray.java new file mode 100644 index 000000000..565773837 --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/CharIndexedCharArray.java @@ -0,0 +1,48 @@ +/* gnu/regexp/CharIndexedCharArray.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.java.util.regex; +import java.nio.CharBuffer; + +class CharIndexedCharArray extends CharIndexedCharSequence +{ + + CharIndexedCharArray (char[]str, int index) + { + super (CharBuffer.wrap (str), index); + } +} diff --git a/libjava/classpath/gnu/java/util/regex/CharIndexedCharSequence.java b/libjava/classpath/gnu/java/util/regex/CharIndexedCharSequence.java new file mode 100644 index 000000000..bc3cbbd1d --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/CharIndexedCharSequence.java @@ -0,0 +1,119 @@ +/* gnu/regexp/CharIndexedCharSequence.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.java.util.regex; +import java.io.Serializable; + +class CharIndexedCharSequence implements CharIndexed, Serializable +{ + private CharSequence s; + private int anchor; + private int len; + + CharIndexedCharSequence (CharSequence s, int index) + { + this.s = s; + len = s.length (); + anchor = index; + } + + public char charAt (int index) + { + int pos = anchor + index; + return ((pos < len) && (pos >= 0)) ? s.charAt (pos) : OUT_OF_BOUNDS; + } + + public boolean isValid () + { + return (anchor < len); + } + + public boolean move (int index) + { + return ((anchor += index) < len); + } + + public boolean move1 (int index) + { + return ((anchor += index) <= len); + } + + public CharIndexed lookBehind (int index, int length) + { + if (length > (anchor + index)) + length = anchor + index; + return new CharIndexedCharSequence (s, anchor + index - length); + } + + public int length () + { + return len - anchor; + } + + private REMatch lastMatch; + public void setLastMatch (REMatch match) + { + lastMatch = (REMatch) match.clone (); + lastMatch.anchor = anchor; + } + public REMatch getLastMatch () + { + return lastMatch; + } + + private int rightmostTriedPosition = 0; + public void setHitEnd (REMatch match) + { + int pos = anchor + match.index; + if (pos > rightmostTriedPosition) + rightmostTriedPosition = pos; + } + public boolean hitEnd () + { + return rightmostTriedPosition >= len; + } + + public int getAnchor () + { + return anchor; + } + public void setAnchor (int anchor) + { + this.anchor = anchor; + } + +} diff --git a/libjava/classpath/gnu/java/util/regex/CharIndexedInputStream.java b/libjava/classpath/gnu/java/util/regex/CharIndexedInputStream.java new file mode 100644 index 000000000..d6340298a --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/CharIndexedInputStream.java @@ -0,0 +1,253 @@ +/* gnu/regexp/CharIndexedInputStream.java + Copyright (C) 1998-2001, 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.util.regex; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; + +// TODO: move(x) shouldn't rely on calling next() x times + +class CharIndexedInputStream implements CharIndexed +{ + private static final int BUFFER_INCREMENT = 1024; + private static final int UNKNOWN = Integer.MAX_VALUE; // value for end + + private BufferedInputStream br; + + // so that we don't try to reset() right away + private int index = -1; + + private int bufsize = BUFFER_INCREMENT; + + private int end = UNKNOWN; + + private char cached = OUT_OF_BOUNDS; + + // Big enough for a \r\n pair + // lookBehind[0] = most recent + // lookBehind[1] = second most recent + private char[] lookBehind = new char[]{ OUT_OF_BOUNDS, OUT_OF_BOUNDS }; + + CharIndexedInputStream (InputStream str, int index) + { + if (str instanceof BufferedInputStream) + br = (BufferedInputStream) str; + else + br = new BufferedInputStream (str, BUFFER_INCREMENT); + next (); + if (index > 0) + move (index); + } + + private boolean next () + { + if (end == 1) + return false; + end--; // closer to end + + try + { + if (index != -1) + { + br.reset (); + } + int i = br.read (); + br.mark (bufsize); + if (i == -1) + { + end = 1; + cached = OUT_OF_BOUNDS; + return false; + } + cached = (char) i; + index = 1; + } catch (IOException e) + { + e.printStackTrace (); + cached = OUT_OF_BOUNDS; + return false; + } + return true; + } + + public char charAt (int index) + { + if (index == 0) + { + return cached; + } + else if (index >= end) + { + return OUT_OF_BOUNDS; + } + else if (index == -1) + { + return lookBehind[0]; + } + else if (index == -2) + { + return lookBehind[1]; + } + else if (index < -2) + { + return OUT_OF_BOUNDS; + } + else if (index >= bufsize) + { + // Allocate more space in the buffer. + try + { + while (bufsize <= index) + bufsize += BUFFER_INCREMENT; + br.reset (); + br.mark (bufsize); + br.skip (index - 1); + } + catch (IOException e) + { + } + } + else if (this.index != index) + { + try + { + br.reset (); + br.skip (index - 1); + } + catch (IOException e) + { + } + } + char ch = OUT_OF_BOUNDS; + + try + { + int i = br.read (); + this.index = index + 1; // this.index is index of next pos relative to charAt(0) + if (i == -1) + { + // set flag that next should fail next time? + end = index; + return ch; + } + ch = (char) i; + } catch (IOException ie) + { + } + + return ch; + } + + public boolean move (int index) + { + // move read position [index] clicks from 'charAt(0)' + boolean retval = true; + while (retval && (index-- > 0)) + retval = next (); + return retval; + } + + 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"); + } + + public void setLastMatch (REMatch match) + { + throw new + UnsupportedOperationException + ("difficult to support setLastMatch for an input stream"); + } + + public REMatch getLastMatch () + { + throw new + UnsupportedOperationException + ("difficult to support getLastMatch for an input stream"); + } + + public void setHitEnd (REMatch match) + { + throw new + UnsupportedOperationException + ("difficult to support setHitEnd for an input stream"); + } + + public boolean hitEnd () + { + throw new + UnsupportedOperationException + ("difficult to support hitEnd for an input stream"); + } + + public int getAnchor () + { + throw new + UnsupportedOperationException + ("difficult to support getAnchor for an input stream"); + } + + public void setAnchor (int anchor) + { + throw new + UnsupportedOperationException + ("difficult to support setAnchor for an input stream"); + } + + public boolean move1 (int index) + { + throw new + UnsupportedOperationException + ("difficult to support move1 for an input stream"); + } + +} diff --git a/libjava/classpath/gnu/java/util/regex/CharIndexedString.java b/libjava/classpath/gnu/java/util/regex/CharIndexedString.java new file mode 100644 index 000000000..7a56f487e --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/CharIndexedString.java @@ -0,0 +1,46 @@ +/* gnu/regexp/CharIndexedString.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.java.util.regex; + +class CharIndexedString extends CharIndexedCharSequence +{ + CharIndexedString (String str, int index) + { + super (str, index); + } +} diff --git a/libjava/classpath/gnu/java/util/regex/CharIndexedStringBuffer.java b/libjava/classpath/gnu/java/util/regex/CharIndexedStringBuffer.java new file mode 100644 index 000000000..d6484f89b --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/CharIndexedStringBuffer.java @@ -0,0 +1,47 @@ +/* gnu/regexp/CharIndexedStringBuffer.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.java.util.regex; + +class CharIndexedStringBuffer extends CharIndexedCharSequence +{ + + CharIndexedStringBuffer (StringBuffer str, int index) + { + super (str, index); + } +} diff --git a/libjava/classpath/gnu/java/util/regex/RE.java b/libjava/classpath/gnu/java/util/regex/RE.java new file mode 100644 index 000000000..5e9974a49 --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/RE.java @@ -0,0 +1,2675 @@ +/* gnu/regexp/RE.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.java.util.regex; + +import gnu.java.lang.CPStringBuilder; + +import java.io.InputStream; +import java.io.Serializable; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.PropertyResourceBundle; +import java.util.ResourceBundle; + +/** + * RE provides the user interface for compiling and matching regular + * expressions. + *

+ * A regular expression object (class RE) is compiled by constructing it + * from a String, StringBuffer or character array, with optional + * compilation flags (below) + * and an optional syntax specification (see RESyntax; if not specified, + * RESyntax.RE_SYNTAX_PERL5 is used). + *

+ * Once compiled, a regular expression object is reusable as well as + * threadsafe: multiple threads can use the RE instance simultaneously + * to match against different input text. + *

+ * Various methods attempt to match input text against a compiled + * regular expression. These methods are: + *

  • isMatch: returns true if the input text in its + * entirety matches the regular expression pattern. + *
  • getMatch: returns the first match found in the + * input text, or null if no match is found. + *
  • getAllMatches: returns an array of all + * non-overlapping matches found in the input text. If no matches are + * found, the array is zero-length. + *
  • substitute: substitute the first occurence of the + * pattern in the input text with a replacement string (which may + * include metacharacters $0-$9, see REMatch.substituteInto). + *
  • substituteAll: same as above, but repeat for each + * match before returning. + *
  • getMatchEnumeration: returns an REMatchEnumeration + * object that allows iteration over the matches (see + * REMatchEnumeration for some reasons why you may want to do this + * instead of using getAllMatches. + *

    + * + * These methods all have similar argument lists. The input can be a + * CharIndexed, String, a character array, a StringBuffer, or an + * InputStream of some sort. Note that when using an + * InputStream, the stream read position cannot be guaranteed after + * attempting a match (this is not a bug, but a consequence of the way + * regular expressions work). Using an REMatchEnumeration can + * eliminate most positioning problems. + * + * Although the input object can be of various types, it is recommended + * that it should be a CharIndexed because {@link CharIndexed#getLastMatch()} + * can show the last match found on this input, which helps the expression + * \G work as the end of the previous match. + * + *

    + * + * The optional index argument specifies the offset from the beginning + * of the text at which the search should start (see the descriptions + * of some of the execution flags for how this can affect positional + * pattern operators). For an InputStream, this means an + * offset from the current read position, so subsequent calls with the + * same index argument on an InputStream will not + * necessarily access the same position on the stream, whereas + * repeated searches at a given index in a fixed string will return + * consistent results. + * + *

    + * You can optionally affect the execution environment by using a + * combination of execution flags (constants listed below). + * + *

    + * All operations on a regular expression are performed in a + * thread-safe manner. + * + * @author Wes Biggs + * @version 1.1.5-dev, to be released + */ + +public class RE extends REToken +{ + + private static final class IntPair implements Serializable + { + public int first, second; + } + + private static final class CharUnit implements Serializable + { + public char ch; + public boolean bk; + } + + // This String will be returned by getVersion() + private static final String VERSION = "1.1.5-dev"; + + // The localized strings are kept in a separate file + // Used by getLocalizedMessage(). + private static ResourceBundle messages; + + // Name of the bundle that contains the localized messages. + private static final String bundle = "gnu/java/util/regex/MessagesBundle"; + + // These are, respectively, the first and last tokens in our linked list + // If there is only one token, firstToken == lastToken + private REToken firstToken, lastToken; + + // This is the number of subexpressions in this regular expression, + // with a minimum value of zero. Returned by getNumSubs() + private int numSubs; + + /** 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 = 0x02; + + /** + * Compilation flag. The match-any-character operator (dot) + * will match a newline character. When set this overrides the syntax + * bit RE_DOT_NEWLINE (see RESyntax for details). This is equivalent to + * the "/s" operator in Perl. + */ + 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 = 0x08; + + /** + * Execution flag. + * The match-beginning operator (^) will not match at the beginning + * of the input string. Useful for matching on a substring when you + * know the context of the input is such that position zero of the + * input to the match test is not actually position zero of the text. + *

    + * This example demonstrates the results of various ways of matching on + * a substring. + *

    + * + * String s = "food bar fool";
    + * RE exp = new RE("^foo.");
    + * REMatch m0 = exp.getMatch(s);
    + * REMatch m1 = exp.getMatch(s.substring(8));
    + * REMatch m2 = exp.getMatch(s.substring(8),0,RE.REG_NOTBOL);
    + * REMatch m3 = exp.getMatch(s,8);
    + * REMatch m4 = exp.getMatch(s,8,RE.REG_ANCHORINDEX);
    + *

    + * // Results:
    + * // m0.toString(): "food"
    + * // m1.toString(): "fool"
    + * // m2.toString(): null
    + * // m3.toString(): null
    + * // m4.toString(): "fool"
    + *
    + */ + 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 = 0x20; + + /** + * Execution flag. + * When a match method is invoked that starts matching at a non-zero + * index into the input, treat the input as if it begins at the index + * given. The effect of this flag is that the engine does not "see" + * any text in the input before the given index. This is useful so + * that the match-beginning operator (^) matches not at position 0 + * in the input string, but at the position the search started at + * (based on the index input given to the getMatch function). See + * the example under REG_NOTBOL. It also affects the use of the \< + * and \b operators. + */ + public static final int REG_ANCHORINDEX = 0x40; + + /** + * Execution flag. + * The substitute and substituteAll methods will not attempt to + * interpolate occurrences of $1-$9 in the replacement text with + * the corresponding subexpressions. For example, you may want to + * replace all matches of "one dollar" with "$1". + */ + 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; + + /** + * Compilation flag. Allow whitespace and comments in pattern. + * This is equivalent to the "/x" operator in Perl. + */ + public static final int REG_X_COMMENTS = 0x0400; + + /** + * Compilation flag. If set, REG_ICASE is effective only for US-ASCII. + */ + public static final int REG_ICASE_USASCII = 0x0800; + + /** + * Execution flag. + * Do not move the position at which the search begins. If not set, + * the starting position will be moved until a match is found. + */ + public static final int REG_FIX_STARTING_POSITION = 0x1000; + + /** Returns a string representing the version of the gnu.regexp package. */ + public static final String version () + { + return VERSION; + } + + // Retrieves a message from the ResourceBundle + static final String getLocalizedMessage (String key) + { + if (messages == null) + messages = + PropertyResourceBundle.getBundle (bundle, Locale.getDefault ()); + return messages.getString (key); + } + + /** + * Constructs a regular expression pattern buffer without any compilation + * flags set, and using the default syntax (RESyntax.RE_SYNTAX_PERL5). + * + * @param pattern A regular expression pattern, in the form of a String, + * StringBuffer or char[]. Other input types will be converted to + * strings using the toString() method. + * @exception REException The input pattern could not be parsed. + * @exception NullPointerException The pattern was null. + */ + public RE (Object pattern) throws REException + { + this (pattern, 0, RESyntax.RE_SYNTAX_PERL5, 0, 0); + } + + /** + * Constructs a regular expression pattern buffer using the specified + * compilation flags and the default syntax (RESyntax.RE_SYNTAX_PERL5). + * + * @param pattern A regular expression pattern, in the form of a String, + * StringBuffer, or char[]. Other input types will be converted to + * strings using the toString() method. + * @param cflags The logical OR of any combination of the compilation flags listed above. + * @exception REException The input pattern could not be parsed. + * @exception NullPointerException The pattern was null. + */ + public RE (Object pattern, int cflags) throws REException + { + this (pattern, cflags, RESyntax.RE_SYNTAX_PERL5, 0, 0); + } + + /** + * Constructs a regular expression pattern buffer using the specified + * compilation flags and regular expression syntax. + * + * @param pattern A regular expression pattern, in the form of a String, + * StringBuffer, or char[]. Other input types will be converted to + * strings using the toString() method. + * @param cflags The logical OR of any combination of the compilation flags listed above. + * @param syntax The type of regular expression syntax to use. + * @exception REException The input pattern could not be parsed. + * @exception NullPointerException The pattern was null. + */ + public RE (Object pattern, int cflags, RESyntax syntax) throws REException + { + this (pattern, cflags, syntax, 0, 0); + } + + // internal constructor used for alternation + 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)); + } + + private RE (Object patternObj, int cflags, RESyntax syntax, int myIndex, + int nextSub) throws REException + { + super (myIndex); // Subexpression index of this token. + initialize (patternObj, cflags, syntax, myIndex, nextSub); + } + + // For use by subclasses + protected RE () + { + super (0); + } + + // The meat of construction + protected void initialize (Object patternObj, int cflags, RESyntax syntax, + int myIndex, int nextSub) throws REException + { + char[] pattern; + if (patternObj instanceof String) + { + pattern = ((String) patternObj).toCharArray (); + } + else if (patternObj instanceof char[]) + { + pattern = (char[]) patternObj; + } + else if (patternObj instanceof StringBuffer) + { + pattern = new char[((StringBuffer) patternObj).length ()]; + ((StringBuffer) patternObj).getChars (0, pattern.length, pattern, 0); + } + else if (patternObj instanceof StringBuilder) + { + pattern = new char[((StringBuilder) patternObj).length ()]; + ((StringBuilder) patternObj).getChars (0, pattern.length, pattern, 0); + } + else if (patternObj instanceof CPStringBuilder) + { + pattern = new char[((CPStringBuilder) patternObj).length ()]; + ((CPStringBuilder) patternObj).getChars (0, pattern.length, pattern, + 0); + } + else + { + pattern = patternObj.toString ().toCharArray (); + } + + int pLength = pattern.length; + + numSubs = 0; // Number of subexpressions in this token. + ArrayList < REToken > branches = null; + + // linked list of tokens (sort of -- some closed loops can exist) + firstToken = lastToken = null; + + // Precalculate these so we don't pay for the math every time we + // need to access them. + boolean insens = ((cflags & REG_ICASE) > 0); + boolean insensUSASCII = ((cflags & REG_ICASE_USASCII) > 0); + + // Parse pattern into tokens. Does anyone know if it's more efficient + // to use char[] than a String.charAt()? I'm assuming so. + + // index tracks the position in the char array + int index = 0; + + // this will be the current parse character (pattern[index]) + CharUnit unit = new CharUnit (); + + // This is used for {x,y} calculations + IntPair minMax = new IntPair (); + + // Buffer a token so we can create a TokenRepeated, etc. + REToken currentToken = null; + 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); + + if (unit.bk) + if (unit.ch == 'Q') + { + quot = true; + continue; + } + else if (unit.ch == 'E') + { + quot = false; + continue; + } + if (quot) + unit.bk = false; + + if (((cflags & REG_X_COMMENTS) > 0) && (!unit.bk) && (!quot)) + { + if (Character.isWhitespace (unit.ch)) + { + continue; + } + if (unit.ch == '#') + { + for (int i = index; i < pLength; i++) + { + if (pattern[i] == '\n') + { + index = i + 1; + continue; + } + else if (pattern[i] == '\r') + { + if (i + 1 < pLength && pattern[i + 1] == '\n') + { + index = i + 2; + } + else + { + index = i + 1; + } + continue; + } + } + index = pLength; + continue; + } + } + + // ALTERNATION OPERATOR + // \| or | (if RE_NO_BK_VBAR) or newline (if RE_NEWLINE_ALT) + // not available if RE_LIMITED_OPS is set + + // TODO: the '\n' literal here should be a test against REToken.newline, + // which unfortunately may be more than a single character. + if (((unit.ch == '|' + && (syntax.get (RESyntax.RE_NO_BK_VBAR) ^ (unit.bk || quot))) + || (syntax.get (RESyntax.RE_NEWLINE_ALT) && (unit.ch == '\n') + && !(unit.bk || quot))) + && !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, + maximumLength); + minimumLength = 0; + maximumLength = 0; + if (branches == null) + { + branches = new ArrayList < REToken > (); + } + branches.add (theBranch); + firstToken = lastToken = currentToken = null; + } + + // INTERVAL OPERATOR: + // {x} | {x,} | {x,y} (RE_INTERVALS && RE_NO_BK_BRACES) + // \{x\} | \{x,\} | \{x,y\} (RE_INTERVALS && !RE_NO_BK_BRACES) + // + // OPEN QUESTION: + // what is proper interpretation of '{' at start of string? + // + // This method used to check "repeat.empty.token" to avoid such regexp + // as "(a*){2,}", but now "repeat.empty.token" is allowed. + + else if ((unit.ch == '{') && syntax.get (RESyntax.RE_INTERVALS) + && (syntax. + get (RESyntax.RE_NO_BK_BRACES) ^ (unit.bk || quot))) + { + int newIndex = getMinMax (pattern, index, minMax, syntax); + if (newIndex > index) + { + if (minMax.first > minMax.second) + throw new + REException (getLocalizedMessage ("interval.order"), + REException.REG_BADRPT, newIndex); + if (currentToken == null) + throw new + REException (getLocalizedMessage ("repeat.no.token"), + REException.REG_BADRPT, newIndex); + if (currentToken instanceof RETokenRepeated) + throw new + REException (getLocalizedMessage ("repeat.chained"), + REException.REG_BADRPT, newIndex); + if (currentToken instanceof RETokenWordBoundary + || currentToken instanceof RETokenWordBoundary) + throw new + REException (getLocalizedMessage ("repeat.assertion"), + REException.REG_BADRPT, newIndex); + index = newIndex; + currentToken = + setRepeated (currentToken, minMax.first, minMax.second, + index); + } + else + { + addToken (currentToken); + currentToken = new RETokenChar (subIndex, unit.ch, insens); + if (insensUSASCII) + currentToken.unicodeAware = false; + } + } + + // LIST OPERATOR: + // [...] | [^...] + + else if ((unit.ch == '[') && !(unit.bk || quot)) + { + // Create a new RETokenOneOf + ParseCharClassResult result = + parseCharClass (subIndex, pattern, index, pLength, cflags, + syntax, 0); + addToken (currentToken); + currentToken = result.token; + index = result.index; + } + + // SUBEXPRESSIONS + // (...) | \(...\) depending on RE_NO_BK_PARENS + + else if ((unit.ch == '(') + && (syntax. + get (RESyntax.RE_NO_BK_PARENS) ^ (unit.bk || quot))) + { + 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 '!': + if (syntax.get (RESyntax.RE_LOOKAHEAD)) + { + pure = true; + negativelh = true; + lookAhead = true; + index += 2; + } + break; + case '=': + if (syntax.get (RESyntax.RE_LOOKAHEAD)) + { + pure = true; + lookAhead = true; + 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': + case 'x': + 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': + if (negate) + newCflags |= REG_ICASE_USASCII; + else + newCflags &= ~REG_ICASE_USASCII; + flagIndex++; + break; + case 'x': + if (negate) + newCflags &= ~REG_X_COMMENTS; + else + newCflags |= REG_X_COMMENTS; + flagIndex++; + break; + 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); + insensUSASCII = ((cflags & REG_ICASE_USASCII) > 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); + insensUSASCII = ((cflags & REG_ICASE_USASCII) > 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; + index += 2; + } + break; + case '#': + if (syntax.get (RESyntax.RE_COMMENTS)) + { + comment = true; + } + break; + default: + throw new + REException (getLocalizedMessage ("repeat.no.token"), + REException.REG_BADRPT, index); + } + } + + if (index >= pLength) + { + throw new + REException (getLocalizedMessage ("unmatched.paren"), + REException.REG_ESUBREG, index); + } + + // find end of subexpression + int endIndex = index; + int nextIndex = index; + int nested = 0; + + while (((nextIndex = + getCharUnit (pattern, endIndex, unit, false)) > 0) + && !(nested == 0 && (unit.ch == ')') + && (syntax. + get (RESyntax.RE_NO_BK_PARENS) ^ (unit.bk + || quot)))) + { + if ((endIndex = nextIndex) >= pLength) + throw new + REException (getLocalizedMessage ("subexpr.no.end"), + REException.REG_ESUBREG, nextIndex); + else + if ((unit.ch == '[') && !(unit.bk || quot)) + { + // I hate to do something similar to the LIST OPERATOR matters + // above, but ... + int listIndex = nextIndex; + if (listIndex < pLength && pattern[listIndex] == '^') + listIndex++; + if (listIndex < pLength && pattern[listIndex] == ']') + listIndex++; + int listEndIndex = -1; + int listNest = 0; + while (listIndex < pLength && listEndIndex < 0) + { + switch (pattern[listIndex++]) + { + case '\\': + listIndex++; + break; + case '[': + // Sun's API document says that regexp like "[a-d[m-p]]" + // is legal. Even something like "[[[^]]]]" is accepted. + listNest++; + if (listIndex < pLength + && pattern[listIndex] == '^') + listIndex++; + if (listIndex < pLength + && pattern[listIndex] == ']') + listIndex++; + break; + case ']': + if (listNest == 0) + listEndIndex = listIndex; + listNest--; + break; + } + } + if (listEndIndex >= 0) + { + nextIndex = listEndIndex; + if ((endIndex = nextIndex) >= pLength) + throw new + REException (getLocalizedMessage ("subexpr.no.end"), + REException.REG_ESUBREG, nextIndex); + else + continue; + } + throw new + REException (getLocalizedMessage ("subexpr.no.end"), + REException.REG_ESUBREG, nextIndex); + } + else if (unit.ch == '(' + && (syntax. + get (RESyntax.RE_NO_BK_PARENS) ^ (unit.bk + || quot))) + nested++; + else if (unit.ch == ')' + && (syntax. + get (RESyntax.RE_NO_BK_PARENS) ^ (unit.bk + || quot))) + nested--; + } + + // endIndex is now position at a ')','\)' + // nextIndex is end of string or position after ')' or '\)' + + if (comment) + index = nextIndex; + else + { // not a comment + // create RE subexpression as token. + addToken (currentToken); + if (!pure) + { + 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); + insensUSASCII = ((cflags & REG_ICASE_USASCII) > 0); + flagsSaved = false; + } + } // not a comment + } // subexpression + + // UNMATCHED RIGHT PAREN + // ) or \) throw exception if + // !syntax.get(RESyntax.RE_UNMATCHED_RIGHT_PAREN_ORD) + else if (!syntax.get (RESyntax.RE_UNMATCHED_RIGHT_PAREN_ORD) + && ((unit.ch == ')') + && (syntax. + get (RESyntax.RE_NO_BK_PARENS) ^ (unit.bk || quot)))) + { + throw new REException (getLocalizedMessage ("unmatched.paren"), + REException.REG_EPAREN, index); + } + + // START OF LINE OPERATOR + // ^ + + else if ((unit.ch == '^') && !(unit.bk || quot)) + { + addToken (currentToken); + currentToken = null; + RETokenStart token = null; + if ((cflags & REG_MULTILINE) > 0) + { + String sep = syntax.getLineSeparator (); + if (sep == null) + { + token = new RETokenStart (subIndex, null, true); + } + else + { + token = new RETokenStart (subIndex, sep); + } + } + else + { + token = new RETokenStart (subIndex, null); + } + addToken (token); + } + + // END OF LINE OPERATOR + // $ + + else if ((unit.ch == '$') && !(unit.bk || quot)) + { + addToken (currentToken); + currentToken = null; + RETokenEnd token = null; + if ((cflags & REG_MULTILINE) > 0) + { + String sep = syntax.getLineSeparator (); + if (sep == null) + { + token = new RETokenEnd (subIndex, null, true); + } + else + { + token = new RETokenEnd (subIndex, sep); + } + } + else + { + token = new RETokenEnd (subIndex, null); + } + addToken (token); + } + + // MATCH-ANY-CHARACTER OPERATOR (except possibly newline and null) + // . + + else if ((unit.ch == '.') && !(unit.bk || quot)) + { + addToken (currentToken); + currentToken = + new RETokenAny (subIndex, syntax.get (RESyntax.RE_DOT_NEWLINE) + || ((cflags & REG_DOT_NEWLINE) > 0), + syntax.get (RESyntax.RE_DOT_NOT_NULL)); + } + + // ZERO-OR-MORE REPEAT OPERATOR + // * + // + // This method used to check "repeat.empty.token" to avoid such regexp + // as "(a*)*", but now "repeat.empty.token" is allowed. + + else if ((unit.ch == '*') && !(unit.bk || quot)) + { + if (currentToken == null) + throw new REException (getLocalizedMessage ("repeat.no.token"), + REException.REG_BADRPT, index); + if (currentToken instanceof RETokenRepeated) + throw new REException (getLocalizedMessage ("repeat.chained"), + REException.REG_BADRPT, index); + if (currentToken instanceof RETokenWordBoundary + || currentToken instanceof RETokenWordBoundary) + throw new REException (getLocalizedMessage ("repeat.assertion"), + REException.REG_BADRPT, index); + currentToken = + setRepeated (currentToken, 0, Integer.MAX_VALUE, index); + } + + // ONE-OR-MORE REPEAT OPERATOR / POSSESSIVE MATCHING OPERATOR + // + | \+ depending on RE_BK_PLUS_QM + // not available if RE_LIMITED_OPS is set + // + // This method used to check "repeat.empty.token" to avoid such regexp + // as "(a*)+", but now "repeat.empty.token" is allowed. + + else if ((unit.ch == '+') && !syntax.get (RESyntax.RE_LIMITED_OPS) + && (!syntax. + get (RESyntax.RE_BK_PLUS_QM) ^ (unit.bk || quot))) + { + if (currentToken == null) + throw new REException (getLocalizedMessage ("repeat.no.token"), + REException.REG_BADRPT, index); + + // Check for possessive matching on RETokenRepeated + if (currentToken instanceof RETokenRepeated) + { + RETokenRepeated tokenRep = (RETokenRepeated) currentToken; + if (syntax.get (RESyntax.RE_POSSESSIVE_OPS) + && !tokenRep.isPossessive () && !tokenRep.isStingy ()) + tokenRep.makePossessive (); + else + throw new + REException (getLocalizedMessage ("repeat.chained"), + REException.REG_BADRPT, index); + + } + else if (currentToken instanceof RETokenWordBoundary + || currentToken instanceof RETokenWordBoundary) + throw new REException (getLocalizedMessage ("repeat.assertion"), + REException.REG_BADRPT, index); + else + currentToken = + setRepeated (currentToken, 1, Integer.MAX_VALUE, index); + } + + // ZERO-OR-ONE REPEAT OPERATOR / STINGY MATCHING OPERATOR + // ? | \? depending on RE_BK_PLUS_QM + // not available if RE_LIMITED_OPS is set + // stingy matching if RE_STINGY_OPS is set and it follows a quantifier + + else if ((unit.ch == '?') && !syntax.get (RESyntax.RE_LIMITED_OPS) + && (!syntax. + get (RESyntax.RE_BK_PLUS_QM) ^ (unit.bk || quot))) + { + if (currentToken == null) + throw new REException (getLocalizedMessage ("repeat.no.token"), + REException.REG_BADRPT, index); + + // Check for stingy matching on RETokenRepeated + if (currentToken instanceof RETokenRepeated) + { + RETokenRepeated tokenRep = (RETokenRepeated) currentToken; + if (syntax.get (RESyntax.RE_STINGY_OPS) + && !tokenRep.isStingy () && !tokenRep.isPossessive ()) + tokenRep.makeStingy (); + else + throw new + REException (getLocalizedMessage ("repeat.chained"), + REException.REG_BADRPT, index); + } + else if (currentToken instanceof RETokenWordBoundary + || currentToken instanceof RETokenWordBoundary) + throw new REException (getLocalizedMessage ("repeat.assertion"), + REException.REG_BADRPT, index); + 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); + if (insensUSASCII) + currentToken.unicodeAware = false; + } + + // BACKREFERENCE OPERATOR + // \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); + 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); + if (insensUSASCII) + currentToken.unicodeAware = false; + index = numEnd; + } + + // START OF STRING OPERATOR + // \A if RE_STRING_ANCHORS is set + + else if (unit.bk && (unit.ch == 'A') + && syntax.get (RESyntax.RE_STRING_ANCHORS)) + { + addToken (currentToken); + currentToken = new RETokenStart (subIndex, null); + } + + // WORD BREAK OPERATOR + // \b if ???? + + else if (unit.bk && (unit.ch == 'b') + && syntax.get (RESyntax.RE_STRING_ANCHORS)) + { + addToken (currentToken); + currentToken = + new RETokenWordBoundary (subIndex, + RETokenWordBoundary. + BEGIN | RETokenWordBoundary.END, + false); + } + + // WORD BEGIN OPERATOR + // \< if ???? + else if (unit.bk && (unit.ch == '<')) + { + addToken (currentToken); + currentToken = + new RETokenWordBoundary (subIndex, RETokenWordBoundary.BEGIN, + false); + } + + // WORD END OPERATOR + // \> if ???? + else if (unit.bk && (unit.ch == '>')) + { + addToken (currentToken); + currentToken = + new RETokenWordBoundary (subIndex, RETokenWordBoundary.END, + false); + } + + // NON-WORD BREAK OPERATOR + // \B if ???? + + else if (unit.bk && (unit.ch == 'B') + && syntax.get (RESyntax.RE_STRING_ANCHORS)) + { + addToken (currentToken); + currentToken = + new RETokenWordBoundary (subIndex, + RETokenWordBoundary. + BEGIN | RETokenWordBoundary.END, true); + } + + + // DIGIT OPERATOR + // \d if RE_CHAR_CLASS_ESCAPES is set + + else if (unit.bk && (unit.ch == 'd') + && syntax.get (RESyntax.RE_CHAR_CLASS_ESCAPES)) + { + addToken (currentToken); + currentToken = + new RETokenPOSIX (subIndex, RETokenPOSIX.DIGIT, insens, false); + if (insensUSASCII) + currentToken.unicodeAware = false; + } + + // NON-DIGIT OPERATOR + // \D + + else if (unit.bk && (unit.ch == 'D') + && syntax.get (RESyntax.RE_CHAR_CLASS_ESCAPES)) + { + addToken (currentToken); + currentToken = + new RETokenPOSIX (subIndex, RETokenPOSIX.DIGIT, insens, true); + if (insensUSASCII) + currentToken.unicodeAware = false; + } + + // NEWLINE ESCAPE + // \n + + else if (unit.bk && (unit.ch == 'n')) + { + addToken (currentToken); + currentToken = new RETokenChar (subIndex, '\n', false); + } + + // RETURN ESCAPE + // \r + + else if (unit.bk && (unit.ch == 'r')) + { + addToken (currentToken); + currentToken = new RETokenChar (subIndex, '\r', false); + } + + // WHITESPACE OPERATOR + // \s if RE_CHAR_CLASS_ESCAPES is set + + else if (unit.bk && (unit.ch == 's') + && syntax.get (RESyntax.RE_CHAR_CLASS_ESCAPES)) + { + addToken (currentToken); + currentToken = + new RETokenPOSIX (subIndex, RETokenPOSIX.SPACE, insens, false); + if (insensUSASCII) + currentToken.unicodeAware = false; + } + + // NON-WHITESPACE OPERATOR + // \S + + else if (unit.bk && (unit.ch == 'S') + && syntax.get (RESyntax.RE_CHAR_CLASS_ESCAPES)) + { + addToken (currentToken); + currentToken = + new RETokenPOSIX (subIndex, RETokenPOSIX.SPACE, insens, true); + if (insensUSASCII) + currentToken.unicodeAware = false; + } + + // TAB ESCAPE + // \t + + else if (unit.bk && (unit.ch == 't')) + { + addToken (currentToken); + currentToken = new RETokenChar (subIndex, '\t', false); + } + + // ALPHANUMERIC OPERATOR + // \w + + else if (unit.bk && (unit.ch == 'w') + && syntax.get (RESyntax.RE_CHAR_CLASS_ESCAPES)) + { + addToken (currentToken); + currentToken = + new RETokenPOSIX (subIndex, RETokenPOSIX.ALNUM, insens, false); + if (insensUSASCII) + currentToken.unicodeAware = false; + } + + // NON-ALPHANUMERIC OPERATOR + // \W + + else if (unit.bk && (unit.ch == 'W') + && syntax.get (RESyntax.RE_CHAR_CLASS_ESCAPES)) + { + addToken (currentToken); + currentToken = + new RETokenPOSIX (subIndex, RETokenPOSIX.ALNUM, insens, true); + if (insensUSASCII) + currentToken.unicodeAware = false; + } + + // END OF STRING OPERATOR + // \Z, \z + + // FIXME: \Z and \z are different in that if the input string + // ends with a line terminator, \Z matches the position before + // the final terminator. This special behavior of \Z is yet + // to be implemented. + + else if (unit.bk && (unit.ch == 'Z' || unit.ch == 'z') && + syntax.get (RESyntax.RE_STRING_ANCHORS)) + { + addToken (currentToken); + 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); + if (insensUSASCII) + currentToken.unicodeAware = false; + } + + // 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); + if (insensUSASCII) + currentToken.unicodeAware = false; + } + + // END OF PREVIOUS MATCH + // \G + + else if (unit.bk && (unit.ch == 'G') && + syntax.get (RESyntax.RE_STRING_ANCHORS)) + { + addToken (currentToken); + currentToken = new RETokenEndOfPreviousMatch (subIndex); + } + + // NON-SPECIAL CHARACTER (or escape to make literal) + // c | \* for example + + else + { // not a special character + addToken (currentToken); + currentToken = new RETokenChar (subIndex, unit.ch, insens); + if (insensUSASCII) + currentToken.unicodeAware = false; + } + } // end while + + // Add final buffered token and an EndSub marker + addToken (currentToken); + + if (branches != null) + { + branches. + add (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)); + } + else + addToken (new RETokenEndSub (subIndex)); + + } + + 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); + boolean insensUSASCII = ((cflags & REG_ICASE_USASCII) > 0); + final ArrayList < REToken > options = new ArrayList < REToken > (); + ArrayList < Object > addition = new ArrayList < Object > (); + 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]) == ']') + { + RETokenChar t = new RETokenChar (subIndex, lastChar, insens); + if (insensUSASCII) + t.unicodeAware = false; + options.add (t); + 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; + } + RETokenRange t = + new RETokenRange (subIndex, lastChar, ch, insens); + if (insensUSASCII) + t.unicodeAware = false; + options.add (t); + 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) + { + RETokenChar t = new RETokenChar (subIndex, lastChar, insens); + if (insensUSASCII) + t.unicodeAware = false; + options.add (t); + } + + if (posixID != -1) + { + RETokenPOSIX t = + new RETokenPOSIX (subIndex, posixID, insens, negate); + if (insensUSASCII) + t.unicodeAware = false; + options.add (t); + } + else if (np != null) + { + RETokenNamedProperty t = + getRETokenNamedProperty (subIndex, np, insens, index); + if (insensUSASCII) + t.unicodeAware = false; + options.add (t); + } + 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] == ':')) + { + CPStringBuilder posixSet = new CPStringBuilder (); + index = getPosixSet (pattern, index + 1, posixSet); + int posixId = RETokenPOSIX.intValue (posixSet.toString ()); + if (posixId != -1) + { + RETokenPOSIX t = + new RETokenPOSIX (subIndex, posixId, insens, false); + if (insensUSASCII) + t.unicodeAware = false; + options.add (t); + } + } + else if ((ch == '[') && (syntax.get (RESyntax.RE_NESTED_CHARCLASS))) + { + ParseCharClassResult result = + parseCharClass (subIndex, pattern, index, pLength, cflags, + syntax, 0); + addition.add (result.token); + addition.add ("|"); + 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.add ("&"); + 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.add ("&"); + addition.add (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.add (result.token); + addition.add ("|"); + // 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) + { + RETokenChar t = new RETokenChar (subIndex, lastChar, insens); + if (insensUSASCII) + t.unicodeAware = false; + options.add (t); + } + 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) + { + RETokenChar t = new RETokenChar (subIndex, lastChar, insens); + if (insensUSASCII) + t.unicodeAware = false; + options.add (t); + } + + ParseCharClassResult result = new ParseCharClassResult (); + // Create a new RETokenOneOf + options.trimToSize (); + if (additionAndAppeared) + addition.add ("&"); + 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 == '\\' + && (!quot || index >= input.length || input[index] == 'E')); + if (unit.bk) + if (index < input.length) + unit.ch = input[index++]; + else + throw new REException (getLocalizedMessage ("ends.with.backslash"), + REException.REG_ESCAPE, index); + 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. + * + * @param input The input text. + */ + public boolean isMatch (Object input) + { + return isMatch (input, 0, 0); + } + + /** + * Checks if the input string, starting from index, is an exact match of + * this regular expression. + * + * @param input The input text. + * @param index The offset index at which the search should be begin. + */ + public boolean isMatch (Object input, int index) + { + return isMatch (input, index, 0); + } + + + /** + * Checks if the input, starting from index and using the specified + * execution flags, is an exact match of this regular expression. + * + * @param input The input text. + * @param index The offset index at which the search should be begin. + * @param eflags The logical OR of any execution flags above. + */ + public boolean isMatch (Object input, int index, int eflags) + { + return isMatchImpl (makeCharIndexed (input, index), index, eflags); + } + + private boolean isMatchImpl (CharIndexed input, int index, int eflags) + { + if (firstToken == null) // Trivial case + return (input.charAt (0) == CharIndexed.OUT_OF_BOUNDS); + REMatch m = new REMatch (numSubs, index, eflags); + if (firstToken.match (input, m)) + { + if (m != null) + { + if (input.charAt (m.index) == CharIndexed.OUT_OF_BOUNDS) + { + return true; + } + } + } + return false; + } + + /** + * Returns the maximum number of subexpressions in this regular expression. + * If the expression contains branches, the value returned will be the + * maximum subexpressions in any of the branches. + */ + public int getNumSubs () + { + return numSubs; + } + + // Overrides REToken.setUncle + void setUncle (REToken uncle) + { + if (lastToken != null) + { + lastToken.setUncle (uncle); + } + else + super.setUncle (uncle); // to deal with empty subexpressions + } + + // Overrides REToken.chain + + boolean chain (REToken next) + { + super.chain (next); + setUncle (next); + return true; + } + + /** + * Returns the minimum number of characters that could possibly + * constitute a match of this regular expression. + */ + public int getMinimumLength () + { + return minimumLength; + } + + public int getMaximumLength () + { + return maximumLength; + } + + /** + * Returns an array of all matches found in the input. + * + * If the regular expression allows the empty string to match, it will + * substitute matches at all positions except the end of the input. + * + * @param input The input text. + * @return a non-null (but possibly zero-length) array of matches + */ + public REMatch[] getAllMatches (Object input) + { + return getAllMatches (input, 0, 0); + } + + /** + * Returns an array of all matches found in the input, + * beginning at the specified index position. + * + * If the regular expression allows the empty string to match, it will + * substitute matches at all positions except the end of the input. + * + * @param input The input text. + * @param index The offset index at which the search should be begin. + * @return a non-null (but possibly zero-length) array of matches + */ + public REMatch[] getAllMatches (Object input, int index) + { + return getAllMatches (input, index, 0); + } + + /** + * Returns an array of all matches found in the input string, + * beginning at the specified index position and using the specified + * execution flags. + * + * If the regular expression allows the empty string to match, it will + * substitute matches at all positions except the end of the input. + * + * @param input The input text. + * @param index The offset index at which the search should be begin. + * @param eflags The logical OR of any execution flags above. + * @return a non-null (but possibly zero-length) array of matches + */ + public REMatch[] getAllMatches (Object input, int index, int eflags) + { + return getAllMatchesImpl (makeCharIndexed (input, index), index, eflags); + } + + // this has been changed since 1.03 to be non-overlapping matches + private REMatch[] getAllMatchesImpl (CharIndexed input, int index, + int eflags) + { + List < REMatch > all = new ArrayList < REMatch > (); + REMatch m = null; + while ((m = getMatchImpl (input, index, eflags, null)) != null) + { + all.add (m); + index = m.getEndIndex (); + if (m.end[0] == 0) + { // handle pathological case of zero-length match + index++; + input.move (1); + } + else + { + input.move (m.end[0]); + } + if (!input.isValid ()) + break; + } + return all.toArray (new REMatch[all.size ()]); + } + + /* Implements abstract method REToken.match() */ + boolean match (CharIndexed input, REMatch mymatch) + { + input.setHitEnd (mymatch); + if (firstToken == null) + { + return next (input, mymatch); + } + + // Note the start of this subexpression + mymatch.start1[subIndex] = mymatch.index; + + return firstToken.match (input, mymatch); + } + + REMatch findMatch (CharIndexed input, REMatch mymatch) + { + if (mymatch.backtrackStack == null) + mymatch.backtrackStack = new BacktrackStack (); + boolean b = match (input, mymatch); + if (b) + { + return mymatch; + } + return null; + } + + /** + * Returns the first match found in the input. If no match is found, + * null is returned. + * + * @param input The input text. + * @return An REMatch instance referencing the match, or null if none. + */ + public REMatch getMatch (Object input) + { + return getMatch (input, 0, 0); + } + + /** + * Returns the first match found in the input, beginning + * the search at the specified index. If no match is found, + * returns null. + * + * @param input The input text. + * @param index The offset within the text to begin looking for a match. + * @return An REMatch instance referencing the match, or null if none. + */ + public REMatch getMatch (Object input, int index) + { + return getMatch (input, index, 0); + } + + /** + * Returns the first match found in the input, beginning + * the search at the specified index, and using the specified + * execution flags. If no match is found, returns null. + * + * @param input The input text. + * @param index The offset index at which the search should be begin. + * @param eflags The logical OR of any execution flags above. + * @return An REMatch instance referencing the match, or null if none. + */ + public REMatch getMatch (Object input, int index, int eflags) + { + return getMatch (input, index, eflags, null); + } + + /** + * Returns the first match found in the input, beginning the search + * at the specified index, and using the specified execution flags. + * If no match is found, returns null. If a StringBuffer is + * provided and is non-null, the contents of the input text from the + * index to the beginning of the match (or to the end of the input, + * if there is no match) are appended to the StringBuffer. + * + * @param input The input text. + * @param index The offset index at which the search should be begin. + * @param eflags The logical OR of any execution flags above. + * @param buffer The StringBuffer to save pre-match text in. + * @return An REMatch instance referencing the match, or null if none. */ + public REMatch getMatch (Object input, int index, int eflags, + CPStringBuilder buffer) + { + return getMatchImpl (makeCharIndexed (input, index), index, eflags, + buffer); + } + + REMatch getMatchImpl (CharIndexed input, int anchor, int eflags, + CPStringBuilder buffer) + { + boolean tryEntireMatch = ((eflags & REG_TRY_ENTIRE_MATCH) != 0); + boolean doMove = ((eflags & REG_FIX_STARTING_POSITION) == 0); + RE re = (tryEntireMatch ? (RE) this.clone () : this); + if (tryEntireMatch) + { + RETokenEnd reEnd = new RETokenEnd (0, null); + reEnd.setFake (true); + re.chain (reEnd); + } + // Create a new REMatch to hold results + REMatch mymatch = new REMatch (numSubs, anchor, eflags); + do + { + /* The following potimization is commented out because + the matching should be tried even if the length of + input is obviously too short in order that + java.util.regex.Matcher#hitEnd() may work correctly. + // Optimization: check if anchor + minimumLength > length + if (minimumLength == 0 || input.charAt(minimumLength-1) != CharIndexed.OUT_OF_BOUNDS) { + */ + 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 > best.index) { + best = mymatch; + } + } + */ + best.end[0] = best.index; + best.finish (input); + input.setLastMatch (best); + return best; + } + /* End of the optimization commented out + } + */ + mymatch.clear (++anchor); + // Append character to buffer if needed + if (buffer != null && input.charAt (0) != CharIndexed.OUT_OF_BOUNDS) + { + buffer.append (input.charAt (0)); + } + // java.util.regex.Matcher#hitEnd() requires that the search should + // be tried at the end of input, so we use move1(1) instead of move(1) + } + while (doMove && input.move1 (1)); + + // Special handling at end of input for e.g. "$" + if (minimumLength == 0) + { + if (match (input, mymatch)) + { + mymatch.finish (input); + return mymatch; + } + } + + return null; + } + + /** + * Returns an REMatchEnumeration that can be used to iterate over the + * matches found in the input text. + * + * @param input The input text. + * @return A non-null REMatchEnumeration instance. + */ + public REMatchEnumeration getMatchEnumeration (Object input) + { + return getMatchEnumeration (input, 0, 0); + } + + + /** + * Returns an REMatchEnumeration that can be used to iterate over the + * matches found in the input text. + * + * @param input The input text. + * @param index The offset index at which the search should be begin. + * @return A non-null REMatchEnumeration instance, with its input cursor + * set to the index position specified. + */ + public REMatchEnumeration getMatchEnumeration (Object input, int index) + { + return getMatchEnumeration (input, index, 0); + } + + /** + * Returns an REMatchEnumeration that can be used to iterate over the + * matches found in the input text. + * + * @param input The input text. + * @param index The offset index at which the search should be begin. + * @param eflags The logical OR of any execution flags above. + * @return A non-null REMatchEnumeration instance, with its input cursor + * set to the index position specified. + */ + public REMatchEnumeration getMatchEnumeration (Object input, int index, + int eflags) + { + return new REMatchEnumeration (this, makeCharIndexed (input, index), + index, eflags); + } + + + /** + * Substitutes the replacement text for the first match found in the input. + * + * @param input The input text. + * @param replace The replacement text, which may contain $x metacharacters (see REMatch.substituteInto). + * @return A String interpolating the substituted text. + * @see REMatch#substituteInto + */ + public String substitute (Object input, String replace) + { + return substitute (input, replace, 0, 0); + } + + /** + * Substitutes the replacement text for the first match found in the input + * beginning at the specified index position. Specifying an index + * effectively causes the regular expression engine to throw away the + * specified number of characters. + * + * @param input The input text. + * @param replace The replacement text, which may contain $x metacharacters (see REMatch.substituteInto). + * @param index The offset index at which the search should be begin. + * @return A String containing the substring of the input, starting + * at the index position, and interpolating the substituted text. + * @see REMatch#substituteInto + */ + public String substitute (Object input, String replace, int index) + { + return substitute (input, replace, index, 0); + } + + /** + * Substitutes the replacement text for the first match found in the input + * string, beginning at the specified index position and using the + * specified execution flags. + * + * @param input The input text. + * @param replace The replacement text, which may contain $x metacharacters (see REMatch.substituteInto). + * @param index The offset index at which the search should be begin. + * @param eflags The logical OR of any execution flags above. + * @return A String containing the substring of the input, starting + * at the index position, and interpolating the substituted text. + * @see REMatch#substituteInto + */ + public String substitute (Object input, String replace, int index, + int eflags) + { + return substituteImpl (makeCharIndexed (input, index), replace, index, + eflags); + } + + private String substituteImpl (CharIndexed input, String replace, int index, + int eflags) + { + CPStringBuilder buffer = new CPStringBuilder (); + REMatch m = getMatchImpl (input, index, eflags, buffer); + if (m == null) + return buffer.toString (); + buffer.append (getReplacement (replace, m, eflags)); + if (input.move (m.end[0])) + { + do + { + buffer.append (input.charAt (0)); + } + while (input.move (1)); + } + return buffer.toString (); + } + + /** + * Substitutes the replacement text for each non-overlapping match found + * in the input text. + * + * @param input The input text. + * @param replace The replacement text, which may contain $x metacharacters (see REMatch.substituteInto). + * @return A String interpolating the substituted text. + * @see REMatch#substituteInto + */ + public String substituteAll (Object input, String replace) + { + return substituteAll (input, replace, 0, 0); + } + + /** + * Substitutes the replacement text for each non-overlapping match found + * in the input text, starting at the specified index. + * + * If the regular expression allows the empty string to match, it will + * substitute matches at all positions except the end of the input. + * + * @param input The input text. + * @param replace The replacement text, which may contain $x metacharacters (see REMatch.substituteInto). + * @param index The offset index at which the search should be begin. + * @return A String containing the substring of the input, starting + * at the index position, and interpolating the substituted text. + * @see REMatch#substituteInto + */ + public String substituteAll (Object input, String replace, int index) + { + return substituteAll (input, replace, index, 0); + } + + /** + * Substitutes the replacement text for each non-overlapping match found + * in the input text, starting at the specified index and using the + * specified execution flags. + * + * @param input The input text. + * @param replace The replacement text, which may contain $x metacharacters (see REMatch.substituteInto). + * @param index The offset index at which the search should be begin. + * @param eflags The logical OR of any execution flags above. + * @return A String containing the substring of the input, starting + * at the index position, and interpolating the substituted text. + * @see REMatch#substituteInto + */ + public String substituteAll (Object input, String replace, int index, + int eflags) + { + return substituteAllImpl (makeCharIndexed (input, index), replace, index, + eflags); + } + + private String substituteAllImpl (CharIndexed input, String replace, + int index, int eflags) + { + CPStringBuilder buffer = new CPStringBuilder (); + REMatch m; + while ((m = getMatchImpl (input, index, eflags, buffer)) != null) + { + buffer.append (getReplacement (replace, m, eflags)); + index = m.getEndIndex (); + if (m.end[0] == 0) + { + char ch = input.charAt (0); + if (ch != CharIndexed.OUT_OF_BOUNDS) + buffer.append (ch); + input.move (1); + } + else + { + input.move (m.end[0]); + } + + if (!input.isValid ()) + break; + } + 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) + { + CPStringBuilder sb = new CPStringBuilder (); + 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 + { + // if chain returns false, it "rejected" the token due to + // an optimization, and next was combined with lastToken + if (lastToken.chain (next)) + { + lastToken = next; + } + } + } + + private static REToken setRepeated (REToken current, int min, int max, + int index) throws REException + { + if (current == null) + throw new REException (getLocalizedMessage ("repeat.no.token"), + REException.REG_BADRPT, index); + return new RETokenRepeated (current.subIndex, current, min, max); + } + + private static int getPosixSet (char[]pattern, int index, + CPStringBuilder buf) + { + // Precondition: pattern[index-1] == ':' + // we will return pos of closing ']'. + int i; + for (i = index; i < (pattern.length - 1); i++) + { + if ((pattern[i] == ':') && (pattern[i + 1] == ']')) + return i + 2; + buf.append (pattern[i]); + } + return index; // didn't match up + } + + private int getMinMax (char[]input, int index, IntPair minMax, + RESyntax syntax) throws REException + { + // Precondition: input[index-1] == '{', minMax != null + + boolean mustMatch = !syntax.get (RESyntax.RE_NO_BK_BRACES); + int startIndex = index; + if (index == input.length) + { + if (mustMatch) + throw new REException (getLocalizedMessage ("unmatched.brace"), + REException.REG_EBRACE, index); + else + return startIndex; + } + + int min, max = 0; + CharUnit unit = new CharUnit (); + CPStringBuilder buf = new CPStringBuilder (); + + // Read string of digits + do + { + index = getCharUnit (input, index, unit, false); + if (Character.isDigit (unit.ch)) + buf.append (unit.ch); + } + while ((index != input.length) && Character.isDigit (unit.ch)); + + // Check for {} tomfoolery + if (buf.length () == 0) + { + if (mustMatch) + throw new REException (getLocalizedMessage ("interval.error"), + REException.REG_EBRACE, index); + else + return startIndex; + } + + min = Integer.parseInt (buf.toString ()); + + if ((unit.ch == '}') && (syntax.get (RESyntax.RE_NO_BK_BRACES) ^ unit.bk)) + max = min; + else if (index == input.length) + if (mustMatch) + throw new REException (getLocalizedMessage ("interval.no.end"), + REException.REG_EBRACE, index); + else + return startIndex; + else + if ((unit.ch == ',') && !unit.bk) + { + buf = new CPStringBuilder (); + // Read string of digits + while (((index = + getCharUnit (input, index, unit, false)) != input.length) + && Character.isDigit (unit.ch)) + buf.append (unit.ch); + + if (! + ((unit.ch == '}') + && (syntax.get (RESyntax.RE_NO_BK_BRACES) ^ unit.bk))) + if (mustMatch) + throw new REException (getLocalizedMessage ("interval.error"), + REException.REG_EBRACE, index); + else + return startIndex; + + // This is the case of {x,} + if (buf.length () == 0) + max = Integer.MAX_VALUE; + else + max = Integer.parseInt (buf.toString ()); + } + else if (mustMatch) + throw new REException (getLocalizedMessage ("interval.error"), + REException.REG_EBRACE, index); + else + return startIndex; + + // We know min and max now, and they are valid. + + minMax.first = min; + minMax.second = max; + + // return the index following the '}' + return index; + } + + /** + * Return a human readable form of the compiled regular expression, + * useful for debugging. + */ + public String toString () + { + CPStringBuilder sb = new CPStringBuilder (); + dump (sb); + return sb.toString (); + } + + void dump (CPStringBuilder os) + { + os.append ("(?#startRE subIndex=" + subIndex + ")"); + if (subIndex == 0) + os.append ("?:"); + if (firstToken != null) + firstToken.dumpAll (os); + if (subIndex == 0) + os.append (")"); + os.append ("(?#endRE subIndex=" + subIndex + ")"); + } + + // Cast input appropriately or throw exception + // This method was originally a private method, but has been made + // public because java.util.regex.Matcher uses this. + public static CharIndexed makeCharIndexed (Object input, int index) + { + // The case where input is already a CharIndexed is supposed + // be the most likely because this is the case with + // java.util.regex.Matcher. + // We could let a String or a CharSequence fall through + // to final input, but since it'a very likely input type, + // we check it first. + if (input instanceof CharIndexed) + { + CharIndexed ci = (CharIndexed) input; + ci.setAnchor (index); + return ci; + } + else if (input instanceof CharSequence) + return new CharIndexedCharSequence ((CharSequence) input, index); + else if (input instanceof String) + return new CharIndexedString ((String) input, index); + else if (input instanceof char[]) + return new CharIndexedCharArray ((char[]) input, index); + else if (input instanceof StringBuffer) + return new CharIndexedStringBuffer ((StringBuffer) input, index); + else if (input instanceof InputStream) + return new CharIndexedInputStream ((InputStream) input, index); + else + return new CharIndexedString (input.toString (), index); + } +} diff --git a/libjava/classpath/gnu/java/util/regex/REException.java b/libjava/classpath/gnu/java/util/regex/REException.java new file mode 100644 index 000000000..5681ceeea --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/REException.java @@ -0,0 +1,198 @@ +/* gnu/regexp/REException.java + Copyright (C) 1998-2001, 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.util.regex; + +import gnu.java.lang.CPStringBuilder; + +import java.text.MessageFormat; + +/** + * This is the regular expression exception class. An exception of this type + * defines the three attributes: + *

      + *
    1. A descriptive message of the error. + *
    2. An integral type code equivalent to one of the statically + * defined symbols listed below. + *
    3. The approximate position in the input string where the error + * occurred. + *
    + * + * @author Wes Biggs + */ + +public class REException extends Exception +{ + private int type; + private int pos; + + // Error conditions from GNU regcomp(3) manual + + /** + * Error flag. + * Invalid use of repetition operators such as using + * `*' as the first character. + */ + public static final int REG_BADRPT = 1; + + /** + * Error flag. + * Invalid use of back reference operator. + */ + public static final int REG_BADBR = 2; + + /** + * Error flag. + * Un-matched brace interval operators. + */ + public static final int REG_EBRACE = 3; + + /** + * Error flag. + * Un-matched bracket list operators. + */ + public static final int REG_EBRACK = 4; + + /** + * Error flag. + * Invalid use of the range operator, eg. the ending + * point of the range occurs prior to the starting + * point. + */ + public static final int REG_ERANGE = 5; + + /** + * Error flag. + * Unknown character class name. Not implemented. + */ + public static final int REG_ECTYPE = 6; + + /** + * Error flag. + * Un-matched parenthesis group operators. + */ + public static final int REG_EPAREN = 7; + + /** + * Error flag. + * Invalid back reference to a subexpression. + */ + public static final int REG_ESUBREG = 8; + + /** + * Error flag. + * Non specific error. Not implemented. + */ + public static final int REG_EEND = 9; + + /** + * Error flag. + * Invalid escape sequence. Not implemented. + */ + public static final int REG_ESCAPE = 10; + + /** + * Error flag. + * Invalid use of pattern operators such as group or list. + */ + public static final int REG_BADPAT = 11; + + /** + * Error flag. + * Compiled regular expression requires a pattern + * buffer larger than 64Kb. Not implemented. + */ + public static final int REG_ESIZE = 12; + + /** + * Error flag. + * The regex routines ran out of memory. Not implemented. + */ + public static final int REG_ESPACE = 13; + + REException (String msg, int type, int position) + { + super (msg); + this.type = type; + this.pos = position; + } + + REException (String msg, Throwable cause, int type, int position) + { + super (msg, cause); + this.type = type; + this.pos = position; + } + + /** + * Returns the type of the exception, one of the constants listed above. + */ + + public int getType () + { + return type; + } + + /** + * Returns the position, relative to the string or character array being + * compiled, where the error occurred. This position is generally the point + * where the error was detected, not necessarily the starting index of + * a bad subexpression. + */ + public int getPosition () + { + return pos; + } + + /** + * Reports the descriptive message associated with this exception + * as well as its index position in the string or character array + * being compiled. + */ + public String getMessage () + { + Object[]args = + { + new Integer (pos)}; + CPStringBuilder sb = new CPStringBuilder (); + String prefix = RE.getLocalizedMessage ("error.prefix"); + sb.append (MessageFormat.format (prefix, args)); + sb.append ('\n'); + sb.append (super.getMessage ()); + return sb.toString (); + } +} diff --git a/libjava/classpath/gnu/java/util/regex/REFilterInputStream.java b/libjava/classpath/gnu/java/util/regex/REFilterInputStream.java new file mode 100644 index 000000000..c9fb346ba --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/REFilterInputStream.java @@ -0,0 +1,153 @@ +/* gnu/regexp/REFilterInputStream.java + Copyright (C) 1998-2001, 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.util.regex; +import java.io.FilterInputStream; +import java.io.InputStream; + +/** + * Replaces instances of a given RE found within an InputStream + * with replacement text. The replacements are interpolated into the + * stream when a match is found. + * + * @author Wes Biggs + * @deprecated This class cannot properly handle all character + * encodings. For proper handling, use the REFilterReader + * class instead. + */ + +public class REFilterInputStream extends FilterInputStream +{ + + private RE expr; + private String replace; + private String buffer; + private int bufpos; + private int offset; + private CharIndexedInputStream stream; + + /** + * Creates an REFilterInputStream. When reading from this stream, + * occurrences of patterns matching the supplied regular expression + * will be replaced with the supplied replacement text (the + * metacharacters $0 through $9 may be used to refer to the full + * match or subexpression matches). + * + * @param stream The InputStream to be filtered. + * @param expr The regular expression to search for. + * @param replace The text pattern to replace matches with. + */ + public REFilterInputStream (InputStream stream, RE expr, String replace) + { + super (stream); + this.stream = new CharIndexedInputStream (stream, 0); + this.expr = expr; + this.replace = replace; + } + + /** + * Reads the next byte from the stream per the general contract of + * InputStream.read(). Returns -1 on error or end of stream. + */ + public int read () + { + // If we have buffered replace data, use it. + if ((buffer != null) && (bufpos < buffer.length ())) + { + return (int) buffer.charAt (bufpos++); + } + + // check if input is at a valid position + if (!stream.isValid ()) + return -1; + + REMatch mymatch = new REMatch (expr.getNumSubs (), offset, 0); + if (expr.match (stream, mymatch)) + { + mymatch.end[0] = mymatch.index; + mymatch.finish (stream); + stream.move (mymatch.toString ().length ()); + offset += mymatch.toString ().length (); + buffer = mymatch.substituteInto (replace); + bufpos = 1; + + // This is prone to infinite loops if replace string turns out empty. + if (buffer.length () > 0) + { + return buffer.charAt (0); + } + } + char ch = stream.charAt (0); + if (ch == CharIndexed.OUT_OF_BOUNDS) + return -1; + stream.move (1); + offset++; + return ch; + } + + /** + * Returns false. REFilterInputStream does not support mark() and + * reset() methods. + */ + public boolean markSupported () + { + return false; + } + + /** Reads from the stream into the provided array. */ + public int read (byte[]b, int off, int len) + { + int i; + int ok = 0; + while (len-- > 0) + { + i = read (); + if (i == -1) + return (ok == 0) ? -1 : ok; + b[off++] = (byte) i; + ok++; + } + return ok; + } + + /** Reads from the stream into the provided array. */ + public int read (byte[]b) + { + return read (b, 0, b.length); + } +} diff --git a/libjava/classpath/gnu/java/util/regex/REMatch.java b/libjava/classpath/gnu/java/util/regex/REMatch.java new file mode 100644 index 000000000..5940094ba --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/REMatch.java @@ -0,0 +1,362 @@ +/* gnu/regexp/REMatch.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.java.util.regex; + +import gnu.java.lang.CPStringBuilder; + +import java.io.Serializable; + +/** + * An instance of this class represents a match + * completed by a gnu.regexp matching function. It can be used + * to obtain relevant information about the location of a match + * or submatch. + * + * @author Wes Biggs + */ +public final class REMatch implements Serializable, Cloneable +{ + private String matchedText; + private CharIndexed matchedCharIndexed; + + // These variables are package scope for fast access within the engine + int eflags; // execution flags this match was made using + + // Offset in source text where match was tried. This is zero-based; + // the actual position in the source text is given by (offset + anchor). + int offset; + + // Anchor position refers to the index into the source input + // at which the matching operation began. + // This is also useful for the ANCHORINDEX option. + int anchor; + + // Package scope; used by RE. + int index; // used while matching to mark current match position in input + // start1[i] is set when the i-th subexp starts. And start1[i] is copied + // to start[i] when the i-th subexp ends. So start[i] keeps the previously + // assigned value while the i-th subexp is being processed. This makes + // backreference to the i-th subexp within the i-th subexp possible. + int[] start; // start positions (relative to offset) for each (sub)exp. + int[] start1; // start positions (relative to offset) for each (sub)exp. + int[] end; // end positions for the same + // start[i] == -1 or end[i] == -1 means that the start/end position is void. + // start[i] == p or end[i] == p where p < 0 and p != -1 means that + // the actual start/end position is (p+1). Start/end positions may + // become negative when the subexpression is in a RETokenLookBehind. + boolean empty; // empty string matched. This flag is used only within + // RETokenRepeated. + + BacktrackStack backtrackStack; + + public Object clone () + { + try + { + REMatch copy = (REMatch) super.clone (); + + copy.start = (int[]) start.clone (); + copy.start1 = (int[]) start1.clone (); + copy.end = (int[]) end.clone (); + + return copy; + } + catch (CloneNotSupportedException e) + { + throw new Error (); // doesn't happen + } + } + + void assignFrom (REMatch other) + { + start = other.start; + start1 = other.start1; + end = other.end; + index = other.index; + backtrackStack = other.backtrackStack; + } + + REMatch (int subs, int anchor, int eflags) + { + start = new int[subs + 1]; + start1 = new int[subs + 1]; + end = new int[subs + 1]; + this.anchor = anchor; + this.eflags = eflags; + clear (anchor); + } + + void finish (CharIndexed text) + { + start[0] = 0; + CPStringBuilder sb = new CPStringBuilder (); + int i; + for (i = 0; i < end[0]; i++) + sb.append (text.charAt (i)); + matchedText = sb.toString (); + matchedCharIndexed = text; + for (i = 0; i < start.length; i++) + { + // If any subexpressions didn't terminate, they don't count + // TODO check if this code ever gets hit + if ((start[i] == -1) ^ (end[i] == -1)) + { + start[i] = -1; + end[i] = -1; + } + } + backtrackStack = null; + } + + /** Clears the current match and moves the offset to the new index. */ + void clear (int index) + { + offset = index; + this.index = 0; + for (int i = 0; i < start.length; i++) + { + start[i] = start1[i] = end[i] = -1; + } + backtrackStack = null; + } + + /** + * Returns the string matching the pattern. This makes it convenient + * to write code like the following: + *

    + * + * REMatch myMatch = myExpression.getMatch(myString);
    + * if (myMatch != null) System.out.println("Regexp found: "+myMatch); + *
    + */ + public String toString () + { + return matchedText; + } + + /** + * Returns the index within the input text where the match in its entirety + * began. + */ + public int getStartIndex () + { + return offset + start[0]; + } + + /** + * Returns the index within the input string where the match in + * its entirety ends. The return value is the next position after + * the end of the string; therefore, a match created by the + * following call: + * + *

    + * REMatch myMatch = myExpression.getMatch(myString); + *

    + * can be viewed (given that myMatch is not null) by creating + *

    + * String theMatch = myString.substring(myMatch.getStartIndex(), + * myMatch.getEndIndex()); + *

    + * But you can save yourself that work, since the toString() + * method (above) does exactly that for you. + */ + public int getEndIndex () + { + return offset + end[0]; + } + + /** + * Returns the string matching the given subexpression. The subexpressions + * are indexed starting with one, not zero. That is, the subexpression + * identified by the first set of parentheses in a regular expression + * could be retrieved from an REMatch by calling match.toString(1). + * + * @param sub Index of the subexpression. + */ + public String toString (int sub) + { + if ((sub >= start.length) || sub < 0) + throw new IndexOutOfBoundsException ("No group " + sub); + if (start[sub] == -1) + return null; + if (start[sub] >= 0 && end[sub] <= matchedText.length ()) + return (matchedText.substring (start[sub], end[sub])); + else + { + // This case occurs with RETokenLookAhead or RETokenLookBehind. + CPStringBuilder sb = new CPStringBuilder (); + int s = start[sub]; + int e = end[sub]; + if (s < 0) + s += 1; + if (e < 0) + e += 1; + for (int i = start[0] + s; i < start[0] + e; i++) + sb.append (matchedCharIndexed.charAt (i)); + return sb.toString (); + } + } + + /** + * Returns the index within the input string used to generate this match + * where subexpression number sub begins, or -1 if + * the subexpression does not exist. The initial position is zero. + * + * @param sub Subexpression index + * @deprecated Use getStartIndex(int) instead. + */ + public int getSubStartIndex (int sub) + { + if (sub >= start.length) + return -1; + int x = start[sub]; + return (x == -1) ? x : (x >= 0) ? offset + x : offset + x + 1; + } + + /** + * Returns the index within the input string used to generate this match + * where subexpression number sub begins, or -1 if + * the subexpression does not exist. The initial position is zero. + * + * @param sub Subexpression index + * @since gnu.regexp 1.1.0 + */ + public int getStartIndex (int sub) + { + if (sub >= start.length) + return -1; + int x = start[sub]; + return (x == -1) ? x : (x >= 0) ? offset + x : offset + x + 1; + } + + /** + * Returns the index within the input string used to generate this match + * where subexpression number sub ends, or -1 if + * the subexpression does not exist. The initial position is zero. + * + * @param sub Subexpression index + * @deprecated Use getEndIndex(int) instead + */ + public int getSubEndIndex (int sub) + { + if (sub >= start.length) + return -1; + int x = end[sub]; + return (x == -1) ? x : (x >= 0) ? offset + x : offset + x + 1; + } + + /** + * Returns the index within the input string used to generate this match + * where subexpression number sub ends, or -1 if + * the subexpression does not exist. The initial position is zero. + * + * @param sub Subexpression index + */ + public int getEndIndex (int sub) + { + if (sub >= start.length) + return -1; + int x = end[sub]; + return (x == -1) ? x : (x >= 0) ? offset + x : offset + x + 1; + } + + /** + * Substitute the results of this match to create a new string. + * This is patterned after PERL, so the tokens to watch out for are + * $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. + */ + public String substituteInto (String input) + { + // a la Perl, $0 is whole thing, $1 - $9 are subexpressions + CPStringBuilder output = new CPStringBuilder (); + int pos; + 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)); + } + } + else + output.append (input.charAt (pos)); + } + if (pos < input.length ()) + output.append (input.charAt (pos)); + return output.toString (); + } + +/* The following are used for debugging purpose + public static String d(REMatch m) { + if (m == null) return "null"; + else return "[" + m.index + "]"; + } + + public String substringUptoIndex(CharIndexed input) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < index; i++) { + sb.append(input.charAt(i)); + } + return sb.toString(); + } +*/ + +} diff --git a/libjava/classpath/gnu/java/util/regex/REMatchEnumeration.java b/libjava/classpath/gnu/java/util/regex/REMatchEnumeration.java new file mode 100644 index 000000000..04432d07c --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/REMatchEnumeration.java @@ -0,0 +1,141 @@ +/* gnu/regexp/REMatchEnumeration.java + Copyright (C) 1998-2001, 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.util.regex; + +import gnu.java.lang.CPStringBuilder; + +import java.io.Serializable; +import java.util.Enumeration; +import java.util.NoSuchElementException; + +/** + * An REMatchEnumeration enumerates regular expression matches over a + * given input text. You obtain a reference to an enumeration using + * the getMatchEnumeration() methods on an instance of + * RE. + * + *

    + * + * REMatchEnumeration does lazy computation; that is, it will not + * search for a match until it needs to. If you'd rather just get all + * the matches at once in a big array, use the + * getAllMatches() methods on RE. However, using an + * enumeration can help speed performance when the entire text does + * not need to be searched immediately. + * + *

    + * + * The enumerated type is especially useful when searching on a Reader + * or InputStream, because the InputStream read position cannot be + * guaranteed after calling getMatch() (see the + * description of that method for an explanation of why). Enumeration + * also saves a lot of overhead required when calling + * getMatch() multiple times. + * + * @author Wes Biggs + */ +public class REMatchEnumeration + implements Enumeration < REMatch >, Serializable +{ + private static final int YES = 1; + private static final int MAYBE = 0; + private static final int NO = -1; + + private int more; + private REMatch match; + private final RE expr; + private final CharIndexed input; + private final int eflags; + private int index; + + // Package scope constructor is used by RE.getMatchEnumeration() + REMatchEnumeration (RE expr, CharIndexed input, int index, int eflags) + { + more = MAYBE; + this.expr = expr; + this.input = input; + this.index = index; + this.eflags = eflags; + } + + /** Returns true if there are more matches in the input text. */ + public boolean hasMoreElements () + { + return hasMoreMatches (null); + } + + /** Returns true if there are more matches in the input text. */ + public boolean hasMoreMatches () + { + return hasMoreMatches (null); + } + + /** Returns true if there are more matches in the input text. + * Saves the text leading up to the match (or to the end of the input) + * in the specified buffer. + */ + public boolean hasMoreMatches (CPStringBuilder buffer) + { + if (more == MAYBE) + { + match = expr.getMatchImpl (input, index, eflags, buffer); + if (match != null) + { + input.move ((match.end[0] > 0) ? match.end[0] : 1); + + index = + (match.end[0] > 0) ? match.end[0] + match.offset : index + 1; + more = YES; + } + else + more = NO; + } + return (more == YES); + } + + /** Returns the next match in the input text. */ + public REMatch nextElement () throws NoSuchElementException + { + if (hasMoreElements ()) + { + more = (input.isValid ())? MAYBE : NO; + return match; + } + throw new NoSuchElementException (); + } +} diff --git a/libjava/classpath/gnu/java/util/regex/RESyntax.java b/libjava/classpath/gnu/java/util/regex/RESyntax.java new file mode 100644 index 000000000..2080cb763 --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/RESyntax.java @@ -0,0 +1,537 @@ +/* gnu/regexp/RESyntax.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.java.util.regex; +import java.io.Serializable; +import java.util.BitSet; + +/** + * An RESyntax specifies the way a regular expression will be compiled. + * This class provides a number of predefined useful constants for + * emulating popular regular expression syntaxes. Additionally the + * user may construct his or her own syntax, using any combination of the + * syntax bit constants. The syntax is an optional argument to any of the + * matching methods on class RE. + * + * @author Wes Biggs + */ + +public final class RESyntax implements Serializable +{ + static final String DEFAULT_LINE_SEPARATOR = + System.getProperty ("line.separator"); + + private BitSet bits; + + // true for the constant defined syntaxes + private boolean isFinal = false; + + private String lineSeparator = DEFAULT_LINE_SEPARATOR; + + // Values for constants are bit indexes + + /** + * Syntax bit. Backslash is an escape character in lists. + */ + public static final int RE_BACKSLASH_ESCAPE_IN_LISTS = 0; + + /** + * Syntax bit. Use \? instead of ? and \+ instead of +. + */ + public static final int RE_BK_PLUS_QM = 1; + + /** + * Syntax bit. POSIX character classes ([:...:]) in lists are allowed. + */ + public static final int RE_CHAR_CLASSES = 2; + + /** + * Syntax bit. ^ and $ are special everywhere. + * Not implemented. + */ + public static final int RE_CONTEXT_INDEP_ANCHORS = 3; + + /** + * Syntax bit. Repetition operators are only special in valid positions. + * Not implemented. + */ + public static final int RE_CONTEXT_INDEP_OPS = 4; + + /** + * Syntax bit. Repetition and alternation operators are invalid + * at start and end of pattern and other places. + * Not implemented. + */ + public static final int RE_CONTEXT_INVALID_OPS = 5; + + /** + * Syntax bit. Match-any-character operator (.) matches a newline. + */ + public static final int RE_DOT_NEWLINE = 6; + + /** + * Syntax bit. Match-any-character operator (.) does not match a null. + */ + public static final int RE_DOT_NOT_NULL = 7; + + /** + * Syntax bit. Intervals ({x}, {x,}, {x,y}) are allowed. + */ + public static final int RE_INTERVALS = 8; + + /** + * Syntax bit. No alternation (|), match one-or-more (+), or + * match zero-or-one (?) operators. + */ + public static final int RE_LIMITED_OPS = 9; + + /** + * Syntax bit. Newline is an alternation operator. + */ + public static final int RE_NEWLINE_ALT = 10; // impl. + + /** + * Syntax bit. Intervals use { } instead of \{ \} + */ + public static final int RE_NO_BK_BRACES = 11; + + /** + * Syntax bit. Grouping uses ( ) instead of \( \). + */ + public static final int RE_NO_BK_PARENS = 12; + + /** + * Syntax bit. Backreferences not allowed. + */ + public static final int RE_NO_BK_REFS = 13; + + /** + * Syntax bit. Alternation uses | instead of \| + */ + public static final int RE_NO_BK_VBAR = 14; + + /** + * Syntax bit. Not implemented. + */ + public static final int RE_NO_EMPTY_RANGES = 15; + + /** + * Syntax bit. An unmatched right parenthesis (')' or '\)', depending + * on RE_NO_BK_PARENS) will throw an exception when compiling. + */ + public static final int RE_UNMATCHED_RIGHT_PAREN_ORD = 16; + + /** + * Syntax bit. Not implemented. + */ + public static final int RE_HAT_LISTS_NOT_NEWLINE = 17; + + /** + * Syntax bit. Stingy matching is allowed (+?, *?, ??, {x,y}?). + */ + public static final int RE_STINGY_OPS = 18; + + /** + * Syntax bit. Allow character class escapes (\d, \D, \s, \S, \w, \W). + */ + public static final int RE_CHAR_CLASS_ESCAPES = 19; + + /** + * Syntax bit. Allow use of (?:xxx) grouping (subexpression is not saved). + */ + public static final int RE_PURE_GROUPING = 20; + + /** + * Syntax bit. Allow use of (?=xxx) and (?!xxx) apply the subexpression + * to the text following the current position without consuming that text. + */ + public static final int RE_LOOKAHEAD = 21; + + /** + * Syntax bit. Allow beginning- and end-of-string anchors (\A, \Z). + */ + public static final int RE_STRING_ANCHORS = 22; + + /** + * Syntax bit. Allow embedded comments, (?#comment), as in Perl5. + */ + public static final int RE_COMMENTS = 23; + + /** + * Syntax bit. Allow character class escapes within lists, as in Perl5. + */ + public static final int RE_CHAR_CLASS_ESC_IN_LISTS = 24; + + /** + * Syntax bit. Possessive matching is allowed (++, *+, ?+, {x,y}+). + */ + public static final int RE_POSSESSIVE_OPS = 25; + + /** + * 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. + * Emulates regular expression support in the awk utility. + */ + public static final RESyntax RE_SYNTAX_AWK; + + /** + * Predefined syntax. + * Emulates regular expression support in the ed utility. + */ + public static final RESyntax RE_SYNTAX_ED; + + /** + * Predefined syntax. + * Emulates regular expression support in the egrep utility. + */ + public static final RESyntax RE_SYNTAX_EGREP; + + /** + * Predefined syntax. + * Emulates regular expression support in the GNU Emacs editor. + */ + public static final RESyntax RE_SYNTAX_EMACS; + + /** + * Predefined syntax. + * Emulates regular expression support in the grep utility. + */ + public static final RESyntax RE_SYNTAX_GREP; + + /** + * Predefined syntax. + * Emulates regular expression support in the POSIX awk specification. + */ + public static final RESyntax RE_SYNTAX_POSIX_AWK; + + /** + * Predefined syntax. + * Emulates POSIX basic regular expression support. + */ + public static final RESyntax RE_SYNTAX_POSIX_BASIC; + + /** + * Predefined syntax. + * Emulates regular expression support in the POSIX egrep specification. + */ + public static final RESyntax RE_SYNTAX_POSIX_EGREP; + + /** + * Predefined syntax. + * Emulates POSIX extended regular expression support. + */ + public static final RESyntax RE_SYNTAX_POSIX_EXTENDED; + + /** + * Predefined syntax. + * Emulates POSIX basic minimal regular expressions. + */ + public static final RESyntax RE_SYNTAX_POSIX_MINIMAL_BASIC; + + /** + * Predefined syntax. + * Emulates POSIX extended minimal regular expressions. + */ + public static final RESyntax RE_SYNTAX_POSIX_MINIMAL_EXTENDED; + + /** + * Predefined syntax. + * Emulates regular expression support in the sed utility. + */ + public static final RESyntax RE_SYNTAX_SED; + + /** + * Predefined syntax. + * Emulates regular expression support in Larry Wall's perl, version 4, + */ + public static final RESyntax RE_SYNTAX_PERL4; + + /** + * Predefined syntax. + * Emulates regular expression support in Larry Wall's perl, version 4, + * using single line mode (/s modifier). + */ + public static final RESyntax RE_SYNTAX_PERL4_S; // single line mode (/s) + + /** + * Predefined syntax. + * Emulates regular expression support in Larry Wall's perl, version 5. + */ + public static final RESyntax RE_SYNTAX_PERL5; + + /** + * Predefined syntax. + * Emulates regular expression support in Larry Wall's perl, version 5, + * using single line mode (/s modifier). + */ + public static final RESyntax RE_SYNTAX_PERL5_S; + + /** + * Predefined syntax. + * Emulates regular expression support in Java 1.4's java.util.regex + * package. + */ + public static final RESyntax RE_SYNTAX_JAVA_1_4; + + static + { + // Define syntaxes + + RE_SYNTAX_EMACS = new RESyntax ().makeFinal (); + + RESyntax RE_SYNTAX_POSIX_COMMON = + new RESyntax ().set (RE_CHAR_CLASSES).set (RE_DOT_NEWLINE). + set (RE_DOT_NOT_NULL).set (RE_INTERVALS).set (RE_NO_EMPTY_RANGES). + makeFinal (); + + RE_SYNTAX_POSIX_BASIC = + new RESyntax (RE_SYNTAX_POSIX_COMMON).set (RE_BK_PLUS_QM).makeFinal (); + + RE_SYNTAX_POSIX_EXTENDED = + new RESyntax (RE_SYNTAX_POSIX_COMMON).set (RE_CONTEXT_INDEP_ANCHORS). + set (RE_CONTEXT_INDEP_OPS).set (RE_NO_BK_BRACES).set (RE_NO_BK_PARENS). + set (RE_NO_BK_VBAR).set (RE_UNMATCHED_RIGHT_PAREN_ORD).makeFinal (); + + RE_SYNTAX_AWK = + new RESyntax ().set (RE_BACKSLASH_ESCAPE_IN_LISTS). + set (RE_DOT_NOT_NULL).set (RE_NO_BK_PARENS).set (RE_NO_BK_REFS). + set (RE_NO_BK_VBAR).set (RE_NO_EMPTY_RANGES). + set (RE_UNMATCHED_RIGHT_PAREN_ORD).makeFinal (); + + RE_SYNTAX_POSIX_AWK = + new RESyntax (RE_SYNTAX_POSIX_EXTENDED). + set (RE_BACKSLASH_ESCAPE_IN_LISTS).makeFinal (); + + RE_SYNTAX_GREP = + new RESyntax ().set (RE_BK_PLUS_QM).set (RE_CHAR_CLASSES). + set (RE_HAT_LISTS_NOT_NEWLINE).set (RE_INTERVALS).set (RE_NEWLINE_ALT). + makeFinal (); + + RE_SYNTAX_EGREP = + new RESyntax ().set (RE_CHAR_CLASSES).set (RE_CONTEXT_INDEP_ANCHORS). + set (RE_CONTEXT_INDEP_OPS).set (RE_HAT_LISTS_NOT_NEWLINE). + set (RE_NEWLINE_ALT).set (RE_NO_BK_PARENS).set (RE_NO_BK_VBAR). + makeFinal (); + + RE_SYNTAX_POSIX_EGREP = + new RESyntax (RE_SYNTAX_EGREP).set (RE_INTERVALS).set (RE_NO_BK_BRACES). + makeFinal (); + + /* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */ + + RE_SYNTAX_ED = new RESyntax (RE_SYNTAX_POSIX_BASIC).makeFinal (); + + RE_SYNTAX_SED = new RESyntax (RE_SYNTAX_POSIX_BASIC).makeFinal (); + + RE_SYNTAX_POSIX_MINIMAL_BASIC = + new RESyntax (RE_SYNTAX_POSIX_COMMON).set (RE_LIMITED_OPS).makeFinal (); + + /* Differs from RE_SYNTAX_POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS + replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added. */ + + RE_SYNTAX_POSIX_MINIMAL_EXTENDED = + new RESyntax (RE_SYNTAX_POSIX_COMMON).set (RE_CONTEXT_INDEP_ANCHORS). + set (RE_CONTEXT_INVALID_OPS).set (RE_NO_BK_BRACES). + set (RE_NO_BK_PARENS).set (RE_NO_BK_REFS).set (RE_NO_BK_VBAR). + set (RE_UNMATCHED_RIGHT_PAREN_ORD).makeFinal (); + + /* There is no official Perl spec, but here's a "best guess" */ + + RE_SYNTAX_PERL4 = new RESyntax ().set (RE_BACKSLASH_ESCAPE_IN_LISTS).set (RE_CONTEXT_INDEP_ANCHORS).set (RE_CONTEXT_INDEP_OPS) // except for '{', apparently + .set (RE_INTERVALS).set (RE_NO_BK_BRACES).set (RE_NO_BK_PARENS).set (RE_NO_BK_VBAR).set (RE_NO_EMPTY_RANGES).set (RE_CHAR_CLASS_ESCAPES) // \d,\D,\w,\W,\s,\S + .makeFinal (); + + RE_SYNTAX_PERL4_S = + new RESyntax (RE_SYNTAX_PERL4).set (RE_DOT_NEWLINE).makeFinal (); + + RE_SYNTAX_PERL5 = new RESyntax (RE_SYNTAX_PERL4).set (RE_PURE_GROUPING) // (?:) + .set (RE_STINGY_OPS) // *?,??,+?,{}? + .set (RE_LOOKAHEAD) // (?=)(?!) + .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).set (RE_DOT_NEWLINE).makeFinal (); + + 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 (); + } + + /** + * Construct a new syntax object with all bits turned off. + * This is equivalent to RE_SYNTAX_EMACS. + */ + public RESyntax () + { + bits = new BitSet (BIT_TOTAL); + } + + /** + * Called internally when constructing predefined syntaxes + * so their interpretation cannot vary. Conceivably useful + * for your syntaxes as well. Causes IllegalAccessError to + * be thrown if any attempt to modify the syntax is made. + * + * @return this object for convenient chaining + */ + public RESyntax makeFinal () + { + isFinal = true; + return this; + } + + /** + * Construct a new syntax object with all bits set the same + * as the other syntax. + */ + public RESyntax (RESyntax other) + { + bits = (BitSet) other.bits.clone (); + } + + /** + * Check if a given bit is set in this syntax. + */ + public boolean get (int index) + { + return bits.get (index); + } + + /** + * Set a given bit in this syntax. + * + * @param index the constant (RESyntax.RE_xxx) bit to set. + * @return a reference to this object for easy chaining. + */ + public RESyntax set (int index) + { + if (isFinal) + throw new IllegalAccessError (RE.getLocalizedMessage ("syntax.final")); + bits.set (index); + return this; + } + + /** + * Clear a given bit in this syntax. + * + * @param index the constant (RESyntax.RE_xxx) bit to clear. + * @return a reference to this object for easy chaining. + */ + public RESyntax clear (int index) + { + if (isFinal) + throw new IllegalAccessError (RE.getLocalizedMessage ("syntax.final")); + bits.clear (index); + return this; + } + + /** + * Changes the line separator string for regular expressions + * created using this RESyntax. The default separator is the + * value returned by the system property "line.separator", which + * should be correct when reading platform-specific files from a + * filesystem. However, many programs may collect input from + * sources where the line separator is differently specified (for + * example, in the applet environment, the text box widget + * interprets line breaks as single-character newlines, + * regardless of the host platform. + * + * Note that setting the line separator to a character or + * characters that have specific meaning within the current syntax + * can cause unexpected chronosynclastic infundibula. + * + * @return this object for convenient chaining + */ + public RESyntax setLineSeparator (String aSeparator) + { + if (isFinal) + throw new IllegalAccessError (RE.getLocalizedMessage ("syntax.final")); + lineSeparator = aSeparator; + return this; + } + + /** + * Returns the currently active line separator string. The default + * is the platform-dependent system property "line.separator". + */ + public String getLineSeparator () + { + return lineSeparator; + } +} diff --git a/libjava/classpath/gnu/java/util/regex/REToken.java b/libjava/classpath/gnu/java/util/regex/REToken.java new file mode 100644 index 000000000..ed9b31747 --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/REToken.java @@ -0,0 +1,244 @@ +/* gnu/regexp/REToken.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.java.util.regex; + +import gnu.java.lang.CPStringBuilder; + +import java.io.Serializable; + +abstract class REToken implements Serializable, Cloneable +{ + + protected REToken next = null; + protected REToken uncle = null; + protected int subIndex; + protected boolean unicodeAware = true; + + 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; + } + + int getMinimumLength () + { + return 0; + } + + int getMaximumLength () + { + return Integer.MAX_VALUE; + } + + void setUncle (REToken anUncle) + { + uncle = anUncle; + } + + /** Returns true if the match succeeded, false if it failed. */ + boolean match (CharIndexed input, REMatch mymatch) + { + return match (input, mymatch, false); + } + boolean matchFake (CharIndexed input, REMatch mymatch) + { + return match (input, mymatch, true); + } + + private boolean match (CharIndexed input, REMatch mymatch, boolean fake) + { + if (!fake) + { + setHitEnd (input, mymatch); + } + REMatch m = matchThis (input, mymatch); + if (m == null) + return false; + if (next (input, m)) + { + mymatch.assignFrom (m); + return true; + } + return false; + } + + /** Sets whether the matching occurs at the end of input */ + void setHitEnd (CharIndexed input, REMatch mymatch) + { + input.setHitEnd (mymatch); + } + + /** Returns true if the match succeeded, false if it failed. + * The matching is done against this REToken only. Chained + * tokens are not checked. + * This method is used to define the default match method. + * Simple subclasses of REToken, for example, such that + * matches only one character, should implement this method. + * Then the default match method will work. But complicated + * subclasses of REToken, which needs a special match method, + * do not have to implement this method. + */ + REMatch matchThis (CharIndexed input, REMatch mymatch) + { + throw new + UnsupportedOperationException + ("This REToken does not have a matchThis method"); + } + + /** Returns true if the rest of the tokens match, false if they fail. */ + protected boolean next (CharIndexed input, REMatch mymatch) + { + REToken nextToken = getNext (); + if (nextToken == null) + return true; + return nextToken.match (input, mymatch); + } + + /** Returns the next REToken chained to this REToken. */ + REToken getNext () + { + return (next != null ? next : uncle); + } + + /** Finds a match at the position specified by the given REMatch. + * If necessary, adds a BacktrackStack.Backtrack object to backtrackStack + * of the REmatch found this time so that another possible match + * may be found when backtrack is called. + * By default, nothing is added to the backtrackStack. + * @param input Input character sequence. + * @param mymatch Position at which a match should be found + * @return REMatch object if a match was found, null otherwise. + */ + REMatch findMatch (CharIndexed input, REMatch mymatch) + { + boolean b = match (input, mymatch); + if (b) + return mymatch; + return null; + } + + boolean returnsFixedLengthMatches () + { + return false; + } + + int findFixedLengthMatches (CharIndexed input, REMatch mymatch, int max) + { + throw new + UnsupportedOperationException + ("This token does not support findFixedLengthMatches"); + } + + /** + * Backtrack to another possibility. + * Ordinary REToken cannot do anything if this method is called. + */ + REMatch backtrack (CharIndexed input, REMatch mymatch, Object param) + { + throw new IllegalStateException ("This token cannot be backtracked to"); + } + + boolean chain (REToken token) + { + next = token; + return true; // Token was accepted + } + + abstract void dump (CPStringBuilder os); + + void dumpAll (CPStringBuilder os) + { + dump (os); + if (next != null) + next.dumpAll (os); + } + + public String toString () + { + CPStringBuilder os = new CPStringBuilder (); + dump (os); + return os.toString (); + } + + /** + * Converts the character argument to lowercase. + * @param ch the character to be converted. + * @param unicodeAware If true, use java.lang.Character#toLowerCase; + * otherwise, only US-ASCII charactes can be converted. + * @return the lowercase equivalent of the character, if any; + * otherwise, the character itself. + */ + public static char toLowerCase (char ch, boolean unicodeAware) + { + if (unicodeAware) + return Character.toLowerCase (ch); + if (ch >= 'A' && ch <= 'Z') + return (char) (ch + 'a' - 'A'); + return ch; + } + + /** + * Converts the character argument to uppercase. + * @param ch the character to be converted. + * @param unicodeAware If true, use java.lang.Character#toUpperCase; + * otherwise, only US-ASCII charactes can be converted. + * @return the uppercase equivalent of the character, if any; + * otherwise, the character itself. + */ + public static char toUpperCase (char ch, boolean unicodeAware) + { + if (unicodeAware) + return Character.toUpperCase (ch); + if (ch >= 'a' && ch <= 'z') + return (char) (ch + 'A' - 'a'); + return ch; + } + +} diff --git a/libjava/classpath/gnu/java/util/regex/RETokenAny.java b/libjava/classpath/gnu/java/util/regex/RETokenAny.java new file mode 100644 index 000000000..f5039682d --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/RETokenAny.java @@ -0,0 +1,115 @@ +/* gnu/regexp/RETokenAny.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.java.util.regex; + +import gnu.java.lang.CPStringBuilder; + +final class RETokenAny extends REToken +{ + /** True if '.' can match a newline (RE_DOT_NEWLINE) */ + private boolean newline; + + /** True if '.' can't match a null (RE_DOT_NOT_NULL) */ + private boolean matchNull; + + RETokenAny (int subIndex, boolean newline, boolean matchNull) + { + super (subIndex); + this.newline = newline; + this.matchNull = matchNull; + } + + int getMinimumLength () + { + return 1; + } + + int getMaximumLength () + { + return 1; + } + + REMatch matchThis (CharIndexed input, REMatch mymatch) + { + char ch = input.charAt (mymatch.index); + boolean retval = matchOneChar (ch); + if (retval) + { + ++mymatch.index; + return mymatch; + } + return null; + } + + boolean matchOneChar (char ch) + { + if ((ch == CharIndexed.OUT_OF_BOUNDS) + || (!newline && (ch == '\n')) || (matchNull && (ch == 0))) + { + return false; + } + return true; + } + + boolean returnsFixedLengthMatches () + { + return true; + } + + int findFixedLengthMatches (CharIndexed input, REMatch mymatch, int max) + { + int index = mymatch.index; + int numRepeats = 0; + while (true) + { + if (numRepeats >= max) + break; + char ch = input.charAt (index++); + if (!matchOneChar (ch)) + break; + numRepeats++; + } + return numRepeats; + } + + void dump (CPStringBuilder os) + { + os.append ('.'); + } +} diff --git a/libjava/classpath/gnu/java/util/regex/RETokenBackRef.java b/libjava/classpath/gnu/java/util/regex/RETokenBackRef.java new file mode 100644 index 000000000..52061ca2e --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/RETokenBackRef.java @@ -0,0 +1,100 @@ +/* gnu/regexp/RETokenBackRef.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.java.util.regex; + +import gnu.java.lang.CPStringBuilder; + +final class RETokenBackRef extends REToken +{ + private int num; + private boolean insens; + + RETokenBackRef (int subIndex, int num, boolean insens) + { + super (subIndex); + this.num = num; + this.insens = insens; + } + + // should implement getMinimumLength() -- any ideas? + + REMatch matchThis (CharIndexed input, REMatch mymatch) + { + if (num >= mymatch.start.length) + return null; + if (num >= mymatch.end.length) + return null; + int b, e; + b = mymatch.start[num]; + e = mymatch.end[num]; + if ((b == -1) || (e == -1)) + return null; // this shouldn't happen, but... + if (b < 0) + b += 1; + if (e < 0) + e += 1; + for (int i = b; i < e; i++) + { + char c1 = input.charAt (mymatch.index + i - b); + char c2 = input.charAt (i); + if (c1 != c2) + { + if (insens) + { + if (c1 != toLowerCase (c2, unicodeAware) && + c1 != toUpperCase (c2, unicodeAware)) + { + return null; + } + } + else + { + return null; + } + } + } + mymatch.index += e - b; + return mymatch; + } + + void dump (CPStringBuilder os) + { + os.append ('\\').append (num); + } +} diff --git a/libjava/classpath/gnu/java/util/regex/RETokenChar.java b/libjava/classpath/gnu/java/util/regex/RETokenChar.java new file mode 100644 index 000000000..3469ecfa8 --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/RETokenChar.java @@ -0,0 +1,162 @@ +/* gnu/regexp/RETokenChar.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.java.util.regex; + +import gnu.java.lang.CPStringBuilder; + +final class RETokenChar extends REToken +{ + private char[] ch; + private boolean insens; + + RETokenChar (int subIndex, char c, boolean ins) + { + super (subIndex); + insens = ins; + ch = new char[1]; + ch[0] = c; + } + + int getMinimumLength () + { + return ch.length; + } + + int getMaximumLength () + { + return ch.length; + } + + REMatch matchThis (CharIndexed input, REMatch mymatch) + { + if (matchOneString (input, mymatch.index)) + { + mymatch.index += matchedLength; + return mymatch; + } + // java.util.regex.Matcher#hitEnd() requires that the length of + // partial match be counted. + mymatch.index += matchedLength; + input.setHitEnd (mymatch); + return null; + } + + private int matchedLength; + private boolean matchOneString (CharIndexed input, int index) + { + matchedLength = 0; + int z = ch.length; + char c; + for (int i = 0; i < z; i++) + { + c = input.charAt (index + i); + if (!charEquals (c, ch[i])) + { + return false; + } + ++matchedLength; + } + return true; + } + + private boolean charEquals (char c1, char c2) + { + if (c1 == c2) + return true; + if (!insens) + return false; + if (toLowerCase (c1, unicodeAware) == c2) + return true; + if (toUpperCase (c1, unicodeAware) == c2) + return true; + return false; + } + + boolean returnsFixedLengthMatches () + { + return true; + } + + int findFixedLengthMatches (CharIndexed input, REMatch mymatch, int max) + { + int index = mymatch.index; + int numRepeats = 0; + int z = ch.length; + while (true) + { + if (numRepeats >= max) + break; + if (matchOneString (input, index)) + { + index += z; + numRepeats++; + } + else + break; + } + return numRepeats; + } + + // Overrides REToken.chain() to optimize for strings + boolean chain (REToken next) + { + if (next instanceof RETokenChar && ((RETokenChar) next).insens == insens) + { + RETokenChar cnext = (RETokenChar) next; + int newsize = ch.length + cnext.ch.length; + + char[] chTemp = new char[newsize]; + + System.arraycopy (ch, 0, chTemp, 0, ch.length); + System.arraycopy (cnext.ch, 0, chTemp, ch.length, cnext.ch.length); + + ch = chTemp; + if (cnext.next == null) + return false; + return chain (cnext.next); + } + else + return super.chain (next); + } + + void dump (CPStringBuilder os) + { + os.append (ch); + } +} diff --git a/libjava/classpath/gnu/java/util/regex/RETokenEnd.java b/libjava/classpath/gnu/java/util/regex/RETokenEnd.java new file mode 100644 index 000000000..28d78231a --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/RETokenEnd.java @@ -0,0 +1,151 @@ +/* gnu/regexp/RETokenEnd.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.java.util.regex; + +import gnu.java.lang.CPStringBuilder; + +final class RETokenEnd extends REToken +{ + /** + * Indicates whether this token should match on a line break. + */ + private String newline; + private boolean check_java_line_terminators; + + /** + * Indicates whether this token is a real one generated at compile time, + * or a fake one temporarily added by RE#getMatchImpl. + */ + private boolean fake = false; + + RETokenEnd (int subIndex, String newline) + { + super (subIndex); + this.newline = newline; + this.check_java_line_terminators = false; + } + + RETokenEnd (int subIndex, String newline, boolean b) + { + super (subIndex); + this.newline = newline; + this.check_java_line_terminators = b; + } + + void setFake (boolean fake) + { + this.fake = fake; + } + + int getMaximumLength () + { + return 0; + } + + boolean match (CharIndexed input, REMatch mymatch) + { + if (!fake) + return super.match (input, mymatch); + return super.matchFake (input, mymatch); + } + + REMatch matchThis (CharIndexed input, REMatch mymatch) + { + char ch = input.charAt (mymatch.index); + if (ch == CharIndexed.OUT_OF_BOUNDS) + return ((mymatch.eflags & RE.REG_NOTEOL) > 0) ? null : mymatch; + if (check_java_line_terminators) + { + if (ch == '\n') + { + char ch1 = input.charAt (mymatch.index - 1); + if (ch1 == '\r') + return null; + return mymatch; + } + if (ch == '\r') + return mymatch; + if (ch == '\u0085') + return mymatch; // A next-line character + if (ch == '\u2028') + return mymatch; // A line-separator character + if (ch == '\u2029') + return mymatch; // A paragraph-separator character + return null; + } + if (newline != null) + { + char z; + int i = 0; // position in newline + do + { + z = newline.charAt (i); + if (ch != z) + return null; + ++i; + ch = input.charAt (mymatch.index + i); + } + while (i < newline.length ()); + + return mymatch; + } + return null; + } + + boolean returnsFixedLengthMatches () + { + return true; + } + + int findFixedLengthMatches (CharIndexed input, REMatch mymatch, int max) + { + REMatch m = (REMatch) mymatch.clone (); + REToken tk = (REToken) this.clone (); + tk.chain (null); + if (tk.match (input, m)) + return max; + else + return 0; + } + + void dump (CPStringBuilder os) + { + os.append ('$'); + } +} diff --git a/libjava/classpath/gnu/java/util/regex/RETokenEndOfPreviousMatch.java b/libjava/classpath/gnu/java/util/regex/RETokenEndOfPreviousMatch.java new file mode 100644 index 000000000..67a1b852e --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/RETokenEndOfPreviousMatch.java @@ -0,0 +1,88 @@ +/* gnu/regexp/RETokenEndOfPreviousMatch.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.java.util.regex; + +import gnu.java.lang.CPStringBuilder; + +class RETokenEndOfPreviousMatch extends RETokenStart +{ + + RETokenEndOfPreviousMatch (int subIndex) + { + super (subIndex, null); + } + + int getMaximumLength () + { + return 0; + } + + REMatch matchThis (CharIndexed input, REMatch mymatch) + { + REMatch lastMatch = input.getLastMatch (); + if (lastMatch == null) + return super.matchThis (input, mymatch); + if (input.getAnchor () + mymatch.index == + lastMatch.anchor + lastMatch.index) + { + return mymatch; + } + else + { + return null; + } + } + + boolean returnsFixedLengthmatches () + { + return true; + } + + int findFixedLengthMatches (CharIndexed input, REMatch mymatch, int max) + { + if (matchThis (input, mymatch) != null) + return max; + else + return 0; + } + + void dump (CPStringBuilder os) + { + os.append ("\\G"); + } +} diff --git a/libjava/classpath/gnu/java/util/regex/RETokenEndSub.java b/libjava/classpath/gnu/java/util/regex/RETokenEndSub.java new file mode 100644 index 000000000..0848207f4 --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/RETokenEndSub.java @@ -0,0 +1,79 @@ +/* gnu/regexp/RETokenEndSub.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.java.util.regex; + +import gnu.java.lang.CPStringBuilder; + +final class RETokenEndSub extends REToken +{ + RETokenEndSub (int subIndex) + { + super (subIndex); + } + + int getMaximumLength () + { + return 0; + } + + REMatch matchThis (CharIndexed input, REMatch mymatch) + { + mymatch.start[subIndex] = mymatch.start1[subIndex]; + mymatch.end[subIndex] = mymatch.index; + return mymatch; + } + + REMatch findMatch (CharIndexed input, REMatch mymatch) + { + mymatch.start[subIndex] = mymatch.start1[subIndex]; + mymatch.end[subIndex] = mymatch.index; + return super.findMatch (input, mymatch); + } + + void setHitEnd (CharIndexed input, REMatch mymatch) + { + // Do nothing + } + + void dump (CPStringBuilder os) + { + // handled by RE + // But add something for debugging. + os.append ("(?#RETokenEndSub subIndex=" + subIndex + ")"); + } +} diff --git a/libjava/classpath/gnu/java/util/regex/RETokenIndependent.java b/libjava/classpath/gnu/java/util/regex/RETokenIndependent.java new file mode 100644 index 000000000..089aa18af --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/RETokenIndependent.java @@ -0,0 +1,85 @@ +/* gnu/regexp/RETokenIndependent.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.java.util.regex; + +import gnu.java.lang.CPStringBuilder; + +/** + * @author Ito Kazumitsu + */ +final class RETokenIndependent extends REToken +{ + REToken re; + + RETokenIndependent (REToken re) throws REException + { + super (0); + this.re = re; + } + + int getMinimumLength () + { + return re.getMinimumLength (); + } + + int getMaximumLength () + { + return re.getMaximumLength (); + } + + REMatch matchThis (CharIndexed input, REMatch mymatch) + { + boolean b = re.match (input, mymatch); + if (b) + { + // Once we have found a match, we do not see other possible matches. + if (mymatch.backtrackStack != null) + mymatch.backtrackStack.clear (); + return mymatch; + + } + return null; + } + + void dump (CPStringBuilder os) + { + os.append ("(?>"); + re.dumpAll (os); + os.append (')'); + } +} diff --git a/libjava/classpath/gnu/java/util/regex/RETokenLookAhead.java b/libjava/classpath/gnu/java/util/regex/RETokenLookAhead.java new file mode 100644 index 000000000..34625aac6 --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/RETokenLookAhead.java @@ -0,0 +1,88 @@ +/* gnu/regexp/RETokenLookAhead.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.java.util.regex; + +import gnu.java.lang.CPStringBuilder; + +/** + * @since gnu.regexp 1.1.3 + * @author Shashank Bapat + */ +final class RETokenLookAhead extends REToken +{ + REToken re; + boolean negative; + + RETokenLookAhead (REToken re, boolean negative) throws REException + { + super (0); + this.re = re; + this.negative = negative; + } + + int getMaximumLength () + { + return 0; + } + + REMatch matchThis (CharIndexed input, REMatch mymatch) + { + REMatch trymatch = (REMatch) mymatch.clone (); + if (re.match (input, trymatch)) + { + if (negative) + return null; + trymatch.index = mymatch.index; + return trymatch; + } + else + { + if (negative) + return mymatch; + return null; + } + } + + void dump (CPStringBuilder os) + { + os.append ("(?"); + os.append (negative ? '!' : '='); + re.dumpAll (os); + os.append (')'); + } +} diff --git a/libjava/classpath/gnu/java/util/regex/RETokenLookBehind.java b/libjava/classpath/gnu/java/util/regex/RETokenLookBehind.java new file mode 100644 index 000000000..c85e37f69 --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/RETokenLookBehind.java @@ -0,0 +1,136 @@ +/* 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.java.util.regex; + +import gnu.java.lang.CPStringBuilder; + +/** + * @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; + } + + REMatch matchThis (CharIndexed input, REMatch mymatch) + { + int max = re.getMaximumLength (); + CharIndexed behind = input.lookBehind (mymatch.index, max); + REMatch trymatch = (REMatch) mymatch.clone (); + int diff = behind.length () - input.length (); + int curIndex = trymatch.index + diff; + trymatch.index = 0; + trymatch.offset = 0; + RETokenMatchHereOnly stopper = new RETokenMatchHereOnly (curIndex); + REToken re1 = (REToken) re.clone (); + re1.chain (stopper); + if (re1.match (behind, trymatch)) + { + if (negative) + return null; + for (int i = 0; i < trymatch.start.length; i++) + { + if (trymatch.start[i] != -1 && trymatch.end[i] != -1) + { + trymatch.start[i] -= diff; + if (trymatch.start[i] < 0) + trymatch.start[i] -= 1; + trymatch.end[i] -= diff; + if (trymatch.end[i] < 0) + trymatch.end[i] -= 1; + } + } + trymatch.index = mymatch.index; + trymatch.offset = mymatch.offset; + return trymatch; + } + else + { + if (negative) + return mymatch; + return null; + } + } + + void dump (CPStringBuilder 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; + } + + REMatch matchThis (CharIndexed input, REMatch mymatch) + { + return (index == mymatch.index ? mymatch : null); + } + + void dump (CPStringBuilder os) + { + } + + } +} diff --git a/libjava/classpath/gnu/java/util/regex/RETokenNamedProperty.java b/libjava/classpath/gnu/java/util/regex/RETokenNamedProperty.java new file mode 100644 index 000000000..340da03fb --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/RETokenNamedProperty.java @@ -0,0 +1,410 @@ +/* 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.java.util.regex; + +import gnu.java.lang.CPStringBuilder; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +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; + } + + REMatch matchThis (CharIndexed input, REMatch mymatch) + { + char ch = input.charAt (mymatch.index); + boolean retval = matchOneChar (ch); + if (retval) + { + ++mymatch.index; + return mymatch; + } + return null; + } + + private boolean matchOneChar (char ch) + { + if (ch == CharIndexed.OUT_OF_BOUNDS) + return false; + + boolean retval = handler.includes (ch); + if (insens) + { + retval = retval || + handler.includes (toUpperCase (ch, unicodeAware)) || + handler.includes (toLowerCase (ch, unicodeAware)); + } + + if (negate) + retval = !retval; + return retval; + } + + boolean returnsFixedLengthMatches () + { + return true; + } + + int findFixedLengthMatches (CharIndexed input, REMatch mymatch, int max) + { + int index = mymatch.index; + int numRepeats = 0; + while (true) + { + if (numRepeats >= max) + break; + char ch = input.charAt (index++); + if (!matchOneChar (ch)) + break; + numRepeats++; + } + return numRepeats; + } + + void dump (CPStringBuilder 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); + if (name.equals ("all")) + return new Handler () + { + public boolean includes (char c) + { + return true; + } + }; + if (name.startsWith ("java")) + { + try + { + Method m = Character.class.getMethod ("is" + name.substring (4), + Character.TYPE); + return new JavaCategoryHandler (m); + } + catch (NoSuchMethodException e) + { + throw new REException ("Unsupported Java handler: " + name, e, + REException.REG_ESCAPE, 0); + } + } + throw new REException ("unsupported name " + name, REException.REG_ESCAPE, + 0); + } + + private static class POSIXHandler extends Handler + { + private RETokenPOSIX retoken; + 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) + { + return retoken.matchOneChar (c); + } + } + + 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)); + } + } + + /** + * Handle the Java-specific extensions \p{javaX} where X + * is a method from Character of the form isX + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ + private static class JavaCategoryHandler extends Handler + { + private Method method; + + public JavaCategoryHandler (Method m) + { + this.method = m; + } + + public boolean includes (char c) + { + try + { + return (Boolean) method.invoke (null, c); + } + catch (IllegalAccessException e) + { + throw new InternalError ("Unable to access method " + method); + } + catch (InvocationTargetException e) + { + throw new InternalError ("Error invoking " + method); + } + } + } + +} diff --git a/libjava/classpath/gnu/java/util/regex/RETokenOneOf.java b/libjava/classpath/gnu/java/util/regex/RETokenOneOf.java new file mode 100644 index 000000000..3bea889ec --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/RETokenOneOf.java @@ -0,0 +1,332 @@ +/* gnu/regexp/RETokenOneOf.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.java.util.regex; + +import gnu.java.lang.CPStringBuilder; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Deque; +import java.util.List; + +final class RETokenOneOf extends REToken +{ + private final List < REToken > options; + private boolean negative; + // True if this RETokenOneOf is supposed to match only one character, + // which is typically the case of a character class expression. + private boolean matchesOneChar; + + private final List < Object > addition; + // This ArrayList 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 ArrayList options, and + // the additional part /[f-k][m-z]&&[^p-v][st]/ is stored in the + // ArrayList 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 ArrayList 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, ..) + + RETokenOneOf (int subIndex, String optionsStr, boolean negative, + boolean insens) + { + super (subIndex); + options = new ArrayList < REToken > (); + this.negative = negative; + for (int i = 0; i < optionsStr.length (); i++) + options.add (new RETokenChar (subIndex, optionsStr.charAt (i), insens)); + matchesOneChar = true; + addition = null; + } + + RETokenOneOf (int subIndex, List < REToken > options, boolean negative) + { + this (subIndex, options, null, negative); + } + + RETokenOneOf (int subIndex, List < REToken > options, + List < Object > addition, boolean negative) + { + super (subIndex); + this.options = options; + this.addition = addition; + this.negative = negative; + matchesOneChar = (negative || addition != null); + } + + int getMinimumLength () + { + if (matchesOneChar) + return 1; + int min = Integer.MAX_VALUE; + int x; + for (REToken t:options) + { + if ((x = t.getMinimumLength ()) < min) + min = x; + } + return min; + } + + int getMaximumLength () + { + if (matchesOneChar) + return 1; + int max = 0; + int x; + for (REToken t:options) + { + if ((x = t.getMaximumLength ()) > max) + max = x; + } + return max; + } + + boolean match (CharIndexed input, REMatch mymatch) + { + setHitEnd (input, mymatch); + if (matchesOneChar) + return matchOneChar (input, mymatch); + else + return matchOneRE (input, mymatch); + } + + boolean matchOneChar (CharIndexed input, REMatch mymatch) + { + 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; + + final Deque < Boolean > stack = new ArrayDeque < Boolean > (); + stack.push (new Boolean (b)); + for (Object obj:addition) + { + if (obj instanceof REToken) + { + b = ((REToken) obj).match (input, (REMatch) mymatch.clone ()); + stack.push (new Boolean (b)); + } + else if (obj instanceof Boolean) + { + stack.push ((Boolean) obj); + } + else if (obj.equals ("|")) + { + b = stack.pop (); + b = stack.pop () || b; + stack.push (new Boolean (b)); + } + else if (obj.equals ("&")) + { + b = stack.pop (); + b = stack.pop () && b; + stack.push (new Boolean (b)); + } + else + { + throw new RuntimeException ("Invalid object found"); + } + } + if (stack.pop ()) + { + ++mymatch.index; + return next (input, mymatch); + } + return false; + } + + private boolean matchN (CharIndexed input, REMatch mymatch, boolean tryOnly) + { + if (input.charAt (mymatch.index) == CharIndexed.OUT_OF_BOUNDS) + return false; + + for (REToken tk:options) + { + REMatch tryMatch = (REMatch) mymatch.clone (); + if (tk.match (input, tryMatch)) + { // match was successful + return false; + } // is a match + } // try next option + + if (tryOnly) + return true; + ++mymatch.index; + return next (input, mymatch); + } + + private boolean matchP (CharIndexed input, REMatch mymatch, boolean tryOnly) + { + for (REToken tk:options) + { + REMatch tryMatch = (REMatch) mymatch.clone (); + if (tk.match (input, tryMatch)) + { // match was successful + if (tryOnly) + return true; + if (next (input, tryMatch)) + { + mymatch.assignFrom (tryMatch); + return true; + } + } + } + return false; + } + + private boolean matchOneRE (CharIndexed input, REMatch mymatch) + { + REMatch newMatch = findMatch (input, mymatch); + if (newMatch != null) + { + mymatch.assignFrom (newMatch); + return true; + } + return false; + } + + REMatch findMatch (CharIndexed input, REMatch mymatch) + { + if (matchesOneChar) + return super.findMatch (input, mymatch); + return findMatch (input, mymatch, 0); + } + + REMatch backtrack (CharIndexed input, REMatch mymatch, Object param) + { + return findMatch (input, mymatch, ((Integer) param).intValue ()); + } + + private REMatch findMatch (CharIndexed input, REMatch mymatch, + int optionIndex) + { + for (int i = optionIndex; i < options.size (); i++) + { + REToken tk = options.get (i); + tk = (REToken) tk.clone (); + tk.chain (getNext ()); + REMatch tryMatch = (REMatch) mymatch.clone (); + if (tryMatch.backtrackStack == null) + { + tryMatch.backtrackStack = new BacktrackStack (); + } + boolean stackPushed = false; + if (i + 1 < options.size ()) + { + tryMatch.backtrackStack.push (new BacktrackStack. + Backtrack (this, input, mymatch, + i + 1)); + stackPushed = true; + } + if (tk.match (input, tryMatch)) + { + return tryMatch; + } + if (stackPushed) + tryMatch.backtrackStack.pop (); + } + return null; + } + + boolean returnsFixedLengthMatches () + { + return matchesOneChar; + } + + int findFixedLengthMatches (CharIndexed input, REMatch mymatch, int max) + { + if (!matchesOneChar) + return super.findFixedLengthMatches (input, mymatch, max); + int numRepeats = 0; + REMatch m = (REMatch) mymatch.clone (); + REToken tk = (REToken) this.clone (); + tk.chain (null); + while (true) + { + if (numRepeats >= max) + break; + m = tk.findMatch (input, m); + if (m == null) + break; + numRepeats++; + } + return numRepeats; + } + + void dump (CPStringBuilder os) + { + os.append (negative ? "[^" : "(?:"); + for (int i = 0; i < options.size (); i++) + { + if (!negative && (i > 0)) + os.append ('|'); + options.get (i).dumpAll (os); + } + os.append (negative ? ']' : ')'); + } +} diff --git a/libjava/classpath/gnu/java/util/regex/RETokenPOSIX.java b/libjava/classpath/gnu/java/util/regex/RETokenPOSIX.java new file mode 100644 index 000000000..f0fd04bd3 --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/RETokenPOSIX.java @@ -0,0 +1,195 @@ +/* gnu/regexp/RETokenPOSIX.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.java.util.regex; + +import gnu.java.lang.CPStringBuilder; + +final class RETokenPOSIX extends REToken +{ + int type; + boolean insens; + boolean negated; + + static final int ALNUM = 0; + static final int ALPHA = 1; + static final int BLANK = 2; + static final int CNTRL = 3; + static final int DIGIT = 4; + static final int GRAPH = 5; + static final int LOWER = 6; + static final int PRINT = 7; + static final int PUNCT = 8; + static final int SPACE = 9; + static final int UPPER = 10; + static final int XDIGIT = 11; + + // Array indices correspond to constants defined above. + static final String[] s_nameTable = { + "alnum", "alpha", "blank", "cntrl", "digit", "graph", "lower", + "print", "punct", "space", "upper", "xdigit" + }; + + // The RE constructor uses this to look up the constant for a string + static int intValue (String key) + { + for (int i = 0; i < s_nameTable.length; i++) + { + if (s_nameTable[i].equals (key)) + return i; + } + return -1; + } + + RETokenPOSIX (int subIndex, int type, boolean insens, boolean negated) + { + super (subIndex); + this.type = type; + this.insens = insens; + this.negated = negated; + } + + int getMinimumLength () + { + return 1; + } + + int getMaximumLength () + { + return 1; + } + + REMatch matchThis (CharIndexed input, REMatch mymatch) + { + char ch = input.charAt (mymatch.index); + boolean retval = matchOneChar (ch); + if (retval) + { + ++mymatch.index; + return mymatch; + } + return null; + } + + boolean matchOneChar (char ch) + { + if (ch == CharIndexed.OUT_OF_BOUNDS) + return false; + + boolean retval = false; + switch (type) + { + case ALNUM: + // Note that there is some debate over whether '_' should be included + retval = Character.isLetterOrDigit (ch) || (ch == '_'); + break; + case ALPHA: + retval = Character.isLetter (ch); + break; + case BLANK: + retval = ((ch == ' ') || (ch == '\t')); + break; + case CNTRL: + retval = Character.isISOControl (ch); + break; + case DIGIT: + retval = Character.isDigit (ch); + break; + case GRAPH: + retval = + (!(Character.isWhitespace (ch) || Character.isISOControl (ch))); + break; + case LOWER: + retval = ((insens && Character.isLetter (ch)) + || Character.isLowerCase (ch)); + break; + case PRINT: + retval = + (!(Character.isWhitespace (ch) || Character.isISOControl (ch))) + || (ch == ' '); + break; + case PUNCT: + // This feels sloppy, especially for non-U.S. locales. + retval = ("`~!@#$%^&*()-_=+[]{}\\|;:'\"/?,.<>".indexOf (ch) != -1); + break; + case SPACE: + retval = Character.isWhitespace (ch); + break; + case UPPER: + retval = ((insens && Character.isLetter (ch)) + || Character.isUpperCase (ch)); + break; + case XDIGIT: + retval = (Character.isDigit (ch) + || ("abcdefABCDEF".indexOf (ch) != -1)); + break; + } + + if (negated) + retval = !retval; + return retval; + } + + boolean returnsFixedLengthMatches () + { + return true; + } + + int findFixedLengthMatches (CharIndexed input, REMatch mymatch, int max) + { + int index = mymatch.index; + int numRepeats = 0; + while (true) + { + if (numRepeats >= max) + break; + char ch = input.charAt (index++); + if (!matchOneChar (ch)) + break; + numRepeats++; + } + return numRepeats; + } + + void dump (CPStringBuilder os) + { + if (negated) + os.append ('^'); + os.append ("[:" + s_nameTable[type] + ":]"); + } +} diff --git a/libjava/classpath/gnu/java/util/regex/RETokenRange.java b/libjava/classpath/gnu/java/util/regex/RETokenRange.java new file mode 100644 index 000000000..8898ef502 --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/RETokenRange.java @@ -0,0 +1,119 @@ +/* gnu/regexp/RETokenRange.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.java.util.regex; + +import gnu.java.lang.CPStringBuilder; + +final class RETokenRange extends REToken +{ + private char lo, hi; + private boolean insens; + + RETokenRange (int subIndex, char lo, char hi, boolean ins) + { + super (subIndex); + insens = ins; + this.lo = lo; + this.hi = hi; + } + + int getMinimumLength () + { + return 1; + } + + int getMaximumLength () + { + return 1; + } + + REMatch matchThis (CharIndexed input, REMatch mymatch) + { + char c = input.charAt (mymatch.index); + if (matchOneChar (c)) + { + ++mymatch.index; + return mymatch; + } + return null; + } + + boolean matchOneChar (char c) + { + if (c == CharIndexed.OUT_OF_BOUNDS) + return false; + boolean matches = (c >= lo) && (c <= hi); + if (!matches && insens) + { + char c1 = toLowerCase (c, unicodeAware); + matches = (c1 >= lo) && (c1 <= hi); + if (!matches) + { + c1 = toUpperCase (c, unicodeAware); + matches = (c1 >= lo) && (c1 <= hi); + } + } + return matches; + } + + boolean returnsFixedLengthMatches () + { + return true; + } + + int findFixedLengthMatches (CharIndexed input, REMatch mymatch, int max) + { + int index = mymatch.index; + int numRepeats = 0; + while (true) + { + if (numRepeats >= max) + break; + char ch = input.charAt (index++); + if (!matchOneChar (ch)) + break; + numRepeats++; + } + return numRepeats; + } + + void dump (CPStringBuilder os) + { + os.append (lo).append ('-').append (hi); + } +} diff --git a/libjava/classpath/gnu/java/util/regex/RETokenRepeated.java b/libjava/classpath/gnu/java/util/regex/RETokenRepeated.java new file mode 100644 index 000000000..cd8635396 --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/RETokenRepeated.java @@ -0,0 +1,639 @@ +/* gnu/regexp/RETokenRepeated.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.java.util.regex; + +import gnu.java.lang.CPStringBuilder; + +import java.util.ArrayDeque; +import java.util.Deque; + +final class RETokenRepeated extends REToken +{ + private REToken token; + private int min, max; + private boolean stingy; + private boolean possessive; + private int tokenFixedLength; + + RETokenRepeated (int subIndex, REToken token, int min, int max) + { + super (subIndex); + this.token = token; + this.min = min; + this.max = max; + if (token.returnsFixedLengthMatches ()) + { + tokenFixedLength = token.getMaximumLength (); + } + else + { + tokenFixedLength = -1; + } + } + + /** Sets the minimal matching mode to true. */ + void makeStingy () + { + stingy = true; + } + + /** Queries if this token has minimal matching enabled. */ + boolean isStingy () + { + return stingy; + } + + /** Sets possessive matching mode to true. */ + void makePossessive () + { + possessive = true; + } + + /** Queries if this token has possessive matching enabled. */ + boolean isPossessive () + { + return possessive; + } + + /** + * The minimum length of a repeated token is the minimum length + * of the token multiplied by the minimum number of times it must + * match. + */ + int getMinimumLength () + { + 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); + } + + // The comment "MUST make a clone" below means that some tests + // failed without doing clone(), + + private static class DoablesFinder + { + private REToken tk; + private CharIndexed input; + private REMatch rematch; + private boolean findFirst; + + private DoablesFinder (REToken tk, CharIndexed input, REMatch mymatch) + { + this.tk = tk; + this.input = input; + this.rematch = (REMatch) mymatch.clone (); // MUST make a clone + this.rematch.backtrackStack = new BacktrackStack (); + findFirst = true; + } + + private REMatch find () + { + int origin = rematch.index; + REMatch rem; + if (findFirst) + { + rem = tk.findMatch (input, rematch); + findFirst = false; + } + else + { + while (true) + { + if (rematch.backtrackStack.empty ()) + { + rem = null; + break; + } + BacktrackStack.Backtrack bt = rematch.backtrackStack.pop (); + rem = bt.token.backtrack (bt.input, bt.match, bt.param); + if (rem != null) + break; + } + } + if (rem == null) + return null; + if (rem.index == origin) + rem.empty = true; + rematch = rem; + return (REMatch) rem.clone (); // MUST make a clone. + } + + boolean noMore () + { + return rematch.backtrackStack.empty (); + } + } + + REMatch findMatch (CharIndexed input, REMatch mymatch) + { + if (tokenFixedLength >= 0) + return findMatchFixedLength (input, mymatch); + BacktrackStack stack = new BacktrackStack (); + stack.push (new StackedInfo (input, 0, mymatch, null, null)); + return findMatch (stack); + } + + REMatch backtrack (CharIndexed input, REMatch mymatch, Object param) + { + if (tokenFixedLength >= 0) + return backtrackFixedLength (input, mymatch, param); + return findMatch ((BacktrackStack) param); + } + + private static class StackedInfo extends BacktrackStack.Backtrack + { + int numRepeats; + int[] visited; + DoablesFinder finder; + StackedInfo (CharIndexed input, int numRepeats, REMatch match, + int[]visited, DoablesFinder finder) + { + super (null, input, match, null); + this.numRepeats = numRepeats; + this.visited = visited; + this.finder = finder; + } + } + + private static class FindMatchControl + { + DoablesFinder finder; + FindMatchControl (DoablesFinder finder) + { + this.finder = finder; + } + } + + private REMatch findMatch (BacktrackStack stack) + { + return findMatch (stack, new ArrayDeque < FindMatchControl > ()); + } + + private REMatch findMatch (BacktrackStack stack, + Deque < FindMatchControl > controlStack) + { + REMatch result = null; + StackedInfo si = null; + CharIndexed input = null; + int numRepeats = 0; + REMatch mymatch = null; + int[] visited = null; + DoablesFinder finder = null; + + // Avoid using recursive calls because a match can be very long. + + // This is the first entry point of this method. + // If you want to call this method recursively and you need the + // result returned, save necessary information in a FindMatchControl + // object and push it to controlStack, then continue from this point. + // You can check the result after exiting MAIN_LOOP. + MAIN_LOOP0: + while (true) + { + + // This is the second entry point of this method. + // If you want to call this method recursively but you do not need the + // result returned, just continue from this point. + MAIN_LOOP: + while (true) + { + + if (stack.empty ()) + break MAIN_LOOP; + si = (StackedInfo) (stack.peek ()); + input = si.input; + numRepeats = si.numRepeats; + mymatch = si.match; + visited = si.visited; + finder = si.finder; + + if (mymatch.backtrackStack == null) + mymatch.backtrackStack = new BacktrackStack (); + + if (numRepeats >= max) + { + stack.pop (); + REMatch m1 = matchRest (input, mymatch); + if (m1 != null) + { + if (!stack.empty ()) + { + m1.backtrackStack.push (new BacktrackStack. + Backtrack (this, input, + mymatch, stack)); + } + result = m1; + break MAIN_LOOP; + } + if (stingy) + { + continue MAIN_LOOP; + } + break MAIN_LOOP; + } + + if (finder == null) + { + finder = new DoablesFinder (token, input, mymatch); + si.finder = finder; + } + + if (numRepeats < min) + { + while (true) + { + REMatch doable = finder.find (); + if (doable == null) + { + if (stack.empty ()) + return null; + stack.pop (); + continue MAIN_LOOP; + } + if (finder.noMore ()) + stack.pop (); + int newNumRepeats = (doable.empty ? min : numRepeats + 1); + stack. + push (new + StackedInfo (input, newNumRepeats, doable, + visited, null)); + continue MAIN_LOOP; + } + } + + if (visited == null) + visited = initVisited (); + + if (stingy) + { + REMatch nextMatch = finder.find (); + if (nextMatch != null && !nextMatch.empty) + { + stack. + push (new + StackedInfo (input, numRepeats + 1, nextMatch, + visited, null)); + } + else + { + stack.pop (); + } + REMatch m1 = matchRest (input, mymatch); + if (m1 != null) + { + if (!stack.empty ()) + { + m1.backtrackStack.push (new BacktrackStack. + Backtrack (this, input, + mymatch, stack)); + } + result = m1; + break MAIN_LOOP; + } + else + { + continue MAIN_LOOP; + } + } + + visited = addVisited (mymatch.index, visited); + + TryAnotherResult taresult = + tryAnother (stack, input, mymatch, numRepeats, finder, visited); + visited = taresult.visited; + switch (taresult.status) + { + case TryAnotherResult.TRY_FURTHER: + controlStack.push (new FindMatchControl (finder)); + continue MAIN_LOOP0; + case TryAnotherResult.RESULT_FOUND: + result = taresult.result; + break MAIN_LOOP; + } + + if (!stack.empty ()) + { + stack.pop (); + } + if (possessive) + { + stack.clear (); + } + REMatch m1 = matchRest (input, mymatch); + if (m1 != null) + { + if (!stack.empty ()) + { + m1.backtrackStack.push (new BacktrackStack. + Backtrack (this, input, mymatch, + stack)); + } + result = m1; + break MAIN_LOOP; + } + + } // MAIN_LOOP + + if (controlStack.isEmpty ()) + return result; + FindMatchControl control = controlStack.pop (); + if (possessive) + { + return result; + } + if (result != null) + { + result.backtrackStack.push (new BacktrackStack. + Backtrack (this, input, mymatch, + stack)); + return result; + } + + finder = control.finder; + + TryAnotherResult taresult = + tryAnother (stack, input, mymatch, numRepeats, finder, visited); + visited = taresult.visited; + switch (taresult.status) + { + case TryAnotherResult.TRY_FURTHER: + controlStack.push (new FindMatchControl (finder)); + continue MAIN_LOOP0; + case TryAnotherResult.RESULT_FOUND: + return taresult.result; + } + continue MAIN_LOOP0; + + } // MAIN_LOOP0 + } + + private static class TryAnotherResult + { + REMatch result; + int status; + static final int RESULT_FOUND = 1; + static final int TRY_FURTHER = 2; + static final int NOTHING_FOUND = 3; + int[] visited; + } + + private TryAnotherResult tryAnother (BacktrackStack stack, + CharIndexed input, REMatch mymatch, + int numRepeats, DoablesFinder finder, + int[]visited) + { + + TryAnotherResult taresult = new TryAnotherResult (); + taresult.visited = visited; + + DO_THIS: + { + + boolean emptyMatchFound = false; + + DO_ONE_DOABLE: + while (true) + { + + REMatch doable = finder.find (); + if (doable == null) + { + break DO_THIS; + } + if (doable.empty) + emptyMatchFound = true; + + if (!emptyMatchFound) + { + int n = doable.index; + if (visitedContains (n, visited)) + { + continue DO_ONE_DOABLE; + } + visited = addVisited (n, visited); + stack. + push (new + StackedInfo (input, numRepeats + 1, doable, visited, + null)); + taresult.visited = visited; + taresult.status = TryAnotherResult.TRY_FURTHER; + return taresult; + } + else + { + REMatch m1 = matchRest (input, doable); + if (possessive) + { + taresult.result = m1; + taresult.status = TryAnotherResult.RESULT_FOUND; + return taresult; + } + if (m1 != null) + { + if (!stack.empty ()) + { + m1.backtrackStack.push (new BacktrackStack. + Backtrack (this, input, mymatch, + stack)); + } + taresult.result = m1; + taresult.status = TryAnotherResult.RESULT_FOUND; + return taresult; + } + } + + } // DO_ONE_DOABLE + + } // DO_THIS + + taresult.status = TryAnotherResult.NOTHING_FOUND; + return taresult; + + } + + boolean match (CharIndexed input, REMatch mymatch) + { + setHitEnd (input, mymatch); + REMatch m1 = findMatch (input, mymatch); + if (m1 != null) + { + mymatch.assignFrom (m1); + return true; + } + return false; + } + + // 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 matchRest (CharIndexed input, final REMatch newMatch) + { + if (next (input, newMatch)) + { + return newMatch; + } + return null; + } + + private REMatch findMatchFixedLength (CharIndexed input, REMatch mymatch) + { + if (mymatch.backtrackStack == null) + mymatch.backtrackStack = new BacktrackStack (); + int numRepeats = + token.findFixedLengthMatches (input, (REMatch) mymatch.clone (), max); + if (numRepeats == Integer.MAX_VALUE) + numRepeats = min; + int count = numRepeats - min + 1; + if (count <= 0) + return null; + int index = 0; + if (!stingy) + index = mymatch.index + (tokenFixedLength * numRepeats); + else + index = mymatch.index + (tokenFixedLength * min); + return findMatchFixedLength (input, mymatch, index, count); + } + + private REMatch backtrackFixedLength (CharIndexed input, REMatch mymatch, + Object param) + { + int[] params = (int[]) param; + int index = params[0]; + int count = params[1]; + return findMatchFixedLength (input, mymatch, index, count); + } + + private REMatch findMatchFixedLength (CharIndexed input, REMatch mymatch, + int index, int count) + { + REMatch tryMatch = (REMatch) mymatch.clone (); + while (true) + { + tryMatch.index = index; + REMatch m = matchRest (input, tryMatch); + count--; + if (stingy) + index += tokenFixedLength; + else + index -= tokenFixedLength; + if (possessive) + return m; + if (m != null) + { + if (count > 0) + { + m.backtrackStack.push (new BacktrackStack. + Backtrack (this, input, mymatch, + new int[] + { + index, count})); + } + return m; + } + if (count <= 0) + return null; + } + } + + void dump (CPStringBuilder os) + { + os.append ("(?:"); + token.dumpAll (os); + os.append (')'); + if ((max == Integer.MAX_VALUE) && (min <= 1)) + os.append ((min == 0) ? '*' : '+'); + else if ((min == 0) && (max == 1)) + os.append ('?'); + else + { + os.append ('{').append (min); + if (max > min) + { + os.append (','); + if (max != Integer.MAX_VALUE) + os.append (max); + } + os.append ('}'); + } + if (stingy) + os.append ('?'); + } +} diff --git a/libjava/classpath/gnu/java/util/regex/RETokenStart.java b/libjava/classpath/gnu/java/util/regex/RETokenStart.java new file mode 100644 index 000000000..c57ba9c75 --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/RETokenStart.java @@ -0,0 +1,153 @@ +/* gnu/regexp/RETokenStart.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.java.util.regex; + +import gnu.java.lang.CPStringBuilder; + +class RETokenStart extends REToken +{ + private String newline; // matches after a newline + private boolean check_java_line_terminators; + + RETokenStart (int subIndex, String newline) + { + super (subIndex); + this.newline = newline; + this.check_java_line_terminators = false; + } + + RETokenStart (int subIndex, String newline, boolean b) + { + super (subIndex); + this.newline = newline; + this.check_java_line_terminators = b; + } + + @Override + int getMaximumLength () + { + return 0; + } + + @Override + REMatch matchThis (CharIndexed input, REMatch mymatch) + { + // charAt(index-n) may be unknown on a Reader/InputStream. FIXME + // Match after a newline if in multiline mode + + if (check_java_line_terminators) + { + char ch = input.charAt (mymatch.index - 1); + if (ch != CharIndexed.OUT_OF_BOUNDS) + { + if (ch == '\n') + return mymatch; + if (ch == '\r') + { + char ch1 = input.charAt (mymatch.index); + if (ch1 != '\n') + return mymatch; + return null; + } + if (ch == '\u0085') + return mymatch; // A next-line character + if (ch == '\u2028') + return mymatch; // A line-separator character + if (ch == '\u2029') + return mymatch; // A paragraph-separator character + } + } + + if (newline != null) + { + int len = newline.length (); + if (mymatch.offset >= len) + { + boolean found = true; + char z; + int i = 0; // position in REToken.newline + char ch = input.charAt (mymatch.index - len); + do + { + z = newline.charAt (i); + if (ch != z) + { + found = false; + break; + } + ++i; + ch = input.charAt (mymatch.index - len + i); + } + while (i < len); + + if (found) + return mymatch; + } + } + + // Don't match at all if REG_NOTBOL is set. + if ((mymatch.eflags & RE.REG_NOTBOL) > 0) + return null; + + if ((mymatch.eflags & RE.REG_ANCHORINDEX) > 0) + return (mymatch.anchor == mymatch.offset) ? mymatch : null; + else + return ((mymatch.index == 0) && (mymatch.offset == 0)) ? mymatch : null; + } + + @Override + boolean returnsFixedLengthMatches () + { + return true; + } + + @Override + int findFixedLengthMatches (CharIndexed input, REMatch mymatch, int max) + { + if (matchThis (input, mymatch) != null) + return max; + else + return 0; + } + + @Override + void dump (CPStringBuilder os) + { + os.append ('^'); + } +} diff --git a/libjava/classpath/gnu/java/util/regex/RETokenWordBoundary.java b/libjava/classpath/gnu/java/util/regex/RETokenWordBoundary.java new file mode 100644 index 000000000..04fd8391f --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/RETokenWordBoundary.java @@ -0,0 +1,141 @@ +/* gnu/regexp/RETokenWordBoundary.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.java.util.regex; + +import gnu.java.lang.CPStringBuilder; + +/** + * Represents a combination lookahead/lookbehind for POSIX [:alnum:]. + */ +final class RETokenWordBoundary extends REToken +{ + private boolean negated; + private int where; + static final int BEGIN = 1; + static final int END = 2; + + RETokenWordBoundary (int subIndex, int where, boolean negated) + { + super (subIndex); + this.where = where; + this.negated = negated; + } + + int getMaximumLength () + { + return 0; + } + + + REMatch matchThis (CharIndexed input, REMatch mymatch) + { + // Word boundary means input[index-1] was a word character + // and input[index] is not, or input[index] is a word character + // and input[index-1] was not + // In the string "one two three", these positions match: + // |o|n|e| |t|w|o| |t|h|r|e|e| + // ^ ^ ^ ^ ^ ^ + boolean after = false; // is current character a letter or digit? + boolean before = false; // is previous character a letter or digit? + char ch; + + // TODO: Also check REG_ANCHORINDEX vs. anchor + if (((mymatch.eflags & RE.REG_ANCHORINDEX) != RE.REG_ANCHORINDEX) + || (mymatch.offset + mymatch.index > mymatch.anchor)) + { + if ((ch = + input.charAt (mymatch.index - 1)) != CharIndexed.OUT_OF_BOUNDS) + { + before = Character.isLetterOrDigit (ch) || (ch == '_'); + } + } + + if ((ch = input.charAt (mymatch.index)) != CharIndexed.OUT_OF_BOUNDS) + { + after = Character.isLetterOrDigit (ch) || (ch == '_'); + } + + // if (before) and (!after), we're at end (\>) + // if (after) and (!before), we're at beginning (\<) + boolean doNext = false; + + if ((where & BEGIN) == BEGIN) + { + doNext = after && !before; + } + if ((where & END) == END) + { + doNext ^= before && !after; + } + + if (negated) + doNext = !doNext; + + return (doNext ? mymatch : null); + } + + boolean returnsFixedLengthMatches () + { + return true; + } + + int findFixedLengthMatches (CharIndexed input, REMatch mymatch, int max) + { + if (matchThis (input, mymatch) != null) + return max; + else + return 0; + } + + void dump (CPStringBuilder os) + { + if (where == (BEGIN | END)) + { + os.append (negated ? "\\B" : "\\b"); + } + else if (where == BEGIN) + { + os.append ("\\<"); + } + else + { + os.append ("\\>"); + } + } +} diff --git a/libjava/classpath/gnu/java/util/regex/UncheckedRE.java b/libjava/classpath/gnu/java/util/regex/UncheckedRE.java new file mode 100644 index 000000000..7d215a6c1 --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/UncheckedRE.java @@ -0,0 +1,114 @@ +/* gnu/regexp/UncheckedRE.java + Copyright (C) 2001, 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.util.regex; + +/** + * UncheckedRE is a subclass of RE that allows programmers an easier means + * of programmatically precompiling regular expressions. It is constructed + * and used in exactly the same manner as an instance of the RE class; the + * only difference is that its constructors do not throw REException. + * Instead, if a syntax error is encountered during construction, a + * RuntimeException will be thrown. + *

    + * Note that this makes UncheckedRE dangerous if constructed with + * dynamic data. Do not use UncheckedRE unless you are completely sure + * that all input being passed to it contains valid, well-formed + * regular expressions for the syntax specified. + * + * @author Wes Biggs + * @see gnu.java.util.regex.RE + * @since gnu.regexp 1.1.4 + */ + +public final class UncheckedRE extends RE +{ + /** + * Constructs a regular expression pattern buffer without any compilation + * flags set, and using the default syntax (RESyntax.RE_SYNTAX_PERL5). + * + * @param pattern A regular expression pattern, in the form of a String, + * StringBuffer or char[]. Other input types will be converted to + * strings using the toString() method. + * @exception RuntimeException The input pattern could not be parsed. + * @exception NullPointerException The pattern was null. + */ + public UncheckedRE (Object pattern) + { + this (pattern, 0, RESyntax.RE_SYNTAX_PERL5); + } + + /** + * Constructs a regular expression pattern buffer using the specified + * compilation flags and the default syntax (RESyntax.RE_SYNTAX_PERL5). + * + * @param pattern A regular expression pattern, in the form of a String, + * StringBuffer, or char[]. Other input types will be converted to + * strings using the toString() method. + * @param cflags The logical OR of any combination of the compilation flags in the RE class. + * @exception RuntimeException The input pattern could not be parsed. + * @exception NullPointerException The pattern was null. + */ + public UncheckedRE (Object pattern, int cflags) + { + this (pattern, cflags, RESyntax.RE_SYNTAX_PERL5); + } + + /** + * Constructs a regular expression pattern buffer using the specified + * compilation flags and regular expression syntax. + * + * @param pattern A regular expression pattern, in the form of a String, + * StringBuffer, or char[]. Other input types will be converted to + * strings using the toString() method. + * @param cflags The logical OR of any combination of the compilation flags in the RE class. + * @param syntax The type of regular expression syntax to use. + * @exception RuntimeException The input pattern could not be parsed. + * @exception NullPointerException The pattern was null. + */ + public UncheckedRE (Object pattern, int cflags, RESyntax syntax) + { + try + { + initialize (pattern, cflags, syntax, 0, 0); + } + catch (REException e) + { + throw new RuntimeException (e.getMessage ()); + } + } +} diff --git a/libjava/classpath/gnu/javax/activation/viewers/ImageViewer.java b/libjava/classpath/gnu/javax/activation/viewers/ImageViewer.java new file mode 100644 index 000000000..5bddf7311 --- /dev/null +++ b/libjava/classpath/gnu/javax/activation/viewers/ImageViewer.java @@ -0,0 +1,138 @@ +/* ImageViewer.java -- Simple image display component. + 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.javax.activation.viewers; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Image; +import java.awt.Graphics; +import java.awt.MediaTracker; +import java.awt.Toolkit; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.IOException; + +import javax.activation.CommandObject; +import javax.activation.DataHandler; + +/** + * Simple image display component. + * + * @author Chris Burdess + * @version 1.0.2 + */ +public class ImageViewer extends Component + implements CommandObject +{ + + private Image image; + + /** + * Returns the preferred size for this component (the image size). + */ + public Dimension getPreferredSize() + { + Dimension ps = new Dimension(0, 0); + if (image != null) + { + ps.width = image.getWidth(this); + ps.height = image.getHeight(this); + } + return ps; + } + + public void setCommandContext(String verb, DataHandler dh) + throws IOException + { + // Read image into a byte array + InputStream in = dh.getInputStream(); + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + byte[] buf = new byte[4096]; + for (int len = in.read(buf); len != -1; len = in.read(buf)) + bytes.write(buf, 0, len); + in.close(); + // Create and prepare the image + Toolkit toolkit = getToolkit(); + Image img = toolkit.createImage(bytes.toByteArray()); + try + { + MediaTracker tracker = new MediaTracker(this); + tracker.addImage(img, 0); + tracker.waitForID(0); + } + catch (InterruptedException e) + { + } + toolkit.prepareImage(img, -1, -1, this); + } + + /** + * Image bits arrive. + */ + public boolean imageUpdate(Image image, int flags, int x, int y, + int width, int height) + { + if ((flags & ALLBITS) != 0) + { + this.image = image; + invalidate(); + repaint(); + return false; + } + return ((flags & ERROR) == 0); + } + + /** + * Scale the image into this component's bounds. + */ + public void paint(Graphics g) + { + if (image != null) + { + Dimension is = new Dimension(image.getWidth(this), + image.getHeight(this)); + if (is.width > -1 && is.height > -1) + { + Dimension cs = getSize(); + g.drawImage(image, 0, 0, cs.width, cs.height, + 0, 0, is.width, is.height, this); + } + } + } + +} diff --git a/libjava/classpath/gnu/javax/activation/viewers/TextEditor.java b/libjava/classpath/gnu/javax/activation/viewers/TextEditor.java new file mode 100644 index 000000000..0eedc85db --- /dev/null +++ b/libjava/classpath/gnu/javax/activation/viewers/TextEditor.java @@ -0,0 +1,119 @@ +/* TextEditor.java -- Simple text editor component. + 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.javax.activation.viewers; + +import java.awt.Dimension; +import java.awt.TextArea; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import javax.activation.CommandObject; +import javax.activation.DataHandler; + +/** + * Simple text editor component. + * + * @author Chris Burdess + * @version 1.0.2 + */ +public class TextEditor extends TextArea + implements CommandObject, ActionListener +{ + + private transient DataHandler dh; + + public TextEditor() + { + super("", 24, 80, 1); + } + + public Dimension getPreferredSize() + { + return getMinimumSize(24, 80); + } + + public void setCommandContext(String verb, DataHandler dh) + throws IOException + { + this.dh = dh; + InputStream in = dh.getInputStream(); + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + byte[] buf = new byte[4096]; + for (int len = in.read(buf); len != -1; len = in.read(buf)) + bytes.write(buf, 0, len); + in.close(); + setText(bytes.toString()); + } + + public void actionPerformed(ActionEvent event) + { + if ("save".equals(event.getActionCommand()) && dh != null) + { + OutputStream out = null; + try + { + out = dh.getOutputStream(); + if (out != null) + out.write(getText().getBytes()); + } + catch (IOException e) + { + e.printStackTrace(System.err); + } + finally + { + if (out != null) + { + try + { + + out.close(); + } + catch (IOException e) + { + e.printStackTrace(System.err); + } + } + } + } + } + +} diff --git a/libjava/classpath/gnu/javax/activation/viewers/TextViewer.java b/libjava/classpath/gnu/javax/activation/viewers/TextViewer.java new file mode 100644 index 000000000..deac80d5e --- /dev/null +++ b/libjava/classpath/gnu/javax/activation/viewers/TextViewer.java @@ -0,0 +1,81 @@ +/* TextViewer.java -- Simple text viewer component. + 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.javax.activation.viewers; + +import java.awt.Dimension; +import java.awt.TextArea; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.IOException; +import javax.activation.CommandObject; +import javax.activation.DataHandler; + +/** + * Simple text display component. + * + * @author Chris Burdess + * @version 1.0.2 + */ +public class TextViewer extends TextArea + implements CommandObject +{ + + public TextViewer() + { + super("", 24, 80, 1); + setEditable(false); + } + + public Dimension getPreferredSize() + { + return getMinimumSize(24, 80); + } + + public void setCommandContext(String verb, DataHandler dh) + throws IOException + { + InputStream in = dh.getInputStream(); + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + byte[] buf = new byte[4096]; + for (int len = in.read(buf); len != -1; len = in.read(buf)) + bytes.write(buf, 0, len); + in.close(); + setText(bytes.toString()); + } + +} diff --git a/libjava/classpath/gnu/javax/crypto/RSACipherImpl.java b/libjava/classpath/gnu/javax/crypto/RSACipherImpl.java new file mode 100644 index 000000000..a4adff007 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/RSACipherImpl.java @@ -0,0 +1,299 @@ +/* RSACipherImpl.java -- + 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; + +import gnu.classpath.debug.Component; +import gnu.classpath.debug.SystemLogger; +import gnu.java.security.sig.rsa.EME_PKCS1_V1_5; +import gnu.java.security.util.ByteArray; + +import java.math.BigInteger; +import java.security.AlgorithmParameters; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.interfaces.RSAKey; +import java.security.interfaces.RSAPrivateCrtKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.AlgorithmParameterSpec; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.CipherSpi; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.ShortBufferException; + +public class RSACipherImpl + extends CipherSpi +{ + private static final SystemLogger logger = SystemLogger.SYSTEM; + + private static final byte[] EMPTY = new byte[0]; + private int opmode = -1; + private RSAPrivateKey decipherKey = null; + private RSAPublicKey blindingKey = null; + private RSAPublicKey encipherKey = null; + private SecureRandom random = null; + private byte[] dataBuffer = null; + private int pos = 0; + + protected void engineSetMode(String mode) throws NoSuchAlgorithmException + { + throw new NoSuchAlgorithmException("only one mode available"); + } + + protected void engineSetPadding(String pad) throws NoSuchPaddingException + { + throw new NoSuchPaddingException("only one padding available"); + } + + protected int engineGetBlockSize() + { + return 1; + } + + protected int engineGetOutputSize(int inputLen) + { + int outputLen = 0; + if (decipherKey != null) + outputLen = (decipherKey.getModulus().bitLength() + 7) / 8; + else if (encipherKey != null) + outputLen = (encipherKey.getModulus().bitLength() + 7) / 8; + else + throw new IllegalStateException("not initialized"); + if (inputLen > outputLen) + throw new IllegalArgumentException("not configured to encode " + inputLen + + "bytes; at most " + outputLen); + return outputLen; + } + + protected int engineGetKeySize(final Key key) throws InvalidKeyException + { + if (! (key instanceof RSAKey)) + throw new InvalidKeyException("not an RSA key"); + return ((RSAKey) key).getModulus().bitLength(); + } + + protected byte[] engineGetIV() + { + return null; + } + + protected AlgorithmParameters engineGetParameters() + { + return null; + } + + protected void engineInit(int opmode, Key key, SecureRandom random) + throws InvalidKeyException + { + int outputLen = 0; + if (opmode == Cipher.ENCRYPT_MODE) + { + if (! (key instanceof RSAPublicKey)) + throw new InvalidKeyException("expecting a RSAPublicKey"); + encipherKey = (RSAPublicKey) key; + decipherKey = null; + blindingKey = null; + outputLen = (encipherKey.getModulus().bitLength() + 7) / 8; + } + else if (opmode == Cipher.DECRYPT_MODE) + { + if (key instanceof RSAPrivateKey) + { + decipherKey = (RSAPrivateKey) key; + encipherKey = null; + blindingKey = null; + outputLen = (decipherKey.getModulus().bitLength() + 7) / 8; + } + else if (key instanceof RSAPublicKey) + { + if (decipherKey == null) + throw new IllegalStateException("must configure decryption key first"); + if (! decipherKey.getModulus().equals(((RSAPublicKey) key).getModulus())) + throw new InvalidKeyException("blinding key is not compatible"); + blindingKey = (RSAPublicKey) key; + return; + } + else + throw new InvalidKeyException( + "expecting either an RSAPrivateKey or an RSAPublicKey (for blinding)"); + } + else + throw new IllegalArgumentException("only encryption and decryption supported"); + this.random = random; + this.opmode = opmode; + pos = 0; + dataBuffer = new byte[outputLen]; + } + + protected void engineInit(int opmode, Key key, AlgorithmParameterSpec spec, + SecureRandom random) throws InvalidKeyException + { + engineInit(opmode, key, random); + } + + protected void engineInit(int opmode, Key key, AlgorithmParameters params, + SecureRandom random) throws InvalidKeyException + { + engineInit(opmode, key, random); + } + + protected byte[] engineUpdate(byte[] in, int offset, int length) + { + if (opmode != Cipher.ENCRYPT_MODE && opmode != Cipher.DECRYPT_MODE) + throw new IllegalStateException("not initialized"); + System.arraycopy(in, offset, dataBuffer, pos, length); + pos += length; + return EMPTY; + } + + protected int engineUpdate(byte[] in, int offset, int length, byte[] out, + int outOffset) + { + engineUpdate(in, offset, length); + return 0; + } + + protected byte[] engineDoFinal(byte[] in, int offset, int length) + throws IllegalBlockSizeException, BadPaddingException + { + engineUpdate(in, offset, length); + if (opmode == Cipher.DECRYPT_MODE) + { + BigInteger enc = new BigInteger (1, dataBuffer); + byte[] dec = rsaDecrypt (enc); + logger.log (Component.CRYPTO, "RSA: decryption produced\n{0}", + new ByteArray (dec)); + EME_PKCS1_V1_5 pkcs = EME_PKCS1_V1_5.getInstance(decipherKey); + byte[] result = pkcs.decode(dec); + return result; + } + else + { + offset = dataBuffer.length - pos; + if (offset < 3) + throw new IllegalBlockSizeException("input is too large to encrypt"); + EME_PKCS1_V1_5 pkcs = EME_PKCS1_V1_5.getInstance(encipherKey); + if (random == null) + random = new SecureRandom(); + byte[] em = new byte[pos]; + System.arraycopy(dataBuffer, 0, em, 0, pos); + byte[] dec = pkcs.encode(em, random); + logger.log (Component.CRYPTO, "RSA: produced padded plaintext\n{0}", + new ByteArray (dec)); + BigInteger x = new BigInteger (1, dec); + BigInteger y = x.modPow (encipherKey.getPublicExponent (), + encipherKey.getModulus ()); + byte[] enc = y.toByteArray (); + if (enc[0] == 0x00) + { + byte[] tmp = new byte[enc.length - 1]; + System.arraycopy(enc, 1, tmp, 0, tmp.length); + enc = tmp; + } + pos = 0; + return enc; + } + } + + protected int engineDoFinal(byte[] out, int offset) + throws ShortBufferException, IllegalBlockSizeException, + BadPaddingException + { + byte[] result = engineDoFinal(EMPTY, 0, 0); + if (out.length - offset < result.length) + throw new ShortBufferException("need " + result.length + ", have " + + (out.length - offset)); + System.arraycopy(result, 0, out, offset, result.length); + return result.length; + } + + protected int engineDoFinal(final byte[] input, final int offset, + final int length, final byte[] output, + final int outputOffset) + throws ShortBufferException, IllegalBlockSizeException, + BadPaddingException + { + byte[] result = engineDoFinal(input, offset, length); + if (output.length - outputOffset < result.length) + throw new ShortBufferException("need " + result.length + ", have " + + (output.length - outputOffset)); + System.arraycopy(result, 0, output, outputOffset, result.length); + return result.length; + } + + /** + * Decrypts the ciphertext, employing RSA blinding if possible. + */ + private byte[] rsaDecrypt(BigInteger enc) + { + if (random == null) + random = new SecureRandom(); + BigInteger n = decipherKey.getModulus(); + BigInteger r = null; + BigInteger pubExp = null; + if (blindingKey != null) + pubExp = blindingKey.getPublicExponent(); + if (pubExp != null && (decipherKey instanceof RSAPrivateCrtKey)) + pubExp = ((RSAPrivateCrtKey) decipherKey).getPublicExponent(); + if (pubExp != null) + { + r = new BigInteger(n.bitLength() - 1, random); + enc = r.modPow(pubExp, n).multiply(enc).mod(n); + } + BigInteger dec = enc.modPow(decipherKey.getPrivateExponent(), n); + if (pubExp != null) + { + dec = dec.multiply (r.modInverse (n)).mod (n); + } + + byte[] decb = dec.toByteArray(); + if (decb[0] != 0x00) + { + byte[] b = new byte[decb.length + 1]; + System.arraycopy(decb, 0, b, 1, decb.length); + decb = b; + } + return decb; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/assembly/Assembly.java b/libjava/classpath/gnu/javax/crypto/assembly/Assembly.java new file mode 100644 index 000000000..f570d2012 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/Assembly.java @@ -0,0 +1,272 @@ +/* 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 + */ +public class Assembly +{ + 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; + + /** + * Trivial constructor that sets the chain to a + * LoopbackTransformer. + */ + public Assembly() + { + super(); + + wired = null; + head = new LoopbackTransformer(); + } + + /** + * 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; + } + + 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/libjava/classpath/gnu/javax/crypto/assembly/Cascade.java b/libjava/classpath/gnu/javax/crypto/assembly/Cascade.java new file mode 100644 index 000000000..685cef5b2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/Cascade.java @@ -0,0 +1,348 @@ +/* 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.javax.crypto.mode.IMode}, including the + * {@link gnu.javax.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. + *
    + */ +public class Cascade +{ + 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; + + public Cascade() + { + super(); + + stages = new HashMap(3); + stageKeys = new LinkedList(); + wired = null; + blockSize = 0; + } + + /** + * 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(); + } + + /** + * 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/libjava/classpath/gnu/javax/crypto/assembly/CascadeStage.java b/libjava/classpath/gnu/javax/crypto/assembly/CascadeStage.java new file mode 100644 index 000000000..196edafdf --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/CascadeStage.java @@ -0,0 +1,93 @@ +/* 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. + */ +class CascadeStage + extends Stage +{ + private Cascade delegate; + + CascadeStage(Cascade cascade, Direction forwardDirection) + { + super(forwardDirection); + + this.delegate = cascade; + } + + 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(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/libjava/classpath/gnu/javax/crypto/assembly/CascadeTransformer.java b/libjava/classpath/gnu/javax/crypto/assembly/CascadeTransformer.java new file mode 100644 index 000000000..8e3a9a5a1 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/CascadeTransformer.java @@ -0,0 +1,123 @@ +/* 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}. + */ +class CascadeTransformer + extends Transformer +{ + private Cascade delegate; + + private int blockSize; + + CascadeTransformer(Cascade delegate) + { + super(); + + this.delegate = delegate; + } + + 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) + { + IllegalStateException cause = new IllegalStateException( + "Cascade transformer, after last update, must be empty but isn't"); + throw new TransformerException("lastUpdateDelegate()", cause); + } + 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/libjava/classpath/gnu/javax/crypto/assembly/DeflateTransformer.java b/libjava/classpath/gnu/javax/crypto/assembly/DeflateTransformer.java new file mode 100644 index 000000000..97f9f0365 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/DeflateTransformer.java @@ -0,0 +1,177 @@ +/* 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. + */ +class DeflateTransformer + extends Transformer +{ + private Deflater compressor; + + private Inflater decompressor; + + private int outputBlockSize = 512; // default zlib buffer size + + private byte[] zlibBuffer; + + DeflateTransformer() + { + super(); + + } + + void initDelegate(Map attributes) throws TransformerException + { + if (tail == null) + { + IllegalStateException cause = new IllegalStateException( + "Compression transformer missing its tail!"); + throw new TransformerException("initDelegate()", cause); + } + 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 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() 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()) + { + IllegalStateException cause = new IllegalStateException( + "Compression transformer, after last update, must be finished " + + "but isn't"); + throw new TransformerException("lastUpdateDelegate()", cause); + } + } + 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/libjava/classpath/gnu/javax/crypto/assembly/Direction.java b/libjava/classpath/gnu/javax/crypto/assembly/Direction.java new file mode 100644 index 000000000..40ddfc429 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/Direction.java @@ -0,0 +1,78 @@ +/* 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.javax.crypto.mode.IMode#ENCRYPTION}, + * and its inverse value
    2. + *
    3. REVERSED: equivalent to {@link gnu.javax.crypto.mode.IMode#DECRYPTION}. + *
    4. + *
    + */ +public final class Direction +{ + public static final Direction FORWARD = new Direction(1); + + public static final Direction REVERSED = new Direction(2); + + private int value; + + private Direction(int value) + { + super(); + + this.value = value; + } + + public static final Direction reverse(Direction d) + { + return (d.equals(FORWARD) ? REVERSED : FORWARD); + } + + public String toString() + { + return (this == FORWARD ? "forward" : "reversed"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/assembly/LoopbackTransformer.java b/libjava/classpath/gnu/javax/crypto/assembly/LoopbackTransformer.java new file mode 100644 index 000000000..5bcfe5ffc --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/LoopbackTransformer.java @@ -0,0 +1,100 @@ +/* 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. + */ +final class LoopbackTransformer + extends Transformer +{ + /** Trivial package-private constructor. */ + LoopbackTransformer() + { + super(); + } + + 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(); + } + + 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/libjava/classpath/gnu/javax/crypto/assembly/ModeStage.java b/libjava/classpath/gnu/javax/crypto/assembly/ModeStage.java new file mode 100644 index 000000000..8bdbef7c4 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/ModeStage.java @@ -0,0 +1,112 @@ +/* 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. + */ +class ModeStage + extends Stage +{ + private IMode delegate; + + private transient Set cachedBlockSizes; + + ModeStage(IMode mode, Direction forwardDirection) + { + super(forwardDirection); + + delegate = mode; + cachedBlockSizes = null; + } + + 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, + Integer.valueOf(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/libjava/classpath/gnu/javax/crypto/assembly/Operation.java b/libjava/classpath/gnu/javax/crypto/assembly/Operation.java new file mode 100644 index 000000000..6861a1377 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/Operation.java @@ -0,0 +1,73 @@ +/* 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. + *
    + */ +public final class Operation +{ + public static final Operation PRE_PROCESSING = new Operation(1); + + public static final Operation POST_PROCESSING = new Operation(2); + + private int value; + + private Operation(int value) + { + super(); + + this.value = value; + } + + public String toString() + { + return (this == PRE_PROCESSING ? "pre-processing" : "post-processing"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/assembly/PaddingTransformer.java b/libjava/classpath/gnu/javax/crypto/assembly/PaddingTransformer.java new file mode 100644 index 000000000..494ca34ca --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/PaddingTransformer.java @@ -0,0 +1,164 @@ +/* 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. + */ +class PaddingTransformer + extends Transformer +{ + private IPad delegate; + + private int outputBlockSize = 1; + + PaddingTransformer(IPad padding) + { + super(); + + this.delegate = padding; + } + + void initDelegate(Map attributes) throws TransformerException + { + if (tail == null) + { + IllegalStateException cause = new IllegalStateException( + "Padding transformer missing its tail!"); + throw new TransformerException("initDelegate()", cause); + } + 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/libjava/classpath/gnu/javax/crypto/assembly/Stage.java b/libjava/classpath/gnu/javax/crypto/assembly/Stage.java new file mode 100644 index 000000000..5d0ab5353 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/Stage.java @@ -0,0 +1,202 @@ +/* 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 + */ +public abstract class Stage +{ + public static final String DIRECTION = "gnu.crypto.assembly.stage.direction"; + + protected Direction forward; + + protected Direction wired; + + protected Stage(Direction forwardDirection) + { + super(); + + this.forward = forwardDirection; + this.wired = null; + } + + 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); + } + + /** + * 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 void initDelegate(Map attributes) throws InvalidKeyException; + + abstract void resetDelegate(); + + abstract void updateDelegate(byte[] in, int inOffset, byte[] out, + int outOffset); +} diff --git a/libjava/classpath/gnu/javax/crypto/assembly/Transformer.java b/libjava/classpath/gnu/javax/crypto/assembly/Transformer.java new file mode 100644 index 000000000..1937f9950 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/Transformer.java @@ -0,0 +1,421 @@ +/* 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.javax.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 + */ +public abstract class Transformer +{ + public static final String DIRECTION = "gnu.crypto.assembly.transformer.direction"; + + protected Direction wired; + + protected Operation mode; + + protected Transformer tail = null; + + protected ByteArrayOutputStream inBuffer = new ByteArrayOutputStream(2048); + + protected ByteArrayOutputStream outBuffer = new ByteArrayOutputStream(2048); + + /** Trivial protected constructor. */ + protected Transformer() + { + super(); + + this.wired = null; + } + + 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(); + } + + /** + * 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; + } + + 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 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/libjava/classpath/gnu/javax/crypto/assembly/TransformerException.java b/libjava/classpath/gnu/javax/crypto/assembly/TransformerException.java new file mode 100644 index 000000000..295fded7b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/assembly/TransformerException.java @@ -0,0 +1,140 @@ +/* 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 gnu.java.lang.CPStringBuilder; + +import java.io.PrintStream; +import java.io.PrintWriter; + +/** + */ +public class TransformerException + extends Exception +{ + private Throwable _exception = null; + + 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; + } + + 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() + { + CPStringBuilder sb = new CPStringBuilder(this.getClass().getName()) + .append(": ").append(super.toString()); + if (_exception != null) + sb.append("; caused by: ").append(_exception.toString()); + return sb.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/Anubis.java b/libjava/classpath/gnu/javax/crypto/cipher/Anubis.java new file mode 100644 index 000000000..3526ad612 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/Anubis.java @@ -0,0 +1,491 @@ +/* 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.Configuration; +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; +import java.util.logging.Logger; + +/** + * 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 +{ + private static final Logger log = Logger.getLogger(Anubis.class.getName()); + 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 + { + 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 (Configuration.DEBUG) + { + log.fine("Static data"); + log.fine("T0[]:"); + StringBuilder sb; + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (t = 0; t < 4; t++) + sb.append("0x").append(Util.toString(T0[i * 4 + t])).append(", "); + log.fine(sb.toString()); + } + log.fine("T1[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (t = 0; t < 4; t++) + sb.append("0x").append(Util.toString(T1[i * 4 + t])).append(", "); + log.fine(sb.toString()); + } + log.fine("T2[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (t = 0; t < 4; t++) + sb.append("0x").append(Util.toString(T2[i * 4 + t])).append(", "); + log.fine(sb.toString()); + } + log.fine("T3[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (t = 0; t < 4; t++) + sb.append("0x").append(Util.toString(T3[i * 4 + t])).append(", "); + log.fine(sb.toString()); + } + log.fine("T4[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (t = 0; t < 4; t++) + sb.append("0x").append(Util.toString(T4[i * 4 + t])).append(", "); + log.fine(sb.toString()); + } + log.fine("T5[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (t = 0; t < 4; t++) + sb.append("0x").append(Util.toString(T5[i * 4 + t])).append(", "); + log.fine(sb.toString()); + } + log.fine("rc[]:"); + for (i = 0; i < 18; i++) + log.fine("0x" + Util.toString(rc[i])); + log.fine("Total initialization time: " + time + " ms."); + } + } + + /** Trivial 0-arguments constructor. */ + public Anubis() + { + super(Registry.ANUBIS_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + 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 (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("T=" + Util.toString(out, j - 15, 16) + "\n"); + } + + public Object clone() + { + Anubis result = new Anubis(); + result.currentBlockSize = this.currentBlockSize; + + return result; + } + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(DEFAULT_BLOCK_SIZE)); + + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + for (int n = 4; n < 10; n++) + al.add(Integer.valueOf(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 (Configuration.DEBUG) + { + log.fine("Key schedule"); + log.fine("Ke[]:"); + StringBuilder sb; + for (r = 0; r < R + 1; r++) + { + sb = new StringBuilder("#").append(r).append(": "); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(Ke[r][j])).append(", "); + log.fine(sb.toString()); + } + log.fine("Kd[]:"); + for (r = 0; r < R + 1; r++) + { + sb = new StringBuilder("#").append(r).append(": "); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(Kd[r][j])).append(", "); + log.fine(sb.toString()); + } + } + 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 = Boolean.valueOf(result); + } + return valid.booleanValue(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/BaseCipher.java b/libjava/classpath/gnu/javax/crypto/cipher/BaseCipher.java new file mode 100644 index 000000000..45aa2d6fd --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/BaseCipher.java @@ -0,0 +1,249 @@ +/* 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.lang.CPStringBuilder; + +import gnu.java.security.Configuration; + +import java.security.InvalidKeyException; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * A basic abstract class to facilitate implementing symmetric key block + * ciphers. + */ +public abstract class BaseCipher + implements IBlockCipher, IBlockCipherSpi +{ + private static final Logger log = Logger.getLogger(BaseCipher.class.getName()); + /** 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(); + + /** + * 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; + } + + public abstract Object clone(); + + public String name() + { + CPStringBuilder sb = new CPStringBuilder(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) + { + 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; + } + + 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) + { + if (Configuration.DEBUG) + log.log(Level.FINE, "Exception in testSymmetry() for " + name(), x); + 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) + { + if (Configuration.DEBUG) + log.log(Level.FINE, "Exception in testKat() for " + name(), x); + return false; + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/Blowfish.java b/libjava/classpath/gnu/javax/crypto/cipher/Blowfish.java new file mode 100644 index 000000000..0c6d9b12b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/Blowfish.java @@ -0,0 +1,611 @@ +/* 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 +{ + 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"); + + public Blowfish() + { + super(Registry.BLOWFISH_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + public Object clone() + { + Blowfish result = new Blowfish(); + result.currentBlockSize = currentBlockSize; + return result; + } + + public Iterator keySizes() + { + return new Sequence(8, MAX_KEY_LENGTH, 8).iterator(); + } + + public Iterator blockSizes() + { + return Collections.singleton(Integer.valueOf(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; + } + + /** 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 = Boolean.valueOf(result); + } + return valid.booleanValue(); + } + + /** A simple wrapper for the P- and S-boxes. */ + private class Context + implements Cloneable + { + /** The P-array. */ + int[] p, s0, s1, s2, s3; + + /** 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(); + } + + public Object clone() + { + return new Context(this); + } + } + + private class Block + { + int left, right; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/Cast5.java b/libjava/classpath/gnu/javax/crypto/cipher/Cast5.java new file mode 100644 index 000000000..47b29226f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/Cast5.java @@ -0,0 +1,987 @@ +/* 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 +{ + 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; + + /** Trivial 0-arguments constructor. */ + public Cast5() + { + super(Registry.CAST5_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + /** + * 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 }; + } + + public Object clone() + { + Cast5 result = new Cast5(); + result.currentBlockSize = this.currentBlockSize; + return result; + } + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(DEFAULT_BLOCK_SIZE)); + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + for (int n = 5; n < 17; n++) + al.add(Integer.valueOf(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 = Boolean.valueOf(result); + } + return valid.booleanValue(); + } + + 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]; + } + + /** 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/libjava/classpath/gnu/javax/crypto/cipher/CipherFactory.java b/libjava/classpath/gnu/javax/crypto/cipher/CipherFactory.java new file mode 100644 index 000000000..fc9023626 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/CipherFactory.java @@ -0,0 +1,129 @@ +/* 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 +{ + /** Trivial constructor to enforce Singleton pattern. */ + private CipherFactory() + { + super(); + } + + /** + * 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); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/DES.java b/libjava/classpath/gnu/javax/crypto/cipher/DES.java new file mode 100644 index 000000000..ce538b75a --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/DES.java @@ -0,0 +1,652 @@ +/* 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 +{ + /** 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") }; + + /** Default 0-argument constructor. */ + public DES() + { + super(Registry.DES_CIPHER, BLOCK_SIZE, KEY_SIZE); + } + + /** + * 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 < offset + 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) + { + 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) + { + 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; + } + + public Object clone() + { + return new DES(); + } + + public Iterator blockSizes() + { + return Collections.singleton(Integer.valueOf(BLOCK_SIZE)).iterator(); + } + + public Iterator keySizes() + { + return Collections.singleton(Integer.valueOf(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); + } + + /** + * Simple wrapper class around the session keys. Package-private so TripleDES + * can see it. + */ + final class Context + { + private static final int EXPANDED_KEY_SIZE = 32; + + /** The encryption key. */ + int[] ek; + + /** The decryption key. */ + int[] dk; + + /** Default 0-arguments constructor. */ + Context() + { + ek = new int[EXPANDED_KEY_SIZE]; + dk = new int[EXPANDED_KEY_SIZE]; + } + + 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; + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/IBlockCipher.java b/libjava/classpath/gnu/javax/crypto/cipher/IBlockCipher.java new file mode 100644 index 000000000..86f8b34e0 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/IBlockCipher.java @@ -0,0 +1,195 @@ +/* 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 +{ + /** + * 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"; + + /** + * 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(); +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/IBlockCipherSpi.java b/libjava/classpath/gnu/javax/crypto/cipher/IBlockCipherSpi.java new file mode 100644 index 000000000..9b2172158 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/IBlockCipherSpi.java @@ -0,0 +1,124 @@ +/* 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 BaseCipher} sub-classes. + */ +interface IBlockCipherSpi + extends Cloneable +{ + /** + * Returns an {@link 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 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(); +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/Khazad.java b/libjava/classpath/gnu/javax/crypto/cipher/Khazad.java new file mode 100644 index 000000000..55e42628b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/Khazad.java @@ -0,0 +1,449 @@ +/* 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.Configuration; +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; +import java.util.logging.Logger; + +/** + * 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 +{ + private static final Logger log = Logger.getLogger(Khazad.class.getName()); + 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 + { + 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 (Configuration.DEBUG) + { + log.fine("Static data"); + log.fine("T0[]:"); + StringBuilder b; + for (i = 0; i < 64; i++) + { + b = new StringBuilder(); + for (j = 0; j < 4; j++) + b.append("0x").append(Util.toString(T0[i * 4 + j])).append(", "); + log.fine(b.toString()); + } + log.fine("T1[]:"); + for (i = 0; i < 64; i++) + { + b = new StringBuilder(); + for (j = 0; j < 4; j++) + b.append("0x").append(Util.toString(T1[i * 4 + j])).append(", "); + log.fine(b.toString()); + } + log.fine("T2[]:"); + for (i = 0; i < 64; i++) + { + b = new StringBuilder(); + for (j = 0; j < 4; j++) + b.append("0x").append(Util.toString(T2[i * 4 + j])).append(", "); + log.fine(b.toString()); + } + log.fine("T3[]:"); + for (i = 0; i < 64; i++) + { + b = new StringBuilder(); + for (j = 0; j < 4; j++) + b.append("0x").append(Util.toString(T3[i * 4 + j])).append(", "); + log.fine(b.toString()); + } + log.fine("T4[]:"); + for (i = 0; i < 64; i++) + { + b = new StringBuilder(); + for (j = 0; j < 4; j++) + b.append("0x").append(Util.toString(T4[i * 4 + j])).append(", "); + log.fine(b.toString()); + } + log.fine("T5[]:"); + for (i = 0; i < 64; i++) + { + b = new StringBuilder(); + for (j = 0; j < 4; j++) + b.append("0x").append(Util.toString(T5[i * 4 + j])).append(", "); + log.fine(b.toString()); + } + log.fine("T6[]:"); + for (i = 0; i < 64; i++) + { + b = new StringBuilder(); + for (j = 0; j < 4; j++) + b.append("0x").append(Util.toString(T6[i * 4 + j])).append(", "); + log.fine(b.toString()); + } + log.fine("T7[]:"); + for (i = 0; i < 64; i++) + { + b = new StringBuilder(); + for (j = 0; j < 4; j++) + b.append("0x").append(Util.toString(T7[i * 4 + j])).append(", "); + log.fine(b.toString()); + } + log.fine("rc[]:"); + for (i = 0; i < R + 1; i++) + log.fine("0x" + Util.toString(rc[i][0]) + Util.toString(rc[i][1])); + log.fine("Total initialization time: " + time + " ms."); + } + } + + /** Trivial 0-arguments constructor. */ + public Khazad() + { + super(Registry.KHAZAD_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + 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 (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("T=" + Util.toString(out, j - 7, 8) + "\n"); + } + + public Object clone() + { + Khazad result = new Khazad(); + result.currentBlockSize = this.currentBlockSize; + + return result; + } + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(DEFAULT_BLOCK_SIZE)); + + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(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 (Configuration.DEBUG) + { + log.fine("Key schedule"); + log.fine("Ke[]:"); + for (r = 0; r < R + 1; r++) + log.fine("#" + r + ": 0x" + Util.toString(Ke[r][0]) + + Util.toString(Ke[r][1])); + log.fine("Kd[]:"); + for (r = 0; r < R + 1; r++) + log.fine("#" + r + ": 0x" + Util.toString(Kd[r][0]) + + Util.toString(Kd[r][1])); + } + 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 = Boolean.valueOf(result); + } + return valid.booleanValue(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/NullCipher.java b/libjava/classpath/gnu/javax/crypto/cipher/NullCipher.java new file mode 100644 index 000000000..f23ea489f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/NullCipher.java @@ -0,0 +1,108 @@ +/* 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 +{ + /** Trivial 0-arguments constructor. */ + public NullCipher() + { + super(Registry.NULL_CIPHER, 16, 16); + } + + public Object clone() + { + NullCipher result = new NullCipher(); + result.currentBlockSize = this.currentBlockSize; + return result; + } + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(64 / 8)); + al.add(Integer.valueOf(128 / 8)); + al.add(Integer.valueOf(192 / 8)); + al.add(Integer.valueOf(256 / 8)); + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + for (int n = 8; n < 64; n++) + al.add(Integer.valueOf(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; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/Rijndael.java b/libjava/classpath/gnu/javax/crypto/cipher/Rijndael.java new file mode 100644 index 000000000..0463fe51d --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/Rijndael.java @@ -0,0 +1,704 @@ +/* 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.Configuration; +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; +import java.util.logging.Logger; + +/** + * 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 +{ + private static final Logger log = Logger.getLogger(Rijndael.class.getName()); + 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 + { + 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 (Configuration.DEBUG) + { + log.fine("Static Data"); + log.fine("S[]:"); + StringBuilder sb; + for (i = 0; i < 16; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 16; j++) + sb.append("0x").append(Util.toString(S[i * 16 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("Si[]:"); + for (i = 0; i < 16; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 16; j++) + sb.append("0x").append(Util.toString(Si[i * 16 + j])).append(", "); + log.fine(sb.toString()); + } + + log.fine("T1[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T1[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("T2[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T2[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("T3[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T3[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("T4[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T4[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("T5[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T5[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("T6[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T6[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("T7[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T7[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("T8[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T8[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + + log.fine("U1[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(U1[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("U2[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(U2[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("U3[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(U3[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("U4[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(U4[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + + log.fine("rcon[]:"); + for (i = 0; i < 5; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 6; j++) + sb.append("0x").append(Util.toString(rcon[i * 6 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("Total initialization time: " + time + " ms."); + } + } + + /** Trivial 0-arguments constructor. */ + public Rijndael() + { + super(Registry.RIJNDAEL_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + /** + * 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 (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("CT=" + Util.toString(out, outOffset - bs, bs)); + } + + 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 (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("PT=" + Util.toString(out, outOffset - bs, bs)); + } + + 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 (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("CT=" + Util.toString(out, j - 16, 16)); + } + + 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 (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("PT=" + Util.toString(out, j - 16, 16)); + } + + public Object clone() + { + Rijndael result = new Rijndael(); + result.currentBlockSize = this.currentBlockSize; + + return result; + } + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(128 / 8)); + al.add(Integer.valueOf(192 / 8)); + al.add(Integer.valueOf(256 / 8)); + + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(128 / 8)); + al.add(Integer.valueOf(192 / 8)); + al.add(Integer.valueOf(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 = Boolean.valueOf(result); + } + return valid.booleanValue(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/Serpent.java b/libjava/classpath/gnu/javax/crypto/cipher/Serpent.java new file mode 100644 index 000000000..1175fcfd2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/Serpent.java @@ -0,0 +1,1781 @@ +/* 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 +{ + 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; + + /** Trivial zero-argument constructor. */ + public Serpent() + { + super(Registry.SERPENT_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + public Object clone() + { + Serpent result = new Serpent(); + result.currentBlockSize = this.currentBlockSize; + return result; + } + + public Iterator blockSizes() + { + return Collections.singleton(Integer.valueOf(DEFAULT_BLOCK_SIZE)).iterator(); + } + + public Iterator keySizes() + { + ArrayList keySizes = new ArrayList(); + keySizes.add(Integer.valueOf(16)); + keySizes.add(Integer.valueOf(24)); + keySizes.add(Integer.valueOf(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 = Boolean.valueOf(result); + } + return valid.booleanValue(); + } + + // 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; + } + + /** 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; + } + + private class Key + implements Cloneable + { + 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; + + /** 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; + } + + public Object clone() + { + return new Key(this); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/Square.java b/libjava/classpath/gnu/javax/crypto/cipher/Square.java new file mode 100644 index 000000000..231df0a47 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/Square.java @@ -0,0 +1,425 @@ +/* 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. + *
    + */ +public final class Square + extends BaseCipher +{ + 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 + { + int i, j; + // 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); + } + } + + /** Trivial 0-arguments constructor. */ + public Square() + { + super(Registry.SQUARE_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + 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; + } + + public Object clone() + { + Square result = new Square(); + result.currentBlockSize = this.currentBlockSize; + + return result; + } + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(DEFAULT_BLOCK_SIZE)); + + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(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 = Boolean.valueOf(result); + } + return valid.booleanValue(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/TripleDES.java b/libjava/classpath/gnu/javax/crypto/cipher/TripleDES.java new file mode 100644 index 000000000..1d684c20a --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/TripleDES.java @@ -0,0 +1,257 @@ +/* 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.ArrayList; +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 theoretically improve + * the security of plain DES, at the cost of speed. + *

    + * Triple-DES runs the DES algorithm three times with one, two or three + * independent 56-bit (DES) keys. When used with one DES key, the cipher behaves + * exactly like a (slower) DES. + *

    + * 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 +{ + /** Triple-DES only operates on 64 bit blocks. */ + public static final int BLOCK_SIZE = 8; + /** By default, 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; + + /** + * Default 0-arguments constructor. + */ + public TripleDES() + { + super(Registry.TRIPLEDES_CIPHER, BLOCK_SIZE, KEY_SIZE); + des = new DES(); + } + + /** + * Convenience method which calls the method with same name and three + * arguments, passing 3 as the value of the first parameter. + * + * @param kb The key bytes to adjust. + * @param offset The starting offset into the key bytes. + */ + public static void adjustParity(byte[] kb, int offset) + { + adjustParity(3, kb, offset); + } + + /** + * Adjusts, in-situ, the parity of the designated bytes, so they can be used + * as DES keys for a 3-DES 1-, 2- or 3-key cipher. + * + * @param keyCount the number of independent DES keys. Can be either + * 1, 2 or 3. Any other value + * will cause an {@link IllegalArgumentException} to be raised. + * @param kb the array containing the key bytes to adjust. MUST have at least + * 8 * keyCount bytes starting at offset position + * offset, otherwise an + * {@link ArrayIndexOutOfBoundsException} will be raised. + * @param offset the starting offset into the array. + * @see DES#adjustParity(byte[],int) + */ + public static void adjustParity(int keyCount, byte[] kb, int offset) + { + if (keyCount < 1 || keyCount > 3) + throw new IllegalArgumentException("Invalid keyCount value: " + keyCount); + DES.adjustParity(kb, offset); + if (keyCount > 1) + DES.adjustParity(kb, offset + 8); + if (keyCount > 2) + DES.adjustParity(kb, offset + 16); + } + + /** + * Convenience method which calls the method with same name and three + * arguments, passing 3 as the value of the first parameter. + * + * @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 isParityAdjusted(3, kb, offset); + } + + /** + * Tests if enough bytes, expected to be used as DES keys for a 3-DES 1-, 2- + * or 3-key cipher, located in a designated byte array, has already been + * parity adjusted. + * + * @param keyCount the number of independent DES keys. Can be either + * 1, 2 or 3. Any other value + * will cause an {@link IllegalArgumentException} to be raised. + * @param kb the array containing the key bytes to test. MUST have at least + * 8 * keyCount bytes starting at offset position + * offset, otherwise an + * {@link ArrayIndexOutOfBoundsException} will be raised. + * @param offset the starting offset into the array. + * @return true if the bytes in kb starting at + * offset are parity adjusted. + * @see DES#isParityAdjusted(byte[],int) + * @see #adjustParity(int,byte[],int) + */ + public static boolean isParityAdjusted(int keyCount, byte[] kb, int offset) + { + if (keyCount < 1 || keyCount > 3) + throw new IllegalArgumentException("Invalid keyCount value: " + keyCount); + boolean result = DES.isParityAdjusted(kb, offset); + if (keyCount > 1) + result = result && DES.isParityAdjusted(kb, offset + 8); + if (keyCount > 2) + result = result && DES.isParityAdjusted(kb, offset + 16); + return result; + } + + public Object clone() + { + return new TripleDES(); + } + + public Iterator blockSizes() + { + return Collections.singleton(Integer.valueOf(BLOCK_SIZE)).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(8)); + al.add(Integer.valueOf(16)); + al.add(Integer.valueOf(24)); + return Collections.unmodifiableList(al).iterator(); + } + + public Object makeKey(byte[] kb, int bs) throws InvalidKeyException + { + if (kb.length != 8 && kb.length != 16 && kb.length != 24) + throw new InvalidKeyException("TripleDES key must be 8, 16 or 24 bytes: " + + kb.length); + Context ctx = new Context(); + byte[] k1 = new byte[DES.KEY_SIZE]; + System.arraycopy(kb, 0, k1, 0, DES.KEY_SIZE); + if (! DES.isParityAdjusted(k1, 0)) + DES.adjustParity(k1, 0); + ctx.k1 = (DES.Context) des.makeKey(k1, bs); + + if (kb.length == 8) + { + ctx.k2 = (DES.Context) des.makeKey(k1, bs); + ctx.k3 = (DES.Context) des.makeKey(k1, bs); + } + else + { + byte[] k2 = new byte[DES.KEY_SIZE]; + System.arraycopy(kb, DES.KEY_SIZE, k2, 0, DES.KEY_SIZE); + if (! DES.isParityAdjusted(k2, 0)) + DES.adjustParity(k2, 0); + ctx.k2 = (DES.Context) des.makeKey(k2, bs); + + byte[] k3 = new byte[DES.KEY_SIZE]; + if (kb.length == 16) + ctx.k3 = (DES.Context) des.makeKey(k1, bs); + else + { + System.arraycopy(kb, 2 * DES.KEY_SIZE, k3, 0, DES.KEY_SIZE); + if (! DES.isParityAdjusted(k3, 0)) + DES.adjustParity(k3, 0); + 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); + } + + private final class Context + { + DES.Context k1, k2, k3; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/Twofish.java b/libjava/classpath/gnu/javax/crypto/cipher/Twofish.java new file mode 100644 index 000000000..c9789a699 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/Twofish.java @@ -0,0 +1,737 @@ +/* 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.Configuration; +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; +import java.util.logging.Logger; + +/** + * 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 +{ + private static final Logger log = Logger.getLogger(Twofish.class.getName()); + 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 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_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 + { + 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 + | 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 (Configuration.DEBUG) + { + log.fine("Static Data"); + log.fine("MDS[0][]:"); + StringBuilder sb; + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(MDS[0][i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("MDS[1][]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(MDS[1][i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("MDS[2][]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(MDS[2][i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("MDS[3][]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(MDS[3][i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("Total initialization time: " + time + " ms."); + } + } + + 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_X(int x) + { // 5B + return x ^ LFSR2(x); + } + + private static final int Mx_Y(int x) + { // EF + return x ^ LFSR1(x) ^ LFSR2(x); + } + + /** Trivial 0-arguments constructor. */ + public Twofish() + { + super(Registry.TWOFISH_CIPHER, DEFAULT_BLOCK_SIZE, DEFAULT_KEY_SIZE); + } + + 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) + { + switch (N % 4) + { + case 0: + return x & 0xFF; + case 1: + return (x >>> 8) & 0xFF; + case 2: + return (x >>> 16) & 0xFF; + default: + return x >>> 24; + } + } + + public Object clone() + { + Twofish result = new Twofish(); + result.currentBlockSize = this.currentBlockSize; + return result; + } + + public Iterator blockSizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(DEFAULT_BLOCK_SIZE)); + return Collections.unmodifiableList(al).iterator(); + } + + public Iterator keySizes() + { + ArrayList al = new ArrayList(); + al.add(Integer.valueOf(8)); // 64-bit + al.add(Integer.valueOf(16)); // 128-bit + al.add(Integer.valueOf(24)); // 192-bit + al.add(Integer.valueOf(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 (Configuration.DEBUG) + { + StringBuilder sb; + log.fine("S-box[]:"); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(sBox[i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine(""); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(sBox[256 + i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine(""); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(sBox[512 + i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine(""); + for (i = 0; i < 64; i++) + { + sb = new StringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(sBox[768 + i * 4 + j])).append(", "); + log.fine(sb.toString()); + } + log.fine("User (odd, even) keys --> S-Box keys:"); + for (i = 0; i < k64Cnt; i++) + log.fine("0x" + Util.toString(k32o[i]) + + " 0x" + Util.toString(k32e[i]) + + " --> 0x" + Util.toString(sBoxKey[k64Cnt - 1 - i])); + log.fine("Round keys:"); + for (i = 0; i < ROUND_SUBKEYS + 2 * ROUNDS; i += 2) + log.fine("0x" + Util.toString(subKeys[i]) + + " 0x" + Util.toString(subKeys[i + 1])); + } + 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 (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("CT=" + Util.toString(out, outOffset - 15, 16) + "\n"); + } + + 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 (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("PT=" + Util.toString(out, outOffset - 15, 16) + "\n"); + } + + public boolean selfTest() + { + if (valid == null) + { + boolean result = super.selfTest(); // do symmetry tests + if (result) + result = testKat(KAT_KEY, KAT_CT); + valid = Boolean.valueOf(result); + } + return valid.booleanValue(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/cipher/WeakKeyException.java b/libjava/classpath/gnu/javax/crypto/cipher/WeakKeyException.java new file mode 100644 index 000000000..e12f899e4 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/cipher/WeakKeyException.java @@ -0,0 +1,59 @@ +/* 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 +{ + public WeakKeyException() + { + super(); + } + + public WeakKeyException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/DiffieHellmanImpl.java b/libjava/classpath/gnu/javax/crypto/jce/DiffieHellmanImpl.java new file mode 100644 index 000000000..205b5ed57 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/DiffieHellmanImpl.java @@ -0,0 +1,171 @@ +/* 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.ShortBufferException; +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 byte[] 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())) + throw new InvalidKeyException("Incompatible key"); + if (! lastPhase) + throw new IllegalArgumentException( + "This key-agreement MUST be concluded in one step only"); + BigInteger resultBI = pub.getY().modPow(key.getX(), s1.getP()); + result = resultBI.toByteArray(); + if (result[0] == 0x00) + { + byte[] buf = new byte[result.length - 1]; + System.arraycopy(result, 1, buf, 0, buf.length); + result = buf; + } + last_phase_done = true; + return null; + } + + protected byte[] engineGenerateSecret() + { + checkState(); + byte[] res = (byte[]) result.clone(); + reset(); + return res; + } + + protected int engineGenerateSecret(byte[] secret, int offset) + throws ShortBufferException + { + checkState(); + if (result.length > secret.length - offset) + throw new ShortBufferException(); + System.arraycopy(result, 0, secret, offset, result.length); + int res = result.length; + reset(); + return res; + } + + protected SecretKey engineGenerateSecret(String algorithm) + throws InvalidKeyException + { + checkState(); + byte[] s = (byte[]) result.clone(); + SecretKey res = new SecretKeySpec(s, algorithm); + reset(); + return res; + } + + 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; + reset(); + } + + protected void engineInit(Key key, AlgorithmParameterSpec params, + SecureRandom random) + throws InvalidKeyException + { + engineInit(key, random); + } + + private void reset() + { + result = null; + last_phase_done = false; + } + + private void checkState() + { + if (result == null || ! last_phase_done) + throw new IllegalStateException("Not finished"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/GnuCrypto.java b/libjava/classpath/gnu/javax/crypto/jce/GnuCrypto.java new file mode 100644 index 000000000..ec335b735 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/GnuCrypto.java @@ -0,0 +1,598 @@ +/* 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 additional GNU algorithm implementation as a Java Cryptographic Extension + * (JCE) Provider. + * + * @see java.security.Provider + */ +public final class GnuCrypto + extends 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()); + + // Key Wrapping Algorithm cipher + put("Cipher." + Registry.AES128_KWA, + gnu.javax.crypto.jce.cipher.AES128KeyWrapSpi.class.getName()); + put("Cipher." + Registry.AES192_KWA, + gnu.javax.crypto.jce.cipher.AES192KeyWrapSpi.class.getName()); + put("Cipher." + Registry.AES256_KWA, + gnu.javax.crypto.jce.cipher.AES256KeyWrapSpi.class.getName()); + put("Cipher." + Registry.TRIPLEDES_KWA, + gnu.javax.crypto.jce.cipher.TripleDESKeyWrapSpi.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()); + put("Alg.Alias.AlgorithmParameters.Anubis", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.Blowfish", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.Cast5", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.DES", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.Khazad", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.Rijndael", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.AES", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.Serpent", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.Square", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.TripleDES", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.DESede", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.3-DES", "BlockCipherParameters"); + put("Alg.Alias.AlgorithmParameters.3DES", "BlockCipherParameters"); + + // 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; + } + }); + } + + /** + * 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(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/GnuSasl.java b/libjava/classpath/gnu/javax/crypto/jce/GnuSasl.java new file mode 100644 index 000000000..6ab89e2fa --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/GnuSasl.java @@ -0,0 +1,124 @@ +/* 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 +{ + public GnuSasl() + { + super(Registry.GNU_SASL, 2.1, "GNU 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/libjava/classpath/gnu/javax/crypto/jce/PBKDF2SecretKeyFactory.java b/libjava/classpath/gnu/javax/crypto/jce/PBKDF2SecretKeyFactory.java new file mode 100644 index 000000000..cda8f34e8 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/PBKDF2SecretKeyFactory.java @@ -0,0 +1,218 @@ +/* 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 +{ + protected String macName; + private static final int DEFAULT_ITERATION_COUNT = 1000; + private static final int DEFAULT_KEY_LEN = 32; + + protected PBKDF2SecretKeyFactory(String macName) + { + this.macName = macName; + } + + 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, Integer.valueOf(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()); + } + + 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"); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/AES128KeyWrapSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/AES128KeyWrapSpi.java new file mode 100644 index 000000000..14ce480ae --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/AES128KeyWrapSpi.java @@ -0,0 +1,54 @@ +/* AESKeyWrapSpi.java -- AES (128-bit key) Key Wrapping Algorithm 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.cipher; + +import gnu.java.security.Registry; + +/** + * The JCE Cipher Adapter implementation over the GNU AES Key Wrapping + * Algorithm with a 128-bit key-size. + */ +public final class AES128KeyWrapSpi + extends AESKeyWrapSpi +{ + public AES128KeyWrapSpi() + { + super(Registry.AES128_KWA, 128 / 8, Registry.ECB_MODE); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/AES192KeyWrapSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/AES192KeyWrapSpi.java new file mode 100644 index 000000000..784fc5a15 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/AES192KeyWrapSpi.java @@ -0,0 +1,54 @@ +/* AES192KeyWrapSpi.java -- AES (192-bit key) Key Wrapping Algorithm 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.cipher; + +import gnu.java.security.Registry; + +/** + * The JCE Cipher Adapter implementation over the GNU AES Key Wrapping + * Algorithm with a 192-bit key-size. + */ +public final class AES192KeyWrapSpi + extends AESKeyWrapSpi +{ + public AES192KeyWrapSpi() + { + super(Registry.AES192_KWA, 192 / 8, Registry.ECB_MODE); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/AES256KeyWrapSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/AES256KeyWrapSpi.java new file mode 100644 index 000000000..dd7357b0e --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/AES256KeyWrapSpi.java @@ -0,0 +1,54 @@ +/* AES256KeyWrapSpi.java -- AES (256-bit key) Key Wrapping Algorithm 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.cipher; + +import gnu.java.security.Registry; + +/** + * The JCE Cipher Adapter implementation over the GNU AES Key Wrapping + * Algorithm with a 256-bit key-size. + */ +public final class AES256KeyWrapSpi + extends AESKeyWrapSpi +{ + public AES256KeyWrapSpi() + { + super(Registry.AES256_KWA, 256 / 8, Registry.ECB_MODE); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/AESKeyWrapSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/AESKeyWrapSpi.java new file mode 100644 index 000000000..08f4e7820 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/AESKeyWrapSpi.java @@ -0,0 +1,88 @@ +/* AESKeyWrapSpi.java -- Common AES Key Wrapping Algorithm 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.javax.crypto.jce.cipher; + +/** + * Base abstract class to group common AES Key Wrapping Algorithm Adapter + * methods. + */ +abstract class AESKeyWrapSpi + extends KeyWrappingAlgorithmAdapter +{ + protected AESKeyWrapSpi(String name, int keySize, String supportedMode) + { + super(name, 16, keySize, supportedMode); + } + + /** + * AES Key Wrapping algorithms operate on an 8-byte block; a block half the + * size of the AES block itself. + *

    + * In wrapping, the number of 8-byte output blocks is ALWAYS one block longer + * than the input. + * + * @param inputLength the size of the plain text. + * @return the size in bytes of n + 1 8-byte blocks where + * n is the smallest number of 8-byte blocks that contain the + * designated number of input bytes. + */ + protected int getOutputSizeForWrap(int inputLength) + { + int n = (inputLength + 7) / 8; + return 8 * (n + 1); + } + + /** + * AES Key Wrapping algorithms operate on an 8-byte block; a block half the + * size of the AES block itself. + *

    + * In unwrapping, the number of 8-byte output blocks is ALWAYS one block + * shorter than the input. + * + * @param inputLength the size of the cipher text. + * @return the size in bytes of n - 1 8-byte blocks where + * n is the smallest number of 8-byte blocks that contain the + * designated number of input bytes. + */ + protected int getOutputSizeForUnwrap(int inputLength) + { + int n = (inputLength + 7) / 8; + return 8 * (n - 1); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/AESSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/AESSpi.java new file mode 100644 index 000000000..4c3e1aecc --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/AESSpi.java @@ -0,0 +1,92 @@ +/* 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. + */ +public final class AESSpi + extends CipherAdapter +{ + public AESSpi() + { + super(Registry.AES_CIPHER, 16); + } + + 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); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/ARCFourSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/ARCFourSpi.java new file mode 100644 index 000000000..2e1422e6b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/ARCFourSpi.java @@ -0,0 +1,183 @@ +/* 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. + */ +public class ARCFourSpi + extends CipherSpi +{ + private IRandom keystream; + + public ARCFourSpi() + { + super(); + keystream = PRNGFactory.getInstance(Registry.ARCFOUR_PRNG); + } + + 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); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/AnubisSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/AnubisSpi.java new file mode 100644 index 000000000..ab0c64867 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/AnubisSpi.java @@ -0,0 +1,54 @@ +/* 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. + */ +public final class AnubisSpi + extends CipherAdapter +{ + public AnubisSpi() + { + super(Registry.ANUBIS_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/BlowfishSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/BlowfishSpi.java new file mode 100644 index 000000000..55d71dbf5 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/BlowfishSpi.java @@ -0,0 +1,54 @@ +/* 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. + */ +public final class BlowfishSpi + extends CipherAdapter +{ + public BlowfishSpi() + { + super(Registry.BLOWFISH_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/Cast5Spi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/Cast5Spi.java new file mode 100644 index 000000000..95a663e2f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/Cast5Spi.java @@ -0,0 +1,54 @@ +/* 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. + */ +public class Cast5Spi + extends CipherAdapter +{ + public Cast5Spi() + { + super(Registry.CAST5_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/CipherAdapter.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/CipherAdapter.java new file mode 100644 index 000000000..0871c5402 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/CipherAdapter.java @@ -0,0 +1,531 @@ +/* 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.java.security.Registry; +import gnu.javax.crypto.cipher.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; +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.Iterator; +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 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. + */ +class CipherAdapter + extends CipherSpi +{ + /** 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; + + /** + * Protected constructor to be called by subclasses. The cipher name argument + * should be the appropriate one listed in {@link Registry}. The basic cipher + * instance is created, along with an instance of the + * {@link gnu.javax.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, Integer.valueOf(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, Integer.valueOf(blockLen)); + } + + 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, Integer.valueOf(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() + { + byte[] iv = (byte[]) attributes.get(IMode.IV); + int cipherBlockSize = cipher.currentBlockSize(); + BlockCipherParameterSpec spec = new BlockCipherParameterSpec(iv, + cipherBlockSize, + 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 + { + try + { + engineInit(opmode, key, (AlgorithmParameterSpec) null, random); + } + catch (InvalidAlgorithmParameterException e) + { + throw new InvalidKeyException(e.getMessage(), e); + } + } + + /** + * Executes initialization logic after all parameters have been handled by the + * engineInit()s. + * + * @param opmode the desired mode of operation for this instance. + * @param key the key material to use for initialization. + * @param random a source of randmoness to use if/when needed. + * @throws InvalidKeyException if key is invalid or the cipher + * needs extra parameters which can not be derived from + * key; e.g. an IV. + */ + private void engineInitHandler(int opmode, Key key, SecureRandom random) + throws InvalidKeyException + { + switch (opmode) + { + case Cipher.ENCRYPT_MODE: + attributes.put(IMode.STATE, Integer.valueOf(IMode.ENCRYPTION)); + break; + case Cipher.DECRYPT_MODE: + attributes.put(IMode.STATE, Integer.valueOf(IMode.DECRYPTION)); + break; + } + if (! key.getFormat().equalsIgnoreCase("RAW")) + throw new InvalidKeyException("bad key format " + key.getFormat()); + byte[] kb = key.getEncoded(); + int kbLength = kb.length; + if (keyLen == 0) + { + // no key-size given; instead key-material is provided in kb --which + // can be more than what we need. if we don't cull this down to what + // the cipher likes/wants we may get an InvalidKeyException. + // + // try to find the largest key-size value that is less than or equal + // to kbLength + for (Iterator it = cipher.keySizes(); it.hasNext();) + { + int aKeySize = ((Integer) it.next()).intValue(); + if (aKeySize == kbLength) + { + keyLen = aKeySize; + break; + } + else if (aKeySize < kbLength) + keyLen = aKeySize; + else // all remaining key-sizes are longer than kb.length + break; + } + } + if (keyLen == 0) + { + // we were unable to find a key-size, among those advertised by the + // cipher, that is less than or equal to the length of the kb array. + // set keyLen to kbLength. either the cipher implementation will throw + // an InvalidKeyException, or it is implemented in a way which can deal + // with an unsupported key-size. + keyLen = kbLength; + } + if (keyLen < kbLength) + { + 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) + { + // All cipher modes require parameters (like an IV) except ECB. When + // these cant be derived from the given key then it must be generated + // randomly if in ENCRYPT or WRAP mode. Parameters that have defaults + // for our cipher must be set to these defaults. + if (! mode.name().toLowerCase().startsWith(Registry.ECB_MODE + "(")) + { + switch (opmode) + { + case Cipher.ENCRYPT_MODE: + case Cipher.WRAP_MODE: + byte[] iv = new byte[blockLen]; + random.nextBytes(iv); + attributes.put(IMode.IV, iv); + break; + default: + throw new InvalidAlgorithmParameterException( + "Required algorithm parameters are missing for mode: " + + mode.name()); + } + } + // Add default for block length etc. + blockLen = cipher.defaultBlockSize(); + attributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, + Integer.valueOf(blockLen)); + keyLen = 0; + } + else if (params instanceof BlockCipherParameterSpec) + { + BlockCipherParameterSpec bcps = (BlockCipherParameterSpec) params; + blockLen = bcps.getBlockSize(); + attributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, Integer.valueOf(blockLen)); + attributes.put(IMode.IV, bcps.getIV()); + keyLen = bcps.getKeySize(); + } + else if (params instanceof IvParameterSpec) + { + // The size of the IV must match the block size + if (((IvParameterSpec) params).getIV().length != cipher.defaultBlockSize()) + { + throw new InvalidAlgorithmParameterException(); + } + + attributes.put(IMode.IV, ((IvParameterSpec) params).getIV()); + blockLen = cipher.defaultBlockSize(); + attributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, Integer.valueOf(blockLen)); + keyLen = 0; + } + engineInitHandler(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 inOff, int inLen) + { + if (inLen == 0) // nothing to process + return new byte[0]; + final int blockSize = mode.currentBlockSize(); + int blockCount = (partLen + inLen) / blockSize; + + // always keep data for unpadding in padded decryption mode; + // might even be a complete block + if (pad != null + && ((Integer) attributes.get(IMode.STATE)).intValue() == IMode.DECRYPTION + && (partLen + inLen) % blockSize == 0) + blockCount--; + + final byte[] out = new byte[blockCount * blockSize]; + try + { + engineUpdate(input, inOff, inLen, 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 + { + if (inLen == 0) // nothing to process + return 0; + final int blockSize = mode.currentBlockSize(); + int blockCount = (partLen + inLen) / blockSize; + + // always keep data for unpadding in padded decryption mode; + // might even be a complete block + if (pad != null + && ((Integer) attributes.get(IMode.STATE)).intValue() == IMode.DECRYPTION + && (partLen + inLen) % blockSize == 0) + blockCount--; + + 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; + byte[] buf3 = new byte[buf.length + partLen]; + try + { + if (partLen != mode.currentBlockSize()) + throw new WrongPaddingException(); + System.arraycopy(buf, 0, buf3, 0, buf.length); + mode.update(partBlock, 0, buf3, buf.length); + padLen = pad.unpad(buf3, 0, buf3.length); + } + catch (WrongPaddingException wpe) + { + throw new BadPaddingException(wpe.getMessage()); + } + result = new byte[buf3.length - padLen]; + System.arraycopy(buf3, 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; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/DESSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/DESSpi.java new file mode 100644 index 000000000..0da913a44 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/DESSpi.java @@ -0,0 +1,54 @@ +/* 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. + */ +public final class DESSpi + extends CipherAdapter +{ + public DESSpi() + { + super(Registry.DES_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/KeyWrappingAlgorithmAdapter.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/KeyWrappingAlgorithmAdapter.java new file mode 100644 index 000000000..97fdd5331 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/KeyWrappingAlgorithmAdapter.java @@ -0,0 +1,423 @@ +/* KeyWrappingAlgorithmAdapter.java -- Base Adapter for Key Wrapping algorithms + 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.cipher; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.javax.crypto.jce.spec.BlockCipherParameterSpec; +import gnu.javax.crypto.kwa.IKeyWrappingAlgorithm; +import gnu.javax.crypto.kwa.KeyUnwrappingException; +import gnu.javax.crypto.kwa.KeyWrappingAlgorithmFactory; + +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.InvalidParameterSpecException; +import java.security.spec.X509EncodedKeySpec; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Logger; + +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; +import javax.crypto.spec.SecretKeySpec; + +/** + * An abstract base class to facilitate implementations of JCE Adapters for + * symmetric key block ciphers capable of providing key-wrapping functionality. + */ +abstract class KeyWrappingAlgorithmAdapter + extends CipherSpi +{ + private static final Logger log = Logger.getLogger(KeyWrappingAlgorithmAdapter.class.getName()); + /** JCE canonical name of a null-padder. */ + private static final String NO_PADDING = "nopadding"; + /** Concrete Key Wrapping Algorithm SPI. */ + protected IKeyWrappingAlgorithm kwAlgorithm; + /** Size in bytes of the padding block to be provided by external padders. */ + protected int kwaBlockSize; + /** KEK size in bytes. */ + protected int kwaKeySize; + /** Name of the supported mode. */ + protected String supportedMode; + /** Operational mode in which this instance was initialised. */ + protected int opmode = -1; + /** Initialisation Vector if/when user wants to override default one. */ + byte[] iv; + + /** + * Creates a new JCE Adapter for the designated Key Wrapping Algorithm name. + * + * @param name the canonical name of the key-wrapping algorithm. + * @param blockSize the block size in bytes of the underlying symmetric-key + * block cipher algorithm. + * @param keySize the allowed size in bytes of the KEK bytes to initialise the + * underlying symmetric-key block cipher algorithm with. + * @param supportedMode canonical name of the block mode the underlying cipher + * is supporting. + */ + protected KeyWrappingAlgorithmAdapter(String name, int blockSize, int keySize, + String supportedMode) + { + super(); + + this.kwAlgorithm = KeyWrappingAlgorithmFactory.getInstance(name); + this.kwaBlockSize = blockSize; + this.kwaKeySize = keySize; + this.supportedMode = supportedMode; + } + + /** + * Wraps the encoded form of a designated {@link Key}. + * + * @param key the key-material to wrap. + * @return the wrapped key. + * @throws InvalidKeyException If the key cannot be wrapped. + */ + protected byte[] engineWrap(Key key) + throws InvalidKeyException, IllegalBlockSizeException + { + byte[] keyMaterial = key.getEncoded(); + byte[] result = kwAlgorithm.wrap(keyMaterial, 0, keyMaterial.length); + return result; + } + + /** + * Unwraps a previously-wrapped key-material. + * + * @param wrappedKey the wrapped key-material to unwrap. + * @param wrappedKeyAlgorithm the canonical name of the algorithm, which the + * unwrapped key-material represents. This name is used to + * instantiate a concrete instance of a {@link Key} for that + * algorithm. For example, if the value of this parameter is + * DSS and the type (the next parameter) is + * {@link Cipher#PUBLIC_KEY} then an attempt to construct a concrete + * instance of a {@link java.security.interfaces.DSAPublicKey}, + * using the unwrapped key material, shall be made. + * @param wrappedKeyType the type of wrapped key-material. MUST be one of + * {@link Cipher#PRIVATE_KEY}, {@link Cipher#PUBLIC_KEY}, or + * {@link Cipher#SECRET_KEY}. + * @return the unwrapped key-material as an instance of {@link Key} or one of + * its subclasses. + * @throws InvalidKeyException If the key cannot be unwrapped, or if + * wrappedKeyType is an inappropriate type for the + * unwrapped key. + * @throws NoSuchAlgorithmException If the wrappedKeyAlgorithm + * is unknown to every currently installed Security Provider. + */ + protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, + int wrappedKeyType) + throws InvalidKeyException, NoSuchAlgorithmException + { + byte[] keyBytes; + try + { + keyBytes = kwAlgorithm.unwrap(wrappedKey, 0, wrappedKey.length); + } + catch (KeyUnwrappingException x) + { + InvalidKeyException y = new InvalidKeyException("engineUnwrap()"); + y.initCause(x); + throw y; + } + Key result; + switch (wrappedKeyType) + { + case Cipher.SECRET_KEY: + result = new SecretKeySpec(keyBytes, wrappedKeyAlgorithm); + break; + case Cipher.PRIVATE_KEY: + case Cipher.PUBLIC_KEY: + X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance(wrappedKeyAlgorithm); + try + { + if (wrappedKeyType == Cipher.PRIVATE_KEY) + result = keyFactory.generatePrivate(keySpec); + else + result = keyFactory.generatePublic(keySpec); + } + catch (InvalidKeySpecException x) + { + InvalidKeyException y = new InvalidKeyException("engineUnwrap()"); + y.initCause(x); + throw y; + } + break; + default: + IllegalArgumentException x = new IllegalArgumentException("Invalid 'wrappedKeyType': " + + wrappedKeyType); + InvalidKeyException y = new InvalidKeyException("engineUnwrap()"); + y.initCause(x); + throw y; + } + return result; + } + + protected int engineGetBlockSize() + { + return kwaBlockSize; + } + + protected byte[] engineGetIV() + { + return iv == null ? null : (byte[]) iv.clone(); + } + + protected int engineGetOutputSize(int inputLength) + { + switch (opmode) + { + case Cipher.WRAP_MODE: + return getOutputSizeForWrap(inputLength); + case Cipher.UNWRAP_MODE: + return getOutputSizeForUnwrap(inputLength); + default: + throw new IllegalStateException(); + } + } + + protected AlgorithmParameters engineGetParameters() + { + BlockCipherParameterSpec spec = new BlockCipherParameterSpec(iv, + kwaBlockSize, + kwaKeySize); + AlgorithmParameters result = null; + try + { + result = AlgorithmParameters.getInstance("BlockCipherParameters"); + result.init(spec); + } + catch (NoSuchAlgorithmException x) + { + if (Configuration.DEBUG) + log.fine("Unable to find BlockCipherParameters. Return null"); + } + catch (InvalidParameterSpecException x) + { + if (Configuration.DEBUG) + log.fine("Unable to initialise BlockCipherParameters. Return null"); + } + return result; + } + + protected void engineInit(int opmode, Key key, SecureRandom random) + throws InvalidKeyException + { + checkOpMode(opmode); + byte[] kekBytes = checkAndGetKekBytes(key); + initAlgorithm(opmode, kekBytes, null, random); + } + + protected void engineInit(int opmode, Key key, AlgorithmParameters params, + SecureRandom random) + throws InvalidAlgorithmParameterException, InvalidKeyException + { + AlgorithmParameterSpec spec = null; + try + { + if (params != null) + spec = params.getParameterSpec(BlockCipherParameterSpec.class); + } + catch (InvalidParameterSpecException x) + { + if (Configuration.DEBUG) + log.fine("Unable to translate algorithm parameters into an instance " + + "of BlockCipherParameterSpec. Discard"); + } + engineInit(opmode, key, spec, random); + } + + protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, + SecureRandom random) + throws InvalidAlgorithmParameterException, InvalidKeyException + { + checkOpMode(opmode); + byte[] kekBytes = checkAndGetKekBytes(key); + byte[] ivBytes = null; + if (params instanceof BlockCipherParameterSpec) + ivBytes = ((BlockCipherParameterSpec) params).getIV(); + else if (params instanceof IvParameterSpec) + ivBytes = ((IvParameterSpec) params).getIV(); + + initAlgorithm(opmode, kekBytes, ivBytes, random); + } + + protected void engineSetMode(String mode) throws NoSuchAlgorithmException + { + if (! supportedMode.equalsIgnoreCase(mode)) + throw new UnsupportedOperationException("Only " + supportedMode + + " is supported"); + } + + /** + * NoPadding is the only padding algorithm supported by Key Wrapping Algorithm + * implementations in RI. + */ + protected void engineSetPadding(String padding) throws NoSuchPaddingException + { + if (! NO_PADDING.equalsIgnoreCase(padding)) + throw new UnsupportedOperationException("Only NoPadding is supported"); + } + + protected byte[] engineUpdate(byte[] input, int inputOffset, int inputLength) + { + throw new UnsupportedOperationException(); + } + + protected int engineUpdate(byte[] input, int inputOffset, int inputLength, + byte[] output, int outputOffset) + throws ShortBufferException + { + throw new UnsupportedOperationException(); + } + + protected byte[] engineDoFinal(byte[] input, int inputOffset, int inputLength) + throws IllegalBlockSizeException, BadPaddingException + { + throw new UnsupportedOperationException(); + } + + protected int engineDoFinal(byte[] input, int inputOffset, int inputLength, + byte[] output, int outputOffset) + throws IllegalBlockSizeException, BadPaddingException, ShortBufferException + { + throw new UnsupportedOperationException(); + } + + /** + * Return the minimum size in bytes of a place holder large enough to receive + * the cipher text resulting from a wrap method with the designated size of + * the plain text. + *

    + * This default implementation ALWAYS returns the smallest multiple of the + * kwaBlockSize --passed to this method through its + * constructor-- greater than or equal to the designated + * inputLength. + * + * @param inputLength the size of a plain text. + * @return an estimate of the size, in bytes, of the place holder to receive + * the resulting bytes of a wrap method. + */ + protected int getOutputSizeForWrap(int inputLength) + { + return kwaBlockSize * (inputLength + kwaBlockSize - 1) / kwaBlockSize; + } + + /** + * Return the minimum size in bytes of a place holder large enough to receive + * the plain text resulting from an unwrap method with the designated size of + * the cipher text. + *

    + * This default implementation ALWAYS returns the smallest multiple of the + * paddingBlockSize --passed to this method through its + * constructor-- greater than or equal to the designated + * inputLength. + * + * @param inputLength the size of a cipher text. + * @return an estimate of the size, in bytes, of the place holder to receive + * the resulting bytes of an uwrap method. + */ + protected int getOutputSizeForUnwrap(int inputLength) + { + return kwaBlockSize * (inputLength + kwaBlockSize - 1) / kwaBlockSize; + } + + private void checkOpMode(int opmode) + { + switch (opmode) + { + case Cipher.WRAP_MODE: + case Cipher.UNWRAP_MODE: + return; + } + throw new IllegalArgumentException("Unsupported operational mode: " + opmode); + } + + /** + * Returns the key bytes, iff it was in RAW format. + * + * @param key the opaque JCE secret key to use as the KEK. + * @return the bytes of the encoded form of the designated kek, iff it was in + * RAW format. + * @throws InvalidKeyException if the designated key is not in the RAW format. + */ + private byte[] checkAndGetKekBytes(Key key) throws InvalidKeyException + { + if (! Registry.RAW_ENCODING_SHORT_NAME.equalsIgnoreCase(key.getFormat())) + throw new InvalidKeyException("Only RAW key format is supported"); + byte[] result = key.getEncoded(); + int kekSize = result.length; + if (kekSize != kwaKeySize) + throw new InvalidKeyException("Invalid key material size. Expected " + + kwaKeySize + " but found " + kekSize); + return result; + } + + private void initAlgorithm(int opmode, byte[] kek, byte[] ivBytes, + SecureRandom rnd) + throws InvalidKeyException + { + this.opmode = opmode; + Map attributes = new HashMap(); + attributes.put(IKeyWrappingAlgorithm.KEY_ENCRYPTION_KEY_MATERIAL, kek); + if (ivBytes != null) + { + this.iv = (byte[]) ivBytes.clone(); + attributes.put(IKeyWrappingAlgorithm.INITIAL_VALUE, this.iv); + } + else + this.iv = null; + if (rnd != null) + attributes.put(IKeyWrappingAlgorithm.SOURCE_OF_RANDOMNESS, rnd); + + kwAlgorithm.init(attributes); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/KhazadSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/KhazadSpi.java new file mode 100644 index 000000000..df0833fb5 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/KhazadSpi.java @@ -0,0 +1,54 @@ +/* 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. + */ +public final class KhazadSpi + extends CipherAdapter +{ + public KhazadSpi() + { + super(Registry.KHAZAD_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/NullCipherSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/NullCipherSpi.java new file mode 100644 index 000000000..70ff575da --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/NullCipherSpi.java @@ -0,0 +1,54 @@ +/* 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. + */ +public final class NullCipherSpi + extends CipherAdapter +{ + public NullCipherSpi() + { + super(Registry.NULL_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/PBES2.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/PBES2.java new file mode 100644 index 000000000..9961c15b1 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/PBES2.java @@ -0,0 +1,1379 @@ +/* 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; + +/** + */ +public abstract class PBES2 + extends CipherAdapter +{ + /** The HMac (PRF) algorithm name. */ + protected String macName; + + 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; + } + + 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, Integer.valueOf(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(String.valueOf(shouldNotHappen)); + } + return new SecretKeySpec(dk, cipher.name()); + } + + public static class HMacSHA1 + extends PBES2 + { + public HMacSHA1(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-SHA1"); + } + + public HMacSHA1(String cipher) + { + super(cipher, "HMAC-SHA1"); + } + + 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 + { + public HMacMD5(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-MD5"); + } + + public HMacMD5(String cipher) + { + super(cipher, "HMAC-MD5"); + } + + 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 + { + public HMacMD2(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-MD2"); + } + + public HMacMD2(String cipher) + { + super(cipher, "HMAC-MD2"); + } + + 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 + { + public HMacMD4(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-MD4"); + } + + public HMacMD4(String cipher) + { + super(cipher, "HMAC-MD4"); + } + + 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 + { + public HMacHaval(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-HAVAL"); + } + + public HMacHaval(String cipher) + { + super(cipher, "HMAC-HAVAL"); + } + + 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 + { + public HMacRipeMD128(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-RIPEMD128"); + } + + public HMacRipeMD128(String cipher) + { + super(cipher, "HMAC-RIPEMD128"); + } + + 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 + { + public HMacRipeMD160(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-RIPEMD160"); + } + + public HMacRipeMD160(String cipher) + { + super(cipher, "HMAC-RIPEMD160"); + } + + 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 + { + public HMacSHA256(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-SHA-256"); + } + + public HMacSHA256(String cipher) + { + super(cipher, "HMAC-SHA-256"); + } + + 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 + { + public HMacSHA384(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-SHA-384"); + } + + public HMacSHA384(String cipher) + { + super(cipher, "HMAC-SHA-384"); + } + + 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 + { + public HMacSHA512(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-SHA-512"); + } + + public HMacSHA512(String cipher) + { + super(cipher, "HMAC-SHA-512"); + } + + 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 + { + public HMacTiger(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-TIGER"); + } + + public HMacTiger(String cipher) + { + super(cipher, "HMAC-TIGER"); + } + + 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 + { + public HMacWhirlpool(String cipher, int blockLen) + { + super(cipher, blockLen, "HMAC-WHIRLPOOL"); + } + + public HMacWhirlpool(String cipher) + { + super(cipher, "HMAC-WHIRLPOOL"); + } + + 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"); + } + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/RijndaelSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/RijndaelSpi.java new file mode 100644 index 000000000..f25aca028 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/RijndaelSpi.java @@ -0,0 +1,54 @@ +/* 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. + */ +public final class RijndaelSpi + extends CipherAdapter +{ + public RijndaelSpi() + { + super(Registry.RIJNDAEL_CIPHER, 16); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/SerpentSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/SerpentSpi.java new file mode 100644 index 000000000..1f17b18c8 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/SerpentSpi.java @@ -0,0 +1,54 @@ +/* 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. + */ +public final class SerpentSpi + extends CipherAdapter +{ + public SerpentSpi() + { + super(Registry.SERPENT_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/SquareSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/SquareSpi.java new file mode 100644 index 000000000..d08aa2cd3 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/SquareSpi.java @@ -0,0 +1,54 @@ +/* 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. + */ +public final class SquareSpi + extends CipherAdapter +{ + public SquareSpi() + { + super(Registry.SQUARE_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/TripleDESKeyWrapSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/TripleDESKeyWrapSpi.java new file mode 100644 index 000000000..55087755e --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/TripleDESKeyWrapSpi.java @@ -0,0 +1,54 @@ +/* TripleDESKeyWrapSpi.java -- DES-EDE Key Wrapping Algorithm 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.cipher; + +import gnu.java.security.Registry; + +/** + * The JCE Cipher Adapter implementation over the GNU TripleDES Key Wrapping + * Algorithm. + */ +public final class TripleDESKeyWrapSpi + extends KeyWrappingAlgorithmAdapter +{ + public TripleDESKeyWrapSpi() + { + super(Registry.TRIPLEDES_KWA, 8, 192 / 8, Registry.CBC_MODE); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/TripleDESSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/TripleDESSpi.java new file mode 100644 index 000000000..c22409020 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/TripleDESSpi.java @@ -0,0 +1,54 @@ +/* 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. + */ +public final class TripleDESSpi + extends CipherAdapter +{ + public TripleDESSpi() + { + super(Registry.TRIPLEDES_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/cipher/TwofishSpi.java b/libjava/classpath/gnu/javax/crypto/jce/cipher/TwofishSpi.java new file mode 100644 index 000000000..a1bbe4b71 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/cipher/TwofishSpi.java @@ -0,0 +1,54 @@ +/* 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. + */ +public final class TwofishSpi + extends CipherAdapter +{ + public TwofishSpi() + { + super(Registry.TWOFISH_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/AnubisKeyGeneratorImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/AnubisKeyGeneratorImpl.java new file mode 100644 index 000000000..a1cc8fd7f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/AnubisKeyGeneratorImpl.java @@ -0,0 +1,50 @@ +/* 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 +{ + public AnubisKeyGeneratorImpl() + { + super(Registry.ANUBIS_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/AnubisSecretKeyFactoryImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/AnubisSecretKeyFactoryImpl.java new file mode 100644 index 000000000..dc99b332b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/AnubisSecretKeyFactoryImpl.java @@ -0,0 +1,47 @@ +/* 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; + +public class AnubisSecretKeyFactoryImpl + extends SecretKeyFactoryImpl +{ + public AnubisSecretKeyFactoryImpl() + { + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/BlowfishKeyGeneratorImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/BlowfishKeyGeneratorImpl.java new file mode 100644 index 000000000..2297980fb --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/BlowfishKeyGeneratorImpl.java @@ -0,0 +1,50 @@ +/* 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 +{ + public BlowfishKeyGeneratorImpl() + { + super(Registry.BLOWFISH_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/BlowfishSecretKeyFactoryImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/BlowfishSecretKeyFactoryImpl.java new file mode 100644 index 000000000..8d964bb96 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/BlowfishSecretKeyFactoryImpl.java @@ -0,0 +1,47 @@ +/* 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; + +public class BlowfishSecretKeyFactoryImpl + extends SecretKeyFactoryImpl +{ + public BlowfishSecretKeyFactoryImpl() + { + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/Cast5KeyGeneratorImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/Cast5KeyGeneratorImpl.java new file mode 100644 index 000000000..b328e48b3 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/Cast5KeyGeneratorImpl.java @@ -0,0 +1,50 @@ +/* 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 +{ + public Cast5KeyGeneratorImpl() + { + super(Registry.CAST5_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/Cast5SecretKeyFactoryImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/Cast5SecretKeyFactoryImpl.java new file mode 100644 index 000000000..f2681eda1 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/Cast5SecretKeyFactoryImpl.java @@ -0,0 +1,47 @@ +/* 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; + +public class Cast5SecretKeyFactoryImpl + extends SecretKeyFactoryImpl +{ + public Cast5SecretKeyFactoryImpl() + { + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/DESKeyGeneratorImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/DESKeyGeneratorImpl.java new file mode 100644 index 000000000..2cd29a67f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/DESKeyGeneratorImpl.java @@ -0,0 +1,68 @@ +/* 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 +{ + public DESKeyGeneratorImpl() + { + super(Registry.DES_CIPHER); + } + + 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/libjava/classpath/gnu/javax/crypto/jce/key/DESSecretKeyFactoryImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/DESSecretKeyFactoryImpl.java new file mode 100644 index 000000000..a138e2902 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/DESSecretKeyFactoryImpl.java @@ -0,0 +1,82 @@ +/* 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/libjava/classpath/gnu/javax/crypto/jce/key/DESedeSecretKeyFactoryImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/DESedeSecretKeyFactoryImpl.java new file mode 100644 index 000000000..f380603e4 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/DESedeSecretKeyFactoryImpl.java @@ -0,0 +1,82 @@ +/* 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/libjava/classpath/gnu/javax/crypto/jce/key/KhazadKeyGeneratorImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/KhazadKeyGeneratorImpl.java new file mode 100644 index 000000000..21ae627eb --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/KhazadKeyGeneratorImpl.java @@ -0,0 +1,50 @@ +/* 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 +{ + public KhazadKeyGeneratorImpl() + { + super(Registry.KHAZAD_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/KhazadSecretKeyFactoryImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/KhazadSecretKeyFactoryImpl.java new file mode 100644 index 000000000..19315d22e --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/KhazadSecretKeyFactoryImpl.java @@ -0,0 +1,47 @@ +/* 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; + +public class KhazadSecretKeyFactoryImpl + extends SecretKeyFactoryImpl +{ + public KhazadSecretKeyFactoryImpl() + { + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/RijndaelKeyGeneratorImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/RijndaelKeyGeneratorImpl.java new file mode 100644 index 000000000..b60f7d6d0 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/RijndaelKeyGeneratorImpl.java @@ -0,0 +1,50 @@ +/* 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 +{ + public RijndaelKeyGeneratorImpl() + { + super(Registry.RIJNDAEL_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/RijndaelSecretKeyFactoryImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/RijndaelSecretKeyFactoryImpl.java new file mode 100644 index 000000000..f88b07752 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/RijndaelSecretKeyFactoryImpl.java @@ -0,0 +1,47 @@ +/* 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; + +public class RijndaelSecretKeyFactoryImpl + extends SecretKeyFactoryImpl +{ + public RijndaelSecretKeyFactoryImpl() + { + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/SecretKeyFactoryImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/SecretKeyFactoryImpl.java new file mode 100644 index 000000000..4bba171f9 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/crypto/jce/key/SecretKeyGeneratorImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/SecretKeyGeneratorImpl.java new file mode 100644 index 000000000..d2acf8716 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/SecretKeyGeneratorImpl.java @@ -0,0 +1,111 @@ +/* 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 +{ + protected final int defaultKeySize; + protected final List keySizes; + protected final String algorithm; + protected boolean init; + protected int currentKeySize; + protected SecureRandom random; + + 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; + } + + 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(Integer.valueOf(keySize))) + throw new InvalidParameterException("unsupported key size: " + keySize + + ", valid sizes are: " + keySizes); + currentKeySize = keySize; + this.random = random; + init = true; + } + + protected void engineInit(SecureRandom random) + { + engineInit(defaultKeySize << 3, random); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/SerpentKeyGeneratorImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/SerpentKeyGeneratorImpl.java new file mode 100644 index 000000000..c53190514 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/SerpentKeyGeneratorImpl.java @@ -0,0 +1,50 @@ +/* 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 +{ + public SerpentKeyGeneratorImpl() + { + super(Registry.SERPENT_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/SerpentSecretKeyFactoryImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/SerpentSecretKeyFactoryImpl.java new file mode 100644 index 000000000..5d5ac88df --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/SerpentSecretKeyFactoryImpl.java @@ -0,0 +1,47 @@ +/* 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; + +public class SerpentSecretKeyFactoryImpl + extends SecretKeyFactoryImpl +{ + public SerpentSecretKeyFactoryImpl() + { + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/SquareKeyGeneratorImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/SquareKeyGeneratorImpl.java new file mode 100644 index 000000000..3d496e8a9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/SquareKeyGeneratorImpl.java @@ -0,0 +1,50 @@ +/* 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 +{ + public SquareKeyGeneratorImpl() + { + super(Registry.SQUARE_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/SquareSecretKeyFactoryImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/SquareSecretKeyFactoryImpl.java new file mode 100644 index 000000000..f35835912 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/SquareSecretKeyFactoryImpl.java @@ -0,0 +1,47 @@ +/* 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; + +public class SquareSecretKeyFactoryImpl + extends SecretKeyFactoryImpl +{ + public SquareSecretKeyFactoryImpl() + { + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/TripleDESKeyGeneratorImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/TripleDESKeyGeneratorImpl.java new file mode 100644 index 000000000..6fd557ccb --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/TripleDESKeyGeneratorImpl.java @@ -0,0 +1,50 @@ +/* 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 +{ + public TripleDESKeyGeneratorImpl() + { + super(Registry.TRIPLEDES_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/TwofishKeyGeneratorImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/TwofishKeyGeneratorImpl.java new file mode 100644 index 000000000..9dd5a8f30 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/TwofishKeyGeneratorImpl.java @@ -0,0 +1,50 @@ +/* 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 +{ + public TwofishKeyGeneratorImpl() + { + super(Registry.TWOFISH_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/key/TwofishSecretKeyFactoryImpl.java b/libjava/classpath/gnu/javax/crypto/jce/key/TwofishSecretKeyFactoryImpl.java new file mode 100644 index 000000000..0767d4cac --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/key/TwofishSecretKeyFactoryImpl.java @@ -0,0 +1,47 @@ +/* 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; + +public class TwofishSecretKeyFactoryImpl + extends SecretKeyFactoryImpl +{ + public TwofishSecretKeyFactoryImpl() + { + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/keyring/GnuKeyring.java b/libjava/classpath/gnu/javax/crypto/jce/keyring/GnuKeyring.java new file mode 100644 index 000000000..c30da69a2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/keyring/GnuKeyring.java @@ -0,0 +1,507 @@ +/* GnuKeyring.java -- KeyStore adapter for a pair of private and public Keyrings + 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 gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.javax.crypto.keyring.GnuPrivateKeyring; +import gnu.javax.crypto.keyring.GnuPublicKeyring; +import gnu.javax.crypto.keyring.IKeyring; +import gnu.javax.crypto.keyring.IPrivateKeyring; +import gnu.javax.crypto.keyring.IPublicKeyring; +import gnu.javax.crypto.keyring.MalformedKeyringException; +import gnu.javax.crypto.keyring.PrimitiveEntry; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.Key; +import java.security.KeyStoreException; +import java.security.KeyStoreSpi; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.util.Collections; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.logging.Logger; + +import javax.crypto.SecretKey; + +/** + * An Adapter over a pair of one private, and one public keyrings to + * emulate the keystore operations. + */ +public class GnuKeyring + extends KeyStoreSpi +{ + private static final Logger log = Logger.getLogger(GnuKeyring.class.getName()); + private static final String NOT_LOADED = "not loaded"; + + /** TRUE if the keystore is loaded; FALSE otherwise. */ + private boolean loaded; + /** our underlying private keyring. */ + private IPrivateKeyring privateKR; + /** our underlying public keyring. */ + private IPublicKeyring publicKR; + + // default 0-arguments constructor + + public Enumeration engineAliases() + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineAliases"); + ensureLoaded(); + Enumeration result; + if (privateKR == null) + result = Collections.enumeration(Collections.EMPTY_SET); + else + { + Set aliases = new HashSet(); + for (Enumeration e = privateKR.aliases(); e.hasMoreElements();) + { + String alias = (String) e.nextElement(); + if (alias != null) + { + alias = alias.trim(); + if (alias.length() > 0) + { + if (Configuration.DEBUG) + log.fine("Adding alias (from private keyring): " + alias); + aliases.add(alias); + } + } + } + for (Enumeration e = publicKR.aliases(); e.hasMoreElements();) + { + String alias = (String) e.nextElement(); + if (alias != null) + { + alias = alias.trim(); + if (alias.length() > 0) + { + if (Configuration.DEBUG) + log.fine("Adding alias (from public keyring): " + alias); + aliases.add(alias); + } + } + } + if (Configuration.DEBUG) + log.fine("Will enumerate: " + aliases); + result = Collections.enumeration(aliases); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineAliases"); + return result; + } + + public boolean engineContainsAlias(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineContainsAlias", alias); + ensureLoaded(); + boolean inPrivateKR = privateKR.containsAlias(alias); + if (Configuration.DEBUG) + log.fine("inPrivateKR=" + inPrivateKR); + boolean inPublicKR = publicKR.containsAlias(alias); + if (Configuration.DEBUG) + log.fine("inPublicKR=" + inPublicKR); + boolean result = inPrivateKR || inPublicKR; + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineContainsAlias", + Boolean.valueOf(result)); + return result; + } + + public void engineDeleteEntry(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineDeleteEntry", alias); + ensureLoaded(); + if (privateKR.containsAlias(alias)) + privateKR.remove(alias); + else if (publicKR.containsAlias(alias)) + publicKR.remove(alias); + else if (Configuration.DEBUG) + log.fine("Unknwon alias: " + alias); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineDeleteEntry"); + } + + public Certificate engineGetCertificate(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineGetCertificate", alias); + ensureLoaded(); + Certificate result = publicKR.getCertificate(alias); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineGetCertificate", result); + return result; + } + + public String engineGetCertificateAlias(Certificate cert) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineGetCertificateAlias", cert); + ensureLoaded(); + String result = null; + for (Enumeration aliases = publicKR.aliases(); aliases.hasMoreElements();) + { + String alias = (String) aliases.nextElement(); + Certificate cert2 = publicKR.getCertificate(alias); + if (cert.equals(cert2)) + { + result = alias; + break; + } + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineGetCertificateAlias", result); + return result; + } + + public void engineSetCertificateEntry(String alias, Certificate cert) + throws KeyStoreException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineSetCertificateEntry", + new Object[] { alias, cert }); + ensureLoaded(); + if (privateKR.containsAlias(alias)) + throw new KeyStoreException("Alias [" + alias + + "] already exists and DOES NOT identify a " + + "Trusted Certificate Entry"); + if (publicKR.containsCertificate(alias)) + { + if (Configuration.DEBUG) + log.fine("Public keyring already contains Alias [" + alias + + "]. Will remove it"); + publicKR.remove(alias); + } + publicKR.putCertificate(alias, cert); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineSetCertificateEntry"); + } + + public Certificate[] engineGetCertificateChain(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineGetCertificateChain", alias); + ensureLoaded(); + Certificate[] result = privateKR.getCertPath(alias); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineGetCertificateChain", result); + return result; + } + + public Date engineGetCreationDate(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineGetCreationDate", alias); + ensureLoaded(); + Date result = getCreationDate(alias, privateKR); + if (result == null) + result = getCreationDate(alias, publicKR); + + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineGetCreationDate", result); + return result; + } + + public Key engineGetKey(String alias, char[] password) + throws UnrecoverableKeyException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineGetKey", alias); + ensureLoaded(); + Key result = null; + if (password == null) + { + if (privateKR.containsPublicKey(alias)) + result = privateKR.getPublicKey(alias); + } + else if (privateKR.containsPrivateKey(alias)) + result = privateKR.getPrivateKey(alias, password); + + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineGetKey", + result == null ? "null" : result.getClass().getName()); + return result; + } + + public void engineSetKeyEntry(String alias, Key key, char[] password, + Certificate[] chain) + throws KeyStoreException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineSetKeyEntry", + new Object[] { alias, key.getClass().getName(), chain }); + ensureLoaded(); + if (publicKR.containsAlias(alias)) + throw new KeyStoreException("Alias [" + alias + + "] already exists and DOES NOT identify a " + + "Key Entry"); + if (key instanceof PublicKey) + { + privateKR.remove(alias); + PublicKey pk = (PublicKey) key; + privateKR.putPublicKey(alias, pk); + } + else + { + if (! (key instanceof PrivateKey) && ! (key instanceof SecretKey)) + throw new KeyStoreException("cannot store keys of type " + + key.getClass().getName()); + privateKR.remove(alias); + privateKR.putCertPath(alias, chain); + if (Configuration.DEBUG) + log.fine("About to put private key in keyring..."); + privateKR.putPrivateKey(alias, key, password); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineSetKeyEntry"); + } + + public void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain) + throws KeyStoreException + { + KeyStoreException x = new KeyStoreException("method not supported"); + if (Configuration.DEBUG) + log.throwing(this.getClass().getName(), "engineSetKeyEntry(3)", x); + throw x; + } + + public boolean engineIsCertificateEntry(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineIsCertificateEntry", alias); + ensureLoaded(); + boolean result = publicKR.containsCertificate(alias); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineIsCertificateEntry", + Boolean.valueOf(result)); + return result; + } + + public boolean engineIsKeyEntry(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineIsKeyEntry", alias); + ensureLoaded(); + boolean result = privateKR.containsPublicKey(alias) + || privateKR.containsPrivateKey(alias); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineIsKeyEntry", + Boolean.valueOf(result)); + return result; + } + + public void engineLoad(InputStream in, char[] password) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineLoad"); + if (in != null) + { + if (! in.markSupported()) + in = new BufferedInputStream(in); + + loadPrivateKeyring(in, password); + loadPublicKeyring(in, password); + } + else + createNewKeyrings(); + + loaded = true; + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineLoad"); + } + + public void engineStore(OutputStream out, char[] password) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineStore"); + ensureLoaded(); + HashMap attr = new HashMap(); + attr.put(IKeyring.KEYRING_DATA_OUT, out); + attr.put(IKeyring.KEYRING_PASSWORD, password); + + privateKR.store(attr); + publicKR.store(attr); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineStore"); + } + + public int engineSize() + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineSize"); + int result = 0; + for (Enumeration e = engineAliases(); e.hasMoreElements(); result++) + e.nextElement(); + + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineSize", Integer.valueOf(result)); + return result; + } + + /** + * Ensure that the underlying keyring pair is loaded. Throw an exception if it + * isn't; otherwise returns silently. + * + * @throws IllegalStateException if the keyring is not loaded. + */ + private void ensureLoaded() + { + if (! loaded) + throw new IllegalStateException(NOT_LOADED); + } + + /** + * Load the private keyring from the designated input stream. + * + * @param in the input stream to process. + * @param password the password protecting the keyring. + * @throws MalformedKeyringException if the keyring is not a private one. + * @throws IOException if an I/O related exception occurs during the process. + */ + private void loadPrivateKeyring(InputStream in, char[] password) + throws MalformedKeyringException, IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "loadPrivateKeyring"); + 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(); + if (usage != GnuPrivateKeyring.USAGE) + throw new MalformedKeyringException( + "Was expecting a private keyring but got a wrong USAGE: " + + Integer.toBinaryString(usage)); + HashMap attr = new HashMap(); + attr.put(IKeyring.KEYRING_DATA_IN, in); + attr.put(IKeyring.KEYRING_PASSWORD, password); + privateKR = new GnuPrivateKeyring(); + privateKR.load(attr); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "loadPrivateKeyring"); + } + + /** + * Load the public keyring from the designated input stream. + * + * @param in the input stream to process. + * @param password the password protecting the keyring. + * @throws MalformedKeyringException if the keyring is not a public one. + * @throws IOException if an I/O related exception occurs during the process. + */ + private void loadPublicKeyring(InputStream in, char[] password) + throws MalformedKeyringException, IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "loadPublicKeyring"); + 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(); + if (usage != GnuPublicKeyring.USAGE) + throw new MalformedKeyringException( + "Was expecting a public keyring but got a wrong USAGE: " + + Integer.toBinaryString(usage)); + HashMap attr = new HashMap(); + attr.put(IKeyring.KEYRING_DATA_IN, in); + attr.put(IKeyring.KEYRING_PASSWORD, password); + publicKR = new GnuPublicKeyring(); + publicKR.load(attr); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "loadPublicKeyring"); + } + + /** + * Return the creation date of a named alias in a designated keyring. + * + * @param alias the alias to look for. + * @param keyring the keyring to search. + * @return the creattion date of the entry named alias. Return + * null if alias was not found in + * keyring. + */ + private Date getCreationDate(String alias, IKeyring keyring) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "getCreationDate", + new Object[] { alias, keyring }); + Date result = null; + if (keyring != null) + for (Iterator it = keyring.get(alias).iterator(); it.hasNext();) + { + Object o = it.next(); + if (o instanceof PrimitiveEntry) + { + result = ((PrimitiveEntry) o).getCreationDate(); + break; + } + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "getCreationDate", result); + return result; + } + + /** Create empty keyrings. */ + private void createNewKeyrings() + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "createNewKeyrings"); + privateKR = new GnuPrivateKeyring("HMAC-SHA-1", 20, "AES", "OFB", 16); + publicKR = new GnuPublicKeyring("HMAC-SHA-1", 20); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "createNewKeyrings"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacHavalSpi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacHavalSpi.java new file mode 100644 index 000000000..fc5f3b578 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacHavalSpi.java @@ -0,0 +1,54 @@ +/* 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. + */ +public class HMacHavalSpi + extends MacAdapter +{ + public HMacHavalSpi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.HAVAL_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD2Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD2Spi.java new file mode 100644 index 000000000..c50feb8cf --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD2Spi.java @@ -0,0 +1,54 @@ +/* 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. + */ +public final class HMacMD2Spi + extends MacAdapter +{ + public HMacMD2Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.MD2_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD4Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD4Spi.java new file mode 100644 index 000000000..c0eae5b22 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD4Spi.java @@ -0,0 +1,54 @@ +/* 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. + */ +public final class HMacMD4Spi + extends MacAdapter +{ + public HMacMD4Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.MD4_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD5Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD5Spi.java new file mode 100644 index 000000000..78e884761 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD5Spi.java @@ -0,0 +1,54 @@ +/* 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. + */ +public final class HMacMD5Spi + extends MacAdapter +{ + public HMacMD5Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.MD5_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacRipeMD128Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacRipeMD128Spi.java new file mode 100644 index 000000000..b5835177c --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacRipeMD128Spi.java @@ -0,0 +1,54 @@ +/* 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. + */ +public final class HMacRipeMD128Spi + extends MacAdapter +{ + public HMacRipeMD128Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.RIPEMD128_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacRipeMD160Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacRipeMD160Spi.java new file mode 100644 index 000000000..4d7c6caec --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacRipeMD160Spi.java @@ -0,0 +1,54 @@ +/* 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. + */ +public final class HMacRipeMD160Spi + extends MacAdapter +{ + public HMacRipeMD160Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.RIPEMD160_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA160Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA160Spi.java new file mode 100644 index 000000000..1c7c9443d --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA160Spi.java @@ -0,0 +1,54 @@ +/* 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. + */ +public final class HMacSHA160Spi + extends MacAdapter +{ + public HMacSHA160Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.SHA160_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA256Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA256Spi.java new file mode 100644 index 000000000..7d7c91de6 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA256Spi.java @@ -0,0 +1,54 @@ +/* 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. + */ +public final class HMacSHA256Spi + extends MacAdapter +{ + public HMacSHA256Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.SHA256_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA384Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA384Spi.java new file mode 100644 index 000000000..b66b0f0f3 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA384Spi.java @@ -0,0 +1,54 @@ +/* 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. + */ +public class HMacSHA384Spi + extends MacAdapter +{ + public HMacSHA384Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.SHA384_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA512Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA512Spi.java new file mode 100644 index 000000000..c825a14e9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA512Spi.java @@ -0,0 +1,54 @@ +/* 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. + */ +public class HMacSHA512Spi + extends MacAdapter +{ + public HMacSHA512Spi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.SHA512_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacTigerSpi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacTigerSpi.java new file mode 100644 index 000000000..0d979f08f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacTigerSpi.java @@ -0,0 +1,54 @@ +/* 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. + */ +public final class HMacTigerSpi + extends MacAdapter +{ + public HMacTigerSpi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.TIGER_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/HMacWhirlpoolSpi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacWhirlpoolSpi.java new file mode 100644 index 000000000..6dde69b7e --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/HMacWhirlpoolSpi.java @@ -0,0 +1,54 @@ +/* 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. + */ +public final class HMacWhirlpoolSpi + extends MacAdapter +{ + public HMacWhirlpoolSpi() + { + super(Registry.HMAC_NAME_PREFIX + Registry.WHIRLPOOL_HASH); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/MacAdapter.java b/libjava/classpath/gnu/javax/crypto/jce/mac/MacAdapter.java new file mode 100644 index 000000000..cb3d934fa --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/MacAdapter.java @@ -0,0 +1,136 @@ +/* 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 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. + */ +class MacAdapter + extends MacSpi + implements Cloneable +{ + /** Our MAC instance. */ + protected IMac mac; + /** Our MAC attributes. */ + protected Map attributes; + + /** + * 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; + } + + public Object clone() throws CloneNotSupportedException + { + return new MacAdapter((IMac) mac.clone(), new HashMap(attributes)); + } + + 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); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/OMacAnubisImpl.java b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacAnubisImpl.java new file mode 100644 index 000000000..566e56fd1 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacAnubisImpl.java @@ -0,0 +1,50 @@ +/* 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 +{ + public OMacAnubisImpl() + { + super(Registry.OMAC_PREFIX + Registry.ANUBIS_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/OMacBlowfishImpl.java b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacBlowfishImpl.java new file mode 100644 index 000000000..55768166f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacBlowfishImpl.java @@ -0,0 +1,50 @@ +/* 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 +{ + public OMacBlowfishImpl() + { + super(Registry.OMAC_PREFIX + Registry.BLOWFISH_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/OMacCast5Impl.java b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacCast5Impl.java new file mode 100644 index 000000000..535352c39 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacCast5Impl.java @@ -0,0 +1,50 @@ +/* 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 +{ + public OMacCast5Impl() + { + super(Registry.OMAC_PREFIX + Registry.CAST5_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/OMacDESImpl.java b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacDESImpl.java new file mode 100644 index 000000000..a01c0ac87 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacDESImpl.java @@ -0,0 +1,50 @@ +/* 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 +{ + public OMacDESImpl() + { + super(Registry.OMAC_PREFIX + Registry.DES_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/OMacImpl.java b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacImpl.java new file mode 100644 index 000000000..960c68aaf --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacImpl.java @@ -0,0 +1,140 @@ +/* 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; + +public abstract class OMacImpl + extends MacAdapter +{ + protected OMacImpl(String name) + { + super(Registry.OMAC_PREFIX + name); + } + + 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); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/OMacKhazadImpl.java b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacKhazadImpl.java new file mode 100644 index 000000000..c349f9f5e --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacKhazadImpl.java @@ -0,0 +1,50 @@ +/* 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 +{ + public OMacKhazadImpl() + { + super(Registry.OMAC_PREFIX + Registry.KHAZAD_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/OMacRijndaelImpl.java b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacRijndaelImpl.java new file mode 100644 index 000000000..d63b777a3 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacRijndaelImpl.java @@ -0,0 +1,50 @@ +/* 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 +{ + public OMacRijndaelImpl() + { + super(Registry.OMAC_PREFIX + Registry.RIJNDAEL_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/OMacSerpentImpl.java b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacSerpentImpl.java new file mode 100644 index 000000000..5c1b8a9b9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacSerpentImpl.java @@ -0,0 +1,50 @@ +/* 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 +{ + public OMacSerpentImpl() + { + super(Registry.OMAC_PREFIX + Registry.SERPENT_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/OMacSquareImpl.java b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacSquareImpl.java new file mode 100644 index 000000000..c9d1b1aca --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacSquareImpl.java @@ -0,0 +1,50 @@ +/* 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 +{ + public OMacSquareImpl() + { + super(Registry.OMAC_PREFIX + Registry.SQUARE_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/OMacTripleDESImpl.java b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacTripleDESImpl.java new file mode 100644 index 000000000..4f58723d3 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacTripleDESImpl.java @@ -0,0 +1,50 @@ +/* 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 +{ + public OMacTripleDESImpl() + { + super(Registry.OMAC_PREFIX + Registry.TRIPLEDES_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/OMacTwofishImpl.java b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacTwofishImpl.java new file mode 100644 index 000000000..4c816a096 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/OMacTwofishImpl.java @@ -0,0 +1,50 @@ +/* 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 +{ + public OMacTwofishImpl() + { + super(Registry.OMAC_PREFIX + Registry.TWOFISH_CIPHER); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/TMMH16Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/TMMH16Spi.java new file mode 100644 index 000000000..d610cc0c2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/TMMH16Spi.java @@ -0,0 +1,81 @@ +/* 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. + */ +public final class TMMH16Spi + extends MacAdapter +{ + public TMMH16Spi() + { + super(Registry.TMMH16); + } + + 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()); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/UHash32Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/UHash32Spi.java new file mode 100644 index 000000000..c6784d633 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/UHash32Spi.java @@ -0,0 +1,54 @@ +/* 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. + */ +public final class UHash32Spi + extends MacAdapter +{ + public UHash32Spi() + { + super(Registry.UHASH32); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/mac/UMac32Spi.java b/libjava/classpath/gnu/javax/crypto/jce/mac/UMac32Spi.java new file mode 100644 index 000000000..85c859c38 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/mac/UMac32Spi.java @@ -0,0 +1,79 @@ +/* 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. + */ +public final class UMac32Spi + extends MacAdapter +{ + public UMac32Spi() + { + super(Registry.UMAC32); + } + + 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()); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/params/BlockCipherParameters.java b/libjava/classpath/gnu/javax/crypto/jce/params/BlockCipherParameters.java new file mode 100644 index 000000000..fde83b1f3 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/params/BlockCipherParameters.java @@ -0,0 +1,149 @@ +/* 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.java.security.Configuration; +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; +import java.util.logging.Logger; + +import javax.crypto.spec.IvParameterSpec; + +/** + * An implementation of algorithm parameters for the GNU block ciphers. This + * encompasses the cipher's block size, its key size, and an optional + * initialization vector (IV). + */ +public class BlockCipherParameters + extends AlgorithmParametersSpi +{ + private static final Logger log = Logger.getLogger(BlockCipherParameters.class.getName()); + /** The underlying block cipher specification. */ + protected BlockCipherParameterSpec cipherSpec; + private static final String DEFAULT_FORMAT = "ASN.1"; + + /** + * Return these parameters encoded in ASN.1 (DER). + *

    + * For GNU 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 + "\""); + DERWriter writer = new DERWriter(); + int cipherBlockSize = cipherSpec.getBlockSize(); + int cipherKeySize = cipherSpec.getKeySize(); + byte[] iv = cipherSpec.getIV(); + return writer.joinarrays( + writer.writeBigInteger(BigInteger.valueOf(cipherBlockSize)), + writer.writeBigInteger(BigInteger.valueOf(cipherKeySize)), + (iv != null) ? writer.writeBigInteger(new BigInteger(iv)) + : 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 + { + 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); + if (Configuration.DEBUG) + log.fine("cipherSpec: " + cipherSpec); + } + + protected AlgorithmParameterSpec engineGetParameterSpec(Class c) + throws InvalidParameterSpecException + { + if (c.isInstance(cipherSpec)) + return cipherSpec; + if (IvParameterSpec.class.isAssignableFrom(c)) + { + IvParameterSpec result = new IvParameterSpec(cipherSpec.getIV()); + return result; + } + throw new InvalidParameterSpecException(); + } + + protected String engineToString() + { + return cipherSpec.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/params/DEREncodingException.java b/libjava/classpath/gnu/javax/crypto/jce/params/DEREncodingException.java new file mode 100644 index 000000000..436f5d4cd --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/params/DEREncodingException.java @@ -0,0 +1,54 @@ +/* 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); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/params/DERReader.java b/libjava/classpath/gnu/javax/crypto/jce/params/DERReader.java new file mode 100644 index 000000000..9fc1e2cd7 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/params/DERReader.java @@ -0,0 +1,139 @@ +/* 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); + // get tag + int tag = (0x1f & identifier); + // get length + byte len = source[tmp]; // may be length of length parameter + long length = 0x7f & len; + int i; + if ((0x80 & len) != 0) + { + len &= 0x7f; + // get length here + length = 0; + for (i = 0; i < len; i++) + { + tmp++; + length <<= 8; + length += (source[tmp] < 0) ? (256 + source[tmp]) : source[tmp]; + } + tmp++; + } + else + tmp++; + + 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; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/params/DERWriter.java b/libjava/classpath/gnu/javax/crypto/jce/params/DERWriter.java new file mode 100644 index 000000000..7553e20d2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/params/DERWriter.java @@ -0,0 +1,143 @@ +/* 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; + return b; + } + else + { + b = new byte[1]; + b[0] = (byte)((translateLeadIdentifierByte(identifierencoding) + | (byte)(identifier & 0x1f)) & 0xdf); + 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)); + 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))); + return b; + } + else + { + b = new byte[1]; + b[0] = (byte) (length & 0x7f); + return b; + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java b/libjava/classpath/gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java new file mode 100644 index 000000000..3816fb648 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java @@ -0,0 +1,102 @@ +/* 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.java.security.jce.prng.SecureRandomAdapter; + +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; + +import gnu.javax.crypto.prng.ARCFour; +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 +{ + /** Our underlying prng instance. */ + private IRandom adaptee; + /** Have we been initialized? */ + private boolean virgin; + + /** + * Default 0-arguments constructor. + */ + public ARCFourRandomSpi() + { + super(); + adaptee = PRNGFactory.getInstance(Registry.ARCFOUR_PRNG); + virgin = true; + } + + public byte[] engineGenerateSeed(int numBytes) + { + return SecureRandomAdapter.getSeed(numBytes); + } + + public void engineNextBytes(byte[] bytes) + { + if (virgin) + this.engineSetSeed(engineGenerateSeed(32)); + 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; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/prng/CSPRNGSpi.java b/libjava/classpath/gnu/javax/crypto/jce/prng/CSPRNGSpi.java new file mode 100644 index 000000000..9a893af9d --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/prng/CSPRNGSpi.java @@ -0,0 +1,97 @@ +/* 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.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.jce.prng.SecureRandomAdapter; +import gnu.javax.crypto.prng.CSPRNG; + +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 +{ + private final IRandom adaptee; + private boolean virgin = true; + + public CSPRNGSpi() throws ClassNotFoundException, MalformedURLException, + NumberFormatException + { + super(); + + adaptee = CSPRNG.getSystemInstance(); + } + + protected byte[] engineGenerateSeed(final int numBytes) + { + return SecureRandomAdapter.getSeed(numBytes); + } + + protected void engineNextBytes(final byte[] buffer) + { + if (buffer == null) + throw new NullPointerException(); + if (virgin) + { + engineSetSeed(engineGenerateSeed(32)); + } + 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); + virgin = false; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/prng/FortunaImpl.java b/libjava/classpath/gnu/javax/crypto/jce/prng/FortunaImpl.java new file mode 100644 index 000000000..d2073b98d --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/prng/FortunaImpl.java @@ -0,0 +1,100 @@ +/* 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.java.security.jce.prng.SecureRandomAdapter; + +import gnu.javax.crypto.prng.Fortuna; + +import java.security.SecureRandomSpi; +import java.util.Collections; + +public final class FortunaImpl + extends SecureRandomSpi +{ + private boolean virgin = true; + private final Fortuna adaptee; + + public FortunaImpl() + { + adaptee = new Fortuna(); + } + + protected void engineSetSeed(byte[] seed) + { + synchronized (adaptee) + { + if (virgin) + { + adaptee.init (Collections.singletonMap (Fortuna.SEED, seed)); + virgin = false; + } + else + { + adaptee.addRandomBytes (seed); + } + } + } + + protected void engineNextBytes(byte[] buffer) + { + synchronized (adaptee) + { + if (virgin) + { + this.engineSetSeed(engineGenerateSeed(32)); + } + try + { + adaptee.nextBytes(buffer); + } + catch (LimitReachedException shouldNotHappen) + { + throw new Error(shouldNotHappen); + } + } + } + + protected byte[] engineGenerateSeed(int numBytes) + { + return SecureRandomAdapter.getSeed(numBytes); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/prng/ICMRandomSpi.java b/libjava/classpath/gnu/javax/crypto/jce/prng/ICMRandomSpi.java new file mode 100644 index 000000000..bbd5d4768 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/prng/ICMRandomSpi.java @@ -0,0 +1,206 @@ +/* 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.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.jce.prng.SecureRandomAdapter; +import gnu.java.security.prng.LimitReachedException; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.prng.ICMGenerator; + +import java.math.BigInteger; +import java.security.SecureRandomSpi; +import java.util.HashMap; +import java.util.Random; +import java.util.logging.Logger; + +/** + * An Adapter class around {@link ICMGenerator} to allow using this + * algorithm as a JCE {@link java.security.SecureRandom}. + */ +public class ICMRandomSpi + extends SecureRandomSpi +{ + private static final Logger log = Logger.getLogger(ICMRandomSpi.class.getName()); + /** 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(); + + // default 0-arguments constructor + + private static void resetLocalPRNG() + { + if (Configuration.DEBUG) + log.entering(ICMRandomSpi.class.getName(), "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, Integer.valueOf(ndxLen)); + byte[] index = new byte[ndxLen]; + rand.nextBytes(index); + attributes.put(ICMGenerator.SEGMENT_INDEX, new BigInteger(1, index)); + prng.setup(attributes); + if (Configuration.DEBUG) + log.exiting(ICMRandomSpi.class.getName(), "resetLocalPRNG"); + } + + public byte[] engineGenerateSeed(int numBytes) + { + return SecureRandomAdapter.getSeed(numBytes); + } + + public void engineNextBytes(byte[] bytes) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineNextBytes"); + if (! adaptee.isInitialised()) + this.engineSetSeed(engineGenerateSeed(32)); + while (true) + { + try + { + adaptee.nextBytes(bytes, 0, bytes.length); + break; + } + catch (LimitReachedException x) + { // reseed the generator + if (Configuration.DEBUG) + { + log.fine(LIMIT_REACHED_MSG + String.valueOf(x)); + log.fine(RESEED); + } + resetLocalPRNG(); + } + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineNextBytes"); + } + + public void engineSetSeed(byte[] seed) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "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 (Configuration.DEBUG) + { + log.fine(MSG + String.valueOf(x)); + log.fine(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, Integer.valueOf(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[4]; + System.arraycopy(material, 32, index, 0, 4); + attributes.put(ICMGenerator.SEGMENT_INDEX, new BigInteger(1, index)); + adaptee.init(attributes); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineSetSeed"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/prng/UMacRandomSpi.java b/libjava/classpath/gnu/javax/crypto/jce/prng/UMacRandomSpi.java new file mode 100644 index 000000000..910e65c70 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/prng/UMacRandomSpi.java @@ -0,0 +1,166 @@ +/* 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.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.jce.prng.SecureRandomAdapter; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.prng.UMacGenerator; + +import java.security.SecureRandomSpi; +import java.util.HashMap; +import java.util.Random; +import java.util.logging.Logger; + +/** + * An Adapter class around {@link UMacGenerator} to allow using this + * algorithm as a JCE {@link java.security.SecureRandom}. + */ +public class UMacRandomSpi + extends SecureRandomSpi +{ + private static final Logger log = Logger.getLogger(UMacRandomSpi.class.getName()); + + /** 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(); + + // default 0-arguments constructor + + 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, Integer.valueOf(index)); + prng.setup(attributes); + } + + public byte[] engineGenerateSeed(int numBytes) + { + return SecureRandomAdapter.getSeed(numBytes); + } + + public void engineNextBytes(byte[] bytes) + { + if (! adaptee.isInitialised()) + engineSetSeed(engineGenerateSeed(32)); + 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 (Configuration.DEBUG) + { + log.fine(MSG + String.valueOf(x)); + log.fine(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, Integer.valueOf(material[16] & 0xFF)); + adaptee.init(attributes); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/sig/DHKeyFactory.java b/libjava/classpath/gnu/javax/crypto/jce/sig/DHKeyFactory.java new file mode 100644 index 000000000..98b265dd3 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/sig/DHKeyFactory.java @@ -0,0 +1,219 @@ +/* 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/libjava/classpath/gnu/javax/crypto/jce/sig/DHKeyPairGeneratorSpi.java b/libjava/classpath/gnu/javax/crypto/jce/sig/DHKeyPairGeneratorSpi.java new file mode 100644 index 000000000..e26f07124 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/sig/DHKeyPairGeneratorSpi.java @@ -0,0 +1,93 @@ +/* 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 javax.crypto.spec.DHParameterSpec; + +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, Integer.valueOf(keysize)); + if (random != null) + attributes.put(GnuDHKeyPairGenerator.SOURCE_OF_RANDOMNESS, random); + + attributes.put(GnuDHKeyPairGenerator.PREFERRED_ENCODING_FORMAT, + Integer.valueOf(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) && + ! (params instanceof DHParameterSpec)) + 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, + Integer.valueOf(Registry.ASN1_ENCODING_ID)); + adaptee.setup(attributes); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/sig/DHParameters.java b/libjava/classpath/gnu/javax/crypto/jce/sig/DHParameters.java new file mode 100644 index 000000000..cc656d2c8 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/sig/DHParameters.java @@ -0,0 +1,222 @@ +/* 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.lang.CPStringBuilder; + +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() + { + CPStringBuilder sb = new CPStringBuilder("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/libjava/classpath/gnu/javax/crypto/jce/sig/DHParametersGenerator.java b/libjava/classpath/gnu/javax/crypto/jce/sig/DHParametersGenerator.java new file mode 100644 index 000000000..3687ac3ca --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/crypto/jce/spec/BlockCipherParameterSpec.java b/libjava/classpath/gnu/javax/crypto/jce/spec/BlockCipherParameterSpec.java new file mode 100644 index 000000000..b17fa3497 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/spec/BlockCipherParameterSpec.java @@ -0,0 +1,122 @@ +/* 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 are the cipher's name, its block and key + * sizes, and an optional initialization vector. + */ +public class BlockCipherParameterSpec + implements AlgorithmParameterSpec +{ + /** 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; + + /** + * 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); + } + + /** + * 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/libjava/classpath/gnu/javax/crypto/jce/spec/TMMHParameterSpec.java b/libjava/classpath/gnu/javax/crypto/jce/spec/TMMHParameterSpec.java new file mode 100644 index 000000000..31199538c --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/spec/TMMHParameterSpec.java @@ -0,0 +1,117 @@ +/* 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.javax.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 +{ + /** The keystream. */ + protected IRandom keystream; + /** The tag length. */ + protected Integer tagLength; + /** The prefix. */ + protected byte[] prefix; + + /** + * 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); + } + + /** + * 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; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/jce/spec/UMac32ParameterSpec.java b/libjava/classpath/gnu/javax/crypto/jce/spec/UMac32ParameterSpec.java new file mode 100644 index 000000000..3c13faf04 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/jce/spec/UMac32ParameterSpec.java @@ -0,0 +1,73 @@ +/* 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 +{ + /** The Nonce material. */ + protected byte[] nonce; + + /** + * Create a new parameter instance. + * + * @param nonce The nonce material. + */ + public UMac32ParameterSpec(byte[] nonce) + { + this.nonce = nonce; + } + + /** + * Return the nonce material. + * + * @return The nonce material. + */ + public byte[] getNonce() + { + return nonce; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/BaseKeyAgreementParty.java b/libjava/classpath/gnu/javax/crypto/key/BaseKeyAgreementParty.java new file mode 100644 index 000000000..3f4e0a22c --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/BaseKeyAgreementParty.java @@ -0,0 +1,168 @@ +/* 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 +{ + 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; + + protected BaseKeyAgreementParty(String name) + { + super(); + + this.name = name; + } + + 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; + } + } + + 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(); + + /** + * 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; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/GnuPBEKey.java b/libjava/classpath/gnu/javax/crypto/key/GnuPBEKey.java new file mode 100644 index 000000000..5642e59ed --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/GnuPBEKey.java @@ -0,0 +1,95 @@ +/* GnuPBEKey.java -- A password-based encryption 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.crypto.key; + +import javax.crypto.interfaces.PBEKey; +import javax.crypto.spec.PBEKeySpec; + +/** + * An implementation of a password-based encryption key. + * + * @author Casey Marshall (csm@gnu.org) + */ +public class GnuPBEKey + implements PBEKey +{ + private final PBEKeySpec spec; + + public GnuPBEKey (final PBEKeySpec spec) + { + if (spec == null) + throw new NullPointerException (); + this.spec = spec; + } + + public GnuPBEKey (char[] password, byte[] salt, int iterationCount) + { + this (new PBEKeySpec (password, salt, iterationCount)); + } + + public int getIterationCount () + { + return spec.getIterationCount (); + } + + public char[] getPassword () + { + return spec.getPassword (); + } + + public byte[] getSalt () + { + return spec.getSalt (); + } + + public String getAlgorithm () + { + return "PBE"; + } + + public String getFormat () + { + return "NONE"; // FIXME? + } + + public byte[] getEncoded () + { + return null; // FIXME? + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/GnuSecretKey.java b/libjava/classpath/gnu/javax/crypto/key/GnuSecretKey.java new file mode 100644 index 000000000..c8ca1edab --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/GnuSecretKey.java @@ -0,0 +1,131 @@ +/* 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 +{ + private final byte[] key; + private final String algorithm; + + /** + * 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; + } + + /** + * 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) + " ]"; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/IKeyAgreementParty.java b/libjava/classpath/gnu/javax/crypto/key/IKeyAgreementParty.java new file mode 100644 index 000000000..64434212f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/IKeyAgreementParty.java @@ -0,0 +1,100 @@ +/* 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 +{ + /** + * 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(); +} diff --git a/libjava/classpath/gnu/javax/crypto/key/IncomingMessage.java b/libjava/classpath/gnu/javax/crypto/key/IncomingMessage.java new file mode 100644 index 000000000..3b68392d6 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/IncomingMessage.java @@ -0,0 +1,318 @@ +/* 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 +{ + /** 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; + + /** + * 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(); + } + + /** + * 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; + } + + 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); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/KeyAgreementException.java b/libjava/classpath/gnu/javax/crypto/key/KeyAgreementException.java new file mode 100644 index 000000000..06a7db70b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/KeyAgreementException.java @@ -0,0 +1,168 @@ +/* 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 gnu.java.lang.CPStringBuilder; + +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 +{ + /** @serial The possibly null root cause exception. */ + private Throwable cause = null; + + /** + * 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; + } + + /** + * 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() + { + CPStringBuilder sb = new CPStringBuilder(this.getClass().getName()).append(": ") + .append(super.toString()); + if (cause != null) + sb.append("; caused by: ").append(cause.toString()); + return sb.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/KeyAgreementFactory.java b/libjava/classpath/gnu/javax/crypto/key/KeyAgreementFactory.java new file mode 100644 index 000000000..a4e14bc69 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/KeyAgreementFactory.java @@ -0,0 +1,143 @@ +/* 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 +{ + /** Trivial constructor to enforce Singleton pattern. */ + private KeyAgreementFactory() + { + super(); + } + + /** + * 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); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/OutgoingMessage.java b/libjava/classpath/gnu/javax/crypto/key/OutgoingMessage.java new file mode 100644 index 000000000..e011330fe --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/OutgoingMessage.java @@ -0,0 +1,234 @@ +/* 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 +{ + /** The internal output stream. */ + private ByteArrayOutputStream out; + + public OutgoingMessage() + { + super(); + + out = new ByteArrayOutputStream(); + } + + /** + * 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()); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairPKCS8Codec.java b/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairPKCS8Codec.java new file mode 100644 index 000000000..8c03cbb00 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairPKCS8Codec.java @@ -0,0 +1,240 @@ +/* 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
    +   *   }
    +   * 
    + *

    + * IMPORTANT: with RI's {@link javax.crypto.spec.DHGenParameterSpec} + * and {@link javax.crypto.spec.DHParameterSpec} classes, we may end up with + * Diffie-Hellman keys that have a null for the q + * parameter. RFC-2631 DOES NOT allow for an optional value for that + * parameter, hence we replace such null values with 0, and do + * the reverse in the corresponding decode method. + * + * @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(); + if (q == null) + q = BigInteger.ZERO; + 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(); + if (q.compareTo(BigInteger.ZERO) == 0) + q = null; + + 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/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairRawCodec.java b/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairRawCodec.java new file mode 100644 index 000000000..4275389ce --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairRawCodec.java @@ -0,0 +1,336 @@ +/* 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 +{ + 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/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairX509Codec.java b/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairX509Codec.java new file mode 100644 index 000000000..893716eef --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairX509Codec.java @@ -0,0 +1,255 @@ +/* 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
    +   * 
    + *

    + * IMPORTANT: with RI's {@link javax.crypto.spec.DHGenParameterSpec} + * and {@link javax.crypto.spec.DHParameterSpec} classes, we may end up with + * Diffie-Hellman keys that have a null for the q + * parameter. RFC-2631 DOES NOT allow for an optional value for that + * parameter, hence we replace such null values with 0, and do + * the reverse in the corresponding decode method. + * + * @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(); + if (q == null) + q = BigInteger.ZERO; + 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(); + if (q.compareTo(BigInteger.ZERO) == 0) + q = null; + + 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/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanKeyAgreement.java b/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanKeyAgreement.java new file mode 100644 index 000000000..893d84d32 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanKeyAgreement.java @@ -0,0 +1,119 @@ +/* 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 +{ + 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; + + protected DiffieHellmanKeyAgreement() + { + super(Registry.DH_KA); + } + + protected byte[] engineSharedSecret() throws KeyAgreementException + { + return Util.trim(ZZ); + } + + protected void engineReset() + { + ownerKey = null; + ZZ = null; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanReceiver.java b/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanReceiver.java new file mode 100644 index 000000000..3194f682d --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanReceiver.java @@ -0,0 +1,117 @@ +/* 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 +{ + private BigInteger y; // the receiver's random secret + + // default 0-arguments constructor + + 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"); + } + } + + 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/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanSender.java b/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanSender.java new file mode 100644 index 000000000..7fc997354 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanSender.java @@ -0,0 +1,126 @@ +/* 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 + */ +public class DiffieHellmanSender + extends DiffieHellmanKeyAgreement +{ + private BigInteger x; // the sender's random secret + + // default 0-arguments constructor + + 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"); + } + } + + 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/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalKeyAgreement.java b/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalKeyAgreement.java new file mode 100644 index 000000000..4283dc59b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalKeyAgreement.java @@ -0,0 +1,115 @@ +/* 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 +{ + 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; + + protected ElGamalKeyAgreement() + { + super(Registry.ELGAMAL_KA); + } + + protected byte[] engineSharedSecret() throws KeyAgreementException + { + return Util.trim(ZZ); + } + + protected void engineReset() + { + ZZ = null; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalReceiver.java b/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalReceiver.java new file mode 100644 index 000000000..ad606f6c9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalReceiver.java @@ -0,0 +1,99 @@ +/* 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 +{ + /** The recipient's private key. */ + private DHPrivateKey B; + + // default 0-arguments constructor + + 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"); + } + } + + 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/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalSender.java b/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalSender.java new file mode 100644 index 000000000..bc9643500 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/ElGamalSender.java @@ -0,0 +1,112 @@ +/* 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 +{ + /** The recipient's public key. */ + private DHPublicKey B; + + // default 0-arguments constructor + + 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"); + } + } + + 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/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHKey.java b/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHKey.java new file mode 100644 index 000000000..03a18c310 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHKey.java @@ -0,0 +1,174 @@ +/* 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.action.GetPropertyAction; +import gnu.java.security.util.FormatUtil; + +import java.math.BigInteger; +import java.security.AccessController; +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 +{ + /** 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; + /** String representation of this key. Cached for speed. */ + private transient String str; + + /** + * 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; + } + + public DHParameterSpec getParams() + { + if (q == null) + return new DHParameterSpec(p, g); + return new DHParameterSpec(p, g, q.bitLength()); + } + + public String getAlgorithm() + { + return Registry.DH_KPG; + } + + /** @deprecated see getEncoded(int). */ + public byte[] getEncoded() + { + return getEncoded(defaultFormat); + } + + public String getFormat() + { + return FormatUtil.getEncodingShortName(defaultFormat); + } + + 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()); + } + + public String toString() + { + if (str == null) + { + String ls = (String) AccessController.doPrivileged + (new GetPropertyAction("line.separator")); + StringBuilder sb = new StringBuilder(ls) + .append("defaultFormat=").append(defaultFormat).append(",").append(ls); + if (q == null) + sb.append("q=null,"); + else + sb.append("q=0x").append(q.toString(16)).append(","); + sb.append(ls).append("p=0x").append(p.toString(16)).append(",").append(ls) + .append("g=0x").append(g.toString(16)); + str = sb.toString(); + } + return str; + } + + public abstract byte[] getEncoded(int format); +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java b/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java new file mode 100644 index 000000000..89e9c4c80 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java @@ -0,0 +1,235 @@ +/* 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.Configuration; +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.math.BigInteger; +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.util.Map; +import java.util.logging.Logger; + +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 +{ + private static final Logger log = Logger.getLogger(GnuDHKeyPairGenerator.class.getName()); + /** + * 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). */ + 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; + + // default 0-arguments constructor + + 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) + { + // FIXME: I'm not sure this is correct. It seems to behave the + // same way as Sun's RI, but I don't know if this behavior is + // documented anywhere. + DHParameterSpec jceSpec = (DHParameterSpec) params; + p = jceSpec.getP(); + g = jceSpec.getG(); + l = p.bitLength(); + m = jceSpec.getL(); + // If no exponent size was given, generate an exponent as + // large as the prime. + if (m == 0) + m = l; + } + 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 < 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 (Configuration.DEBUG) + { + log.fine("seed: 0x" + seed.toString(16)); + log.fine("counter: " + counter.intValue()); + log.fine("q: 0x" + q.toString(16)); + log.fine("p: 0x" + p.toString(16)); + log.fine("j: 0x" + j.toString(16)); + log.fine("g: 0x" + g.toString(16)); + } + } + // generate a private number x of length m such as: 1 < x < q - 1 + BigInteger q_minus_1 = null; + if (q != null) + q_minus_1 = q.subtract(BigInteger.ONE); + // We already check if m is modulo 8 in `setup.' This could just + // be m >>> 3. + 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 + && (q_minus_1 == null || 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); + } + + /** + * 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/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHPrivateKey.java b/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHPrivateKey.java new file mode 100644 index 000000000..881421a74 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHPrivateKey.java @@ -0,0 +1,200 @@ +/* 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.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.action.GetPropertyAction; +import gnu.java.security.key.IKeyPairCodec; + +import java.math.BigInteger; +import java.security.AccessController; + +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 +{ + /** The private exponent. */ + private final BigInteger x; + /** String representation of this key. Cached for speed. */ + private transient String str; + + /** + * 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; + } + + /** + * 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); + } + + public BigInteger getX() + { + return x; + } + + /** + * 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 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()); + } + + public String toString() + { + if (str == null) + { + String ls = (String) AccessController.doPrivileged + (new GetPropertyAction("line.separator")); + str = new StringBuilder(this.getClass().getName()).append("(") + .append(super.toString()).append(",").append(ls) + .append("x=0x").append(Configuration.DEBUG ? x.toString(16) + : "**...*").append(ls) + .append(")") + .toString(); + } + return str; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHPublicKey.java b/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHPublicKey.java new file mode 100644 index 000000000..5f1771bb0 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/GnuDHPublicKey.java @@ -0,0 +1,196 @@ +/* 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.action.GetPropertyAction; +import gnu.java.security.key.IKeyPairCodec; + +import java.math.BigInteger; +import java.security.AccessController; + +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 +{ + private BigInteger y; + /** String representation of this key. Cached for speed. */ + private transient String str; + + /** + * 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; + } + + /** + * 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); + } + + public BigInteger getY() + { + return y; + } + + /** + * 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()); + } + + public String toString() + { + if (str == null) + { + String ls = (String) AccessController.doPrivileged + (new GetPropertyAction("line.separator")); + str = new StringBuilder(this.getClass().getName()).append("(") + .append(super.toString()).append(",").append(ls) + .append("y=0x").append(y.toString(16)).append(ls) + .append(")") + .toString(); + } + return str; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/dh/RFC2631.java b/libjava/classpath/gnu/javax/crypto/key/dh/RFC2631.java new file mode 100644 index 000000000..60ef49409 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/dh/RFC2631.java @@ -0,0 +1,217 @@ +/* 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 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 +{ + 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; + + public RFC2631(int m, int L, SecureRandom rnd) + { + super(); + + this.m = m; + this.L = L; + this.rnd = rnd; + } + + 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 (q.isProbablePrime(80)) + break step4; + } + // 8. Let counter = 0 + counter = 0; + 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 (p.isProbablePrime(80)) + { + 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 }; + } + + /** + * 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/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6Host.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6Host.java new file mode 100644 index 000000000..2c8e66fa2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6Host.java @@ -0,0 +1,161 @@ +/* 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 +{ + /** The user's ephemeral key pair. */ + private KeyPair hostKeyPair; + + /** The SRP password database. */ + private SRPAuthInfoProvider passwordDB; + + // default 0-arguments constructor + + 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 || md.trim().length() == 0) + 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(); + } + + 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))); + 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/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6KeyAgreement.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6KeyAgreement.java new file mode 100644 index 000000000..d3d27b381 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6KeyAgreement.java @@ -0,0 +1,141 @@ +/* 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 +{ + 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; + + protected SRP6KeyAgreement() + { + super(Registry.SRP6_KA); + } + + protected byte[] engineSharedSecret() throws KeyAgreementException + { + return Util.trim(K); + } + + protected void engineReset() + { + srp = null; + N = null; + g = null; + K = null; + } + + protected BigInteger uValue(final BigInteger A, final BigInteger B) + { + 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/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6SaslClient.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6SaslClient.java new file mode 100644 index 000000000..ec5cd7f17 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6SaslClient.java @@ -0,0 +1,90 @@ +/* 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 +{ + // default 0-arguments constructor + + 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/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6SaslServer.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6SaslServer.java new file mode 100644 index 000000000..a4313f4d3 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6SaslServer.java @@ -0,0 +1,90 @@ +/* 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 +{ + // default 0-arguments constructor + + 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/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6TLSClient.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6TLSClient.java new file mode 100644 index 000000000..c2459f620 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6TLSClient.java @@ -0,0 +1,155 @@ +/* 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 +{ + /** The user's identity. */ + private String I; + /** The user's cleartext password. */ + private byte[] p; + /** The user's ephemeral key pair. */ + private KeyPair userKeyPair; + + // default 0-arguments constructor + + 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 || md.trim().length() == 0) + 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(); + } + + 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/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6TLSServer.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6TLSServer.java new file mode 100644 index 000000000..42e3d9cb1 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6TLSServer.java @@ -0,0 +1,177 @@ +/* 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). + */ +public class SRP6TLSServer + extends SRP6KeyAgreement +{ + /** The user's ephemeral key pair. */ + private KeyPair hostKeyPair; + /** The SRP password database. */ + private SRPAuthInfoProvider passwordDB; + + // default 0-arguments constructor + + 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 || md.trim().length() == 0) + 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(); + } + + 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/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6User.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6User.java new file mode 100644 index 000000000..4a1e8dda9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRP6User.java @@ -0,0 +1,163 @@ +/* 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 +{ + /** The user's identity. */ + private String I; + /** The user's cleartext password. */ + private byte[] p; + /** The user's ephemeral key pair. */ + private KeyPair userKeyPair; + + // default 0-arguments constructor + + 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 || md.trim().length() == 0) + 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(); + } + + 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/libjava/classpath/gnu/javax/crypto/key/srp6/SRPAlgorithm.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPAlgorithm.java new file mode 100644 index 000000000..fb8249e05 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPAlgorithm.java @@ -0,0 +1,131 @@ +/* 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.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 +{ + // 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); + + /** Trivial constructor to enforce usage through class methods. */ + private SRPAlgorithm() + { + super(); + } + + 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 (! N.isProbablePrime(80)) + 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 (! q.isProbablePrime(80)) + 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"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKey.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKey.java new file mode 100644 index 000000000..72ce8d2cf --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKey.java @@ -0,0 +1,147 @@ +/* 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 +{ + /** The public, Germaine prime, shared modulus. */ + protected final BigInteger N; + /** The generator. */ + protected final BigInteger g; + + protected SRPKey(BigInteger N, BigInteger g) + { + super(); + + this.N = N; + this.g = g; + } + + /** + * 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; + } + + /** + * 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()); + } + + public abstract byte[] getEncoded(int format); +} diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKeyPairGenerator.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKeyPairGenerator.java new file mode 100644 index 000000000..59e5bc943 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKeyPairGenerator.java @@ -0,0 +1,282 @@ +/* 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.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairGenerator; +import gnu.java.security.util.PRNG; + +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.SecureRandom; +import java.util.Map; +import java.util.logging.Logger; + +/** + * Reference: + *
      + *
    1. SRP Protocol Design
      + * Thomas J. Wu.
    2. + *
    + */ +public class SRPKeyPairGenerator + implements IKeyPairGenerator +{ + private static final Logger log = Logger.getLogger(SRPKeyPairGenerator.class.getName()); + 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; + + // implicit 0-arguments constructor + + 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 (Configuration.DEBUG) + { + log.fine("q: " + q.toString(16)); + log.fine("N: " + N.toString(16)); + log.fine("g: " + g.toString(16)); + } + } + return (v != null ? hostKeyPair() : userKeyPair()); + } + + 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 (! q.isProbablePrime(80)); + p = q.multiply(TWO).add(ONE); + } + while (p.bitLength() != l || ! p.isProbablePrime(80)); + // 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/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKeyPairRawCodec.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKeyPairRawCodec.java new file mode 100644 index 000000000..b7cc53693 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPKeyPairRawCodec.java @@ -0,0 +1,334 @@ +/* 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 +{ + // implicit 0-arguments constructor + + 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); + } + return new SRPPrivateKey(N, g, x); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/key/srp6/SRPPrivateKey.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPPrivateKey.java new file mode 100644 index 000000000..c2e13be82 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPPrivateKey.java @@ -0,0 +1,227 @@ +/* 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 +{ + /** + * 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; + + /** + * 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"); + } + + /** + * 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); + } + throw new IllegalArgumentException("magic"); + } + + /** + * 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; + } + + /** + * 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/libjava/classpath/gnu/javax/crypto/key/srp6/SRPPublicKey.java b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPPublicKey.java new file mode 100644 index 000000000..2db13ff4c --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/key/srp6/SRPPublicKey.java @@ -0,0 +1,175 @@ +/* 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 +{ + /** + * The public exponent for either the server or the client engaged in the SRP + * protocol exchange. + */ + private final BigInteger Y; + + /** + * 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]; + } + + /** + * 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); + } + throw new IllegalArgumentException("magic"); + } + + /** + * 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; + } + + /** + * 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/libjava/classpath/gnu/javax/crypto/keyring/AuthenticatedEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/AuthenticatedEntry.java new file mode 100644 index 000000000..91c3bc6e2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/AuthenticatedEntry.java @@ -0,0 +1,176 @@ +/* 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 gnu.java.security.Registry; +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mac.MacFactory; +import gnu.javax.crypto.mac.MacOutputStream; + +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.HashMap; +import java.util.Iterator; + +public final class AuthenticatedEntry + extends MaskableEnvelopeEntry + implements Registry +{ + public static final int TYPE = 2; + + 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); + } + + 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; + } + + /** + * 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 + { + int len = payload.length - m.macSize(); + ByteArrayInputStream bais = new ByteArrayInputStream(payload, 0, len); + DataInputStream in = new DataInputStream(bais); + 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"); + } + + 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, Integer.valueOf(maclen)); + mac.init(macAttr); + return mac; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/BaseKeyring.java b/libjava/classpath/gnu/javax/crypto/keyring/BaseKeyring.java new file mode 100644 index 000000000..e93ca8fa3 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/BaseKeyring.java @@ -0,0 +1,158 @@ +/* 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 gnu.java.security.Registry; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Enumeration; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +public abstract class BaseKeyring + implements IKeyring +{ + /** The top-level keyring data. */ + protected PasswordAuthenticatedEntry keyring; + protected CompressedEntry keyring2; + + public BaseKeyring() + { + } + + 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/libjava/classpath/gnu/javax/crypto/keyring/BinaryDataEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/BinaryDataEntry.java new file mode 100644 index 000000000..8fb1e0f39 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/BinaryDataEntry.java @@ -0,0 +1,111 @@ +/* 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 +{ + public static final int TYPE = 9; + + /** + * 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); + } + + public static BinaryDataEntry decode(DataInputStream in) throws IOException + { + BinaryDataEntry entry = new BinaryDataEntry(); + entry.defaultDecode(in); + return entry; + } + + /** + * 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/libjava/classpath/gnu/javax/crypto/keyring/CertPathEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/CertPathEntry.java new file mode 100644 index 000000000..e798a93ce --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/CertPathEntry.java @@ -0,0 +1,112 @@ +/* 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.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 +{ + public static final int TYPE = 8; + private Certificate[] path; + + 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); + } + + 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; + } + + 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/libjava/classpath/gnu/javax/crypto/keyring/CertificateEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/CertificateEntry.java new file mode 100644 index 000000000..f574a4fe4 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/CertificateEntry.java @@ -0,0 +1,128 @@ +/* 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.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; + +/** + * An immutable class representing a trusted certificate entry. + */ +public final class CertificateEntry + extends PrimitiveEntry +{ + public static final int TYPE = 5; + /** The certificate. */ + private Certificate certificate; + + /** + * 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); + } + + 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; + } + + /** + * 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/libjava/classpath/gnu/javax/crypto/keyring/CompressedEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/CompressedEntry.java new file mode 100644 index 000000000..8949a41e9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/CompressedEntry.java @@ -0,0 +1,93 @@ +/* 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 +{ + public static final int TYPE = 4; + + public CompressedEntry(Properties properties) + { + super(TYPE, properties); + this.properties.put("algorithm", "DEFLATE"); + } + + private CompressedEntry() + { + this(new Properties()); + } + + 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; + } + + 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/libjava/classpath/gnu/javax/crypto/keyring/EncryptedEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/EncryptedEntry.java new file mode 100644 index 000000000..68a6c2c8a --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/EncryptedEntry.java @@ -0,0 +1,191 @@ +/* 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 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; + +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.HashMap; +import java.util.Iterator; + +public class EncryptedEntry extends MaskableEnvelopeEntry implements Registry +{ + public static final int TYPE = 0; + + 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); + } + + 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; + } + + 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); + int len = buf.length - padlen; + DataInputStream in = new DataInputStream(new ByteArrayInputStream(buf, 0, len)); + 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"); + } + + 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, Integer.valueOf(state)); + modeAttr.put(IMode.IV, iv); + try + { + mode.init(modeAttr); + } + catch (InvalidKeyException ike) + { + throw new IllegalArgumentException(ike.toString()); + } + return mode; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/Entry.java b/libjava/classpath/gnu/javax/crypto/keyring/Entry.java new file mode 100644 index 000000000..d45924940 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/Entry.java @@ -0,0 +1,179 @@ +/* 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 gnu.java.security.Configuration; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.logging.Logger; + +/** + * An immutable class representing a single entry in a keyring. + */ +public abstract class Entry +{ + private static final Logger log = Logger.getLogger(Entry.class.getName()); + private static final String[] TYPES = new String[] { + "Encrypted", + "PasswordEncrypted", + "Authenticated", + "PasswordAuthenticated", + "Compressed", + "Certificate", + "PublicKey", + "PrivateKey", + "CertPath", + "BinaryData" }; + /** This entry's type identifier. */ + protected int type; + /** This entry's property set. */ + protected Properties properties; + /** This entry's payload. */ + protected byte[] payload; + + /** + * 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(); + } + + /** + * 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); + } + + public String toString() + { + return new StringBuilder("Entry{") + .append("type=").append(TYPES[type]) + .append(", properties=").append(properties) + .append(", payload=") + .append(payload == null ? "-" : "byte[" + payload.length + "]") + .append( "}") + .toString(); + } + + /** + * 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"); + if (Configuration.DEBUG) + log.fine("About to instantiate new payload byte array for " + this); + payload = new byte[len]; + in.readFully(payload); + } + + /** + * 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/libjava/classpath/gnu/javax/crypto/keyring/EnvelopeEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/EnvelopeEntry.java new file mode 100644 index 000000000..76aba7d7b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/EnvelopeEntry.java @@ -0,0 +1,439 @@ +/* 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 gnu.java.security.Configuration; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.StringTokenizer; +import java.util.logging.Logger; + +/** + * An envelope entry is a generic container for some number of primitive and + * other envelope entries. + */ +public abstract class EnvelopeEntry + extends Entry +{ + private static final Logger log = Logger.getLogger(EnvelopeEntry.class.getName()); + /** The envelope that contains this one (if any). */ + protected EnvelopeEntry containingEnvelope; + /** The contained entries. */ + protected List entries; + + 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(); + } + + /** + * Adds an entry to this envelope. + * + * @param entry The entry to add. + */ + public void add(Entry entry) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "add", entry); + if (! containsEntry(entry)) + { + if (entry instanceof EnvelopeEntry) + ((EnvelopeEntry) entry).setContainingEnvelope(this); + entries.add(entry); + if (Configuration.DEBUG) + log.fine("Payload is " + (payload == null ? "" : "not ") + "null"); + makeAliasList(); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "add"); + } + + /** + * 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) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "containsAlias", alias); + String aliases = getAliasList(); + if (Configuration.DEBUG) + log.fine("aliases = [" + aliases + "]"); + boolean result = false; + if (aliases != null) + { + StringTokenizer tok = new StringTokenizer(aliases, ";"); + while (tok.hasMoreTokens()) + if (tok.nextToken().equals(alias)) + { + result = true; + break; + } + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "containsAlias", + Boolean.valueOf(result)); + return result; + } + + /** + * 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); + 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) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "get", alias); + List result = new LinkedList(); + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof EnvelopeEntry) + { + EnvelopeEntry ee = (EnvelopeEntry) e; + if (! ee.containsAlias(alias)) + continue; + if (ee instanceof MaskableEnvelopeEntry) + { + MaskableEnvelopeEntry mee = (MaskableEnvelopeEntry) ee; + if (mee.isMasked()) + { + if (Configuration.DEBUG) + log.fine("Processing masked entry: " + mee); + result.add(mee); + continue; + } + } + if (Configuration.DEBUG) + log.fine("Processing unmasked entry: " + ee); + result.addAll(ee.get(alias)); + } + else if (e instanceof PrimitiveEntry) + { + PrimitiveEntry pe = (PrimitiveEntry) e; + if (pe.getAlias().equals(alias)) + result.add(e); + } + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "get", result); + 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) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "remove", 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) + { + if (Configuration.DEBUG) + log.fine("State before: " + this); + payload = null; + makeAliasList(); + if (Configuration.DEBUG) + log.fine("State after: " + this); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "remove", Boolean.valueOf(ret)); + return ret; + } + + /** + * Removes all primitive entries that have the specified alias. + * + * @param alias The alias of the entries to remove. + * @return true if alias was present and was + * successfully trmoved. Returns false if + * alias was not present in the list of aliases in this + * envelope. + */ + public boolean remove(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "remove", alias); + boolean result = false; + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof EnvelopeEntry) + { + EnvelopeEntry ee = (EnvelopeEntry) e; + result = ee.remove(alias) || result; + } + else if (e instanceof PrimitiveEntry) + { + PrimitiveEntry pe = (PrimitiveEntry) e; + if (pe.getAlias().equals(alias)) + { + it.remove(); + result = true; + } + } + } + if (result) + { + if (Configuration.DEBUG) + log.fine("State before: " + this); + payload = null; + makeAliasList(); + if (Configuration.DEBUG) + log.fine("State after: " + this); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "remove", Boolean.valueOf(result)); + return result; + } + + public String toString() + { + return new StringBuilder("Envelope{") + .append(super.toString()) + .append(", entries=").append(entries) + .append("}") + .toString(); + } + + // 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 + { + this.entries.clear(); + 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); + } + } + } + + private void makeAliasList() + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "makeAliasList"); + if (! entries.isEmpty()) + { + StringBuilder buf = new StringBuilder(); + String aliasOrList; + for (Iterator it = entries.iterator(); it.hasNext();) + { + Entry entry = (Entry) it.next(); + aliasOrList = null; + if (entry instanceof EnvelopeEntry) + aliasOrList = ((EnvelopeEntry) entry).getAliasList(); + else if (entry instanceof PrimitiveEntry) + aliasOrList = ((PrimitiveEntry) entry).getAlias(); + else if (Configuration.DEBUG) + log.fine("Entry with no Alias. Ignored: " + entry); + if (aliasOrList != null) + { + aliasOrList = aliasOrList.trim(); + if (aliasOrList.trim().length() > 0) + { + buf.append(aliasOrList); + if (it.hasNext()) + buf.append(';'); + } + } + } + String aliasList = buf.toString(); + properties.put("alias-list", aliasList); + if (Configuration.DEBUG) + log.fine("alias-list=[" + aliasList + "]"); + if (containingEnvelope != null) + containingEnvelope.makeAliasList(); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "makeAliasList"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/GnuPrivateKeyring.java b/libjava/classpath/gnu/javax/crypto/keyring/GnuPrivateKeyring.java new file mode 100644 index 000000000..ab3933972 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/GnuPrivateKeyring.java @@ -0,0 +1,368 @@ +/* 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.Configuration; +import gnu.java.security.Registry; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +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.logging.Level; +import java.util.logging.Logger; + +/** + * + */ +public class GnuPrivateKeyring + extends BaseKeyring + implements IPrivateKeyring +{ + private static final Logger log = Logger.getLogger(GnuPrivateKeyring.class.getName()); + 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; + + 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); + } + + public boolean containsPrivateKey(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "containsPrivateKey", alias); + boolean result = false; + if (containsAlias(alias)) + for (Iterator it = get(alias).iterator(); it.hasNext();) + if (it.next() instanceof PasswordAuthenticatedEntry) + { + result = true; + break; + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "containsPrivateKey", + Boolean.valueOf(result)); + return result; + } + + public Key getPrivateKey(String alias, char[] password) + throws UnrecoverableKeyException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "getPrivateKey", alias); + Key result = null; + if (containsAlias(alias)) + { + PasswordAuthenticatedEntry e1 = null; + for (Iterator it = get(alias).iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (Configuration.DEBUG) + log.finest("Entry: " + e); + if (e instanceof PasswordAuthenticatedEntry) + { + e1 = (PasswordAuthenticatedEntry) e; + break; + } + } + if (Configuration.DEBUG) + log.fine("e1 = " + e1); + if (e1 != null) + { + try + { + e1.verify(password); + } + catch (Exception e) + { + if (Configuration.DEBUG) + log.throwing(this.getClass().getName(), "getPrivateKey", e); + throw new UnrecoverableKeyException("authentication failed"); + } + PasswordEncryptedEntry e2 = null; + for (Iterator it = e1.getEntries().iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof PasswordEncryptedEntry) + { + e2 = (PasswordEncryptedEntry) e; + break; + } + } + if (e2 != null) + { + try + { + e2.decrypt(password); + } + catch (Exception e) + { + log.throwing(this.getClass().getName(), "getPrivateKey", e); + throw new UnrecoverableKeyException("decryption failed"); + } + for (Iterator it = e2.get(alias).iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof PrivateKeyEntry) + { + result = ((PrivateKeyEntry) e).getKey(); + break; + } + } + } + } + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "getPrivateKey", + result == null ? "null" : result.getClass().getName()); + return result; + } + + public void putPrivateKey(String alias, Key key, char[] password) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "putPrivateKey", + new Object[] { alias, key.getClass().getName() }); + if (! containsPrivateKey(alias)) + { + alias = fixAlias(alias); + Properties p = new Properties(); + p.put("alias", alias); + PrivateKeyEntry pke = new PrivateKeyEntry(key, new Date(), p); + if (Configuration.DEBUG) + log.fine("About to encrypt the key..."); + PasswordEncryptedEntry enc; + enc = new PasswordEncryptedEntry(cipher, mode, keylen, new Properties()); + enc.add(pke); + try + { + enc.encode(null, password); + } + catch (IOException x) + { + if (Configuration.DEBUG) + log.log(Level.FINE, "Exception while encrypting the key. " + + "Rethrow as IllegalArgumentException", x); + throw new IllegalArgumentException(x.toString()); + } + if (Configuration.DEBUG) + log.fine("About to authenticate the encrypted key..."); + PasswordAuthenticatedEntry auth; + auth = new PasswordAuthenticatedEntry(mac, maclen, new Properties()); + auth.add(enc); + try + { + auth.encode(null, password); + } + catch (IOException x) + { + if (Configuration.DEBUG) + log.log(Level.FINE, "Exception while authenticating the encrypted " + + "key. Rethrow as IllegalArgumentException", x); + throw new IllegalArgumentException(x.toString()); + } + keyring.add(auth); + } + else if (Configuration.DEBUG) + log.fine("Keyring already contains alias: " + alias); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "putPrivateKey"); + } + + public boolean containsPublicKey(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "containsPublicKey", alias); + boolean result = false; + if (containsAlias(alias)) + for (Iterator it = get(alias).iterator(); it.hasNext();) + if (it.next() instanceof PublicKeyEntry) + { + result = true; + break; + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "containsPublicKey", + Boolean.valueOf(result)); + return result; + } + + public PublicKey getPublicKey(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "getPublicKey", alias); + PublicKey result = null; + if (containsAlias(alias)) + for (Iterator it = get(alias).iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof PublicKeyEntry) + { + result = ((PublicKeyEntry) e).getKey(); + break; + } + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "getPublicKey", + result == null ? "null" : result.getClass().getName()); + return result; + } + + public void putPublicKey(String alias, PublicKey key) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "putPublicKey", + new Object[] { alias, key.getClass().getName() }); + if (! containsPublicKey(alias)) + { + Properties p = new Properties(); + p.put("alias", fixAlias(alias)); + add(new PublicKeyEntry(key, new Date(), p)); + } + else if (Configuration.DEBUG) + log.fine("Keyring already contains alias: " + alias); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "putPublicKey"); + } + + public boolean containsCertPath(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "containsCertPath", alias); + boolean result = false; + if (containsAlias(alias)) + for (Iterator it = get(alias).iterator(); it.hasNext();) + if (it.next() instanceof CertPathEntry) + { + result = true; + break; + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "containsCertPath", + Boolean.valueOf(result)); + return result; + } + + public Certificate[] getCertPath(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "getCertPath", alias); + Certificate[] result = null; + if (containsAlias(alias)) + for (Iterator it = get(alias).iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof CertPathEntry) + { + result = ((CertPathEntry) e).getCertPath(); + break; + } + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "getCertPath", result); + return result; + } + + public void putCertPath(String alias, Certificate[] path) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "putCertPath", + new Object[] { alias, path }); + if (! containsCertPath(alias)) + { + Properties p = new Properties(); + p.put("alias", fixAlias(alias)); + add(new CertPathEntry(path, new Date(), p)); + } + else if (Configuration.DEBUG) + log.fine("Keyring already contains alias: " + alias); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "putCertPath"); + } + + protected void load(InputStream in, char[] password) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "load"); + 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); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "load"); + } + + protected void store(OutputStream out, char[] password) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "store"); + out.write(USAGE); + keyring.encode(new DataOutputStream(out), password); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "store"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/GnuPublicKeyring.java b/libjava/classpath/gnu/javax/crypto/keyring/GnuPublicKeyring.java new file mode 100644 index 000000000..d7387f892 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/GnuPublicKeyring.java @@ -0,0 +1,151 @@ +/* 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 gnu.java.security.Configuration; +import gnu.java.security.Registry; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.cert.Certificate; +import java.util.Date; +import java.util.Iterator; +import java.util.logging.Logger; + +public class GnuPublicKeyring + extends BaseKeyring + implements IPublicKeyring +{ + private static final Logger log = Logger.getLogger(GnuPublicKeyring.class.getName()); + public static final int USAGE = Registry.GKR_CERTIFICATES; + + public GnuPublicKeyring(String mac, int macLen) + { + keyring = new PasswordAuthenticatedEntry(mac, macLen, new Properties()); + keyring2 = new CompressedEntry(new Properties()); + keyring.add(keyring2); + } + + public GnuPublicKeyring() + { + } + + public boolean containsCertificate(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "containsCertificate", alias); + boolean result = false; + if (containsAlias(alias)) + for (Iterator it = get(alias).iterator(); it.hasNext();) + if (it.next() instanceof CertificateEntry) + { + result = true; + break; + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "containsCertificate", + Boolean.valueOf(result)); + return result; + } + + public Certificate getCertificate(String alias) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "getCertificate", alias); + Certificate result = null; + if (containsAlias(alias)) + for (Iterator it = get(alias).iterator(); it.hasNext();) + { + Entry e = (Entry) it.next(); + if (e instanceof CertificateEntry) + { + result = ((CertificateEntry) e).getCertificate(); + break; + } + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "getCertificate", result); + return result; + } + + public void putCertificate(String alias, Certificate cert) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "putCertificate", + new Object[] { alias, cert }); + if (! containsCertificate(alias)) + { + Properties p = new Properties(); + p.put("alias", fixAlias(alias)); + add(new CertificateEntry(cert, new Date(), p)); + } + else if (Configuration.DEBUG) + log.fine("Keyring already contains alias: " + alias); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "putCertificate"); + } + + protected void load(InputStream in, char[] password) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "load"); + if (in.read() != USAGE) + throw new MalformedKeyringException("incompatible keyring usage"); + if (in.read() != PasswordAuthenticatedEntry.TYPE) + throw new MalformedKeyringException( + "expecting password-authenticated entry tag"); + DataInputStream dis = new DataInputStream(in); + keyring = PasswordAuthenticatedEntry.decode(dis, password); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "load"); + } + + protected void store(OutputStream out, char[] password) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "store"); + out.write(USAGE); + keyring.encode(new DataOutputStream(out), password); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "store"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/IKeyring.java b/libjava/classpath/gnu/javax/crypto/keyring/IKeyring.java new file mode 100644 index 000000000..141f2dcd4 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/IKeyring.java @@ -0,0 +1,162 @@ +/* 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/libjava/classpath/gnu/javax/crypto/keyring/IPrivateKeyring.java b/libjava/classpath/gnu/javax/crypto/keyring/IPrivateKeyring.java new file mode 100644 index 000000000..3bfa10098 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/IPrivateKeyring.java @@ -0,0 +1,144 @@ +/* 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/libjava/classpath/gnu/javax/crypto/keyring/IPublicKeyring.java b/libjava/classpath/gnu/javax/crypto/keyring/IPublicKeyring.java new file mode 100644 index 000000000..d723f5ae9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/IPublicKeyring.java @@ -0,0 +1,82 @@ +/* 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/libjava/classpath/gnu/javax/crypto/keyring/MalformedKeyringException.java b/libjava/classpath/gnu/javax/crypto/keyring/MalformedKeyringException.java new file mode 100644 index 000000000..f6b9d189b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/MalformedKeyringException.java @@ -0,0 +1,55 @@ +/* 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 +{ + public MalformedKeyringException() + { + super(); + } + + public MalformedKeyringException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java new file mode 100644 index 000000000..58254a437 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java @@ -0,0 +1,135 @@ +/* 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 +{ + /** The masked state. */ + protected boolean masked; + + public MaskableEnvelopeEntry(int type, Properties properties) + { + super(type, properties); + } + + protected MaskableEnvelopeEntry(int type) + { + super(type); + } + + /** + * 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 boolean remove(String alias) + { + if (isMasked()) + throw new IllegalStateException("masked envelope"); + return super.remove(alias); + } + + public String toString() + { + return new StringBuilder("MaskableEnvelope{") + .append(super.toString()) + .append(", masked=").append(masked) + .append("}").toString(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/MeteredInputStream.java b/libjava/classpath/gnu/javax/crypto/keyring/MeteredInputStream.java new file mode 100644 index 000000000..65f263359 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/MeteredInputStream.java @@ -0,0 +1,127 @@ +/* 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.IOException; +import java.io.InputStream; + +final class MeteredInputStream + extends FilterInputStream +{ + private int count; + private final int limit; + + MeteredInputStream(InputStream in, int limit) + { + super(in); + if (limit < 0) + throw new IllegalArgumentException("limit must be nonnegative"); + this.limit = limit; + count = 0; + } + + /** + * 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/libjava/classpath/gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java new file mode 100644 index 000000000..d67300442 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java @@ -0,0 +1,286 @@ +/* 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.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.PRNG; +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.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.logging.Logger; + +/** + * An entry authenticated with a password-based MAC. + */ +public final class PasswordAuthenticatedEntry + extends MaskableEnvelopeEntry + implements PasswordProtectedEntry, Registry +{ + private static final Logger log = Logger.getLogger(PasswordAuthenticatedEntry.class.getName()); + public static final int TYPE = 3; + + 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); + } + + 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; + } + + public void verify(char[] password) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "verify"); + if (isMasked() && payload != null) + { + if (Configuration.DEBUG) + log.fine("payload to verify: " + Util.dumpString(payload)); + long tt = -System.currentTimeMillis(); + IMac m = null; + try + { + m = getMac(password); + } + catch (Exception x) + { + throw new IllegalArgumentException(x.toString(), x); + } + int limit = payload.length - m.macSize(); + m.update(payload, 0, limit); + 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"); + setMasked(false); + ByteArrayInputStream bais; + try + { + bais = new ByteArrayInputStream(payload, 0, limit); + DataInputStream in = new DataInputStream(bais); + decodeEnvelope(in); + } + catch (IOException ioe) + { + throw new IllegalArgumentException("malformed keyring fragment"); + } + tt += System.currentTimeMillis(); + if (Configuration.DEBUG) + log.fine("Verified in " + tt + "ms."); + } + else if (Configuration.DEBUG) + log.fine("Skip verification; " + + (isMasked() ? "null payload" : "unmasked")); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "verify"); + } + + public void authenticate(char[] password) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "authenticate"); + long tt = -System.currentTimeMillis(); + long t1 = -System.currentTimeMillis(); + if (isMasked()) + throw new IllegalStateException("entry is masked"); + byte[] salt = new byte[8]; + PRNG.getInstance().nextBytes(salt); + t1 += System.currentTimeMillis(); + if (Configuration.DEBUG) + log.fine("-- Generated salt in " + t1 + "ms."); + 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(); + if (Configuration.DEBUG) + log.fine("-- About to authenticate one " + entry); + t1 = -System.currentTimeMillis(); + entry.encode(out2); + t1 += System.currentTimeMillis(); + if (Configuration.DEBUG) + log.fine("-- Authenticated an Entry in " + t1 + "ms."); + } + bout.write(m.digest()); + payload = bout.toByteArray(); + if (Configuration.DEBUG) + log.fine("authenticated payload: " + Util.dumpString(payload)); + setMasked(true); + tt += System.currentTimeMillis(); + if (Configuration.DEBUG) + { + log.fine("Authenticated in " + tt + "ms."); + log.exiting(this.getClass().getName(), "authenticate"); + } + } + + public void encode(DataOutputStream out, char[] password) throws IOException + { + authenticate(password); + encode(out); + } + + protected void encodePayload(DataOutputStream out) throws IOException + { + if (payload == null) + { + log.fine("Null payload: " + this); + throw new IllegalStateException("mac not computed"); + } + } + + private IMac getMac(char[] password) throws MalformedKeyringException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "getMac"); + String saltString = properties.get("salt"); + if (saltString == null) + throw new MalformedKeyringException("no salt"); + byte[] salt = Util.toBytesFromString(saltString); + String macAlgorithm = properties.get("mac"); + IMac mac = MacFactory.getInstance(macAlgorithm); + if (mac == null) + throw new MalformedKeyringException("no such mac: " + macAlgorithm); + String macLenString = properties.get("maclen"); + if (macLenString == null) + throw new MalformedKeyringException("no MAC length"); + int maclen; + try + { + maclen = Integer.parseInt(macLenString); + } + 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); + int keylen = mac.macSize(); + 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, Integer.valueOf(maclen)); + try + { + mac.init(macAttr); + } + catch (InvalidKeyException shouldNotHappen) + { + throw new Error(shouldNotHappen.toString()); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "getMac"); + return mac; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/PasswordEncryptedEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/PasswordEncryptedEntry.java new file mode 100644 index 000000000..0fa7431a8 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/PasswordEncryptedEntry.java @@ -0,0 +1,293 @@ +/* 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.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.PRNG; +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.util.HashMap; +import java.util.Iterator; +import java.util.logging.Logger; + +/** + * An envelope that is encrypted with a password-derived key. + */ +public class PasswordEncryptedEntry + extends MaskableEnvelopeEntry + implements PasswordProtectedEntry, Registry +{ + private static final Logger log = Logger.getLogger(PasswordEncryptedEntry.class.getName()); + public static final int TYPE = 1; + + 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); + } + + 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; + } + + public void decrypt(char[] password) throws IllegalArgumentException, + WrongPaddingException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "decrypt"); + if (isMasked() && payload != null) + { + long tt = -System.currentTimeMillis(); + IMode mode = getMode(password, IMode.DECRYPTION); + IPad padding = PadFactory.getInstance("PKCS7"); + padding.init(mode.currentBlockSize()); + byte[] buf = new byte[payload.length]; + int count = 0; + while (count + mode.currentBlockSize() <= payload.length) + { + mode.update(payload, count, buf, count); + count += mode.currentBlockSize(); + } + int padlen = padding.unpad(buf, 0, buf.length); + setMasked(false); + int len = buf.length - padlen; + ByteArrayInputStream baos = new ByteArrayInputStream(buf, 0, len); + DataInputStream in = new DataInputStream(baos); + try + { + decodeEnvelope(in); + } + catch (IOException ioe) + { + throw new IllegalArgumentException("decryption failed"); + } + tt += System.currentTimeMillis(); + log.fine("Decrypted in " + tt + "ms."); + } + else if (Configuration.DEBUG) + log.fine("Skip decryption; " + (isMasked() ? "null payload" : "unmasked")); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "decrypt"); + } + + public void encrypt(char[] password) throws IOException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "encrypt", String.valueOf(password)); + long tt = -System.currentTimeMillis(); + long t1 = -System.currentTimeMillis(); + byte[] salt = new byte[8]; + PRNG.getInstance().nextBytes(salt); + t1 += System.currentTimeMillis(); + if (Configuration.DEBUG) + log.fine("-- Generated salt in " + t1 + "ms."); + 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(); + if (Configuration.DEBUG) + log.fine("-- About to encode one " + entry); + t1 = -System.currentTimeMillis(); + entry.encode(out2); + t1 += System.currentTimeMillis(); + if (Configuration.DEBUG) + log.fine("-- Encoded an Entry in " + t1 + "ms."); + } + 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); + setMasked(true); + tt += System.currentTimeMillis(); + if (Configuration.DEBUG) + { + log.fine("Encrypted in " + tt + "ms."); + log.exiting(this.getClass().getName(), "encrypt"); + } + } + + public void encode(DataOutputStream out, char[] password) throws IOException + { + encrypt(password); + encode(out); + } + + protected void encodePayload() throws IOException + { + if (payload == null) + { + if (Configuration.DEBUG) + log.fine("Null payload: " + this); + throw new IllegalStateException("not encrypted"); + } + } + + 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()); + } + String modeName = properties.get("mode"); + IMode mode = ModeFactory.getInstance(modeName, cipher, blockSize); + if (mode == null) + throw new IllegalArgumentException("no such mode: " + modeName); + 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, Integer.valueOf(state)); + modeAttr.put(IMode.IV, iv); + try + { + mode.init(modeAttr); + } + catch (InvalidKeyException ike) + { + throw new IllegalArgumentException(ike.toString()); + } + return mode; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/PasswordProtectedEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/PasswordProtectedEntry.java new file mode 100644 index 000000000..a95f2e4a4 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/PasswordProtectedEntry.java @@ -0,0 +1,57 @@ +/* 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 +{ + /** The iteration count for password-based KDFs. */ + Integer ITERATION_COUNT = Integer.valueOf(1000); + + /** + * 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/libjava/classpath/gnu/javax/crypto/keyring/PrimitiveEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/PrimitiveEntry.java new file mode 100644 index 000000000..8993de716 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/PrimitiveEntry.java @@ -0,0 +1,112 @@ +/* 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 +{ + /** The creation date. */ + protected Date creationDate; + + 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(this.creationDate.getTime())); + } + + protected PrimitiveEntry(int type) + { + super(type); + } + + /** + * 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/libjava/classpath/gnu/javax/crypto/keyring/PrivateKeyEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/PrivateKeyEntry.java new file mode 100644 index 000000000..b2637316e --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/PrivateKeyEntry.java @@ -0,0 +1,194 @@ +/* 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.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. + */ +public final class PrivateKeyEntry + extends PrimitiveEntry +{ + public static final int TYPE = 7; + /** The key. */ + private Key key; + + /** + * 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); + } + + 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"); + PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(entry.payload); + entry.key = kf.generatePrivate(ks); + } + catch (Exception ignored) + { + } + if (entry.key == null) + { + try + { + KeyFactory kf = KeyFactory.getInstance("DSA"); + PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(entry.payload); + entry.key = kf.generatePrivate(ks); + } + catch (Exception ignored) + { + } + if (entry.key == null) + throw new MalformedKeyringException("could not decode PKCS#8 key"); + } + } + else + throw new MalformedKeyringException("unsupported key type " + type); + return entry; + } + + /** + * 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"); + } + + public String toString() + { + return "PrivateKeyEntry{key=" + + (key == null ? "-" : key.getClass().getName()) + "}"; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/Properties.java b/libjava/classpath/gnu/javax/crypto/keyring/Properties.java new file mode 100644 index 000000000..f25c82e36 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/Properties.java @@ -0,0 +1,203 @@ +/* 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 +{ + private HashMap props; + + /** + * Creates a new properties object. + */ + public Properties() + { + props = new HashMap(); + } + + /** + * 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(); + } + + private String canonicalize(String key) + { + return key.toLowerCase(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/keyring/PublicKeyEntry.java b/libjava/classpath/gnu/javax/crypto/keyring/PublicKeyEntry.java new file mode 100644 index 000000000..837706d19 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/keyring/PublicKeyEntry.java @@ -0,0 +1,162 @@ +/* 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 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; + +import java.io.DataInputStream; +import java.io.IOException; +import java.security.KeyFactory; +import java.security.PublicKey; +import java.security.spec.X509EncodedKeySpec; +import java.util.Date; + +public final class PublicKeyEntry + extends PrimitiveEntry +{ + public static final int TYPE = 6; + private PublicKey key; + + 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); + } + + 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; + } + + /** + * 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/libjava/classpath/gnu/javax/crypto/kwa/AESKeyWrap.java b/libjava/classpath/gnu/javax/crypto/kwa/AESKeyWrap.java new file mode 100644 index 000000000..bb86c5477 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/kwa/AESKeyWrap.java @@ -0,0 +1,168 @@ +/* AESWrap.java -- An implementation of RFC-3394 AES Key Wrap Algorithm + 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.kwa; + +import gnu.java.security.Registry; +import gnu.javax.crypto.cipher.IBlockCipher; +import gnu.javax.crypto.cipher.Rijndael; + +import java.security.InvalidKeyException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +/** + * The GNU implementation of the AES Key Wrap Algorithm as described in [1]. + *

    + * References: + *

      + *
    1. .
    2. + *
    3. Advanced + * Encryption Standard (AES) Key Wrap Algorithm.
    4. + *
    5. XML Encryption Syntax and + * Processing.
    6. + *
    + */ +public class AESKeyWrap + extends BaseKeyWrappingAlgorithm +{ + private static final byte[] DEFAULT_IV = new byte[] { + (byte) 0xA6, (byte) 0xA6, (byte) 0xA6, (byte) 0xA6, + (byte) 0xA6, (byte) 0xA6, (byte) 0xA6, (byte) 0xA6 }; + + private Rijndael aes; + private byte[] iv; + + public AESKeyWrap() + { + super(Registry.AES_KWA); + + aes = new Rijndael(); + } + + protected void engineInit(Map attributes) throws InvalidKeyException + { + Map cipherAttributes = new HashMap(); + cipherAttributes.put(IBlockCipher.CIPHER_BLOCK_SIZE, Integer.valueOf(16)); + cipherAttributes.put(IBlockCipher.KEY_MATERIAL, + attributes.get(KEY_ENCRYPTION_KEY_MATERIAL)); + aes.reset(); + aes.init(cipherAttributes); + byte[] initialValue = (byte[]) attributes.get(INITIAL_VALUE); + iv = initialValue == null ? DEFAULT_IV : (byte[]) initialValue.clone(); + } + + protected byte[] engineWrap(byte[] in, int inOffset, int length) + { + // TODO: handle input length which is not a multiple of 8 as suggested by + // section 2.2.3.2 of RFC-3394 + if (length % 8 != 0) + throw new IllegalArgumentException("Input length MUST be a multiple of 8"); + int n = length / 8; + // output is always one block larger than input + byte[] result = new byte[length + 8]; + + // 1. init variables: we'll use out buffer for our work buffer; + // A will be the first block in out, while R will be the rest + System.arraycopy(iv, 0, result, 0, 8); + System.arraycopy(in, inOffset, result, 8, length); + byte[] B = new byte[2 * 8]; + // 2. compute intermediate values + long t; + for (int j = 0; j < 6; j++) + for (int i = 1; i <= n; i++) + { + System.arraycopy(result, 0, B, 0, 8); + System.arraycopy(result, i * 8, B, 8, 8); + aes.encryptBlock(B, 0, B, 0); + t = (n * j) + i; + result[0] = (byte)(B[0] ^ (t >>> 56)); + result[1] = (byte)(B[1] ^ (t >>> 48)); + result[2] = (byte)(B[2] ^ (t >>> 40)); + result[3] = (byte)(B[3] ^ (t >>> 32)); + result[4] = (byte)(B[4] ^ (t >>> 24)); + result[5] = (byte)(B[5] ^ (t >>> 16)); + result[6] = (byte)(B[6] ^ (t >>> 8)); + result[7] = (byte)(B[7] ^ t ); + System.arraycopy(B, 8, result, i * 8, 8); + } + return result; + } + + protected byte[] engineUnwrap(byte[] in, int inOffset, int length) + throws KeyUnwrappingException + { + // TODO: handle input length which is not a multiple of 8 as suggested by + // section 2.2.3.2 of RFC-3394 + if (length % 8 != 0) + throw new IllegalArgumentException("Input length MUST be a multiple of 8"); + // output is always one block shorter than input + byte[] result = new byte[length - 8]; + + // 1. init variables: we'll use out buffer for our R work buffer + byte[] A = new byte[8]; + System.arraycopy(in, inOffset, A, 0, 8); + System.arraycopy(in, inOffset + 8, result, 0, result.length); + byte[] B = new byte[2 * 8]; + // 2. compute intermediate values + int n = length / 8 - 1; + long t; + for (int j = 5; j >= 0; j--) + for (int i = n; i >= 1; i--) + { + t = (n * j) + i; + B[0] = (byte)(A[0] ^ (t >>> 56)); + B[1] = (byte)(A[1] ^ (t >>> 48)); + B[2] = (byte)(A[2] ^ (t >>> 40)); + B[3] = (byte)(A[3] ^ (t >>> 32)); + B[4] = (byte)(A[4] ^ (t >>> 24)); + B[5] = (byte)(A[5] ^ (t >>> 16)); + B[6] = (byte)(A[6] ^ (t >>> 8)); + B[7] = (byte)(A[7] ^ t ); + System.arraycopy(result, (i - 1) * 8, B, 8, 8); + aes.decryptBlock(B, 0, B, 0); + System.arraycopy(B, 0, A, 0, 8); + System.arraycopy(B, 8, result, (i - 1) * 8, 8); + } + if (! Arrays.equals(A, iv)) + throw new KeyUnwrappingException(); + + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/kwa/BaseKeyWrappingAlgorithm.java b/libjava/classpath/gnu/javax/crypto/kwa/BaseKeyWrappingAlgorithm.java new file mode 100644 index 000000000..80b114a02 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/kwa/BaseKeyWrappingAlgorithm.java @@ -0,0 +1,145 @@ +/* BaseKeyWrappingAlgorithm.java -- FIXME: briefly describe file purpose + 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.kwa; + +import gnu.java.security.util.PRNG; + +import java.security.InvalidKeyException; +import java.util.Collections; +import java.util.Map; + +import javax.crypto.ShortBufferException; + +/** + * A base class to facilitate implementation of concrete Key Wrapping + * Algorithms. + */ +public abstract class BaseKeyWrappingAlgorithm + implements IKeyWrappingAlgorithm +{ + /** The canonical name of the key wrapping algorithm. */ + protected String name; + /** A source of randomness if/when needed by concrete implementations. */ + private PRNG prng; + + /** + * Protected constructor. + * + * @param name the key wrapping algorithm canonical name. + */ + protected BaseKeyWrappingAlgorithm(String name) + { + super(); + } + + public String name() + { + return this.name; + } + + public void init(Map attributes) throws InvalidKeyException + { + if (attributes == null) + attributes = Collections.EMPTY_MAP; + + engineInit(attributes); + } + + public int wrap(byte[] in, int inOffset, int length, byte[] out, int outOffset) + throws ShortBufferException + { + if (outOffset < 0) + throw new IllegalArgumentException("Output offset MUST NOT be negative"); + byte[] result = wrap(in, inOffset, length); + if (outOffset + result.length > out.length) + throw new ShortBufferException(); + System.arraycopy(result, 0, out, outOffset, result.length); + return result.length; + } + + public byte[] wrap(byte[] in, int inOffset, int length) + { + if (inOffset < 0) + throw new IllegalArgumentException("Input offset MUST NOT be negative"); + if (length < 0) + throw new IllegalArgumentException("Input length MUST NOT be negative"); + + return engineWrap(in, inOffset, length); + } + + public int unwrap(byte[] in, int inOffset, int length, + byte[] out, int outOffset) + throws ShortBufferException, KeyUnwrappingException + { + if (outOffset < 0) + throw new IllegalArgumentException("Output offset MUST NOT be negative"); + byte[] result = engineUnwrap(in, inOffset, length); + if (outOffset + result.length > out.length) + throw new ShortBufferException(); + System.arraycopy(result, 0, out, outOffset, result.length); + return result.length; + } + + public byte[] unwrap(byte[] in, int inOffset, int length) + throws KeyUnwrappingException + { + if (inOffset < 0) + throw new IllegalArgumentException("Input offset MUST NOT be negative"); + if (length < 0) + throw new IllegalArgumentException("Input length MUST NOT be negative"); + + return engineUnwrap(in, inOffset, length); + } + + protected abstract void engineInit(Map attributes) throws InvalidKeyException; + + protected abstract byte[] engineWrap(byte[] in, int inOffset, int length); + + protected abstract byte[] engineUnwrap(byte[] in, int inOffset, int length) + throws KeyUnwrappingException; + + /** @return a strong pseudo-random number generator if/when needed. */ + protected PRNG getDefaultPRNG() + { + if (prng == null) + prng = PRNG.getInstance(); + + return prng; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/kwa/IKeyWrappingAlgorithm.java b/libjava/classpath/gnu/javax/crypto/kwa/IKeyWrappingAlgorithm.java new file mode 100644 index 000000000..271ec5c1b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/kwa/IKeyWrappingAlgorithm.java @@ -0,0 +1,160 @@ +/* IKeyWrappingAlgorithm.java -- FIXME: briefly describe file purpose + 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.kwa; + +import java.security.InvalidKeyException; +import java.security.SecureRandom; +import java.util.Map; + +import javax.crypto.ShortBufferException; + +/** + * Constants and visible methods available to all GNU Key Wrapping Algorithm + * implementations. + */ +public interface IKeyWrappingAlgorithm +{ + /** + * Name of the property, in the attributes map, that references the Key + * Wrapping Algorithm KEK (Key Encryption Key) material. The object referenced + * by this property is a byte array containing the keying material for the + * underlying block cipher. + */ + String KEY_ENCRYPTION_KEY_MATERIAL = "gnu.crypto.kwa.kek"; + /** + * Name of the property, in the attributes map, that references the Initial + * Value (IV) material. The object referenced by this property is a byte array + * containing the initial integrity check register value. + */ + String INITIAL_VALUE = "gnu.crypto.kwa.iv"; + /** + * Property name of an optional {@link SecureRandom} instance to use. The + * default is to use a {@link gnu.java.security.util.PRNG} instance. + */ + String SOURCE_OF_RANDOMNESS = "gnu.crypto.kwa.prng"; + + /** + * Returns the canonical name of this Key Wrapping Algorithm. + * + * @return the canonical name of this Key Wrapping Algorithm. + */ + String name(); + + /** + * Initializes this instance with the designated algorithm specific + * attributes. + * + * @param attributes a map of name-to-value pairs the Key Wrapping Algorithm + * must use for its setup. + * @throws InvalidKeyException if an exception is encountered while seting up + * the Key Wrapping Algorithm keying material (KEK). + */ + void init(Map attributes) throws InvalidKeyException; + + /** + * Wraps the designated plain text bytes. + * + * @param in the input byte array containing the plain text. + * @param inOffset the offset into in where the first byte of + * the plain text (key material) to wrap is located. + * @param length the number of bytes to wrap. + * @param out the output byte array where the wrapped key material will be + * stored. + * @param outOffset the offset into out of the first wrapped + * byte. + * @return the number of bytes of the wrapped key material; i.e. the length, + * in out, starting from outOffset + * where the cipher text (wrapped key material) are stored. + * @throws ShortBufferException if the output buffer is not long enough to + * accomodate the number of bytes resulting from wrapping the plain + * text. + */ + int wrap(byte[] in, int inOffset, int length, byte[] out, int outOffset) + throws ShortBufferException; + + /** + * Wraps the designated plain text bytes. + * + * @param in the input byte array containing the plain text. + * @param inOffset the offset into in where the first byte of + * the plain text (key material) to wrap is located. + * @param length the number of bytes to wrap. + * @return a newly allocated byte array containing the cipher text. + */ + byte[] wrap(byte[] in, int inOffset, int length); + + /** + * Unwraps the designated cipher text bytes. + * + * @param in the input byte array containing the cipher text. + * @param inOffset the offset into in where the first byte of + * the cipher text (already wrapped key material) to unwrap is + * located. + * @param length the number of bytes to unwrap. + * @param out the output byte array where the unwrapped key material will be + * stored. + * @param outOffset the offset into out of the first unwrapped + * byte. + * @return the number of bytes of the unwrapped key material; i.e. the length, + * in out, starting from outOffset + * where the plain text (unwrapped key material) are stored. + * @throws ShortBufferException if the output buffer is not long enough to + * accomodate the number of bytes resulting from unwrapping the + * cipher text. + * @throws KeyUnwrappingException if after unwrapping the cipher text, the + * bytes at the begining did not match the initial value. + */ + int unwrap(byte[] in, int inOffset, int length, byte[] out, int outOffset) + throws ShortBufferException, KeyUnwrappingException; + + /** + * Unwraps the designated cipher text bytes. + * + * @param in the input byte array containing the cipher text. + * @param inOffset the offset into in where the first byte of + * the cipher text (already wrapped key material) to unwrap is + * located. + * @param length the number of bytes to unwrap. + * @return a newly allocated byte array containing the plain text. + * @throws KeyUnwrappingException if after unwrapping the cipher text, the + * bytes at the begining did not match the initial value. + */ + byte[] unwrap(byte[] in, int inOffset, int length) + throws KeyUnwrappingException; +} diff --git a/libjava/classpath/gnu/javax/crypto/kwa/KeyUnwrappingException.java b/libjava/classpath/gnu/javax/crypto/kwa/KeyUnwrappingException.java new file mode 100644 index 000000000..54b4aff0a --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/kwa/KeyUnwrappingException.java @@ -0,0 +1,67 @@ +/* KeyUnwrappingException.java -- FIXME: briefly describe file purpose + 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.kwa; + +import java.security.GeneralSecurityException; + +/** + * A checked security exception to denote an unexpected problem while unwrapping + * key material with a Key Wrapping Algorithm. + */ +public class KeyUnwrappingException + extends GeneralSecurityException +{ + /** + * Create a new instance with no descriptive error message. + */ + public KeyUnwrappingException() + { + super(); + } + + /** + * Create a new instance with a descriptive error message. + * + * @param msg the descriptive error message + */ + public KeyUnwrappingException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/kwa/KeyWrappingAlgorithmFactory.java b/libjava/classpath/gnu/javax/crypto/kwa/KeyWrappingAlgorithmFactory.java new file mode 100644 index 000000000..abd208c07 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/kwa/KeyWrappingAlgorithmFactory.java @@ -0,0 +1,110 @@ +/* KeyWrappingAlgorithmFactory.java -- FIXME: briefly describe file purpose + 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.kwa; + +import gnu.java.security.Registry; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * A Factory class for the Key Wrapping Algorithm implementations. + */ +public class KeyWrappingAlgorithmFactory +{ + /** Names of Key Wrapping Algorihms cached for speed. */ + private static Set names; + + /** Trivial constructor to enforce Singleton pattern. */ + private KeyWrappingAlgorithmFactory() + { + super(); + } + + /** + * Returns an instance of a key-wrapping algorithm given its name. + * + * @param name the case-insensitive name of the key-wrapping algorithm. + * @return an instance of the designated key-wrapping algorithm, or + * null if none was found. + * @exception InternalError if the implementation does not pass its self-test. + */ + public static final IKeyWrappingAlgorithm getInstance(String name) + { + if (name == null) + return null; + name = name.trim(); + IKeyWrappingAlgorithm result = null; + if (name.equalsIgnoreCase(Registry.AES_KWA) + || name.equalsIgnoreCase(Registry.AES128_KWA) + || name.equalsIgnoreCase(Registry.AES192_KWA) + || name.equalsIgnoreCase(Registry.AES256_KWA) + || name.equalsIgnoreCase(Registry.RIJNDAEL_KWA)) + result = new AESKeyWrap(); + else if (name.equalsIgnoreCase(Registry.TRIPLEDES_KWA) + || name.equalsIgnoreCase(Registry.DESEDE_KWA)) + result = new TripleDESKeyWrap(); + + return result; + } + + /** + * Returns a {@link Set} of key wrapping algorithm names supported by this + * Factory. + * + * @return a {@link Set} of key wrapping algorithm names (Strings). + */ + public static synchronized final Set getNames() + { + if (names == null) + { + HashSet hs = new HashSet(); + hs.add(Registry.AES_KWA); + hs.add(Registry.AES128_KWA); + hs.add(Registry.AES192_KWA); + hs.add(Registry.AES256_KWA); + hs.add(Registry.RIJNDAEL_KWA); + hs.add(Registry.TRIPLEDES_KWA); + hs.add(Registry.DESEDE_KWA); + names = Collections.unmodifiableSet(hs); + } + return names; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/kwa/TripleDESKeyWrap.java b/libjava/classpath/gnu/javax/crypto/kwa/TripleDESKeyWrap.java new file mode 100644 index 000000000..28b16cf31 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/kwa/TripleDESKeyWrap.java @@ -0,0 +1,292 @@ +/* TripleDESKeyWrap.java -- FIXME: briefly describe file purpose + 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.kwa; + +import gnu.java.security.Registry; +import gnu.java.security.hash.Sha160; +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.IBlockCipher; +import gnu.javax.crypto.cipher.TripleDES; +import gnu.javax.crypto.mode.IMode; +import gnu.javax.crypto.mode.ModeFactory; + +import java.security.InvalidKeyException; +import java.security.SecureRandom; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +/** + * The GNU implementation of the Triple DES Key Wrap Algorithm as described in + * [1]. + *

    + * IMPORTANT: This class is NOT thread safe. + *

    + * References: + *

      + *
    1. Triple-DES and + * RC2 Key Wrapping.
    2. + *
    3. XML Encryption Syntax and + * Processing.
    4. + *
    + */ +public class TripleDESKeyWrap + extends BaseKeyWrappingAlgorithm +{ + private static final byte[] DEFAULT_IV = new byte[] { + (byte) 0x4A, (byte) 0xDD, (byte) 0xA2, (byte) 0x2C, + (byte) 0x79, (byte) 0xE8, (byte) 0x21, (byte) 0x05 }; + + private Assembly asm; + private HashMap asmAttributes = new HashMap(); + private HashMap modeAttributes = new HashMap(); + private Sha160 sha = new Sha160(); + private SecureRandom rnd; + + public TripleDESKeyWrap() + { + super(Registry.TRIPLEDES_KWA); + } + + protected void engineInit(Map attributes) throws InvalidKeyException + { + rnd = (SecureRandom) attributes.get(IKeyWrappingAlgorithm.SOURCE_OF_RANDOMNESS); + IMode des3CBC = ModeFactory.getInstance(Registry.CBC_MODE, new TripleDES(), 8); + Stage des3CBCStage = Stage.getInstance(des3CBC, Direction.FORWARD); + Cascade cascade = new Cascade(); + Object modeNdx = cascade.append(des3CBCStage); + + asmAttributes.put(modeNdx, modeAttributes); + + asm = new Assembly(); + asm.addPreTransformer(Transformer.getCascadeTransformer(cascade)); + + modeAttributes.put(IBlockCipher.KEY_MATERIAL, + attributes.get(KEY_ENCRYPTION_KEY_MATERIAL)); + asmAttributes.put(Assembly.DIRECTION, Direction.FORWARD); + } + + protected byte[] engineWrap(byte[] in, int inOffset, int length) + { + // The same key wrap algorithm is used for both Two-key Triple-DES and + // Three-key Triple-DES keys. When a Two-key Triple-DES key is to be + // wrapped, a third DES key with the same value as the first DES key is + // created. Thus, all wrapped Triple-DES keys include three DES keys. + if (length != 16 && length != 24) + throw new IllegalArgumentException("Only 2- and 3-key Triple DES keys are alowed"); + + byte[] CEK = new byte[24]; + if (length == 16) + { + System.arraycopy(in, inOffset, CEK, 0, 16); + System.arraycopy(in, inOffset, CEK, 16, 8); + } + else + System.arraycopy(in, inOffset, CEK, 0, 24); + + // TODO: check for the following: + // However, a Two-key Triple-DES key MUST NOT be used to wrap a Three- + // key Triple-DES key that is comprised of three unique DES keys. + + // 1. Set odd parity for each of the DES key octets comprising the + // Three-Key Triple-DES key that is to be wrapped, call the result + // CEK. + TripleDES.adjustParity(CEK, 0); + + // 2. Compute an 8 octet key checksum value on CEK as described above in + // Section 2, call the result ICV. + sha.update(CEK); + byte[] hash = sha.digest(); + byte[] ICV = new byte[8]; + System.arraycopy(hash, 0, ICV, 0, 8); + + // 3. Let CEKICV = CEK || ICV. + byte[] CEKICV = new byte[CEK.length + ICV.length]; + System.arraycopy(CEK, 0, CEKICV, 0, CEK.length); + System.arraycopy(ICV, 0, CEKICV, CEK.length, ICV.length); + + // 4. Generate 8 octets at random, call the result IV. + byte[] IV = new byte[8]; + nextRandomBytes(IV); + + // 5. Encrypt CEKICV in CBC mode using the key-encryption key. Use the + // random value generated in the previous step as the initialization + // vector (IV). Call the ciphertext TEMP1. + modeAttributes.put(IMode.IV, IV); + asmAttributes.put(Assembly.DIRECTION, Direction.FORWARD); + byte[] TEMP1; + try + { + asm.init(asmAttributes); + TEMP1 = asm.lastUpdate(CEKICV); + } + catch (TransformerException x) + { + throw new RuntimeException(x); + } + + // 6. Let TEMP2 = IV || TEMP1. + byte[] TEMP2 = new byte[IV.length + TEMP1.length]; + System.arraycopy(IV, 0, TEMP2, 0, IV.length); + System.arraycopy(TEMP1, 0, TEMP2, IV.length, TEMP1.length); + + // 7. Reverse the order of the octets in TEMP2. That is, the most + // significant (first) octet is swapped with the least significant + // (last) octet, and so on. Call the result TEMP3. + byte[] TEMP3 = new byte[TEMP2.length]; + for (int i = 0, j = TEMP2.length - 1; i < TEMP2.length; i++, j--) + TEMP3[j] = TEMP2[i]; + + // 8. Encrypt TEMP3 in CBC mode using the key-encryption key. Use an + // initialization vector (IV) of 0x4adda22c79e82105. The ciphertext + // is 40 octets long. + modeAttributes.put(IMode.IV, DEFAULT_IV); + asmAttributes.put(Assembly.DIRECTION, Direction.FORWARD); + byte[] result; + try + { + asm.init(asmAttributes); + result = asm.lastUpdate(TEMP3); + } + catch (TransformerException x) + { + throw new RuntimeException(x); + } + return result; + } + + protected byte[] engineUnwrap(byte[] in, int inOffset, int length) + throws KeyUnwrappingException + { + // 1. If the wrapped key is not 40 octets, then error. + if (length != 40) + throw new IllegalArgumentException("length MUST be 40"); + + // 2. Decrypt the wrapped key in CBC mode using the key-encryption key. + // Use an initialization vector (IV) of 0x4adda22c79e82105. Call the + // output TEMP3. + modeAttributes.put(IMode.IV, DEFAULT_IV); + asmAttributes.put(Assembly.DIRECTION, Direction.REVERSED); + byte[] TEMP3; + try + { + asm.init(asmAttributes); + TEMP3 = asm.lastUpdate(in, inOffset, 40); + } + catch (TransformerException x) + { + throw new RuntimeException(x); + } + + // 3. Reverse the order of the octets in TEMP3. That is, the most + // significant (first) octet is swapped with the least significant + // (last) octet, and so on. Call the result TEMP2. + byte[] TEMP2 = new byte[40]; + for (int i = 0, j = 40 - 1; i < 40; i++, j--) + TEMP2[j] = TEMP3[i]; + + // 4. Decompose TEMP2 into IV and TEMP1. IV is the most significant + // (first) 8 octets, and TEMP1 is the least significant (last) 32 + // octets. + byte[] IV = new byte[8]; + byte[] TEMP1 = new byte[32]; + System.arraycopy(TEMP2, 0, IV, 0, 8); + System.arraycopy(TEMP2, 8, TEMP1, 0, 32); + + // 5. Decrypt TEMP1 in CBC mode using the key-encryption key. Use the + // IV value from the previous step as the initialization vector. + // Call the ciphertext CEKICV. + modeAttributes.put(IMode.IV, IV); + asmAttributes.put(Assembly.DIRECTION, Direction.REVERSED); + byte[] CEKICV; + try + { + asm.init(asmAttributes); + CEKICV = asm.lastUpdate(TEMP1, 0, 32); + } + catch (TransformerException x) + { + throw new RuntimeException(x); + } + + // 6. Decompose CEKICV into CEK and ICV. CEK is the most significant + // (first) 24 octets, and ICV is the least significant (last) 8 + // octets. + byte[] CEK = new byte[24]; + byte[] ICV = new byte[8]; + System.arraycopy(CEKICV, 0, CEK, 0, 24); + System.arraycopy(CEKICV, 24, ICV, 0, 8); + + // 7. Compute an 8 octet key checksum value on CEK as described above in + // Section 2. If the computed key checksum value does not match the + // decrypted key checksum value, ICV, then error. + sha.update(CEK); + byte[] hash = sha.digest(); + byte[] computedICV = new byte[8]; + System.arraycopy(hash, 0, computedICV, 0, 8); + if (! Arrays.equals(ICV, computedICV)) + throw new KeyUnwrappingException("ICV and computed ICV MUST match"); + + // 8. Check for odd parity each of the DES key octets comprising CEK. + // If parity is incorrect, then error. + if (! TripleDES.isParityAdjusted(CEK, 0)) + throw new KeyUnwrappingException("Triple-DES key parity MUST be adjusted"); + + // 9. Use CEK as a Triple-DES key. + return CEK; + } + + /** + * 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); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mac/BaseMac.java b/libjava/classpath/gnu/javax/crypto/mac/BaseMac.java new file mode 100644 index 000000000..4c524e905 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mac/BaseMac.java @@ -0,0 +1,127 @@ +/* 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.security.InvalidKeyException; +import java.util.Map; + +/** + * A base abstract class to facilitate MAC (Message Authentication Code) + * implementations. + */ +public abstract class BaseMac + implements IMac +{ + /** 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; + + /** + * 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; + } + + 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; + } + + public abstract void init(Map attributes) throws InvalidKeyException, + IllegalStateException; + + public abstract byte[] digest(); + + public abstract boolean selfTest(); +} diff --git a/libjava/classpath/gnu/javax/crypto/mac/HMac.java b/libjava/classpath/gnu/javax/crypto/mac/HMac.java new file mode 100644 index 000000000..ae2cd3ce2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mac/HMac.java @@ -0,0 +1,263 @@ +/* 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 +{ + 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; + + /** + * 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; + } + + 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; + } + + 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++) + 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/libjava/classpath/gnu/javax/crypto/mac/HMacFactory.java b/libjava/classpath/gnu/javax/crypto/mac/HMacFactory.java new file mode 100644 index 000000000..0afd8c6ac --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mac/HMacFactory.java @@ -0,0 +1,111 @@ +/* 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 +{ + /** Trivial constructor to enforce Singleton pattern. */ + private HMacFactory() + { + super(); + } + + /** + * 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); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mac/IMac.java b/libjava/classpath/gnu/javax/crypto/mac/IMac.java new file mode 100644 index 000000000..a9582564d --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mac/IMac.java @@ -0,0 +1,181 @@ +/* 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.security.InvalidKeyException; +import java.util.Map; + +/** + * 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 +{ + /** + * 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"; + + /** + * 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; +} diff --git a/libjava/classpath/gnu/javax/crypto/mac/MacFactory.java b/libjava/classpath/gnu/javax/crypto/mac/MacFactory.java new file mode 100644 index 000000000..5e3b50f7f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mac/MacFactory.java @@ -0,0 +1,130 @@ +/* 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 +{ + private static Set names; + + /** Trivial constructor to enforce Singleton pattern. */ + private MacFactory() + { + super(); + } + + /** + * 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(); + + if (result != null && ! result.selfTest()) + throw new InternalError(result.name()); + + return result; + } + + /** + * Returns a {@link Set} of names of MAC algorithms supported by this + * Factory. + * + * @return a {@link 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); + for (Iterator it = CipherFactory.getNames().iterator(); it.hasNext();) + hs.add(OMAC_PREFIX + it.next()); + + names = Collections.unmodifiableSet(hs); + } + } + return names; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mac/MacInputStream.java b/libjava/classpath/gnu/javax/crypto/mac/MacInputStream.java new file mode 100644 index 000000000..7ea808aa9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mac/MacInputStream.java @@ -0,0 +1,124 @@ +/* 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 +{ + /** The digesting state. The MAC is updated only if this flag is true. */ + private boolean digesting; + /** The MAC being updated. */ + private IMac mac; + + /** + * 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; + } + + /** + * 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; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mac/MacOutputStream.java b/libjava/classpath/gnu/javax/crypto/mac/MacOutputStream.java new file mode 100644 index 000000000..2aa352d75 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mac/MacOutputStream.java @@ -0,0 +1,123 @@ +/* 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 +{ + /** The digesting state. The MAC is updated only if this flag is true. */ + private boolean digesting; + /** The MAC being updated. */ + private IMac mac; + + /** + * 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; + } + + /** + * 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); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mac/OMAC.java b/libjava/classpath/gnu/javax/crypto/mac/OMAC.java new file mode 100644 index 000000000..6758b314f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mac/OMAC.java @@ -0,0 +1,303 @@ +/* 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.Configuration; +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 java.security.InvalidKeyException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.logging.Logger; + +/** + * 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 +{ + private static final Logger log = Logger.getLogger(OMAC.class.getName()); + 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; + + public OMAC(IBlockCipher cipher) + { + this.cipher = cipher; + this.name = "OMAC-" + cipher.name(); + } + + 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 (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("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); + } + + private void process() + { + for (int i = 0; i < blockSize; i++) + M[i] = (byte)(M[i] ^ Y[i]); + cipher.encryptBlock(M, 0, Y, 0); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mac/TMMH16.java b/libjava/classpath/gnu/javax/crypto/mac/TMMH16.java new file mode 100644 index 000000000..3427317ab --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mac/TMMH16.java @@ -0,0 +1,339 @@ +/* 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 +{ + 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 + + /** Trivial 0-arguments constructor. */ + public TMMH16() + { + super(Registry.TMMH16); + } + + 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(); + } + + 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; + } + + /** + * 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/libjava/classpath/gnu/javax/crypto/mac/UHash32.java b/libjava/classpath/gnu/javax/crypto/mac/UHash32.java new file mode 100644 index 000000000..53513eda9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mac/UHash32.java @@ -0,0 +1,758 @@ +/* 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 +{ + // 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; + + /** 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.streams]; + for (int i = 0; i < that.streams; i++) + if (that.l1hash[i] != null) + this.l1hash[i] = (L1Hash32) that.l1hash[i].clone(); + } + } + + /** + * 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) + ")"); + } + } + + public Object clone() + { + return new UHash32(this); + } + + 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, Integer.valueOf(0)); + kdf1.init(map); + map.put(UMacGenerator.INDEX, Integer.valueOf(1)); + kdf2.init(map); + map.put(UMacGenerator.INDEX, Integer.valueOf(2)); + kdf3.init(map); + map.put(UMacGenerator.INDEX, Integer.valueOf(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; + } + + /** + * First hash stage of the UHash32 algorithm. + */ + class L1Hash32 + implements Cloneable + { + 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 long totalCount; + private L2Hash32 l2hash; + private L3Hash32 l3hash; + + /** 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(); + } + + public Object clone() + { + return new L1Hash32(this); + } + + 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(); + } + + /** + * 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 + { + private BigInteger k64, k128; + private BigInteger y; + private boolean highBound; + private long bytesSoFar; + private ByteArrayOutputStream buffer; + + 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); + } + } + + public Object clone() + { + return new L2Hash32(this); + } + + // 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(); + } + + 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 + 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; + } + } + + /** + * 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 + { + private static final long PRIME_36 = 0x0000000FFFFFFFFBL; + private int[] k = new int[9]; + + /** + * @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 + 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[8] = K2[0] << 24 + | (K2[1] & 0xFF) << 16 + | (K2[2] & 0xFF) << 8 + | (K2[3] & 0xFF); + } + + private L3Hash32(int[] k) + { + super(); + + this.k = k; + } + + public Object clone() + { + return new L3Hash32((int[]) k.clone()); + } + + /** + * @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 }; + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mac/UMac32.java b/libjava/classpath/gnu/javax/crypto/mac/UMac32.java new file mode 100644 index 000000000..6f53424ea --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mac/UMac32.java @@ -0,0 +1,418 @@ +/* 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 +{ + /** + * 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; + + /** 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; + } + + public Object clone() + { + return new UMac32(this); + } + + 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(); + valid = Boolean.valueOf(TV1.equals(Util.toString(result))); + } + return valid.booleanValue(); + } + + /** + * @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(UMacGenerator.INDEX, Integer.valueOf(128)); + 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; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mode/BaseMode.java b/libjava/classpath/gnu/javax/crypto/mode/BaseMode.java new file mode 100644 index 000000000..831dd9664 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mode/BaseMode.java @@ -0,0 +1,295 @@ +/* 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.java.lang.CPStringBuilder; + +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 +{ + /** 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(); + + /** + * 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; + } + + 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(); + } + } + } + + public String name() + { + return new CPStringBuilder(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 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(Integer.valueOf(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; + } + + 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); + + 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, Integer.valueOf(cipherBlockSize)); + map.put(STATE, Integer.valueOf(ENCRYPTION)); + map.put(IV, iv); + map.put(MODE_BLOCK_SIZE, Integer.valueOf(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, Integer.valueOf(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; + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mode/CBC.java b/libjava/classpath/gnu/javax/crypto/mode/CBC.java new file mode 100644 index 000000000..31c445f4e --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mode/CBC.java @@ -0,0 +1,123 @@ +/* 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 +{ + /** The last (de|en)crypted block */ + private byte[] lastBlock; + /** An intermediate buffer. */ + private byte[] scratch; + + /** + * 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); + } + + public Object clone() + { + return new CBC(this); + } + + 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); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mode/CFB.java b/libjava/classpath/gnu/javax/crypto/mode/CFB.java new file mode 100644 index 000000000..c5f06e11c --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mode/CFB.java @@ -0,0 +1,155 @@ +/* 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 +{ + /** The shift register, the input block to the block cipher. */ + private byte[] shiftRegister; + /** The output block from the block cipher. */ + private byte[] scratch; + + /** + * 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); + } + + 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); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mode/CTR.java b/libjava/classpath/gnu/javax/crypto/mode/CTR.java new file mode 100644 index 000000000..56ea58c25 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mode/CTR.java @@ -0,0 +1,168 @@ +/* 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.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 +{ + private int off; + private byte[] counter, enc; + + /** + * 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); + } + + public Object clone() + { + return new CTR(this); + } + + 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); + } + + public void teardown() + { + if (counter != null) + Arrays.fill(counter, (byte) 0); + if (enc != null) + Arrays.fill(enc, (byte) 0); + } + + 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(); + } + + private void ctr(byte[] in, int inOffset, byte[] out, int outOffset) + { + 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); + } + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mode/EAX.java b/libjava/classpath/gnu/javax/crypto/mode/EAX.java new file mode 100644 index 000000000..b3e4a6a4e --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mode/EAX.java @@ -0,0 +1,289 @@ +/* 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 +{ + /** 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; + + 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; + } + + 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 = Integer.valueOf(cipherBlockSize); + HashMap ctrAttr = new HashMap(); + ctrAttr.put(KEY_MATERIAL, key); + ctrAttr.put(IV, N); + ctrAttr.put(STATE, Integer.valueOf(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 + } + + 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); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mode/ECB.java b/libjava/classpath/gnu/javax/crypto/mode/ECB.java new file mode 100644 index 000000000..7e02b0187 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mode/ECB.java @@ -0,0 +1,121 @@ +/* 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 +{ + /** + * 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); + } + + public Object clone() + { + return new ECB(this); + } + + 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); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mode/IAuthenticatedMode.java b/libjava/classpath/gnu/javax/crypto/mode/IAuthenticatedMode.java new file mode 100644 index 000000000..51a5547f2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mode/IAuthenticatedMode.java @@ -0,0 +1,56 @@ +/* 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. + */ +public interface IAuthenticatedMode + extends IMode, IMac +{ +} diff --git a/libjava/classpath/gnu/javax/crypto/mode/ICM.java b/libjava/classpath/gnu/javax/crypto/mode/ICM.java new file mode 100644 index 000000000..a4737bcdf --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mode/ICM.java @@ -0,0 +1,181 @@ +/* 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 +{ + /** 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; + + /** + * 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); + } + + public Object clone() + { + return new ICM(this); + } + + 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); + } + + private void icm(byte[] in, int inOffset, byte[] out, int outOffset) + { + if (blockNdx.compareTo(maxBlocksPerSegment) >= 0) + throw new RuntimeException("Maximum blocks for segment reached"); + BigInteger Ci = C0.add(blockNdx).modPow(BigInteger.ONE, counterRange); + byte[] result = Ci.toByteArray(); + int limit = result.length; + 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++]); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mode/IMode.java b/libjava/classpath/gnu/javax/crypto/mode/IMode.java new file mode 100644 index 000000000..72c99ba73 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mode/IMode.java @@ -0,0 +1,123 @@ +/* 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 +{ + /** + * 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; + + /** + * 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; +} diff --git a/libjava/classpath/gnu/javax/crypto/mode/ModeFactory.java b/libjava/classpath/gnu/javax/crypto/mode/ModeFactory.java new file mode 100644 index 000000000..c1108ea11 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mode/ModeFactory.java @@ -0,0 +1,151 @@ +/* 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 +{ + private static Set names; + + /** Trivial constructor to enforce Singleton pattern. */ + private ModeFactory() + { + super(); + } + + /** + * 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 Set} of names of mode supported by this Factory. + * + * @return a {@link 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; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/mode/OFB.java b/libjava/classpath/gnu/javax/crypto/mode/OFB.java new file mode 100644 index 000000000..087f99132 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/mode/OFB.java @@ -0,0 +1,174 @@ +/* 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 +{ + private byte[] outputBlock; + + /** + * 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); + } + + public Object clone() + { + return new OFB(this); + } + + 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); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/pad/BasePad.java b/libjava/classpath/gnu/javax/crypto/pad/BasePad.java new file mode 100644 index 000000000..feeaca2f0 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/pad/BasePad.java @@ -0,0 +1,193 @@ +/* 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; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.Configuration; + +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * An abstract class to facilitate implementing padding algorithms. + */ +public abstract class BasePad + implements IPad +{ + private static final Logger log = Logger.getLogger(BasePad.class.getName()); + /** The canonical name prefix of the padding algorithm. */ + protected String name; + /** The block size, in bytes, for this instance. */ + protected int blockSize; + + /** Trivial constructor for use by concrete subclasses. */ + protected BasePad(final String name) + { + super(); + + this.name = name; + blockSize = -1; + } + + public String name() + { + final CPStringBuilder sb = new CPStringBuilder(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(); + } + + /** + * Initialises the algorithm with designated attributes. Names, valid and/or + * recognisable by all concrete implementations are described in {@link IPad} + * class documentation. Other algorithm-specific attributes MUST be documented + * in the implementation class of that padding algorithm. + *

    + * For compatibility reasons, this method is not declared abstract. + * Furthermore, and unless overridden, the default implementation will throw + * an {@link UnsupportedOperationException}. Concrete padding algorithms MUST + * override this method if they wish to offer an initialisation method that + * allows for other than the padding block size parameter to be specified. + * + * @param attributes a set of name-value pairs that describes the desired + * future behaviour of this instance. + * @exception IllegalStateException if the instance is already initialised. + * @exception IllegalArgumentException if the block size value is invalid. + */ + public void init(Map attributes) throws IllegalStateException + { + throw new UnsupportedOperationException(); + } + + public void reset() + { + blockSize = -1; + } + + /** + * A default implementation of a correctness test that exercises the padder + * implementation, using block sizes varying from 2 to 256 bytes. + * + * @return true if the concrete implementation correctly unpads + * what it pads for all tested block sizes. Returns false + * if the test fails for any block size. + */ + public boolean selfTest() + { + final byte[] in = new byte[1024]; + for (int bs = 2; bs < 256; bs++) + if (! test1BlockSize(bs, in)) + return false; + return true; + } + + /** + * The basic symmetric test for a padder given a specific block size. + *

    + * The code ensures that the implementation is capable of unpadding what it + * pads. + * + * @param size the block size to test. + * @param buffer a work buffer. It is exposed as an argument for this method + * to reduce un-necessary object allocations. + * @return true if the test passes; false + * otherwise. + */ + protected boolean test1BlockSize(int size, byte[] buffer) + { + byte[] padBytes; + final int offset = 5; + final int limit = buffer.length; + this.init(size); + for (int i = 0; i < limit - offset - blockSize; i++) + { + padBytes = pad(buffer, offset, i); + if (((i + padBytes.length) % blockSize) != 0) + { + if (Configuration.DEBUG) + log.log(Level.SEVERE, + "Length of padded text MUST be a multiple of " + + blockSize, new RuntimeException(name())); + return false; + } + System.arraycopy(padBytes, 0, buffer, offset + i, padBytes.length); + try + { + if (padBytes.length != unpad(buffer, offset, i + padBytes.length)) + { + if (Configuration.DEBUG) + log.log(Level.SEVERE, + "IPad [" + name() + "] failed symmetric operation", + new RuntimeException(name())); + return false; + } + } + catch (WrongPaddingException x) + { + if (Configuration.DEBUG) + log.throwing(this.getClass().getName(), "test1BlockSize", x); + return false; + } + } + this.reset(); + return true; + } + + /** + * 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; +} diff --git a/libjava/classpath/gnu/javax/crypto/pad/IPad.java b/libjava/classpath/gnu/javax/crypto/pad/IPad.java new file mode 100644 index 000000000..f5160e078 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/pad/IPad.java @@ -0,0 +1,127 @@ +/* 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; + +import java.util.Map; + +/** + * The basic visible methods, and attribute names, of every 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.javax.crypto.mode.IMode} and/or + * {@link gnu.javax.crypto.cipher.IBlockCipher}. + */ +public interface IPad +{ + /** + * Property name of the block size in which to operate the padding algorithm. + * The value associated with this property name is taken to be a positive + * {@link Integer} greater than zero. + */ + String PADDING_BLOCK_SIZE = "gnu.crypto.pad.block.size"; + + /** @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; + + /** + * Initialises the algorithm with designated attributes. Names, valid and/or + * recognisable by all concrete implementations are described in the class + * documentation above. Other algorithm-specific attributes MUST be documented + * in the implementation class of that padding algorithm. + * + * @param attributes a set of name-value pairs that describes the desired + * future behaviour of this instance. + * @exception IllegalStateException if the instance is already initialised. + * @exception IllegalArgumentException if the block size value is invalid. + */ + void init(Map attributes) 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(); +} diff --git a/libjava/classpath/gnu/javax/crypto/pad/ISO10126.java b/libjava/classpath/gnu/javax/crypto/pad/ISO10126.java new file mode 100644 index 000000000..8e8c59254 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/pad/ISO10126.java @@ -0,0 +1,109 @@ +/* ISO10126.java -- An implementation of the ISO 10126-2 padding scheme + 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.pad; + +import gnu.java.security.Registry; +import gnu.java.security.util.PRNG; + +/** + * The implementation of the ISO 10126-2 padding algorithm. + *

    + * The last byte of the padding block is the number of padding bytes, all other + * padding bytes are random. + *

    + * References: + *

      + *
    1. XML Encryption Syntax and + * Processing Section "5.2 Block Encryption Algorithms"; "Padding".
    2. + *
    + */ +public final class ISO10126 + extends BasePad +{ + /** Used to generate random numbers for padding bytes. */ + private PRNG prng; + + ISO10126() + { + super(Registry.ISO10126_PAD); + prng = PRNG.getInstance(); + } + + public void setup() + { + // Nothing to do here + } + + public byte[] pad(byte[] in, int offset, int length) + { + int padLength = blockSize - (length % blockSize); + final byte[] pad = new byte[padLength]; + + // generate random numbers for the padding bytes except for the last byte + prng.nextBytes(pad, 0, padLength - 1); + // the last byte contains the number of padding bytes + pad[padLength - 1] = (byte) padLength; + + return pad; + } + + public int unpad(byte[] in, int offset, int length) + throws WrongPaddingException + { + // the last byte contains the number of padding bytes + int padLength = in[offset + length - 1] & 0xFF; + if (padLength > length) + throw new WrongPaddingException(); + + return padLength; + } + + /** + * The default self-test in the super-class would take too long to finish + * with this type of padder --due to the large amount of random data needed. + * We override the default test and replace it with a simple one for a 16-byte + * block-size (default AES block-size). The Mauve test TestOfISO10126 will + * exercise all block-sizes that the default self-test uses for the other + * padders. + */ + public boolean selfTest() + { + return test1BlockSize(16, new byte[1024]); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/pad/PKCS1_V1_5.java b/libjava/classpath/gnu/javax/crypto/pad/PKCS1_V1_5.java new file mode 100644 index 000000000..e303264ae --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/pad/PKCS1_V1_5.java @@ -0,0 +1,156 @@ +/* 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.Configuration; +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.util.logging.Level; +import java.util.logging.Logger; + +/** + * 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 +{ + private static final Logger log = Logger.getLogger(PKCS1_V1_5.class.getName()); + private EME_PKCS1_V1_5 codec; + + /** + * Trivial package-private constructor for use by the Factory class. + * + * @see PadFactory + */ + PKCS1_V1_5() + { + super(Registry.EME_PKCS1_V1_5_PAD); + } + + 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 (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("padding length: " + String.valueOf(result)); + return result; + } + + 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) + { + if (Configuration.DEBUG) + log.log(Level.SEVERE, + "Length of padded text MUST be a multiple of " + + blockSize, new RuntimeException(name())); + 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)) + { + if (Configuration.DEBUG) + log.log(Level.SEVERE, "Failed symmetric operation", + new RuntimeException(name())); + return false; + } + } + catch (WrongPaddingException x) + { + if (Configuration.DEBUG) + log.throwing(this.getClass().getName(), "selfTest", x); + return false; + } + } + reset(); + } + return true; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/pad/PKCS7.java b/libjava/classpath/gnu/javax/crypto/pad/PKCS7.java new file mode 100644 index 000000000..9dd67fc81 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/pad/PKCS7.java @@ -0,0 +1,111 @@ +/* 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.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import java.util.logging.Logger; + +/** + * 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: + *

      + *
    1. RFC-1423: Privacy + * Enhancement for Internet Electronic Mail: Part III: Algorithms, Modes, and + * Identifiers.
    2. + *
    3. IETF.
    4. + *
    5. [PKCS-7] + * PKCS #7: Cryptographic Message Syntax Standard - An RSA Laboratories + * Technical Note.
    6. + *
    7. RSA Security.
    8. + *
    + */ +public final class PKCS7 + extends BasePad +{ + private static final Logger log = Logger.getLogger(PKCS7.class.getName()); + + /** + * Trivial package-private constructor for use by the Factory class. + * + * @see PadFactory + */ + PKCS7() + { + super(Registry.PKCS7_PAD); + } + + 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 (Configuration.DEBUG) + log.fine("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] & 0xFF; + for (int i = 0; i < result - 1; i++) + if (result != (in[--limit] & 0xFF)) + throw new WrongPaddingException(); + if (Configuration.DEBUG) + log.fine("padding length: " + result); + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/pad/PadFactory.java b/libjava/classpath/gnu/javax/crypto/pad/PadFactory.java new file mode 100644 index 000000000..2df2029fa --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/pad/PadFactory.java @@ -0,0 +1,120 @@ +/* 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 +{ + /** Collection of padding algorithm names --cached for speed. */ + private static Set names; + + /** Trivial constructor to enforce Singleton pattern. */ + private PadFactory() + { + super(); + } + + /** + * 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) || pad.equals(PKCS5_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(); + else if (pad.equals(ISO10126_PAD)) + result = new ISO10126(); + + if (result != null && ! result.selfTest()) + throw new InternalError(result.name()); + + return result; + } + + /** + * Returns a {@link Set} of names of padding algorithms supported by this + * Factory. + * + * @return a {@link Set} of padding algorithm names (Strings). + */ + public static final Set getNames() + { + if (names == null) + { + HashSet hs = new HashSet(); + hs.add(PKCS5_PAD); + hs.add(PKCS7_PAD); + hs.add(TBC_PAD); + hs.add(EME_PKCS1_V1_5_PAD); + hs.add(SSL3_PAD); + hs.add(TLS1_PAD); + hs.add(ISO10126_PAD); + names = Collections.unmodifiableSet(hs); + } + return names; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/pad/SSL3.java b/libjava/classpath/gnu/javax/crypto/pad/SSL3.java new file mode 100644 index 000000000..78964d619 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/pad/SSL3.java @@ -0,0 +1,90 @@ +/* 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 +{ + public SSL3() + { + super("ssl3"); + } + + 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; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/pad/TBC.java b/libjava/classpath/gnu/javax/crypto/pad/TBC.java new file mode 100644 index 000000000..5cd177058 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/pad/TBC.java @@ -0,0 +1,118 @@ +/* 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.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +import java.util.logging.Logger; + +/** + * 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: + *

      + *
    1. + * Recommendation for Block Cipher Modes of Operation Methods and + * Techniques, Morris Dworkin.
    2. + *
    + */ +public final class TBC + extends BasePad +{ + private static final Logger log = Logger.getLogger(TBC.class.getName()); + + /** + * Trivial package-private constructor for use by the Factory class. + * + * @see PadFactory + */ + TBC() + { + super(Registry.TBC_PAD); + } + + 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 (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("padding length: " + result); + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/pad/TLS1.java b/libjava/classpath/gnu/javax/crypto/pad/TLS1.java new file mode 100644 index 000000000..1d690dd59 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/pad/TLS1.java @@ -0,0 +1,91 @@ +/* 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; + +/** + * 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 +{ + public TLS1() + { + super("tls1"); + } + + 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; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/pad/WrongPaddingException.java b/libjava/classpath/gnu/javax/crypto/pad/WrongPaddingException.java new file mode 100644 index 000000000..d15723faf --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/pad/WrongPaddingException.java @@ -0,0 +1,48 @@ +/* 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. + */ +public class WrongPaddingException + extends Exception +{ +} diff --git a/libjava/classpath/gnu/javax/crypto/prng/ARCFour.java b/libjava/classpath/gnu/javax/crypto/prng/ARCFour.java new file mode 100644 index 000000000..60464d5ba --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/prng/ARCFour.java @@ -0,0 +1,137 @@ +/* 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 +{ + /** 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; + + /** Default 0-arguments constructor. */ + public ARCFour() + { + super(Registry.ARCFOUR_PRNG); + } + + 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]; + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/prng/CSPRNG.java b/libjava/classpath/gnu/javax/crypto/prng/CSPRNG.java new file mode 100644 index 000000000..ecea2f469 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/prng/CSPRNG.java @@ -0,0 +1,985 @@ +/* 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.Configuration; +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.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; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * 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 +{ + private static final Logger log = Logger.getLogger(CSPRNG.class.getName()); + /** + * 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.java.security.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; + + 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(); + } + + /** + * 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, Boolean.valueOf(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); + } + + public Object clone() + { + return new CSPRNG(); + } + + public void setup(Map attrib) + { + List list = null; + if (Configuration.DEBUG) + log.fine("attrib=" + String.valueOf(attrib)); + try + { + list = (List) attrib.get(FILE_SOURCES); + if (Configuration.DEBUG) + log.fine("list=" + String.valueOf(list)); + if (list != null) + { + files.clear(); + for (Iterator it = list.iterator(); it.hasNext();) + { + List l = (List) it.next(); + if (Configuration.DEBUG) + log.fine("l=" + l); + if (l.size() != 4) + { + if (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.log(Level.FINE, "bad file list", cce); + throw new IllegalArgumentException("invalid file list"); + } + try + { + list = (List) attrib.get(URL_SOURCES); + if (Configuration.DEBUG) + log.fine("list=" + String.valueOf(list)); + if (list != null) + { + urls.clear(); + for (Iterator it = list.iterator(); it.hasNext();) + { + List l = (List) it.next(); + if (Configuration.DEBUG) + log.fine("l=" + l); + if (l.size() != 4) + { + if (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.log(Level.FINE, "bad URL list", cce); + throw new IllegalArgumentException("invalid URL list"); + } + try + { + list = (List) attrib.get(PROGRAM_SOURCES); + if (Configuration.DEBUG) + log.fine("list=" + String.valueOf(list)); + if (list != null) + { + progs.clear(); + for (Iterator it = list.iterator(); it.hasNext();) + { + List l = (List) it.next(); + if (Configuration.DEBUG) + log.fine("l=" + l); + if (l.size() != 4) + { + if (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.log(Level.FINE, "bad program list", cce); + throw new IllegalArgumentException("invalid program list"); + } + try + { + list = (List) attrib.get(OTHER_SOURCES); + if (Configuration.DEBUG) + log.fine("list=" + String.valueOf(list)); + if (list != null) + { + other.clear(); + for (Iterator it = list.iterator(); it.hasNext();) + { + EntropySource src = (EntropySource) it.next(); + if (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("fillBlock"); + if (getQuality() < 100.0) + { + if (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + { + log.fine("adding random bytes:"); + log.fine(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 (Configuration.DEBUG) + log.fine("adding byte " + Integer.toHexString(b)); + pool[index++] ^= b; + if (index >= pool.length) + { + mixRandomPool(); + index = 0; + } + } + + synchronized void addQuality(double quality) + { + if (Configuration.DEBUG) + log.fine("adding quality " + quality); + if (this.quality < 100) + this.quality += quality; + if (Configuration.DEBUG) + log.fine("quality now " + this.quality); + } + + synchronized double getQuality() + { + return quality; + } + + /** + * 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 (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("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); + } + + /** + * 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 + { + protected byte counter; + + private Spinner() + { + } + + public void run() + { + while (true) + { + counter++; + try + { + Thread.sleep(100); + } + catch (InterruptedException ie) + { + } + } + } + } + + private final class Poller + implements Runnable + { + private final List files; + private final List urls; + private final List progs; + private final List other; + private final CSPRNG pool; + private boolean running; + + 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; + } + + public void run() + { + running = true; + if (Configuration.DEBUG) + { + log.fine("files: " + files); + log.fine("URLs: " + urls); + log.fine("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 (Configuration.DEBUG) + log.fine(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 (Configuration.DEBUG) + log.fine("got " + len + " bytes from " + src); + } + catch (Exception x) + { + if (Configuration.DEBUG) + log.throwing(this.getClass().getName(), "run", x); + } + if (pool.getQuality() >= 100.0 || ! running) + return; + if (urls_it.hasNext()) + try + { + List l = (List) urls_it.next(); + if (Configuration.DEBUG) + log.fine(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 (Configuration.DEBUG) + log.fine("got " + len + " bytes from " + src); + } + catch (Exception x) + { + if (Configuration.DEBUG) + log.throwing(this.getClass().getName(), "run", x); + } + if (pool.getQuality() >= 100.0 || ! running) + return; + Process proc = null; + if (prog_it.hasNext()) + try + { + List l = (List) prog_it.next(); + if (Configuration.DEBUG) + log.finer(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 (Configuration.DEBUG) + log.fine("got " + len + " bytes from " + src); + } + catch (Exception x) + { + if (Configuration.DEBUG) + log.throwing(this.getClass().getName(), "run", x); + 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 (Configuration.DEBUG) + log.fine("got " + buf.length + " bytes from " + src); + } + catch (Exception x) + { + if (Configuration.DEBUG) + log.throwing(this.getClass().getName(), "run", x); + } + } + } + + public void stopUpdating() + { + running = false; + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/prng/Fortuna.java b/libjava/classpath/gnu/javax/crypto/prng/Fortuna.java new file mode 100644 index 000000000..8aec9ab7d --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/prng/Fortuna.java @@ -0,0 +1,349 @@ +/* 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); + try + { + fillBlock(); + } + catch (LimitReachedException shouldNotHappen) + { + throw new RuntimeException(shouldNotHappen); + } + } + + 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); + fillBlock(); + } + + /** + * 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; + } + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/prng/ICMGenerator.java b/libjava/classpath/gnu/javax/crypto/prng/ICMGenerator.java new file mode 100644 index 000000000..a4df5b964 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/prng/ICMGenerator.java @@ -0,0 +1,306 @@ +/* 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.CipherFactory; +import gnu.javax.crypto.cipher.IBlockCipher; + +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. + *
    + */ +public class ICMGenerator + extends BasePRNG + implements Cloneable +{ + /** 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; + + /** Trivial 0-arguments constructor. */ + public ICMGenerator() + { + super(Registry.ICM_PRNG); + } + + // 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, Integer.valueOf(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); + try + { + fillBlock(); + } + catch (LimitReachedException impossible) + { + throw (InternalError) + new InternalError().initCause(impossible); + } + } + + 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 + } +} diff --git a/libjava/classpath/gnu/javax/crypto/prng/IPBE.java b/libjava/classpath/gnu/javax/crypto/prng/IPBE.java new file mode 100644 index 000000000..8138b7b9a --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/prng/IPBE.java @@ -0,0 +1,81 @@ +/* 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 and + * constants. + */ +public interface IPBE +{ + /** + * Property name for the iteration count in a PBE algorithm. The property + * associated with this is expected to be an {@link Integer}. + */ + 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. + */ + String PASSWORD = "gnu.crypto.pbe.password"; + + /** + * Property name for the password character encoding in a PBE algorithm. The + * property associated with this is expected to be a String denoting a valid + * character-encoding name. If this property is not set, and a password is + * used, then {@link #DEFAULT_PASSWORD_ENCODING} will be used when converting + * the password character(s) to bytes. + */ + String PASSWORD_ENCODING = "gnu.crypto.pbe.password.encoding"; + + /** + * Property name for the salt in a PBE algorithm. The property associated + * with this is expected to be a byte array. + */ + String SALT = "gnu.crypto.pbe.salt"; + + /** + * The default character set encoding name to be used if (a) a password is + * to be used as the source for a PBE-based Key Derivation Function (KDF) and + * (b) no character set encoding name was specified among the attributes used + * to initialize the instance. + */ + String DEFAULT_PASSWORD_ENCODING = "UTF-8"; +} diff --git a/libjava/classpath/gnu/javax/crypto/prng/PBKDF2.java b/libjava/classpath/gnu/javax/crypto/prng/PBKDF2.java new file mode 100644 index 000000000..22fcd5504 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/prng/PBKDF2.java @@ -0,0 +1,184 @@ +/* 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. + *
    + */ +public class PBKDF2 + extends BasePRNG + implements Cloneable +{ + /** + * 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; + + /** + * 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; + } + + 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; + byte[] macKeyMaterial; + char[] password = (char[]) attributes.get(IPBE.PASSWORD); + if (password != null) + { + String encoding = (String) attributes.get(IPBE.PASSWORD_ENCODING); + if (encoding == null || encoding.trim().length() == 0) + encoding = IPBE.DEFAULT_PASSWORD_ENCODING; + else + encoding = encoding.trim(); + try + { + macKeyMaterial = new String(password).getBytes(encoding); + } + catch (UnsupportedEncodingException uee) + { + throw new IllegalArgumentException("Unknown or unsupported encoding: " + + encoding, uee); + } + } + else + macKeyMaterial = (byte[]) attributes.get(IMac.MAC_KEY_MATERIAL); + + if (macKeyMaterial != null) + macAttrib.put(IMac.MAC_KEY_MATERIAL, macKeyMaterial); + else if (! initialised) + throw new IllegalArgumentException( + "Neither password nor key-material were specified"); + // otherwise re-use previous password/key-material + 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 (LimitReachedException x) + { + throw new Error(x.getMessage()); + } + } + + public void fillBlock() throws LimitReachedException + { + if (++count > ((1L << 32) - 1)) + throw new LimitReachedException(); + Arrays.fill(buffer, (byte) 0x00); + int limit = salt.length; + in = new byte[limit + 4]; + System.arraycopy(salt, 0, in, 0, salt.length); + 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]; + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/prng/PRNGFactory.java b/libjava/classpath/gnu/javax/crypto/prng/PRNGFactory.java new file mode 100644 index 000000000..0a7c5e377 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/prng/PRNGFactory.java @@ -0,0 +1,115 @@ +/* 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.HMacFactory; +import gnu.javax.crypto.mac.IMac; +import gnu.javax.crypto.mac.MacFactory; + +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 +{ + /** Trivial constructor to enforce Singleton pattern. */ + private PRNGFactory() + { + } + + /** + * 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); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/prng/UMacGenerator.java b/libjava/classpath/gnu/javax/crypto/prng/UMacGenerator.java new file mode 100644 index 000000000..1ee449223 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/prng/UMacGenerator.java @@ -0,0 +1,186 @@ +/* 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 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 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 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 +{ + /** + * 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; + + /** Trivial 0-arguments constructor. */ + public UMacGenerator() + { + super(Registry.UMAC_PRNG); + } + + 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, Integer.valueOf(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); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/AuthInfo.java b/libjava/classpath/gnu/javax/crypto/sasl/AuthInfo.java new file mode 100644 index 000000000..37c1e0852 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/AuthInfo.java @@ -0,0 +1,129 @@ +/* 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 +{ + 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().trim(); + if (! "gnu.javax.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); + } + + /** Trivial constructor to enforce Singleton pattern. */ + private AuthInfo() + { + super(); + } + + /** + * 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/libjava/classpath/gnu/javax/crypto/sasl/AuthInfoProviderFactory.java b/libjava/classpath/gnu/javax/crypto/sasl/AuthInfoProviderFactory.java new file mode 100644 index 000000000..f881e6e11 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/AuthInfoProviderFactory.java @@ -0,0 +1,67 @@ +/* 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 +{ + // implicit 0-args constructor + + 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/libjava/classpath/gnu/javax/crypto/sasl/ClientFactory.java b/libjava/classpath/gnu/javax/crypto/sasl/ClientFactory.java new file mode 100644 index 000000000..30309d2c7 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/ClientFactory.java @@ -0,0 +1,168 @@ +/* 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.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.SaslClient; +import javax.security.sasl.SaslClientFactory; +import javax.security.sasl.SaslException; + +/** + * The implementation of {@link SaslClientFactory}. + */ +public class ClientFactory + implements SaslClientFactory +{ + // implicit 0-arguments constructor + + 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; + } + + 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))); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/ClientMechanism.java b/libjava/classpath/gnu/javax/crypto/sasl/ClientMechanism.java new file mode 100644 index 000000000..5e0dcd096 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/ClientMechanism.java @@ -0,0 +1,293 @@ +/* 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 +{ + /** 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; + + protected ClientMechanism(final String mechanism) + { + super(); + + this.mechanism = mechanism; + this.state = -1; + } + + protected abstract void initMechanism() throws SaslException; + + protected abstract void resetMechanism() throws SaslException; + + 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 + { + } + + 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; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/ConfidentialityException.java b/libjava/classpath/gnu/javax/crypto/sasl/ConfidentialityException.java new file mode 100644 index 000000000..85bd2ae18 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/ConfidentialityException.java @@ -0,0 +1,82 @@ +/* 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. + */ +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); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/IAuthInfoProvider.java b/libjava/classpath/gnu/javax/crypto/sasl/IAuthInfoProvider.java new file mode 100644 index 000000000..88acc2d0a --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/IAuthInfoProvider.java @@ -0,0 +1,116 @@ +/* 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 +{ + /** + * 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; +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/IAuthInfoProviderFactory.java b/libjava/classpath/gnu/javax/crypto/sasl/IAuthInfoProviderFactory.java new file mode 100644 index 000000000..2a0b5bfec --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/IAuthInfoProviderFactory.java @@ -0,0 +1,55 @@ +/* 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 +{ + /** + * 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); +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/IllegalMechanismStateException.java b/libjava/classpath/gnu/javax/crypto/sasl/IllegalMechanismStateException.java new file mode 100644 index 000000000..fade7792c --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/IllegalMechanismStateException.java @@ -0,0 +1,84 @@ +/* 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. + */ +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); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/InputBuffer.java b/libjava/classpath/gnu/javax/crypto/sasl/InputBuffer.java new file mode 100644 index 000000000..f15205765 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/InputBuffer.java @@ -0,0 +1,272 @@ +/* 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 +{ + /** The internal buffer stream containing the buffer's contents. */ + protected ByteArrayInputStream in; + /** The length of the buffer, according to its header. */ + protected int length; + + /** + * 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(); + } + + /** + * 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 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; + } + + 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"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/IntegrityException.java b/libjava/classpath/gnu/javax/crypto/sasl/IntegrityException.java new file mode 100644 index 000000000..ce1b359de --- /dev/null +++ b/libjava/classpath/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); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/NoSuchMechanismException.java b/libjava/classpath/gnu/javax/crypto/sasl/NoSuchMechanismException.java new file mode 100644 index 000000000..d22bff894 --- /dev/null +++ b/libjava/classpath/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); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/NoSuchUserException.java b/libjava/classpath/gnu/javax/crypto/sasl/NoSuchUserException.java new file mode 100644 index 000000000..447c7b919 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/crypto/sasl/OutputBuffer.java b/libjava/classpath/gnu/javax/crypto/sasl/OutputBuffer.java new file mode 100644 index 000000000..4bb3b0ec2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/OutputBuffer.java @@ -0,0 +1,198 @@ +/* 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 +{ + /** The internal output stream. */ + private ByteArrayOutputStream out; + + public OutputBuffer() + { + super(); + + out = new ByteArrayOutputStream(); + } + + /** + * 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/libjava/classpath/gnu/javax/crypto/sasl/SaslEncodingException.java b/libjava/classpath/gnu/javax/crypto/sasl/SaslEncodingException.java new file mode 100644 index 000000000..5836270ac --- /dev/null +++ b/libjava/classpath/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); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/SaslInputStream.java b/libjava/classpath/gnu/javax/crypto/sasl/SaslInputStream.java new file mode 100644 index 000000000..6a6c85751 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/SaslInputStream.java @@ -0,0 +1,393 @@ +/* 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.Configuration; +import gnu.java.security.util.Util; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InterruptedIOException; +import java.util.logging.Logger; + +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 +{ + private static final Logger log = Logger.getLogger(SaslInputStream.class.getName()); + private SaslClient client; + private SaslServer server; + private int maxRawSendSize; + private InputStream source; + private byte[] internalBuf; + + public SaslInputStream(SaslClient client, InputStream source) + throws IOException + { + super(); + + this.client = client; + String size = (String) client.getNegotiatedProperty(Sasl.RAW_SEND_SIZE); + maxRawSendSize = Integer.parseInt(size); + server = null; + this.source = source; + } + + public SaslInputStream(SaslServer server, InputStream source) + throws IOException + { + super(); + + this.server = server; + String size = (String) server.getNegotiatedProperty(Sasl.RAW_SEND_SIZE); + maxRawSendSize = Integer.parseInt(size); + client = null; + this.source = source; + } + + 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, 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 (Configuration.DEBUG) + log.entering(this.getClass().getName(), "read", new Object[] { + b, Integer.valueOf(off), Integer.valueOf(len) + }); + if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) + || ((off + len) < 0)) + throw new IndexOutOfBoundsException("off=" + off + ", len=" + len + + ", b.length=" + b.length); + if (len == 0) + { + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "read", Integer.valueOf(0)); + return 0; + } + if (Configuration.DEBUG) + log.finer("Available: " + available()); + int result = 0; + if (internalBuf == null || internalBuf.length < 1) + try + { + internalBuf = readSaslBuffer(); + if (internalBuf == null) + { + if (Configuration.DEBUG) + { + log.finer("Underlying stream empty. Returning -1"); + log.exiting(this.getClass().getName(), "read", + Integer.valueOf(-1)); + } + return -1; + } + } + catch (InterruptedIOException x) + { + if (Configuration.DEBUG) + { + log.finer("Reading thread was interrupted. Returning -1"); + log.throwing(this.getClass().getName(), "read", x); + log.exiting(this.getClass().getName(), "read", + Integer.valueOf(-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 (Configuration.DEBUG) + log.finer("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 (Configuration.DEBUG) + log.finer("Not enough bytes in source to read a buffer. Breaking..."); + break; + } + } + if (Configuration.DEBUG) + { + log.finer("Remaining: " + + (internalBuf == null ? 0 : internalBuf.length)); + log.exiting(this.getClass().getName(), "read()", String.valueOf(result)); + } + return result; + } + + /** + * 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 (Configuration.DEBUG) + log.entering(this.getClass().getName(), "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 (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "readSaslBuffer"); + return null; + } + } + catch (IOException x) + { + if (Configuration.DEBUG) + log.throwing(this.getClass().getName(), "readSaslBuffer", x); + throw x; + } + if (realLength != 4) + throw new IOException("Was expecting 4 but found " + realLength); + int bufferLength = result[0] << 24 + | (result[1] & 0xFF) << 16 + | (result[2] & 0xFF) << 8 + | (result[3] & 0xFF); + if (Configuration.DEBUG) + log.finer("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 (Configuration.DEBUG) + log.throwing(this.getClass().getName(), "readSaslBuffer", x); + throw x; + } + if (realLength != bufferLength) + throw new IOException("Was expecting " + bufferLength + " but found " + + realLength); + if (Configuration.DEBUG) + { + log.finer("Incoming buffer (before security) (hex): " + + Util.dumpString(result)); + log.finer("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 (Configuration.DEBUG) + { + log.finer("Incoming buffer (after security) (hex): " + + Util.dumpString(result)); + log.finer("Incoming buffer (after security) (str): \"" + + new String(result) + "\""); + log.exiting(this.getClass().getName(), "readSaslBuffer"); + } + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/SaslOutputStream.java b/libjava/classpath/gnu/javax/crypto/sasl/SaslOutputStream.java new file mode 100644 index 000000000..0de1ce850 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/SaslOutputStream.java @@ -0,0 +1,175 @@ +/* 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.Configuration; +import gnu.java.security.util.Util; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.logging.Logger; + +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 +{ + private static final Logger log = Logger.getLogger(SaslOutputStream.class.getName()); + private SaslClient client; + private SaslServer server; + private int maxRawSendSize; + private OutputStream dest; + + public SaslOutputStream(SaslClient client, OutputStream dest) + throws IOException + { + super(); + + this.client = client; + String size = (String) client.getNegotiatedProperty(Sasl.RAW_SEND_SIZE); + maxRawSendSize = Integer.parseInt(size); + server = null; + this.dest = dest; + } + + public SaslOutputStream(SaslServer server, OutputStream dest) + throws IOException + { + super(); + + this.server = server; + String size = (String) server.getNegotiatedProperty(Sasl.RAW_SEND_SIZE); + maxRawSendSize = Integer.parseInt(size); + client = null; + this.dest = dest; + } + + 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 (Configuration.DEBUG) + log.entering(this.getClass().getName(), "write"); + if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) + || ((off + len) < 0)) + throw new IndexOutOfBoundsException("off=" + off + ", len=" + len + + ", b.length=" + b.length); + if (len == 0) + { + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "write"); + return; + } + int chunckSize, length, chunck = 1; + byte[] output = null, result; + if (Configuration.DEBUG) + log.finer("About to wrap " + len + " byte(s)..."); + while (len > 0) + { + chunckSize = (len > maxRawSendSize ? maxRawSendSize : len); + if (Configuration.DEBUG) + { + log.finer("Outgoing buffer (before security) (hex): " + + Util.dumpString(b, off, chunckSize)); + log.finer("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 (Configuration.DEBUG) + { + log.finer("Outgoing buffer (after security) (hex): " + + Util.dumpString(output)); + log.finer("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 (Configuration.DEBUG) + log.finer("Wrapped chunck #" + chunck); + chunck++; + } + dest.flush(); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "write"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/SaslUtil.java b/libjava/classpath/gnu/javax/crypto/sasl/SaslUtil.java new file mode 100644 index 000000000..b17d9536e --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/SaslUtil.java @@ -0,0 +1,75 @@ +/* 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.security.MessageDigest; + +/** + * Utility methods for SASL-related classes. + */ +public class SaslUtil +{ + private SaslUtil() + { + super(); + } + + public static final boolean validEmailAddress(String address) + { + // need to do better than this + return (address.indexOf("@") != -1); + } + + /** 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; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/ServerFactory.java b/libjava/classpath/gnu/javax/crypto/sasl/ServerFactory.java new file mode 100644 index 000000000..6df44c08c --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/ServerFactory.java @@ -0,0 +1,158 @@ +/* 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 +{ + // implicit 0-arguments constructor + + 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; + } + + 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))); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/ServerMechanism.java b/libjava/classpath/gnu/javax/crypto/sasl/ServerMechanism.java new file mode 100644 index 000000000..71dfdd4e0 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/ServerMechanism.java @@ -0,0 +1,294 @@ +/* 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.SaslException; +import javax.security.sasl.SaslServer; + +/** + * A base class to facilitate implementing SASL server-side mechanisms. + */ +public abstract class ServerMechanism + implements SaslServer +{ + /** 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; + + protected ServerMechanism(final String mechanism) + { + super(); + + this.mechanism = mechanism; + this.authenticator = AuthInfo.getProvider(mechanism); + this.state = -1; + } + + protected abstract void initMechanism() throws SaslException; + + protected abstract void resetMechanism() throws SaslException; + + 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(); + } + + 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; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/UserAlreadyExistsException.java b/libjava/classpath/gnu/javax/crypto/sasl/UserAlreadyExistsException.java new file mode 100644 index 000000000..615fabb57 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousClient.java b/libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousClient.java new file mode 100644 index 000000000..860efb4f9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousClient.java @@ -0,0 +1,102 @@ +/* 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.AuthenticationException; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslException; + +/** + * The ANONYMOUS client-side mechanism. + */ +public class AnonymousClient + extends ClientMechanism + implements SaslClient +{ + public AnonymousClient() + { + super(Registry.SASL_ANONYMOUS_MECHANISM); + } + + protected void initMechanism() throws SaslException + { + } + + protected void resetMechanism() throws SaslException + { + } + + 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; + final byte[] result; + try + { + result = authorizationID.getBytes("UTF-8"); + } + catch (UnsupportedEncodingException x) + { + throw new AuthenticationException("response()", x); + } + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousServer.java b/libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousServer.java new file mode 100644 index 000000000..675194caa --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousServer.java @@ -0,0 +1,90 @@ +/* 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 +{ + public AnonymousServer() + { + super(Registry.SASL_ANONYMOUS_MECHANISM); + } + + protected void initMechanism() throws SaslException + { + } + + protected void resetMechanism() throws SaslException + { + } + + 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"); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousUtil.java b/libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousUtil.java new file mode 100644 index 000000000..bb59779d6 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousUtil.java @@ -0,0 +1,83 @@ +/* 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 +{ + /** Trivial private constructor to enforce Singleton pattern. */ + private AnonymousUtil() + { + super(); + } + + 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; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5AuthInfoProvider.java b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5AuthInfoProvider.java new file mode 100644 index 000000000..e3d8b8f08 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5AuthInfoProvider.java @@ -0,0 +1,166 @@ +/* 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 +{ + private PasswordFile passwordFile = null; + + // implicit 0-args constrcutor + + 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()); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Client.java b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Client.java new file mode 100644 index 000000000..44f694e5c --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Client.java @@ -0,0 +1,168 @@ +/* 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 +{ + public CramMD5Client() + { + super(Registry.SASL_CRAM_MD5_MECHANISM); + } + + protected void initMechanism() throws SaslException + { + } + + protected void resetMechanism() throws SaslException + { + } + + 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; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Registry.java b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Registry.java new file mode 100644 index 000000000..560eb854e --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Registry.java @@ -0,0 +1,60 @@ +/* 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"; +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Server.java b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Server.java new file mode 100644 index 000000000..1522f6b35 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Server.java @@ -0,0 +1,158 @@ +/* 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 +{ + private byte[] msgID; + + public CramMD5Server() + { + super(Registry.SASL_CRAM_MD5_MECHANISM); + } + + protected void initMechanism() throws SaslException + { + } + + protected void resetMechanism() throws SaslException + { + } + + 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 = 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; + } + + 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); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Util.java b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Util.java new file mode 100644 index 000000000..a85c4c721 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Util.java @@ -0,0 +1,122 @@ +/* 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.lang.CPStringBuilder; + +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 +{ + private CramMD5Util() + { + super(); + } + + 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 CPStringBuilder("<") + .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(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/crammd5/PasswordFile.java b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/PasswordFile.java new file mode 100644 index 000000000..65da4afdd --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/crammd5/PasswordFile.java @@ -0,0 +1,240 @@ +/* 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.java.lang.CPStringBuilder; + +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 +{ + 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; + + 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(); + } + + 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)) + throw new NoSuchUserException(user); + final String[] fields = (String[]) entries.get(user); // get 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; + CPStringBuilder sb; + int i; + for (Iterator it = entries.keySet().iterator(); it.hasNext();) + { + key = (String) it.next(); + fields = (String[]) entries.get(key); + sb = new CPStringBuilder(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(); + } + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/plain/PasswordFile.java b/libjava/classpath/gnu/javax/crypto/sasl/plain/PasswordFile.java new file mode 100644 index 000000000..51542d2b2 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/plain/PasswordFile.java @@ -0,0 +1,245 @@ +/* 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.java.lang.CPStringBuilder; + +import gnu.java.security.action.GetPropertyAction; +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.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.security.AccessController; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.NoSuchElementException; +import java.util.StringTokenizer; + +/** + * A representation of a Plain password file. + */ +public class PasswordFile +{ + private static String DEFAULT_FILE; + static + { + DEFAULT_FILE = (String) AccessController.doPrivileged + (new GetPropertyAction(PlainRegistry.PASSWORD_FILE, + PlainRegistry.DEFAULT_PASSWORD_FILE)); + } + private Hashtable entries; + private File passwdFile; + private long lastmod; + + 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(); + } + + 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; + CPStringBuilder sb; + Enumeration keys = entries.keys(); + while (keys.hasMoreElements()) + { + key = (String) keys.nextElement(); + fields = (String[]) entries.get(key); + sb = new CPStringBuilder(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(); + } + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainAuthInfoProvider.java b/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainAuthInfoProvider.java new file mode 100644 index 000000000..5f35c455b --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainAuthInfoProvider.java @@ -0,0 +1,166 @@ +/* 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 +{ + private PasswordFile passwordFile = null; + + // implicit 0-args constrcutor + + 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; + 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; + throw new AuthenticationException("update()", x); + } + } + + public Map getConfiguration(String mode) throws AuthenticationException + { + throw new AuthenticationException("", new UnsupportedOperationException()); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainClient.java b/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainClient.java new file mode 100644 index 000000000..f984ed13f --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainClient.java @@ -0,0 +1,156 @@ +/* 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.lang.CPStringBuilder; + +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 +{ + public PlainClient() + { + super(Registry.SASL_PLAIN_MECHANISM); + } + + protected void initMechanism() throws SaslException + { + } + + protected void resetMechanism() throws SaslException + { + } + + 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 CPStringBuilder sb = new CPStringBuilder(); + 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; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainRegistry.java b/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainRegistry.java new file mode 100644 index 000000000..68b121d96 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainRegistry.java @@ -0,0 +1,57 @@ +/* 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 +{ + /** 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"; +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainServer.java b/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainServer.java new file mode 100644 index 000000000..9d97bc029 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/plain/PlainServer.java @@ -0,0 +1,155 @@ +/* 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 +{ + public PlainServer() + { + super(Registry.SASL_PLAIN_MECHANISM); + } + + protected void initMechanism() throws SaslException + { + } + + protected void resetMechanism() throws SaslException + { + } + + 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; + } + + 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); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/CALG.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/CALG.java new file mode 100644 index 000000000..22f9c9751 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/CALG.java @@ -0,0 +1,221 @@ +/* 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 +{ + 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). + + /** 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; + } + + /** + * 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(); + IMode ofbMode = ModeFactory.getInstance(Registry.OFB_MODE, + cipher, + blockSize); + Stage modeStage = Stage.getInstance(ofbMode, Direction.FORWARD); + final Object modeNdx = ofbCipher.append(modeStage); + final IPad pkcs7 = PadFactory.getInstance(Registry.PKCS7_PAD); + final Assembly asm = new Assembly(); + asm.addPreTransformer(Transformer.getCascadeTransformer(ofbCipher)); + asm.addPreTransformer(Transformer.getPaddingTransformer(pkcs7)); + return new CALG(blockSize, keySize, modeNdx, asm); + } + + /** + * 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(final KDF kdf, final byte[] iv, final Direction dir) + throws SaslException + { + 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(); + final byte[] sk = kdf.derive(keySize); + modeAttributes.put(IBlockCipher.KEY_MATERIAL, sk); + modeAttributes.put(IMode.IV, realIV); + final HashMap attributes = new HashMap(); + attributes.put(Assembly.DIRECTION, dir); + attributes.put(modeNdx, modeAttributes); + try + { + assembly.init(attributes); + } + catch (TransformerException x) + { + throw new SaslException("getInstance()", x); + } + } + + /** + * 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; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/ClientStore.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/ClientStore.java new file mode 100644 index 000000000..1d27137d1 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/ClientStore.java @@ -0,0 +1,155 @@ +/* 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 +{ + /** 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(); + + /** Private constructor to enforce Singleton pattern. */ + private ClientStore() + { + super(); + + // TODO: add a cleaning timer thread + } + + /** + * Returns the classloader Singleton. + * + * @return the classloader Singleton instance. + */ + static synchronized final ClientStore instance() + { + if (singleton == null) + singleton = new ClientStore(); + return singleton; + } + + /** + * 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; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/IALG.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/IALG.java new file mode 100644 index 000000000..d0c92ea68 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/IALG.java @@ -0,0 +1,128 @@ +/* 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. + */ +public final class IALG + implements Cloneable +{ + private IMac hmac; + + /** Private constructor to enforce instantiation through Factory method. */ + private IALG(final IMac hmac) + { + super(); + + this.hmac = hmac; + } + + /** + * 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)); + return new IALG(hmac); + } + + public Object clone() throws CloneNotSupportedException + { + return new IALG((IMac) hmac.clone()); + } + + public void init(final KDF kdf) throws SaslException + { + try + { + final byte[] sk = kdf.derive(hmac.macSize()); + final HashMap map = new HashMap(); + map.put(IMac.MAC_KEY_MATERIAL, sk); + hmac.init(map); + } + 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(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/KDF.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/KDF.java new file mode 100644 index 000000000..513aafb94 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/KDF.java @@ -0,0 +1,140 @@ +/* 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 +{ + private static final int AES_BLOCK_SIZE = 16; // default block size for 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 underlying UMAC Generator instance. */ + private UMacGenerator umac = null; + + /** + * 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(); + + final HashMap map = new HashMap(); + map.put(UMacGenerator.CIPHER, Registry.AES_CIPHER); + map.put(UMacGenerator.INDEX, Integer.valueOf(ndx)); + map.put(IBlockCipher.CIPHER_BLOCK_SIZE, Integer.valueOf(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); + } + + /** + * 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); + } + + /** + * 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]; + try + { + umac.nextBytes(result, 0, length); + } + catch (IllegalStateException x) // should not happen + { + x.printStackTrace(System.err); + } + catch (LimitReachedException x) // idem + { + x.printStackTrace(System.err); + } + return result; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/PasswordFile.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/PasswordFile.java new file mode 100644 index 000000000..c13c2fa71 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/PasswordFile.java @@ -0,0 +1,627 @@ +/* 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.lang.CPStringBuilder; + +import gnu.java.security.Registry; +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.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +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 +{ + // 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 }; + + 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(); + } + + /** + * 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"; + } + + /** + * 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; + } + + 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 }; + } + + 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; + CPStringBuilder sb; + for (Iterator it = configurations.keySet().iterator(); it.hasNext();) + { + ndx = (String) it.next(); + mpi = (String[]) configurations.get(ndx); + sb = new CPStringBuilder(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; + CPStringBuilder 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 CPStringBuilder(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 CPStringBuilder(digestID) + .append(":").append(user) + .append(":").append((String) verifiers.get(digestID)); + pw2.println(sb2.toString()); + } + } + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/SRP.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/SRP.java new file mode 100644 index 000000000..569855dd7 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/SRP.java @@ -0,0 +1,255 @@ +/* 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 +{ + /** 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; + + /** Trivial private constructor to enforce Singleton pattern. */ + private SRP(final IMessageDigest mda) + { + super(); + + this.mda = mda; + } + + /** + * 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; + } + + /** @return the message digest algorithm name used by this instance. */ + public String getAlgorithm() + { + return mda.name(); + } + + /** + * 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")); + } + + /** + * 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(); + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPAuthInfoProvider.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPAuthInfoProvider.java new file mode 100644 index 000000000..e42cfffa9 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPAuthInfoProvider.java @@ -0,0 +1,177 @@ +/* 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 +{ + private PasswordFile passwordFile = null; + + // implicit 0-args constrcutor + + 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; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPClient.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPClient.java new file mode 100644 index 000000000..8e44e4ead --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPClient.java @@ -0,0 +1,954 @@ +/* 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.lang.CPStringBuilder; + +import gnu.java.security.Configuration; +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.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.IncomingMessage; +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.KeyAgreementFactory; +import gnu.javax.crypto.key.OutgoingMessage; +import gnu.javax.crypto.key.srp6.SRP6KeyAgreement; +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.ByteArrayOutputStream; +import java.io.IOException; +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 java.util.logging.Logger; + +import javax.security.auth.DestroyFailedException; +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 SASL-SRP client-side mechanism. + */ +public class SRPClient + extends ClientMechanism + implements SaslClient +{ + private static final Logger log = Logger.getLogger(SRPClient.class.getName()); + 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; + + public SRPClient() + { + super(Registry.SASL_SRP_MECHANISM); + } + + 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; + } + + 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 (Configuration.DEBUG) + log.entering(this.getClass().getName(), "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 + { + 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 (Configuration.DEBUG) + log.fine("Got C (received MAC): " + Util.dumpString(received_mac)); + inMac.update(incoming, offset, payloadLength); + if (replayDetection) + { + inCounter++; + if (Configuration.DEBUG) + log.fine("inCounter=" + inCounter); + inMac.update(new byte[] { + (byte)(inCounter >>> 24), + (byte)(inCounter >>> 16), + (byte)(inCounter >>> 8), + (byte) inCounter }); + } + final byte[] computed_mac = inMac.doFinal(); + if (Configuration.DEBUG) + log.fine("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 + result = inCipher.doFinal(incoming, offset, len); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new SaslException("engineUnwrap()", x); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineUnwrap"); + return result; + } + + protected byte[] engineWrap(final byte[] outgoing, final int offset, + final int len) throws SaslException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "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[] result; + try + { + final ByteArrayOutputStream out = new ByteArrayOutputStream(); + // Process the data + if (outCipher != null) + { + result = outCipher.doFinal(outgoing, offset, len); + if (Configuration.DEBUG) + log.fine("Encoding c (encrypted plaintext): " + + Util.dumpString(result)); + out.write(result); + if (outMac != null) + { + outMac.update(result); + if (replayDetection) + { + outCounter++; + if (Configuration.DEBUG) + log.fine("outCounter=" + 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 (Configuration.DEBUG) + log.fine("Encoding C (integrity checksum): " + Util.dumpString(C)); + } + // else confidentiality only; do nothing + } + else // no confidentiality; just integrity [+ replay detection] + { + if (Configuration.DEBUG) + log.fine("Encoding p (plaintext): " + + Util.dumpString(outgoing, offset, len)); + out.write(outgoing, offset, len); + outMac.update(outgoing, offset, len); + if (replayDetection) + { + outCounter++; + if (Configuration.DEBUG) + log.fine("outCounter=" + 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 (Configuration.DEBUG) + log.fine("Encoding C (integrity checksum): " + Util.dumpString(C)); + } + result = out.toByteArray(); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new SaslException("engineWrap()", x); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineWrap"); + return result; + } + + protected String getNegotiatedQOP() + { + if (inMac != null) + { + if (inCipher != null) + return Registry.QOP_AUTH_CONF; + return Registry.QOP_AUTH_INT; + } + return Registry.QOP_AUTH; + } + + protected String getNegotiatedStrength() + { + if (inMac != null) + { + if (inCipher != null) + return Registry.STRENGTH_HIGH; + return Registry.STRENGTH_MEDIUM; + } + return Registry.STRENGTH_LOW; + } + + protected String getNegotiatedRawSendSize() + { + return String.valueOf(rawSendSize); + } + + protected String getReuse() + { + return Registry.REUSE_TRUE; + } + + private byte[] sendIdentities() throws SaslException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "sendIdentities"); + // If necessary, prompt the client for the username and password + getUsernameAndPassword(); + if (Configuration.DEBUG) + { + log.fine("Password: \"" + new String(password.getPassword()) + "\""); + log.fine("Encoding U (username): \"" + U + "\""); + log.fine("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 (Configuration.DEBUG) + { + log.fine("C: " + Util.dumpString(result)); + log.fine(" U = " + U); + log.fine(" I = " + authorizationID); + log.fine("sid = " + new String(sid)); + log.fine(" cn = " + Util.dumpString(cn)); + log.fine("cCB = " + Util.dumpString(channelBinding)); + log.exiting(this.getClass().getName(), "sendIdentities"); + } + return result; + } + + private byte[] sendPublicKey(final byte[] input) throws SaslException + { + if (Configuration.DEBUG) + { + log.entering(this.getClass().getName(), "sendPublicKey"); + log.fine("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 (Configuration.DEBUG) + log.fine("Got N (modulus): " + Util.dump(N)); + g = frameIn.getMPI(); + if (Configuration.DEBUG) + log.fine("Got g (generator): " + Util.dump(g)); + s = frameIn.getOS(); + if (Configuration.DEBUG) + log.fine("Got s (salt): " + Util.dumpString(s)); + B = frameIn.getMPI(); + if (Configuration.DEBUG) + log.fine("Got B (server ephermeral public key): " + Util.dump(B)); + L = frameIn.getText(); + if (Configuration.DEBUG) + log.fine("Got L (available options): \"" + L + "\""); + } + else if (ack == 0xFF) // session re-use + { + sn = frameIn.getOS(); + if (Configuration.DEBUG) + log.fine("Got sn (server nonce): " + Util.dumpString(sn)); + sCB = frameIn.getEOS(); + if (Configuration.DEBUG) + log.fine("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.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 (Configuration.DEBUG) + { + log.fine("K: " + Util.dumpString(K)); + log.fine("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 (Configuration.DEBUG) + { + log.fine("Encoding o (client chosen options): \"" + o + "\""); + log.fine("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 (Configuration.DEBUG) + { + log.fine("New session, or session re-use rejected..."); + log.fine("C: " + Util.dumpString(result)); + log.fine(" A = 0x" + A.toString(16)); + log.fine(" M1 = " + Util.dumpString(M1)); + log.fine(" o = " + o); + log.fine("cIV = " + Util.dumpString(cIV)); + log.exiting(this.getClass().getName(), "sendPublicKey"); + } + return result; + } + else // session re-use accepted ------------------------------------------- + { + setupSecurityServices(true); + if (Configuration.DEBUG) + { + log.fine("Session re-use accepted..."); + log.exiting(this.getClass().getName(), "sendPublicKey"); + } + return null; + } + } + + private byte[] receiveEvidence(byte[] input) throws SaslException + { + if (Configuration.DEBUG) + { + log.entering(this.getClass().getName(), "receiveEvidence"); + log.fine("S: " + Util.dumpString(input)); + } + // Server send M2, sIV, sCB, sid, ttl + final InputBuffer frameIn = new InputBuffer(input); + try + { + M2 = frameIn.getOS(); + if (Configuration.DEBUG) + log.fine("Got M2 (server evidence): " + Util.dumpString(M2)); + sIV = frameIn.getOS(); + if (Configuration.DEBUG) + log.fine("Got sIV (server IV): " + Util.dumpString(sIV)); + sid = frameIn.getEOS(); + if (Configuration.DEBUG) + log.fine("Got sid (session ID): " + new String(sid)); + ttl = (int) frameIn.getScalar(4); + if (Configuration.DEBUG) + log.fine("Got ttl (session time-to-live): " + ttl + "sec."); + sCB = frameIn.getEOS(); + if (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("Expected: " + Util.dumpString(expected)); + if (! Arrays.equals(M2, expected)) + throw new AuthenticationException("M2 mismatch"); + setupSecurityServices(false); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "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 (Configuration.DEBUG) + log.entering(this.getClass().getName(), "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 (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("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 + "=" + maxBufferSize, x); + } + } + } + String s; + Boolean flag; + s = (String) properties.get(SRPRegistry.SRP_REPLAY_DETECTION); + flag = Boolean.valueOf(s); + replayDetection = replaydetectionAvailable && flag.booleanValue(); + s = (String) properties.get(SRPRegistry.SRP_INTEGRITY_PROTECTION); + flag = Boolean.valueOf(s); + boolean integrity = integrityAvailable && flag.booleanValue(); + s = (String) properties.get(SRPRegistry.SRP_CONFIDENTIALITY); + flag = Boolean.valueOf(s); + boolean confidentiality = confidentialityAvailable && flag.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 CPStringBuilder sb = new CPStringBuilder(); + 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 (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "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 (Configuration.DEBUG) + log.fine("Activating confidentiality protection filter"); + inCipher = CALG.getInstance(chosenConfidentialityAlgorithm); + outCipher = CALG.getInstance(chosenConfidentialityAlgorithm); + } + // instantiate hmacs if integrity protection filter is active + if (chosenIntegrityAlgorithm != null) + { + if (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("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; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPRegistry.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPRegistry.java new file mode 100644 index 000000000..b6d24cf14 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPRegistry.java @@ -0,0 +1,165 @@ +/* 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 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 = OPTION_REPLAY_DETECTION; + /** 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; +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPServer.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPServer.java new file mode 100644 index 000000000..fca5c3bf3 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/SRPServer.java @@ -0,0 +1,842 @@ +/* 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.lang.CPStringBuilder; + +import gnu.java.security.Configuration; +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.IncomingMessage; +import gnu.javax.crypto.key.KeyAgreementException; +import gnu.javax.crypto.key.KeyAgreementFactory; +import gnu.javax.crypto.key.OutgoingMessage; +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.ByteArrayOutputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.util.Arrays; +import java.util.HashMap; +import java.util.StringTokenizer; +import java.util.logging.Logger; + +import javax.security.sasl.AuthenticationException; +import javax.security.sasl.SaslException; +import javax.security.sasl.SaslServer; + +/** + * The SASL-SRP server-side mechanism. + */ +public class SRPServer + extends ServerMechanism + implements SaslServer +{ + private static final Logger log = Logger.getLogger(SRPServer.class.getName()); + 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; + + public SRPServer() + { + super(Registry.SASL_SRP_MECHANISM); + } + + 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; + } + + 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 (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineUnwrap"); + if (inMac == null && inCipher == null) + throw new IllegalStateException("connection is not protected"); + if (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("Got C (received MAC): " + Util.dumpString(received_mac)); + inMac.update(incoming, offset, payloadLength); + if (replayDetection) + { + inCounter++; + if (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("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 + result = inCipher.doFinal(incoming, offset, len); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new SaslException("engineUnwrap()", x); + } + if (Configuration.DEBUG) + { + log.fine("Incoming buffer (after security): " + Util.dumpString(result)); + log.exiting(this.getClass().getName(), "engineUnwrap"); + } + return result; + } + + protected byte[] engineWrap(final byte[] outgoing, final int offset, + final int len) throws SaslException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineWrap"); + if (outMac == null && outCipher == null) + throw new IllegalStateException("connection is not protected"); + if (Configuration.DEBUG) + { + log.fine("Outgoing buffer (before security) (hex): " + + Util.dumpString(outgoing, offset, len)); + log.fine("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 (Configuration.DEBUG) + log.fine("Encoding c (encrypted plaintext): " + + Util.dumpString(result)); + out.write(result); + if (outMac != null) + { + outMac.update(result); + if (replayDetection) + { + outCounter++; + if (Configuration.DEBUG) + log.fine("outCounter=" + 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 (Configuration.DEBUG) + log.fine("Encoding C (integrity checksum): " + Util.dumpString(C)); + } + // else ciphertext only; do nothing + } + else // no confidentiality; just integrity [+ replay detection] + { + if (Configuration.DEBUG) + log.fine("Encoding p (plaintext): " + + Util.dumpString(outgoing, offset, len)); + out.write(outgoing, offset, len); + outMac.update(outgoing, offset, len); + if (replayDetection) + { + outCounter++; + if (Configuration.DEBUG) + log.fine("outCounter=" + 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 (Configuration.DEBUG) + log.fine("Encoding C (integrity checksum): " + Util.dumpString(C)); + } + result = out.toByteArray(); + } + catch (IOException x) + { + if (x instanceof SaslException) + throw (SaslException) x; + throw new SaslException("engineWrap()", x); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineWrap"); + return result; + } + + protected String getNegotiatedQOP() + { + if (inMac != null) + { + if (inCipher != null) + return Registry.QOP_AUTH_CONF; + return Registry.QOP_AUTH_INT; + } + return Registry.QOP_AUTH; + } + + protected String getNegotiatedStrength() + { + if (inMac != null) + { + if (inCipher != null) + return Registry.STRENGTH_HIGH; + return Registry.STRENGTH_MEDIUM; + } + return Registry.STRENGTH_LOW; + } + + protected String getNegotiatedRawSendSize() + { + return String.valueOf(rawSendSize); + } + + protected String getReuse() + { + return Registry.REUSE_TRUE; + } + + private byte[] sendProtocolElements(final byte[] input) throws SaslException + { + if (Configuration.DEBUG) + { + log.entering(this.getClass().getName(), "sendProtocolElements"); + log.fine("C: " + Util.dumpString(input)); + } + // Client send U, I, sid, cn + final InputBuffer frameIn = new InputBuffer(input); + try + { + U = frameIn.getText(); // Extract username + if (Configuration.DEBUG) + log.fine("Got U (username): \"" + U + "\""); + authorizationID = frameIn.getText(); // Extract authorisation ID + if (Configuration.DEBUG) + log.fine("Got I (userid): \"" + authorizationID + "\""); + sid = frameIn.getEOS(); + if (Configuration.DEBUG) + log.fine("Got sid (session ID): " + new String(sid)); + cn = frameIn.getOS(); + if (Configuration.DEBUG) + log.fine("Got cn (client nonce): " + Util.dumpString(cn)); + cCB = frameIn.getEOS(); + if (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + { + log.fine("Old session..."); + log.fine("S: " + Util.dumpString(result)); + log.fine(" sn = " + Util.dumpString(sn)); + log.fine(" sCB = " + Util.dumpString(channelBinding)); + log.exiting(this.getClass().getName(), "sendProtocolElements"); + } + return result; + } + else + { // new session + authenticator.activate(properties); + // ------------------------------------------------------------------- + final HashMap mapB = new HashMap(); + 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 (Configuration.DEBUG) + { + log.fine("Encoding N (modulus): " + Util.dump(N)); + log.fine("Encoding g (generator): " + Util.dump(g)); + log.fine("Encoding s (client's salt): " + Util.dumpString(s)); + log.fine("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 (Configuration.DEBUG) + { + log.fine("Encoding L (available options): \"" + L + "\""); + log.fine("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 (Configuration.DEBUG) + { + log.fine("New session..."); + log.fine("S: " + Util.dumpString(result)); + log.fine(" N = 0x" + N.toString(16)); + log.fine(" g = 0x" + g.toString(16)); + log.fine(" s = " + Util.dumpString(s)); + log.fine(" B = 0x" + B.toString(16)); + log.fine(" L = " + L); + log.exiting(this.getClass().getName(), "sendProtocolElements"); + } + return result; + } + } + + private byte[] sendEvidence(final byte[] input) throws SaslException + { + if (Configuration.DEBUG) + { + log.entering(this.getClass().getName(), "sendEvidence"); + log.fine("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 (Configuration.DEBUG) + log.fine("Got A (client ephemeral public key): " + Util.dump(A)); + M1 = frameIn.getOS(); // Extract evidence + if (Configuration.DEBUG) + log.fine("Got M1 (client evidence): " + Util.dumpString(M1)); + o = frameIn.getText(); // Extract client's options list + if (Configuration.DEBUG) + log.fine("Got o (client chosen options): \"" + o + "\""); + cIV = frameIn.getOS(); // Extract client's IV + if (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + { + log.fine("S: " + Util.dumpString(result)); + log.fine(" M2 = " + Util.dumpString(M2)); + log.fine(" sIV = " + Util.dumpString(sIV)); + log.fine(" sid = " + new String(sid)); + log.fine(" ttl = " + ttl); + log.fine(" sCB = " + Util.dumpString(channelBinding)); + log.exiting(this.getClass().getName(), "sendEvidence"); + } + return result; + } + + private String createL() + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "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 (Configuration.DEBUG) + log.fine("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 CPStringBuilder sb = new CPStringBuilder(); + 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 (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "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 (Configuration.DEBUG) + log.fine("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"); + option = option.substring(option.indexOf('=') + 1); + if (Configuration.DEBUG) + log.fine("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"); + option = option.substring(option.indexOf('=') + 1); + if (Configuration.DEBUG) + log.fine("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 + "=" + 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 (Configuration.DEBUG) + log.fine("Activating confidentiality protection filter"); + inCipher = CALG.getInstance(chosenConfidentialityAlgorithm); + outCipher = CALG.getInstance(chosenConfidentialityAlgorithm); + } + // instantiate hmacs if integrity protection filter is active + if (chosenIntegrityAlgorithm != null) + { + if (Configuration.DEBUG) + log.fine("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 (Configuration.DEBUG) + log.fine("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; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/SecurityContext.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/SecurityContext.java new file mode 100644 index 000000000..41ec57c81 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/SecurityContext.java @@ -0,0 +1,140 @@ +/* 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 +{ + 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; + + 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; + } + + 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; + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/ServerStore.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/ServerStore.java new file mode 100644 index 000000000..d98747324 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/ServerStore.java @@ -0,0 +1,177 @@ +/* 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 gnu.java.lang.CPStringBuilder; + +import java.util.HashMap; + +/** + * The server-side implementation of the SRP security context store. + */ +public class ServerStore +{ + /** 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; + + /** Private constructor to enforce Singleton pattern. */ + private ServerStore() + { + super(); + + // TODO: add a cleaning timer thread + } + + /** + * 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 CPStringBuilder("SID-") + .append("0000000000".substring(0, 10 - sid.length())).append(sid) + .toString().getBytes(); + } + + /** + * 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); + } + } +} diff --git a/libjava/classpath/gnu/javax/crypto/sasl/srp/StoreEntry.java b/libjava/classpath/gnu/javax/crypto/sasl/srp/StoreEntry.java new file mode 100644 index 000000000..ae64fa774 --- /dev/null +++ b/libjava/classpath/gnu/javax/crypto/sasl/srp/StoreEntry.java @@ -0,0 +1,75 @@ +/* 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 +{ + private boolean perenial; + private long timeToDie; + + StoreEntry(int ttl) + { + super(); + + if (ttl == 0) + { + perenial = true; + timeToDie = 0L; + } + else + { + perenial = false; + timeToDie = System.currentTimeMillis() + (ttl & 0xFFFFFFFFL) * 1000L; + } + } + + /** + * 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)); + } +} diff --git a/libjava/classpath/gnu/javax/imageio/IIOInputStream.java b/libjava/classpath/gnu/javax/imageio/IIOInputStream.java new file mode 100644 index 000000000..1ede75f78 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/IIOInputStream.java @@ -0,0 +1,102 @@ +/* GIFStream.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.javax.imageio; + +import java.io.InputStream; +import java.io.IOException; +import javax.imageio.stream.ImageInputStream; + +/** + * Implements InputStream on an ImageInputStream + * The purpose of this is to avoid IIO dependencies in the various decoders. + * (which only use read() anyway). + */ +public class IIOInputStream extends InputStream +{ + private ImageInputStream is; + + public IIOInputStream( ImageInputStream is ) + { + this.is = is; + } + + public int available() + { + return 0; + } + + public void close() throws IOException + { + is.close(); + } + + public void mark(int readlimit) + { + is.mark(); + } + + public boolean markSupported() + { + return true; + } + + public int read() throws IOException + { + return is.read(); + } + + public int read(byte[] b) throws IOException + { + return is.read(b); + } + + public int read(byte[] b, int offset, int length) throws IOException + { + return is.read(b, offset, length); + } + + public void reset() throws IOException + { + is.reset(); + } + + public long skip(long n) throws IOException + { + return is.skipBytes(n); + } +} diff --git a/libjava/classpath/gnu/javax/imageio/bmp/BMPDecoder.java b/libjava/classpath/gnu/javax/imageio/bmp/BMPDecoder.java new file mode 100644 index 000000000..108461931 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/bmp/BMPDecoder.java @@ -0,0 +1,168 @@ +/* BMPDecoder.java -- + 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.imageio.bmp; + +import java.io.IOException; +import javax.imageio.stream.ImageInputStream; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.awt.image.IndexColorModel; +import java.awt.image.BufferedImage; + +public abstract class BMPDecoder { + + protected BMPInfoHeader infoHeader; + protected BMPFileHeader fileHeader; + protected long offset; + + public BMPDecoder(BMPFileHeader fh, BMPInfoHeader ih){ + fileHeader = fh; + infoHeader = ih; + offset = BMPFileHeader.SIZE + BMPInfoHeader.SIZE; + } + + /** + * Determines the coding type of the bitmap and returns the corresponding + * decoder. + */ + public static BMPDecoder getDecoder(BMPFileHeader fh, BMPInfoHeader ih){ + switch(ih.getCompression()){ + case BMPInfoHeader.BI_RGB: // uncompressed RGB + switch(ih.getBitCount()){ + case 32: + return new DecodeBF32(fh, ih, true); + + case 24: + return new DecodeRGB24(fh, ih); + + case 16: + return new DecodeBF16(fh, ih, true); + + case 8: + return new DecodeRGB8(fh, ih); + + case 4: + return new DecodeRGB4(fh, ih); + + case 1: + return new DecodeRGB1(fh, ih); + + default: + return null; + } + + case BMPInfoHeader.BI_RLE8: + return new DecodeRLE8(fh, ih); + + case BMPInfoHeader.BI_RLE4: + return new DecodeRLE4(fh, ih); + + case BMPInfoHeader.BI_BITFIELDS: + switch(ih.getBitCount()){ + case 16: + return new DecodeBF16(fh, ih, false); + + case 32: + return new DecodeBF32(fh, ih, false); + + default: + return null; + } + + default: + return null; + } + } + + /** + * The image decoder. + */ + public abstract BufferedImage decode(ImageInputStream in) + throws IOException, BMPException; + + /** + * Reads r,g,b bit masks from an inputstream + */ + protected int[] readBitMasks(ImageInputStream in) throws IOException { + int[] bitmasks = new int[3]; + byte[] temp = new byte[12]; + if(in.read(temp) != 12) + throw new IOException("Couldn't read bit masks."); + offset += 12; + + ByteBuffer buf = ByteBuffer.wrap(temp); + buf.order(ByteOrder.LITTLE_ENDIAN); + bitmasks[0] = buf.getInt(); + bitmasks[1] = buf.getInt(); + bitmasks[2] = buf.getInt(); + return bitmasks; + } + + /** + * Reads an N-color palette from an inputstream in RGBQUAD format and + * returns an equivalent ColorModel object + */ + protected IndexColorModel readPalette(ImageInputStream in) throws IOException { + int N = infoHeader.getNumberOfPaletteEntries(); + byte[] r = new byte[N]; + byte[] g = new byte[N]; + byte[] b = new byte[N]; + for(int i=0;i> 8) & 0x00FF); + return b; + } + + /** + * Converts an int to a double word, where the return value is + * stored in a 4-byte array. + * + * @param val - the value to convert + * @return the array + */ + private byte[] intToDWord(int val) + { + byte b[] = new byte[4]; + b[0] = (byte) (val & 0x00FF); + b[1] = (byte) ((val >> 8) & 0x000000FF); + b[2] = (byte) ((val >> 16) & 0x000000FF); + b[3] = (byte) ((val >> 24) & 0x000000FF); + return b; + } + + + public void setBitCount(short bitcount) throws BMPException + { + switch (bitcount) + { + case 1: + case 4: + case 8: + case 16: + case 24: + case 32: + biBitCount = bitcount; + break; + + default: + throw new BMPException("Invalid number of bits per pixel: " + bitcount); + } + } + + public short getBitCount() + { + return biBitCount; + } + + public void setCompression(int compression) throws BMPException + { + switch (compression) + { + case BI_RLE8: + if (getBitCount() != 8) + throw new BMPException("Invalid number of bits per pixel."); + biCompression = compression; + break; + case BI_RLE4: + if (getBitCount() != 4) + throw new BMPException("Invalid number of bits per pixel."); + biCompression = compression; + break; + + case BI_RGB: + case BI_BITFIELDS: + biCompression = compression; + break; + + default: + throw new BMPException("Unknown bitmap compression type."); + } + } + + public int getNumberOfPaletteEntries() + { + if (biClrUsed == 0) + switch (biBitCount) + { + case 1: + return 2; + case 4: + return 16; + case 8: + return 256; + + default: // should not happen + return 0; + } + + return biClrUsed; + } + + public int getCompression() + { + return biCompression; + } + + public Dimension getSize() + { + return new Dimension(biWidth, biHeight); + } + + public int getWidth() + { + return biWidth; + } + + public int getHeight() + { + return biHeight; + } + + public void setSize(Dimension d) + { + biWidth = (int) d.getWidth(); + biHeight = (int) d.getHeight(); + } +} diff --git a/libjava/classpath/gnu/javax/imageio/bmp/DecodeBF16.java b/libjava/classpath/gnu/javax/imageio/bmp/DecodeBF16.java new file mode 100644 index 000000000..2f94ac613 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/bmp/DecodeBF16.java @@ -0,0 +1,99 @@ +/* DecodeBF16.java -- + 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.imageio.bmp; + +import java.io.IOException; +import javax.imageio.stream.ImageInputStream; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.DirectColorModel; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferUShort; +import java.awt.image.SinglePixelPackedSampleModel; +import java.awt.image.SampleModel; +import java.awt.Dimension; + +public class DecodeBF16 extends BMPDecoder { + private int[] bitmasks; + private boolean useDefaultMasks; + + public DecodeBF16(BMPFileHeader fh, BMPInfoHeader ih, + boolean udm){ + super(fh,ih); + + useDefaultMasks = udm; + if(useDefaultMasks) // 5-6-5 mask, B,G,R + bitmasks = new int[] { 0x00F800, 0x0007E0, 0x00001F }; + } + + public BufferedImage decode(ImageInputStream in) throws IOException, BMPException { + if(!useDefaultMasks) + bitmasks = readBitMasks(in); + skipToImage(in); + + Dimension d = infoHeader.getSize(); + int h = (int)d.getHeight(); + int w = (int)d.getWidth(); + + // BMP scanlines are padded to dword offsets + int scansize = (w + (w&1)) << 1; + short[] data = new short[w*h]; + + for(int y=h-1;y>=0;y--){ + byte[] scanline = new byte[scansize]; + if(in.read(scanline) != scansize) + throw new IOException("Couldn't read image data."); + + for(int x=0;x=0;y--){ + byte[] scanline = new byte[scansize]; + if(in.read(scanline) != scansize) + throw new IOException("Couldn't read image data."); + + for(int x=0;x>3; + + int scansize = w>>3; + byte[] data = new byte[size]; + + for(int y=h-1;y>=0;y--){ + // Scanlines are padded to dword boundries + int readsize = scansize; + if((readsize & 3) != 0) readsize += (4 - (scansize & 3)); + + byte[] scanline = new byte[readsize]; + if(in.read(scanline) != readsize) + throw new IOException("Couldn't read image data."); + + for(int x=0;x=0;y--){ + byte[] scanline = new byte[scansize]; + if(in.read(scanline) != scansize) + throw new IOException("Couldn't read image data."); + + for(int x=0;x> 1; + + // Scanline padded to dword offsets + int wbytes = (w + (w & 1)) >> 1; + int scansize = ((wbytes & 3) != 0)? (wbytes + 4 - (wbytes&3)) : wbytes; + + byte[] data = new byte[wbytes*h]; + + for(int y=h-1;y>=0;y--){ + byte[] scanline = new byte[scansize]; + if(in.read(scanline) != scansize) + throw new IOException("Couldn't read image data."); + + for(int x=0;x=0;y--){ + byte[] scanline = new byte[scansize]; + if(in.read(scanline) != scansize) + throw new IOException("Couldn't read image data."); + + for(int x=0;x>1]; + int offIn = 0; + int x=0,y=0; + + // width in bytes + w += (w&1); + w = w >> 1; + + try { + while(((x>>1) + y*w) < w*h){ + if(in.read(cmd) != 2) + throw new IOException("Error reading compressed data."); + + if(cmd[0] == ESCAPE){ + switch(cmd[1]){ + case EOB: // end of bitmap + return data; + case EOL: // end of line + x = 0; + y++; + break; + case DELTA: // delta + if(in.read(cmd) != 2) + throw new IOException("Error reading compressed data."); + int dx = cmd[0] & (0xFF); + int dy = cmd[1] & (0xFF); + x += dx; + y += dy; + break; + + default: + // decode a literal run + int length = cmd[1] & (0xFF); + + // size of run, which is word aligned. + int bytesize = length; + bytesize += (bytesize & 1); + bytesize >>= 1; + bytesize += (bytesize & 1); + + byte[] run = new byte[bytesize]; + if(in.read(run) != bytesize) + throw new IOException("Error reading compressed data."); + + if((x&1) == 0){ + length += (length&1); + length >>= 1; + System.arraycopy(run, 0, data, ((x>>1) + w*(h-y-1)), + length); + } else { + for(int i=0;i>1) + w*(h-y-1)] + |= ((run[i>>1]&0xF0) >> 4); + else // copy low to high + data[((x+i)>>1) + w*(h-y-1)] + |= ((run[i>>1]&0x0F) << 4); + } + } + x += cmd[1] & (0xFF); + break; + } + } else { + // decode a byte run + int length = cmd[0] & (0xFF); + if((x&1) == 0){ + length += (length&1); + length >>= 1; + for(int i=0;i> 1)] = cmd[1]; + } else { + for(int i=0;i>1) + w*(h-y-1)] + |= ((cmd[1]&0xF0) >> 4); + else // copy low to high + data[((x+i)>>1) + w*(h-y-1)] + |= ((cmd[1]&0x0F) << 4); + } + } + x += cmd[0] & (0xFF); + } + } + return data; + } catch(ArrayIndexOutOfBoundsException e){ + throw new BMPException("Invalid RLE data."); + } + } +} diff --git a/libjava/classpath/gnu/javax/imageio/bmp/DecodeRLE8.java b/libjava/classpath/gnu/javax/imageio/bmp/DecodeRLE8.java new file mode 100644 index 000000000..afc3da89e --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/bmp/DecodeRLE8.java @@ -0,0 +1,142 @@ +/* DecodeRLE8.java -- + 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.imageio.bmp; + +import java.io.IOException; +import javax.imageio.stream.ImageInputStream; +import java.awt.image.BufferedImage; +import java.awt.image.IndexColorModel; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.SinglePixelPackedSampleModel; +import java.awt.image.SampleModel; +import java.awt.Dimension; + +public class DecodeRLE8 extends BMPDecoder { + + public DecodeRLE8(BMPFileHeader fh, BMPInfoHeader ih){ + super(fh, ih); + } + + /** + * RLE control codes + */ + private static final byte ESCAPE = (byte)0; + private static final byte EOL = (byte)0; // end of line + private static final byte EOB = (byte)1; // end of bitmap + private static final byte DELTA = (byte)2; // delta + + public BufferedImage decode(ImageInputStream in) throws IOException, BMPException { + IndexColorModel palette = readPalette(in); + skipToImage(in); + + Dimension d = infoHeader.getSize(); + int h = (int)d.getHeight(); + int w = (int)d.getWidth(); + + byte[] data = uncompress(w, h, in); + SampleModel sm = new SinglePixelPackedSampleModel(DataBuffer.TYPE_BYTE, + w, h, + new int[] {0xFF}); + DataBuffer db = new DataBufferByte(data, w*h, 0); + WritableRaster raster = Raster.createWritableRaster(sm, db, null); + + return new BufferedImage(palette, raster, false, null); + } + + private byte[] uncompress(int w, int h, ImageInputStream in) + throws BMPException, IOException { + byte[] cmd = new byte[2]; + byte[] data = new byte[w*h]; + int offIn = 0; + int x=0,y=0; + + try { + while((x + y*w) < w*h){ + if(in.read(cmd) != 2) + throw new IOException("Error reading compressed data."); + + if(cmd[0] == ESCAPE){ + switch(cmd[1]){ + case EOB: // end of bitmap + return data; + case EOL: // end of line + x = 0; + y++; + break; + case DELTA: // delta + if(in.read(cmd) != 2) + throw new IOException("Error reading compressed data."); + int dx = cmd[0] & (0xFF); + int dy = cmd[1] & (0xFF); + x += dx; + y += dy; + break; + + default: + // decode a literal run + int length = cmd[1] & (0xFF); + int copylength = length; + + // absolute mode must be word-aligned + length += (length & 1); + + byte[] run = new byte[length]; + if(in.read(run) != length) + throw new IOException("Error reading compressed data."); + + System.arraycopy(run, 0, data, (x+w*(h-y-1)), + copylength); + x += copylength; + break; + } + } else { + // decode a byte run + int length = cmd[0] & (0xFF); + for(int i=0;i> 8 & 0xFF); + + o.write(rgb); + if (rowCount == infoHeader.biWidth) + { + rowCount = 1; + rowIndex = lastRowIndex - infoHeader.biWidth; + lastRowIndex = rowIndex; + } + else + rowCount++; + rowIndex++; + } + } + catch (Exception wb) + { + wb.printStackTrace(); + } + } +} diff --git a/libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB24.java b/libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB24.java new file mode 100644 index 000000000..7fbc83e2e --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB24.java @@ -0,0 +1,129 @@ +/* EncodeRGB24.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.javax.imageio.bmp; + +import java.awt.image.BufferedImage; +import java.awt.image.PixelGrabber; +import java.io.IOException; + +import javax.imageio.IIOImage; +import javax.imageio.ImageWriteParam; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.stream.ImageOutputStream; + +public class EncodeRGB24 + extends BMPEncoder +{ + protected BMPInfoHeader infoHeader; + protected BMPFileHeader fileHeader; + protected long offset; + + /** + * Constructs an instance of this class. + * + * @param fh - the file header to use. + * @param ih - the info header to use. + */ + public EncodeRGB24(BMPFileHeader fh, BMPInfoHeader ih) + { + super(); + fileHeader = fh; + infoHeader = ih; + offset = BMPFileHeader.SIZE + BMPInfoHeader.SIZE; + } + + /** + * The image encoder. + * + * @param o - the image output stream + * @param streamMetadata - metadata associated with this stream, or + * null + * @param image - an IIOImage containing image data. + * @param param - image writing parameters, or null + * @exception IOException if a write error occurs + */ + public void encode(ImageOutputStream o, IIOMetadata streamMetadata, + IIOImage image, ImageWriteParam param) throws IOException + { + int size; + int value; + int j; + int rowCount; + int rowIndex; + int lastRowIndex; + int[] bitmap; + byte rgb[] = new byte[3]; + size = (infoHeader.biWidth * infoHeader.biHeight) - 1; + rowCount = 1; + rowIndex = size - infoHeader.biWidth; + lastRowIndex = rowIndex; + try + { + bitmap = new int[infoHeader.biWidth * infoHeader.biHeight]; + PixelGrabber pg = new PixelGrabber((BufferedImage) image.getRenderedImage(), + 0, 0, infoHeader.biWidth, + infoHeader.biHeight, bitmap, 0, + infoHeader.biWidth); + pg.grabPixels(); + + for (j = 0; j < size; j++) + { + value = bitmap[rowIndex]; + + rgb[0] = (byte) (value & 0xFF); + rgb[1] = (byte) ((value >> 8) & 0xFF); + rgb[2] = (byte) ((value >> 16) & 0xFF); + o.write(rgb); + if (rowCount == infoHeader.biWidth) + { + rowCount = 1; + rowIndex = lastRowIndex - infoHeader.biWidth; + lastRowIndex = rowIndex; + } + else + rowCount++; + rowIndex++; + } + } + catch (Exception wb) + { + wb.printStackTrace(); + } + } +} diff --git a/libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB32.java b/libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB32.java new file mode 100644 index 000000000..7deca3049 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB32.java @@ -0,0 +1,129 @@ +/* EncodeRGB32.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.javax.imageio.bmp; + +import java.awt.image.BufferedImage; +import java.awt.image.PixelGrabber; +import java.io.IOException; + +import javax.imageio.IIOImage; +import javax.imageio.ImageWriteParam; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.stream.ImageOutputStream; + +public class EncodeRGB32 + extends BMPEncoder +{ + protected BMPInfoHeader infoHeader; + protected BMPFileHeader fileHeader; + protected long offset; + + /** + * Constructs an instance of this class. + * + * @param fh - the file header to use. + * @param ih - the info header to use. + */ + public EncodeRGB32(BMPFileHeader fh, BMPInfoHeader ih) + { + super(); + fileHeader = fh; + infoHeader = ih; + offset = BMPFileHeader.SIZE + BMPInfoHeader.SIZE; + } + + /** + * The image encoder. + * + * @param o - the image output stream + * @param streamMetadata - metadata associated with this stream, or null + * @param image - an IIOImage containing image data. + * @param param - image writing parameters, or null + * @exception IOException if a write error occurs + */ + public void encode(ImageOutputStream o, IIOMetadata streamMetadata, + IIOImage image, ImageWriteParam param) throws IOException + { + int size; + int value; + int j; + int rowCount; + int rowIndex; + int lastRowIndex; + int[] bitmap; + byte rgb[] = new byte[4]; + size = (infoHeader.biWidth * infoHeader.biHeight) - 1; + rowCount = 1; + rowIndex = size - infoHeader.biWidth; + lastRowIndex = rowIndex; + try + { + bitmap = new int[infoHeader.biWidth * infoHeader.biHeight]; + PixelGrabber pg = new PixelGrabber((BufferedImage) image.getRenderedImage(), + 0, 0, infoHeader.biWidth, + infoHeader.biHeight, bitmap, 0, + infoHeader.biWidth); + pg.grabPixels(); + + for (j = 0; j < size; j++) + { + value = bitmap[rowIndex]; + + rgb[0] = (byte) (value & 0xFF); + rgb[1] = (byte) ((value >> 8) & 0xFF); + rgb[2] = (byte) ((value >> 16) & 0xFF); + rgb[3] = (byte) ((value >> 24) & 0xFF); + o.write(rgb); + if (rowCount == infoHeader.biWidth) + { + rowCount = 1; + rowIndex = lastRowIndex - infoHeader.biWidth; + lastRowIndex = rowIndex; + } + else + rowCount++; + rowIndex++; + } + } + catch (Exception wb) + { + wb.printStackTrace(); + } + } +} diff --git a/libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB4.java b/libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB4.java new file mode 100644 index 000000000..b62283a7d --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB4.java @@ -0,0 +1,128 @@ +/* EncodeRGB4.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.javax.imageio.bmp; + +import java.awt.image.BufferedImage; +import java.awt.image.PixelGrabber; +import java.io.IOException; + +import javax.imageio.IIOImage; +import javax.imageio.ImageWriteParam; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.stream.ImageOutputStream; + +public class EncodeRGB4 + extends BMPEncoder +{ + protected BMPInfoHeader infoHeader; + protected BMPFileHeader fileHeader; + protected long offset; + + /** + * Constructs an instance of this class. + * + * @param fh - the file header to use. + * @param ih - the info header to use. + */ + public EncodeRGB4(BMPFileHeader fh, BMPInfoHeader ih) + { + super(); + fileHeader = fh; + infoHeader = ih; + offset = BMPFileHeader.SIZE + BMPInfoHeader.SIZE; + } + + /** + * The image encoder. + * + * @param o - the image output stream + * @param streamMetadata - metadata associated with this stream, or + * null + * @param image - an IIOImage containing image data. + * @param param - image writing parameters, or null + * @exception IOException if a write error occurs + */ + public void encode(ImageOutputStream o, IIOMetadata streamMetadata, + IIOImage image, ImageWriteParam param) throws IOException + { + int size; + int value; + int j; + int rowCount; + int rowIndex; + int lastRowIndex; + int[] bitmap; + byte rgb[] = new byte[1]; + size = (infoHeader.biWidth * infoHeader.biHeight) - 1; + rowCount = 1; + rowIndex = size - infoHeader.biWidth; + lastRowIndex = rowIndex; + try + { + bitmap = new int[infoHeader.biWidth * infoHeader.biHeight]; + PixelGrabber pg = new PixelGrabber((BufferedImage) image.getRenderedImage(), + 0, 0, infoHeader.biWidth, + infoHeader.biHeight, bitmap, 0, + infoHeader.biWidth); + pg.grabPixels(); + + for (j = 0; j < size; j++) + { + value = bitmap[rowIndex]; + + rgb[0] = (byte) (value & 0xFF); + + o.write(rgb); + if (rowCount == infoHeader.biWidth) + { + rowCount = 1; + rowIndex = lastRowIndex - infoHeader.biWidth; + lastRowIndex = rowIndex; + } + else + rowCount++; + rowIndex++; + } + } + catch (Exception wb) + { + wb.printStackTrace(); + } + } +} diff --git a/libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB8.java b/libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB8.java new file mode 100644 index 000000000..ef0594a5f --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB8.java @@ -0,0 +1,127 @@ +/* EncodeRGB8.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.javax.imageio.bmp; + +import java.awt.image.BufferedImage; +import java.awt.image.PixelGrabber; +import java.io.IOException; + +import javax.imageio.IIOImage; +import javax.imageio.ImageWriteParam; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.stream.ImageOutputStream; + +public class EncodeRGB8 + extends BMPEncoder +{ + protected BMPInfoHeader infoHeader; + protected BMPFileHeader fileHeader; + protected long offset; + + /** + * Constructs an instance of this class. + * + * @param fh - the file header to use. + * @param ih - the info header to use. + */ + public EncodeRGB8(BMPFileHeader fh, BMPInfoHeader ih) + { + super(); + fileHeader = fh; + infoHeader = ih; + offset = BMPFileHeader.SIZE + BMPInfoHeader.SIZE; + } + + /** + * The image encoder. + * + * @param o - the image output stream + * @param streamMetadata - metadata associated with this stream, or + * null + * @param image - an IIOImage containing image data. + * @param param - image writing parameters, or null + * @exception IOException if a write error occurs + */ + public void encode(ImageOutputStream o, IIOMetadata streamMetadata, + IIOImage image, ImageWriteParam param) throws IOException + { + int size; + int value; + int j; + int rowCount; + int rowIndex; + int lastRowIndex; + int[] bitmap; + byte rgb[] = new byte[1]; + size = (infoHeader.biWidth * infoHeader.biHeight) - 1; + rowCount = 1; + rowIndex = size - infoHeader.biWidth; + lastRowIndex = rowIndex; + try + { + bitmap = new int[infoHeader.biWidth * infoHeader.biHeight]; + PixelGrabber pg = new PixelGrabber((BufferedImage) image.getRenderedImage(), + 0, 0, infoHeader.biWidth, + infoHeader.biHeight, bitmap, 0, + infoHeader.biWidth); + pg.grabPixels(); + + for (j = 0; j < size; j++) + { + value = bitmap[rowIndex]; + + rgb[0] = (byte) (value & 0xFF); + o.write(rgb); + if (rowCount == infoHeader.biWidth) + { + rowCount = 1; + rowIndex = lastRowIndex - infoHeader.biWidth; + lastRowIndex = rowIndex; + } + else + rowCount++; + rowIndex++; + } + } + catch (Exception wb) + { + wb.printStackTrace(); + } + } +} diff --git a/libjava/classpath/gnu/javax/imageio/bmp/EncodeRLE4.java b/libjava/classpath/gnu/javax/imageio/bmp/EncodeRLE4.java new file mode 100644 index 000000000..c54c3ca87 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/bmp/EncodeRLE4.java @@ -0,0 +1,269 @@ +/* EncodeRLE4.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.javax.imageio.bmp; + +import java.awt.image.BufferedImage; +import java.awt.image.PixelGrabber; +import java.io.IOException; +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; + +import javax.imageio.IIOImage; +import javax.imageio.ImageWriteParam; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.stream.ImageOutputStream; + +public class EncodeRLE4 + extends BMPEncoder +{ + protected BMPInfoHeader infoHeader; + protected BMPFileHeader fileHeader; + protected long offset; + + /** + * RLE control codes + */ + private static final byte ESCAPE = (byte)0; + private static final byte EOL = (byte)0; // end of line + private static final byte EOB = (byte)1; // end of bitmap + private static final byte DELTA = (byte)2; // delta + + /** + * Constructs an instance of this class. + * + * @param fh - the file header to use. + * @param ih - the info header to use. + */ + public EncodeRLE4(BMPFileHeader fh, BMPInfoHeader ih) + { + super(); + fileHeader = fh; + infoHeader = ih; + offset = BMPFileHeader.SIZE + BMPInfoHeader.SIZE; + } + + /** + * The image encoder. + * + * @param o - the image output stream + * @param streamMetadata - metadata associated with this stream, or + * null + * @param image - an IIOImage containing image data. + * @param param - image writing parameters, or null + * @exception IOException if a write error occurs + */ + public void encode(ImageOutputStream o, IIOMetadata streamMetadata, + IIOImage image, ImageWriteParam param) throws IOException + { + int size; + int value; + int j; + int rowCount; + int rowIndex; + int lastRowIndex; + int[] bitmap; + size = (infoHeader.biWidth * infoHeader.biHeight) - 1; + rowCount = 1; + rowIndex = size - infoHeader.biWidth; + lastRowIndex = rowIndex; + ByteBuffer buf = ByteBuffer.allocate(size); + try + { + bitmap = new int[infoHeader.biWidth * infoHeader.biHeight]; + PixelGrabber pg = new PixelGrabber((BufferedImage) image.getRenderedImage(), + 0, 0, infoHeader.biWidth, + infoHeader.biHeight, bitmap, 0, + infoHeader.biWidth); + pg.grabPixels(); + + for (j = 0; j < size; j++) + { + value = bitmap[rowIndex]; + buf.put((byte) (value & 0xFF)); + + if (rowCount == infoHeader.biWidth) + { + rowCount = 1; + rowIndex = lastRowIndex - infoHeader.biWidth; + lastRowIndex = rowIndex; + } + else + rowCount++; + rowIndex++; + } + + buf.flip(); + o.write(uncompress(infoHeader.biWidth, infoHeader.biHeight, buf)); + } + catch (Exception wb) + { + wb.printStackTrace(); + } + } + + /** + * Uncompresses the image stored in the buffer. + * + * @param w - the width of the image + * @param h - the height of the image + * @param buf - the ByteBuffer containing the pixel values. + * @return byte array containing the uncompressed image + * @throws IOException if an error is encountered while reading + * buffer. + */ + private byte[] uncompress(int w, int h, ByteBuffer buf) + throws IOException + { + byte[] cmd = new byte[2]; + byte[] data = new byte[w * h >> 1]; + int offIn = 0; + int x = 0, y = 0; + + w += (w & 1); + w = w >> 1; + + try + { + while (((x >> 1) + y * w) < w * h) + { + try + { + buf.get(cmd); + } + catch (BufferUnderflowException e) + { + throw new IOException("Error reading compressed data."); + } + + if (cmd[0] == ESCAPE) + { + switch (cmd[1]) + { + case EOB: + return data; + case EOL: + x = 0; + y++; + break; + case DELTA: + try + { + buf.get(cmd); + } + catch (BufferUnderflowException e) + { + throw new IOException("Error reading compressed data."); + } + + int dx = cmd[0] & (0xFF); + int dy = cmd[1] & (0xFF); + x += dx; + y += dy; + break; + + default: + int length = cmd[1] & (0xFF); + + int bytesize = length; + bytesize += (bytesize & 1); + bytesize >>= 1; + bytesize += (bytesize & 1); + + byte[] run = new byte[bytesize]; + try + { + buf.get(run); + } + catch (BufferUnderflowException e) + { + throw new IOException("Error reading compressed data."); + } + + if ((x & 1) == 0) + { + length += (length & 1); + length >>= 1; + System.arraycopy(run, 0, data, + ((x >> 1) + w * (h - y - 1)), length); + } + else + { + for (int i = 0; i < length; i++) + { + if ((i & 1) == 0) + data[((x + i) >> 1) + w * (h - y - 1)] |= ((run[i >> 1] & 0xF0) >> 4); + else + data[((x + i) >> 1) + w * (h - y - 1)] |= ((run[i >> 1] & 0x0F) << 4); + } + } + x += cmd[1] & (0xFF); + break; + } + } + else + { + int length = cmd[0] & (0xFF); + if ((x & 1) == 0) + { + length += (length & 1); + length >>= 1; + for (int i = 0; i < length; i++) + data[(h - y - 1) * w + i + (x >> 1)] = cmd[1]; + } + else + { + for (int i = 0; i < length; i++) + { + if ((i & 1) == 0) + data[((x + i) >> 1) + w * (h - y - 1)] |= ((cmd[1] & 0xF0) >> 4); + else + data[((x + i) >> 1) + w * (h - y - 1)] |= ((cmd[1] & 0x0F) << 4); + } + } + x += cmd[0] & (0xFF); + } + } + return data; + } + catch (ArrayIndexOutOfBoundsException e) + { + throw new BMPException("Invalid RLE data."); + } + } +} diff --git a/libjava/classpath/gnu/javax/imageio/bmp/EncodeRLE8.java b/libjava/classpath/gnu/javax/imageio/bmp/EncodeRLE8.java new file mode 100644 index 000000000..62277ef90 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/bmp/EncodeRLE8.java @@ -0,0 +1,234 @@ +/* EncodeRGB32.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.javax.imageio.bmp; + +import java.awt.image.BufferedImage; +import java.awt.image.PixelGrabber; +import java.io.IOException; +import java.nio.BufferUnderflowException; +import java.nio.ByteBuffer; + +import javax.imageio.IIOImage; +import javax.imageio.ImageWriteParam; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.stream.ImageOutputStream; + +public class EncodeRLE8 + extends BMPEncoder +{ + protected BMPInfoHeader infoHeader; + protected BMPFileHeader fileHeader; + protected long offset; + + /** + * RLE control codes + */ + private static final byte ESCAPE = (byte)0; + private static final byte EOL = (byte)0; // end of line + private static final byte EOB = (byte)1; // end of bitmap + private static final byte DELTA = (byte)2; // delta + + /** + * Constructs an instance of this class. + * + * @param fh - the file header to use. + * @param ih - the info header to use. + */ + public EncodeRLE8(BMPFileHeader fh, BMPInfoHeader ih) + { + super(); + fileHeader = fh; + infoHeader = ih; + offset = BMPFileHeader.SIZE + BMPInfoHeader.SIZE; + } + + /** + * The image encoder. + * + * @param o - the image output stream + * @param streamMetadata - metadata associated with this stream, or + * null + * @param image - an IIOImage containing image data. + * @param param - image writing parameters, or null + * @exception IOException if a write error occurs + */ + public void encode(ImageOutputStream o, IIOMetadata streamMetadata, + IIOImage image, ImageWriteParam param) throws IOException + { + int size; + int value; + int j; + int rowCount; + int rowIndex; + int lastRowIndex; + int[] bitmap; + size = (infoHeader.biWidth * infoHeader.biHeight) - 1; + rowCount = 1; + rowIndex = size - infoHeader.biWidth; + lastRowIndex = rowIndex; + ByteBuffer buf = ByteBuffer.allocate(size); + try + { + bitmap = new int[infoHeader.biWidth * infoHeader.biHeight]; + PixelGrabber pg = new PixelGrabber((BufferedImage) image.getRenderedImage(), + 0, 0, infoHeader.biWidth, + infoHeader.biHeight, bitmap, 0, + infoHeader.biWidth); + pg.grabPixels(); + + for (j = 0; j < size; j++) + { + value = bitmap[rowIndex]; + buf.put((byte) (value & 0xFF)); + + if (rowCount == infoHeader.biWidth) + { + rowCount = 1; + rowIndex = lastRowIndex - infoHeader.biWidth; + lastRowIndex = rowIndex; + } + else + rowCount++; + rowIndex++; + } + + buf.flip(); + o.write(uncompress(infoHeader.biWidth, infoHeader.biHeight, buf)); + } + catch (Exception wb) + { + wb.printStackTrace(); + } + } + + + /** + * Uncompresses the image stored in the buffer. + * + * @param w - the width of the image + * @param h - the height of the image + * @param buf - the ByteBuffer containing the pixel values. + * @return byte array containing the uncompressed image + * @throws IOException if an error is encountered while reading + * buffer. + */ + private byte[] uncompress(int w, int h, ByteBuffer buf) throws IOException + { + byte[] cmd = new byte[2]; + byte[] data = new byte[w * h]; + int offIn = 0; + int x = 0, y = 0; + + try + { + while ((x + y * w) < w * h) + { + try + { + buf.get(cmd); + } + catch (BufferUnderflowException e) + { + throw new IOException("Error reading compressed data."); + } + + if (cmd[0] == ESCAPE) + { + switch (cmd[1]) + { + case EOB: + return data; + case EOL: + x = 0; + y++; + break; + case DELTA: + try + { + buf.get(cmd); + } + catch (BufferUnderflowException e) + { + throw new IOException("Error reading compressed data."); + } + + int dx = cmd[0] & (0xFF); + int dy = cmd[1] & (0xFF); + x += dx; + y += dy; + break; + + default: + int length = cmd[1] & (0xFF); + int copylength = length; + + length += (length & 1); + + byte[] run = new byte[length]; + + try + { + buf.get(run); + } + catch (BufferUnderflowException e) + { + throw new IOException("Error reading compressed data."); + } + + System.arraycopy(run, 0, data, (x + w * (h - y - 1)), + copylength); + x += copylength; + break; + } + } + else + { + int length = cmd[0] & (0xFF); + for (int i = 0; i < length; i++) + data[(h - y - 1) * w + x++] = cmd[1]; + } + } + return data; + } + catch (ArrayIndexOutOfBoundsException e) + { + throw new BMPException("Invalid RLE data."); + } + } +} diff --git a/libjava/classpath/gnu/javax/imageio/gif/GIFFile.java b/libjava/classpath/gnu/javax/imageio/gif/GIFFile.java new file mode 100644 index 000000000..941397a0e --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/gif/GIFFile.java @@ -0,0 +1,709 @@ +/* GIFFile.java -- GIF decoder + 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.imageio.gif; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Vector; + +/** + * GIFFile - reads a GIF file. + * + * This class only does the bare minimum work, and returns the data in raw + * formats (described below). The class is J2ME compatible, and hopefully + * we can keep it that way without any significant overhead. + * + * @author Sven de Marothy. + */ +public class GIFFile +{ + // "NETSCAPE2.0" - identifier + private final static byte[] nsBlock = new byte[] + {0x4e, 0x45, 0x54, 0x53, 0x43, 0x41, 0x50, 0x45, 0x32, 0x2e, 0x30 }; + + /** + * Block identifiers + */ + private final static int EXTENSION = 0x21; + private final static int LOCAL = 0x2C; + private final static int TERMINATOR = 0x3B; + + /** + * Extension block types + */ + private final static int EXTENSION_COMMENT = 254; + private final static int EXTENSION_GCONTROL = 249; + private final static int EXTENSION_APPLICATION = 255; + + /** + * Undraw commands for animation. + */ + private final static int UNDRAW_OVERWRITE = 1; + private final static int UNDRAW_RESTORE_BACKGROUND = 2; + private final static int UNDRAW_RESTORE_PREVIOUS = 3; + + /** + * Image position and dimensions (images may be partial) + */ + private int x, y, width, height; + + /** + * Global dimensions + */ + private int globalWidth, globalHeight; + + /** + * Background color index. + */ + private byte bgIndex; + + /** + * Number of colors + */ + private int nColors; + + /** + * Global palette, if any + */ + private byte[] globalPalette; + + /** + * Any + */ + private boolean hasGlobalColorMap; + + /** + * Local palette, if any (used if available) + */ + private byte[] localPalette; + + /** + * Interlaced GIF or not? + */ + private boolean interlaced; + + /** + * Has transparency? + */ + private boolean hasTransparency; + + /** + * Undraw mode (animations) + */ + private int undraw; + + /** + * Transparent index; + */ + private int transparentIndex; + + /** + * The uncompressed raster + */ + private byte[] raster; + + /** + * The compressed data (freed after uncompressing) + */ + private byte[] compressedData; + + /** + * Frame delay in 100ths of a second ( centiseconds, metrically ) + */ + private int duration; + + /** + * Indices used during decompression + */ + private int dataBlockIndex; + + /** + * The file comment , if a comment block exists. + */ + private String comment; + + /** + * Fields used by getBits() + */ + private int remainingBits = 0; + private int currentBits = 0; + + /** + * Netscape animation extension + */ + private boolean isLooped = false; + + /** Number of loops, 0 = infinite */ + private int loops; + + /** + * Additional frames if it's an animated GIF. + */ + private Vector animationFrames; + + /** + * Loads the file from an input stream, which is not closed. + * @throws IOException if an I/O error occured. + * @throws GIFException if some file parsing error occured + */ + public GIFFile(InputStream in) throws IOException, GIFException + { + // Validate the signature + if( !readSignature( in ) ) + throw new GIFException("Invalid GIF signature."); + + { + byte[] data = new byte[7]; + if (in.read(data) != 7) + throw new IOException("Couldn't read global descriptor."); + + globalWidth = ((data[1] & 0xFF) << 8) | (data[0] & 0xFF); + globalHeight = ((data[3] & 0xFF) << 8) | (data[2] & 0xFF); + byte flags = data[4]; + bgIndex = data[5]; + nColors = (1 << (( flags & 0x07) + 1)); + hasGlobalColorMap = ((flags & 0x80) != 0); + } + + if( hasGlobalColorMap ) + { + globalPalette = new byte[ nColors * 3 ]; + if( in.read( globalPalette ) != nColors * 3 ) + throw new IOException("Couldn't read color map."); + } + + int c = in.read(); + while( c == EXTENSION ) + { + readExtension( in ); + c = in.read(); + } + + if( c != LOCAL ) + throw new GIFException("Extension blocks not followed by a local descriptor ("+c+")"); + + loadImage( in ); + c = in.read(); + + if( c == TERMINATOR ) // Not an animated GIF. + return; + + // Load animation frames. Just quit if an error occurs instead + // of throwing an exception. + animationFrames = new Vector(); + try + { + while( c != TERMINATOR ) + { + animationFrames.add( new GIFFile( this, in, c ) ); + c = in.read(); + } + } + catch(IOException ioe) + { + } + catch(GIFException gife) + { + } + } + + /** + * Constructor for additional animation frames. + */ + private GIFFile(GIFFile parent, InputStream in, int c) + throws IOException, GIFException + { + // Copy global properties. + globalWidth = parent.globalWidth; + globalHeight = parent.globalHeight; + nColors = parent.nColors; + globalPalette = parent.globalPalette; + hasGlobalColorMap = parent.hasGlobalColorMap; + interlaced = parent.interlaced; + comment = parent.comment; + isLooped = parent.isLooped; + loops = parent.loops; + + while( c == EXTENSION ) + { + readExtension( in ); + c = in.read(); + } + + if( c != LOCAL ) + throw new GIFException("Extension blocks not followed by a local descriptor ("+c+")"); + + loadImage( in ); + } + + /** + * Reads a GIF file signature from an inputstream and checks it. + * + * @param in - the stream (reads 6 bytes, does not close or reset). + * @return true if the signature is a valid GIF signature. + * @throws IOException if the signature could not be read. + */ + public static boolean readSignature( InputStream in ) throws IOException + { + byte[] data = new byte[6]; + if (in.read(data) != 6) + throw new IOException("Couldn't read signature."); + + if( data[0] != 0x47 || data[1] != 0x49 || data[2] != 0x46 || + data[3] != 0x38 ) // GIF8 + return false; + + if( (data[4] != 0x39 && data[4] != 0x37) || // 7 | 9 + (data[5] != 0x61 && data[5] != 0x62) ) // 'a' or 'b' + return false; + return true; + } + + + /** + * Loads the image local descriptor and then loads/decodes the image raster, + * and then performs any necessary postprocessing like deinterlacing. + */ + private void loadImage(InputStream in) + throws IOException, GIFException + { + readLocal( in ); + + try + { + decodeRaster( in ); + } + catch(ArrayIndexOutOfBoundsException aioobe) + { + throw new GIFException("Error decompressing image."); + } + + if( interlaced ) // Clean up + deinterlace(); + packPixels(); + } + + /** + * Pack the pixels if it's a 2, 4 or 16 color image. + * While GIF may support any number of colors from 2-256, we won't bother + * trying to pack pixels not resulting in even byte boundaries. + * (AWT doesn't support that anyway, and most apps do the same.) + */ + private void packPixels() + { + if( nColors != 2 && nColors != 4 && nColors != 16 ) + return; + + int nbits = 1; + int ppbyte = 8; + if( nColors == 4 ) + { + nbits = 2; + ppbyte = 4; + } + else if( nColors == 16 ) + { + nbits = 4; + ppbyte = 2; + } + + int rem = (width & (ppbyte - 1)); + int w = ( rem == 0 ) ? (width / ppbyte) : + ((width + ppbyte - rem) / ppbyte); + byte[] nr = new byte[ w * height ]; + for(int j = 0; j < height; j++) + { + for(int i = 0; i < width - ppbyte; i += ppbyte) + for(int k = 0; k < ppbyte; k++) + nr[ j * w + (i / ppbyte) ] |= (byte)((raster[ width * j + i + k ] + << (8 - nbits * (1 + k)))); + for(int i = 0; i < rem; i++) + nr[ j * w + w - 1 ] |= (byte)((raster[ width * j + width - rem + i ] + << (nbits * (rem - i)))); + } + raster = nr; + } + + /** + * Returns the (global) width + */ + public int getWidth() + { + return width; + } + + /** + * Returns the image height + */ + public int getHeight() + { + return height; + } + + /** + * Returns the # of colors. + */ + public int getNColors() + { + return nColors; + } + + /** + * Returns whether the GIF has transparency. + */ + public boolean hasTransparency() + { + return hasTransparency; + } + + /** + * Returns the index of the transparent color. + */ + public int getTransparentIndex() + { + return transparentIndex; + } + + /** + * Retuns the GIF file comment, or null if none exists. + */ + public String getComment() + { + return comment; + } + + /** + * Get duration of the frame for animations. + */ + public int getDuration() + { + return duration; + } + + /** + * Deinterlaces the image. + */ + private void deinterlace() + { + byte[] nr = new byte[ width * height ]; + int n = 0; + for(int i = 0; i < ((height + 7) >> 3); i++) + { + System.arraycopy( raster, n, nr, width * i * 8, width ); + n += width; + } + for(int i = 0; i < ((height + 3) >> 3); i++) + { + System.arraycopy( raster, n, nr, width * ( 8 * i + 4 ), width ); + n += width; + } + for(int i = 0; i < (height >> 2); i++) + { + System.arraycopy( raster, n, nr, width * (4 * i + 2), width ); + n += width; + } + for(int i = 0; i < (height >> 1); i++) + { + System.arraycopy( raster, n, nr, width * (2 * i + 1), width ); + n += width; + } + raster = nr; + } + + /** + * Reads the local descriptor + */ + private void readLocal(InputStream in) throws IOException + { + byte[] data = new byte[9]; + if (in.read(data) != 9) + throw new IOException("Couldn't read local descriptor."); + x = ((data[1] & 0xFF) << 8) | (data[0] & 0xFF); + y = ((data[3] & 0xFF) << 8) | (data[2] & 0xFF); + width = ((data[5] & 0xFF) << 8) | (data[4] & 0xFF); + height = ((data[7] & 0xFF) << 8) | (data[6] & 0xFF); + byte flags = data[8]; + interlaced = (( flags & 0x40 ) != 0); + if( (flags & 0x80) != 0 ) + { // has a local color map + int nLocalColors = (1 << (( flags & 0x07) + 1)); + if( !hasGlobalColorMap ) + nColors = nLocalColors; + localPalette = new byte[ nLocalColors * 3 ]; + if( in.read( localPalette ) != nLocalColors * 3 ) + throw new IOException("Couldn't read color map."); + } + } + + /** + * Returns the image's palette in raw format + * (r0,g0,b0,r1,g1,b2..r(Ncolors-1),g(Ncolors-1),b(Ncolors-1)) + */ + public byte[] getRawPalette() + { + return hasGlobalColorMap ? globalPalette : localPalette; + } + + /** + * Returns the image file for animated gifs. + */ + public GIFFile getImage( int index ) + { + if( index == 0 ) + return this; + if( animationFrames == null ) + throw new ArrayIndexOutOfBoundsException("Only one image in file"); + return (GIFFile)animationFrames.elementAt( index - 1 ); + } + + /** + * Return the image's raw image data. + * If the color depth is 1,2 or 4 bits per pixel the pixels are packed + * and the scanlines padded up to the nearest byte if needed. + */ + public byte[] getRawImage() + { + return raster; + } + + /** + * Return the number of images in the GIF file + */ + public int nImages() + { + if( animationFrames != null ) + return 1 + animationFrames.size(); + return 1; + } + + /** + * Handles extension blocks. + */ + private void readExtension(InputStream in) throws IOException, GIFException + { + int functionCode = in.read(); + byte[] data = readData(in); + switch( functionCode ) + { + case EXTENSION_COMMENT: // comment block + comment = new String(data, "8859_1"); + break; + + case EXTENSION_GCONTROL: // Graphics control extension + undraw = (data[0] & 0x1C) >> 2; + // allegedly there can be bad values of this. + if( undraw < 1 && undraw > 3 ) undraw = 1; + hasTransparency = ((data[0] & 0x01) == 1); + transparentIndex = (data[3] & 0xFF); + duration = ((data[2] & 0xFF) << 8) | (data[1] & 0xFF); + break; + + // Application extension. We only parse the Netscape animation + // extension here. Which is the only one most use anyway. + case EXTENSION_APPLICATION: + boolean isNS = true; + for(int i = 0; i < nsBlock.length; i++ ) + if( nsBlock[i] != data[i] ) + isNS = false; + if( isNS ) + { + isLooped = true; + loops = ((data[12] & 0xFF) << 8) | (data[13] & 0xFF); + } + break; + + default: + break; + } + } + + /** + * Reads a series of data blocks and merges them into a single one. + */ + private byte[] readData(InputStream in) throws IOException + { + Vector v = new Vector(); + int totalBytes = 0; + + int n = in.read(); + do + { + totalBytes += n; + byte[] block = new byte[ n ]; + in.read(block); + v.add(block); + n = in.read(); + } + while( n > 0 ); + + n = 0; + byte[] bigBuffer = new byte[ totalBytes ]; + for( int i = 0; i < v.size(); i++ ) + { + byte[] block = (byte[])v.elementAt(i); + System.arraycopy(block, 0, bigBuffer, n, block.length); + n += block.length; + } + return bigBuffer; + } + + /** + * Loads a compressed image block and decompresses it. + */ + private void decodeRaster(InputStream in) throws IOException + { + int initialCodeSize = in.read(); + compressedData = readData( in ); + dataBlockIndex = 0; + + int rasterIndex = 0; // Index into the raster + int clearCode = (1 << initialCodeSize); // 256 usually + int endCode = clearCode + 1; // The stop code. + + raster = new byte[ width * height ]; + + int codeSize = initialCodeSize + 1; + int code = getBits( codeSize ); // = clear + int nextCode = endCode + 1; + + /* + * Initialize LZW dictionary + * + * First index - code # + * Second index: + * 0 = color index + * 1 = parent (-1 - no parent) + * 2 = first value + * 3 - depth + * The latter two aren't strictly necessary but make things faster, since + * copying the values forward is faster than going back and looking. + */ + short[][] dictionary = new short[ 4096 ][ 4 ]; + + for(short i = 0; i < nColors; i ++ ) + { + dictionary[i][0] = i; // color index + dictionary[i][1] = -1; // parent + dictionary[i][2] = i; // first + dictionary[i][3] = 1; // depth + } + + code = getBits( codeSize ); // get second code + raster[ rasterIndex++ ] = (byte)dictionary[code][0]; + int old = code; + code = getBits( codeSize ); // start at the third code + int c; + + do + { + if( code == clearCode ) + { + codeSize = initialCodeSize + 1; + nextCode = endCode + 1; + // get and output second code + code = getBits( codeSize ); + raster[ rasterIndex++ ] = (byte)dictionary[code][0]; + old = code; + } + else + { + dictionary[nextCode][1] = (short)old; // parent = old + dictionary[nextCode][2] = dictionary[old][2]; // first pixel + dictionary[nextCode][3] = (short)(dictionary[old][3] + 1); // depth + + // appended pixel = first pixel of c + if( code < nextCode ) + { + dictionary[nextCode][0] = dictionary[code][2]; + old = code; + } + else // first of old + { + dictionary[nextCode][0] = dictionary[old][2]; + old = nextCode; + } + + c = old; + // output the code c + int depth = dictionary[c][3]; + for( int i = depth - 1; i >= 0; i-- ) + { + raster[ rasterIndex + i ] = (byte)dictionary[c][0]; + c = dictionary[c][1]; // go to parent. + } + rasterIndex += depth; + nextCode ++; + + if( codeSize < 12 && nextCode >= (1 << codeSize) ) + codeSize++; + } + code = getBits( codeSize ); + } + while( code != endCode && dataBlockIndex < compressedData.length ); + + compressedData = null; // throw away compressed data. + } + + /** + * Returns nbits number of bits (in the LSBs) from compressedData + */ + private int getBits( int nbits ) + { + while( nbits > remainingBits ) + { + int c = (compressedData[ dataBlockIndex++ ] & 0xFF) << remainingBits; + currentBits |= c; + remainingBits += 8; + } + int rval = (currentBits & ((1 << nbits) - 1)); + currentBits = (currentBits >> nbits); + remainingBits -= nbits; + return rval; + } + + /** + * Generic exception used by GIFFile to report decoding errors. + */ + public static class GIFException extends Exception + { + public GIFException(String message) + { + super(message); + } + } +} diff --git a/libjava/classpath/gnu/javax/imageio/gif/GIFImageReader.java b/libjava/classpath/gnu/javax/imageio/gif/GIFImageReader.java new file mode 100644 index 000000000..2cb59226b --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/gif/GIFImageReader.java @@ -0,0 +1,241 @@ +/* GIFImageReader.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.javax.imageio.gif; + +import gnu.javax.imageio.IIOInputStream; + +import java.io.IOException; +import java.io.InputStream; +import javax.imageio.*; +import javax.imageio.spi.*; +import javax.imageio.metadata.*; +import javax.imageio.stream.ImageInputStream; +import java.util.Iterator; +import java.awt.image.BufferedImage; +import java.awt.image.IndexColorModel; +import java.awt.image.SampleModel; +import java.awt.image.MultiPixelPackedSampleModel; +import java.awt.image.SinglePixelPackedSampleModel; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; + +public class GIFImageReader extends ImageReader +{ + private GIFFile file; + + protected GIFImageReader(ImageReaderSpi originatingProvider) + { + super( originatingProvider ); + file = null; + } + + private void readImage() throws IOException + { + if( file != null ) + return; + + try + { + if( input instanceof InputStream ) + file = new GIFFile( (InputStream)input ); + else + file = new GIFFile( new IIOInputStream((ImageInputStream)input) ); + } + catch(GIFFile.GIFException ge) + { + throw new IIOException(ge.getMessage()); + } + } + + /** + * Returns the Global/Local palette as an IndexColorModel + */ + private IndexColorModel getPalette(int index) + { + GIFFile f = file.getImage( index ); + byte[] data = f.getRawPalette(); + int nc = f.getNColors(); + byte[] r = new byte[nc]; + byte[] g = new byte[nc]; + byte[] b = new byte[nc]; + + for(int i = 0; i < nc; i ++ ) + { + r[i] = data[ i * 3 ]; + g[i] = data[ i * 3 + 1 ]; + b[i] = data[ i * 3 + 2 ]; + } + + if( f.hasTransparency() ) + { + byte[] a = new byte[nc]; + for(int i = 0; i < nc; i ++ ) + a[i] = (byte)0xFF; + a[f.getTransparentIndex()] = 0; + return new IndexColorModel(8, nc, r, g, b, a); + } + + return new IndexColorModel(8, nc, r, g, b); + } + + private void validateIndex(int imageIndex) + throws IndexOutOfBoundsException + { + if( imageIndex < 0 || imageIndex >= getNumImages(false) ) + throw new IndexOutOfBoundsException("Invalid image index."); + } + + public void setInput(Object input) + { + super.setInput(input); + } + + public void setInput(Object input, + boolean seekForwardOnly, + boolean ignoreMetadata) + { + super.setInput(input, seekForwardOnly, ignoreMetadata); + } + + public void setInput(Object input, boolean isStreamable) + { + super.setInput(input, isStreamable); + + if (!(input instanceof ImageInputStream) && + !(input instanceof InputStream)) + throw new IllegalArgumentException("Input not an ImageInputStream."); + } + + private void checkStream() throws IOException + { + if (!(input instanceof ImageInputStream) && + !(input instanceof InputStream)) + throw new IllegalStateException("Input not an ImageInputStream or InputStream."); + + if(input == null) + throw new IllegalStateException("No input stream."); + } + + public int getWidth(int imageIndex) throws IOException + { + validateIndex( imageIndex ); + return file.getImage( imageIndex ).getWidth(); + } + + public int getHeight(int imageIndex) throws IOException + { + validateIndex( imageIndex ); + return file.getImage( imageIndex ).getHeight(); + } + + public Iterator getImageTypes(int imageIndex) + { + validateIndex( imageIndex ); + return null; + } + + /** + * Returns the number of images. + */ + public int getNumImages(boolean allowSearch) + { + try // Image should be loaded here already. But just in case: + { + readImage(); + } + catch(IOException ioe) + { + return 0; // Well, now we're in trouble. But return something anyway. + } + return file.nImages(); + } + + + // FIXME: Support metadata + public IIOMetadata getImageMetadata(int imageIndex) + { + validateIndex( imageIndex ); + return null; + } + + // FIXME: Support metadata + public IIOMetadata getStreamMetadata() + { + return null; + } + + /** + * Reads the image indexed by imageIndex and returns it as + * a complete BufferedImage, using a supplied ImageReadParam. + */ + public BufferedImage read(int imageIndex, ImageReadParam param) + throws IOException, IIOException + { + validateIndex( imageIndex ); + GIFFile f = file.getImage( imageIndex ); + int width = f.getWidth(); + int height = f.getHeight(); + SampleModel sm; + switch( f.getNColors() ) + { + case 16: + sm = new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE, + width, height, 4); + break; + case 4: + sm = new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE, + width, height, 2); + break; + case 2: + sm = new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE, + width, height, 1); + break; + default: + sm = new SinglePixelPackedSampleModel(DataBuffer.TYPE_BYTE, + width, height, + new int[] {0xFF}); + break; + } + DataBuffer db = new DataBufferByte(f.getRawImage(), width * height, 0); + WritableRaster raster = Raster.createWritableRaster(sm, db, null); + + return new BufferedImage(getPalette( imageIndex ), raster, false, null); + } +} diff --git a/libjava/classpath/gnu/javax/imageio/gif/GIFImageReaderSpi.java b/libjava/classpath/gnu/javax/imageio/gif/GIFImageReaderSpi.java new file mode 100644 index 000000000..285ca42e4 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/gif/GIFImageReaderSpi.java @@ -0,0 +1,124 @@ +/* GIFImageReaderSpi.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.javax.imageio.gif; + +import gnu.javax.imageio.IIOInputStream; + +import java.io.InputStream; +import java.io.IOException; +import java.util.Locale; +import javax.imageio.ImageReader; +import javax.imageio.spi.ImageReaderSpi; +import javax.imageio.stream.ImageInputStream; + +public class GIFImageReaderSpi extends ImageReaderSpi +{ + static final String vendorName = "GNU"; + static final String version = "0.1"; + static final String readerClassName = + "gnu.javax.imageio.gif.GIFImageReader"; + static final String[] names = { "Compuserve GIF" }; + static final String[] suffixes = { ".gif" }; + static final String[] MIMETypes = { + "image/gif", + "image/x-gif"}; // Not sure this is legal, but it seems to be used a bit + static final String[] writerSpiNames = null; + static final boolean supportsStandardStreamMetadataFormat = false; + static final String nativeStreamMetadataFormatName = null; + static final String nativeStreamMetadataFormatClassName = null; + static final String[] extraStreamMetadataFormatNames = null; + static final String[] extraStreamMetadataFormatClassNames = null; + static final boolean supportsStandardImageMetadataFormat = false; + static final String nativeImageMetadataFormatName = null; + static final String nativeImageMetadataFormatClassName = null; + static final String[] extraImageMetadataFormatNames = null; + static final String[] extraImageMetadataFormatClassNames = null; + + public GIFImageReaderSpi() + { + super(vendorName, version, + names, suffixes, MIMETypes, + readerClassName, + new Class[]{ ImageInputStream.class, InputStream.class }, + writerSpiNames, + supportsStandardStreamMetadataFormat, + nativeStreamMetadataFormatName, + nativeStreamMetadataFormatClassName, + extraStreamMetadataFormatNames, + extraStreamMetadataFormatClassNames, + supportsStandardImageMetadataFormat, + nativeImageMetadataFormatName, + nativeImageMetadataFormatClassName, + extraImageMetadataFormatNames, + extraImageMetadataFormatClassNames); + } + + public String getDescription(Locale locale) + { + return "Compuserve GIF"; + } + + public boolean canDecodeInput(Object input) + throws IOException + { + if( input == null ) + throw new IllegalArgumentException("Input object cannot be null."); + + if( !(input instanceof ImageInputStream) && + !(input instanceof InputStream)) + return false; + + boolean retval; + InputStream in; + if( input instanceof ImageInputStream ) + in = new IIOInputStream( (ImageInputStream)input ); + else + in = (InputStream)input; + + in.mark(10); // we read 6 bytes + retval = GIFFile.readSignature( in ); + in.reset(); + + return retval; + } + + public ImageReader createReaderInstance(Object extension) + { + return new GIFImageReader(this); + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/DCT.java b/libjava/classpath/gnu/javax/imageio/jpeg/DCT.java new file mode 100644 index 000000000..fda52e5f5 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/DCT.java @@ -0,0 +1,347 @@ +/* DCT.java -- + 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.imageio.jpeg; + +/** + * Discrete Cosine Transformations. + */ +public class DCT +{ + + /** + * Cosine matrix + */ + public double c[][] = new double[8][8]; + + /** + * Transformed cosine matrix + */ + public double cT[][] = new double[8][8]; + + public DCT() + { + initMatrix(); + } + + /** + * Figure A.3.3 IDCT, Cu Cv on A-5 of the ISO DIS 10918-1. Requirements and + * Guidelines. + * + * @param u + * @return + */ + public static double C(int u) + { + return ((u == 0) ? (double) 1 / (double) Math.sqrt((double) 2) + : (double) 1); + } + + /** + * Initialize matrix values for the fast_idct function + */ + private void initMatrix() + { + for (int j = 0; j < 8; j++) + { + double nn = (double) (8); + c[0][j] = 1.0 / Math.sqrt(nn); + cT[j][0] = c[0][j]; + } + for (int i = 1; i < 8; i++) + { + for (int j = 0; j < 8; j++) + { + double jj = (double) j; + double ii = (double) i; + c[i][j] = + Math.sqrt(2.0 / 8.0) + * Math.cos(((2.0 * jj + 1.0) * ii * Math.PI) / (2.0 * 8.0)); + cT[j][i] = c[i][j]; + } + } + } + + /** + * slow_idct - Figure A.3.3 IDCT (informative) on A-5 of the ISO DIS + * 10918-1. Requirements and Guidelines. This is a slow IDCT, there are + * better algorithms to use, it's fairly expensive with processor speed. + * + * @param matrix + * @return + */ + public static double[][] slow_idct(double[][] matrix) + { + double[][] output = new double[matrix.length][matrix.length]; + for (int y = 0; y < 8; y++) + { + for (int x = 0; x < 8; x++) + { + double val = 0; + for (double v = 0; v < 8; v++) + { + double innerloop = 0; + for (double u = 0; u < 8; u++) + innerloop += (DCT.C((int) u) / (double) 2) + * matrix[(int) v][(int) u] + * Math.cos((2 * x + 1) * u * Math.PI / (double) 16) + * Math.cos((2 * y + 1) * v * Math.PI / (double) 16); + val += (DCT.C((int) v) / (double) 2) * innerloop; + } + output[y][x] = (val + 128); + } + } + return (output); + } + + public static float[][] slow_fdct(float[][] value) + { + float[][] buffer = new float[8][8]; + + for (int u = 0; u < 8; u++) + { + for (int v = 0; v < 8; v++) + { + buffer[u][v] = + (float) (1 / 4) * (float) C((int) u) * (float) C((int) v); + float innerval = 0; + for (int x = 0; x < 8; x++) + { + for (int y = 0; y < 8; y++) + { + innerval += value[y][x] + * Math.cos(((2 * x + 1) * u * Math.PI) / 16) + * Math.cos(((2 * y + 1) * v * Math.PI) / 16); + } + } + buffer[u][v] *= innerval; + } + } + return (buffer); + } + + public float[][] fast_fdct(float[][] input) + { + float output[][] = new float[8][8]; + double temp[][] = new double[8][8]; + double temp1; + int i; + int j; + int k; + + for (i = 0; i < 8; i++) + { + for (j = 0; j < 8; j++) + { + temp[i][j] = 0.0; + for (k = 0; k < 8; k++) + { + temp[i][j] += (((int) (input[i][k]) - 128) * cT[k][j]); + } + } + } + + for (i = 0; i < 8; i++) + { + for (j = 0; j < 8; j++) + { + temp1 = 0.0; + + for (k = 0; k < 8; k++) + { + temp1 += (c[i][k] * temp[k][j]); + } + + output[i][j] = (int) Math.round(temp1) * 8; + } + } + + return output; + } + + /** + * fast_idct - Figure A.3.3 IDCT (informative) on A-5 of the ISO DIS + * 10918-1. Requires and Guidelines. This is a fast IDCT, it much more + * effecient and only inaccurate at about 1/1000th of a percent of values + * analyzed. Cannot be static because initMatrix must run before any + * fast_idct values can be computed. + * + * @param input + * @return + */ + public double[][] fast_idct(double[][] input) + { + double output[][] = new double[8][8]; + double temp[][] = new double[8][8]; + double temp1; + int i, j, k; + for (i = 0; i < 8; i++) + { + for (j = 0; j < 8; j++) + { + temp[i][j] = 0.0; + for (k = 0; k < 8; k++) + { + temp[i][j] += input[i][k] * c[k][j]; + } + } + } + for (i = 0; i < 8; i++) + { + for (j = 0; j < 8; j++) + { + temp1 = 0.0; + for (k = 0; k < 8; k++) + temp1 += cT[i][k] * temp[k][j]; + temp1 += 128.0; + if (temp1 < 0) + output[i][j] = 0; + else if (temp1 > 255) + output[i][j] = 255; + else + output[i][j] = (int) Math.round(temp1); + } + } + return output; + } + + public double[][] idj_fast_fdct(float input[][]) + { + double output[][] = new double[8][8]; + double tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + double tmp10, tmp11, tmp12, tmp13; + double z1, z2, z3, z4, z5, z11, z13; + int i; + int j; + + // Subtracts 128 from the input values + for (i = 0; i < 8; i++) + { + for (j = 0; j < 8; j++) + { + output[i][j] = ((double) input[i][j] - (double) 128.0); + // input[i][j] -= 128; + + } + } + + for (i = 0; i < 8; i++) + { + tmp0 = output[i][0] + output[i][7]; + tmp7 = output[i][0] - output[i][7]; + tmp1 = output[i][1] + output[i][6]; + tmp6 = output[i][1] - output[i][6]; + tmp2 = output[i][2] + output[i][5]; + tmp5 = output[i][2] - output[i][5]; + tmp3 = output[i][3] + output[i][4]; + tmp4 = output[i][3] - output[i][4]; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + output[i][0] = tmp10 + tmp11; + output[i][4] = tmp10 - tmp11; + + z1 = (tmp12 + tmp13) * (double) 0.707106781; + output[i][2] = tmp13 + z1; + output[i][6] = tmp13 - z1; + + tmp10 = tmp4 + tmp5; + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + z5 = (tmp10 - tmp12) * (double) 0.382683433; + z2 = ((double) 0.541196100) * tmp10 + z5; + z4 = ((double) 1.306562965) * tmp12 + z5; + z3 = tmp11 * ((double) 0.707106781); + + z11 = tmp7 + z3; + z13 = tmp7 - z3; + + output[i][5] = z13 + z2; + output[i][3] = z13 - z2; + output[i][1] = z11 + z4; + output[i][7] = z11 - z4; + } + + for (i = 0; i < 8; i++) + { + tmp0 = output[0][i] + output[7][i]; + tmp7 = output[0][i] - output[7][i]; + tmp1 = output[1][i] + output[6][i]; + tmp6 = output[1][i] - output[6][i]; + tmp2 = output[2][i] + output[5][i]; + tmp5 = output[2][i] - output[5][i]; + tmp3 = output[3][i] + output[4][i]; + tmp4 = output[3][i] - output[4][i]; + + tmp10 = tmp0 + tmp3; + tmp13 = tmp0 - tmp3; + tmp11 = tmp1 + tmp2; + tmp12 = tmp1 - tmp2; + + output[0][i] = tmp10 + tmp11; + output[4][i] = tmp10 - tmp11; + + z1 = (tmp12 + tmp13) * (double) 0.707106781; + output[2][i] = tmp13 + z1; + output[6][i] = tmp13 - z1; + + tmp10 = tmp4 + tmp5; + tmp11 = tmp5 + tmp6; + tmp12 = tmp6 + tmp7; + + z5 = (tmp10 - tmp12) * (double) 0.382683433; + z2 = ((double) 0.541196100) * tmp10 + z5; + z4 = ((double) 1.306562965) * tmp12 + z5; + z3 = tmp11 * ((double) 0.707106781); + + z11 = tmp7 + z3; + z13 = tmp7 - z3; + + output[5][i] = z13 + z2; + output[3][i] = z13 - z2; + output[1][i] = z11 + z4; + output[7][i] = z11 - z4; + } + + return output; + } + +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/HuffmanTable.java b/libjava/classpath/gnu/javax/imageio/jpeg/HuffmanTable.java new file mode 100644 index 000000000..78f3c1c4f --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/HuffmanTable.java @@ -0,0 +1,207 @@ +/* HuffmanTable.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.javax.imageio.jpeg; + +import java.io.IOException; + +import javax.imageio.plugins.jpeg.JPEGHuffmanTable; + + +/** + * This Object construct a JPEGHuffmanTable which can be used to encode/decode + * a scan from a JPEG codec stream. The table must be initalized with either a + * BITS byte amount and a Huffman Table Value for decoding or a Huffman Size + * and Huffman Code table for encoding. + */ +public class HuffmanTable +{ + public final static int HUFFMAN_MAX_TABLES = 4; + + private short[] huffcode = new short[256]; + private short[] huffsize = new short[256]; + private short[] EHUFCO; + private short[] EHUFSI; + private short[] valptr = new short[16]; + private short[] mincode = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1,-1,-1}; + private short[] maxcode = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1}; + private short[] huffval; + private short[] bits; + + static byte JPEG_DC_TABLE = 0; + static byte JPEG_AC_TABLE = 1; + + private short lastk = 0; + + public HuffmanTable(JPEGHuffmanTable table) + { + huffcode = table.getValues(); + bits = table.getLengths(); + } + + /** + * Generated from FIGURE C.1 - Generation of table of Huffman code sizes on + * ISO DIS 10918-1. Requirements and Guidelines + */ + private void generateSizeTable() + { + short index=0; + for(short i=0; i < bits.length ; i++) + { + for(short j=0; j < bits[i] ; j++) + { + huffsize[index] = (short) (i+1); + index++; + } + } + lastk = index; + } + + /** + * Generated from FIGURE C.2 - Generation of table of Huffman codes on + * ISO DIS 10918-1. Requirements and Guidelines + */ + private void generateCodeTable() + { + short k=0; + short si = huffsize[0]; + short code = 0; + for(short i=0; i < huffsize.length ; i++) + { + while(huffsize[k]==si) + { + huffcode[k] = code; + code++; + k++; + } + code <<= 1; + si++; + } + } + + /** + * Generated from FIGURE F.15 - Generation of decode table generation on + * ISO DIS 10918-1. Requirements and Guidelines + */ + private void generateDecoderTables() + { + short bitcount = 0; + for(int i=0; i < 16 ; i++) + { + if(bits[i]!=0) + valptr[i] = bitcount; + for(int j=0 ; j < bits[i] ; j++) + { + if(huffcode[j+bitcount] < mincode[i] || mincode[i] == -1) + mincode[i] = huffcode[j+bitcount]; + + if(huffcode[j+bitcount] > maxcode[i]) + maxcode[i] = huffcode[j+bitcount]; + } + if(mincode[i]!=-1) + valptr[i] = (short) (valptr[i] - mincode[i]); + bitcount += bits[i]; + } + } + + /** + * Generated from FIGURE C.3 - Generation of Order Codes and tables EHUFCO + * and EHUFSI from the ISO DIS 10918-1. Requirements and Guidelines + */ + public void orderCodes(boolean isDC) + { + EHUFCO = new short[isDC ? 15 : 255]; + EHUFSI = new short[isDC ? 15 : 255]; + + for (int p=0; p < lastk ; p++) + { + int i = huffval[p]; + if(i < 0 || i > EHUFCO.length || EHUFSI[i]!=0) + System.err.println("Error, bad huffman table."); + EHUFCO[i] = huffcode[p]; + EHUFSI[i] = huffsize[p]; + } + } + + /** + * Generated from FIGURE F.12 - Extending the sign bit of a decoded value in on + * ISO DIS 10918-1. Requirements and Guidelines

    + * + * @param diff TODO + * @param t TODO + * @return TODO + */ + public static int extend(int diff, int t) + { + int Vt = (int)Math.pow(2,(t-1)); + if(diff + * + * This function takes in a dynamic amount of bits and using the Huffman + * table returns information on how many bits must be read in to a byte in + * order to reconstruct said byte. + * + * @param JPEGStream the bits of the data stream. + */ + public int decode(JPEGImageInputStream JPEGStream) + throws IOException, JPEGException + { + int i=0; + short code = (short) JPEGStream.readBits(1); + while(code > maxcode[i]) + { + i++; + code <<= 1; + code |= JPEGStream.readBits(1); + } + int val = huffval[code+(valptr[i])]; + if(val < 0) + val = 256 + val; + return val; + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/JPEGComponent.java b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGComponent.java new file mode 100644 index 000000000..7be67a02a --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGComponent.java @@ -0,0 +1,351 @@ +/* JPEGComponent.java -- + 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.imageio.jpeg; + +import java.util.ArrayList; +import java.io.IOException; +import java.awt.image.WritableRaster; + +import javax.imageio.plugins.jpeg.JPEGHuffmanTable; + +/** + * This class holds the methods to decode and write a component information to + * a raster. + */ +public class JPEGComponent +{ + public byte factorH, factorV, component_id, quant_id; + public int width = 0, height = 0, maxV = 0, maxH = 0; + public HuffmanTable ACTable; + public HuffmanTable DCTable; + public int[] quantizationTable; + public double previousDC = 0; + ArrayList data = new ArrayList(); + + /** + * Initializes the component + * + * @param id + * @param factorHorizontal + * @param factorVertical + * @param quantizationID + */ + public JPEGComponent(byte id, byte factorHorizontal, byte factorVertical, + byte quantizationID) + { + component_id = id; + factorH = factorHorizontal; + factorV = factorVertical; + quant_id = quantizationID; + } + + /** + * If a restart marker is found with too little of an MCU count (i.e. our + * Restart Interval is 63 and we have 61 we copy the last MCU until it's + * full) + * + * @param index + * @param length + */ + public void padMCU(int index, int length) + { + double[] src = (double[]) data.get(index - 1); + for (int i = 0; i < length; i++) + data.add(index, src); + } + + /** + * Reset the interval by setting the previous DC value + */ + public void resetInterval() + { + previousDC = 0; + } + + /** + * Run the Quantization backward method on all of the block data. + */ + public void quantitizeData() + { + for (int i = 0; i < data.size(); i++) + { + double[] mydata = (double[]) data.get(i); + for (int j = 0; j < mydata.length; j++) + mydata[j] *= quantizationTable[j]; + } + } + + public void setDCTable(JPEGHuffmanTable table) + { + DCTable = new HuffmanTable(table); + } + + public void setACTable(JPEGHuffmanTable table) + { + ACTable = new HuffmanTable(table); + } + + /** + * Run the Inverse DCT method on all of the block data + */ + public void idctData(DCT myDCT) + { + for (int i = 0; i < data.size(); i++) + data.add(i,myDCT.fast_idct(ZigZag.decode8x8_map((double[]) data.remove(i)))); + } + + /** + * This scales up the component size based on the factor size. This + * calculates everyting up automatically so it's simply ran at the end of + * the frame to normalize the size of all of the components. + */ + public void scaleByFactors() + { + int factorUpVertical = maxV / factorV; + int factorUpHorizontal = maxH / factorH; + + if (factorUpVertical > 1) + { + for (int i = 0; i < data.size(); i++) + { + double[][] src = (double[][]) data.remove(i); + double[][] dest = + new double[src.length * factorUpVertical][src[0].length]; + for (int j = 0; j < src.length; j++) + { + for (int u = 0; u < factorUpVertical; u++) + { + dest[j * factorUpVertical + u] = src[j]; + } + } + data.add(i, dest); + } + } + + if (factorUpHorizontal > 1) + { + for (int i = 0; i < data.size(); i++) + { + double[][] src = (double[][]) data.remove(i); + double[][] dest = + new double[src.length][src[0].length * factorUpHorizontal]; + for (int j = 0; j < src.length; j++) + { + for (int u = 0; u < src[0].length; u++) + { + for (int v = 0; v < factorUpHorizontal; v++) + dest[j][u * factorUpHorizontal + v] = src[j][u]; + } + } + data.add(i, dest); + } + } + } + + /** + * This write the block of data to the raster throwing out anything that + * spills over the raster width or height. + * + * @param raster + * @param data + * @param compIndex + * @param x + * @param y + */ + public void writeBlock(WritableRaster raster, double[][] data, + int compIndex, int x, int y) + { + for (int yIndex = 0; yIndex < data.length; yIndex++) + { + for (int xIndex = 0; xIndex < data[yIndex].length; xIndex++) + { + // The if statement is needed because blocks can spill over the + // frame width because they are padded to make sure we keep the + // height of the block the same as the width of the block + if (x + xIndex < raster.getWidth() + && y + yIndex < raster.getHeight()) + raster.setSample(x + xIndex, y + yIndex, compIndex, + data[yIndex][xIndex]); + } + } + } + + /** + * This writes data to a raster block, so really it's reading not writing + * but it writes the data to the raster block by factor size in a zig zag + * fashion. This has the helper function writeBlock which does the actual + * writing. + * + * @param raster + * @param componentIndex + */ + public void writeData(WritableRaster raster, int componentIndex) + { + int x = 0, y = 0, lastblockheight = 0, incrementblock = 0; + + // Keep looping through all of the blocks until there are no more. + while(data.size() > 0) + { + int blockwidth = 0; + int blockheight = 0; + + if (x >= raster.getWidth()) + { + x = 0; + y += incrementblock; + } + + // Loop through the horizontal component blocks of the MCU first + // then for each horizontal line write out all of the vertical + // components + for (int factorVIndex = 0; factorVIndex < factorV; factorVIndex++) + { + blockwidth = 0; + + for (int factorHIndex = 0; factorHIndex < factorH; factorHIndex++) + { + // Captures the width of this block so we can increment the + // X coordinate + double[][] blockdata = (double[][]) data.remove(0); + + // Writes the data at the specific X and Y coordinate of + // this component + writeBlock(raster, blockdata, componentIndex, x, y); + blockwidth += blockdata[0].length; + x += blockdata[0].length; + blockheight = blockdata.length; + } + y += blockheight; + x -= blockwidth; + lastblockheight += blockheight; + } + y -= lastblockheight; + incrementblock = lastblockheight; + lastblockheight = 0; + x += blockwidth; + } + } + + /** + * Set the quantization table for this component. + * + * @param quanttable + */ + public void setQuantizationTable(int[] quanttable) + { + quantizationTable = quanttable; + } + + /** + * Read in a partial MCU for this component + * + * @param stream TODO + * @throws JPEGException TODO + * @throws IOException TODO + */ + public void readComponentMCU(JPEGImageInputStream stream) + throws JPEGException, IOException + { + for (int i = 0; i < factorH * factorV; i++) + { + double dc = decode_dc_coefficient(stream); + double[] datablock = decode_ac_coefficients(stream); + datablock[0] = dc; + data.add(datablock); + } + } + + /** + * Generated from text on F-22, F.2.2.1 - Huffman decoding of DC + * coefficients on ISO DIS 10918-1. Requirements and Guidelines. + * + * @param JPEGStream TODO + * + * @return TODO + * @throws JPEGException TODO + * @throws IOException TODO + */ + public double decode_dc_coefficient(JPEGImageInputStream JPEGStream) + throws JPEGException, IOException + { + int t = DCTable.decode(JPEGStream); + double diff = JPEGStream.readBits(t); + diff = HuffmanTable.extend((int) diff, t); + diff = (previousDC + diff); + previousDC = diff; + return diff; + } + + /** + * Generated from text on F-23, F.13 - Huffman decoded of AC coefficients + * on ISO DIS 10918-1. Requirements and Guidelines. + * + * @param JPEGStream TODO + * @return TODO + * + * @throws JPEGException TODO + * @throws IOException TODO + */ + public double[] decode_ac_coefficients(JPEGImageInputStream JPEGStream) + throws JPEGException, IOException + { + double[] zz = new double[64]; + + for (int k = 1; k < 64; k++) + { + int s = ACTable.decode(JPEGStream); + int r = s >> 4; + s &= 15; + + if (s != 0) + { + k += r; + r = (int) JPEGStream.readBits(s); + s = HuffmanTable.extend(r, s); + zz[k] = s; + } + else + { + if (r != 15) + return (zz); + k += 15; + } + } + return zz; + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/JPEGDecoder.java b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGDecoder.java new file mode 100644 index 000000000..11d547f4d --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGDecoder.java @@ -0,0 +1,625 @@ +/* JPEGDecoder.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.javax.imageio.jpeg; + +import java.io.IOException; +import java.nio.ByteOrder; + +import javax.imageio.plugins.jpeg.JPEGHuffmanTable; +import javax.imageio.plugins.jpeg.JPEGQTable; +import javax.imageio.stream.ImageInputStream; + +import java.util.ArrayList; +import java.util.Hashtable; +import java.awt.Point; +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.awt.image.BufferedImage; +import java.awt.image.ComponentColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; + +public class JPEGDecoder +{ + byte majorVersion; + byte minorVersion; + byte units; + short Xdensity; + short Ydensity; + byte Xthumbnail; + byte Ythumbnail; + byte[] thumbnail; + BufferedImage image; + int width; + int height; + + byte marker; + + /** + * This decoder expects JFIF 1.02 encoding. + */ + public static final byte MAJOR_VERSION = (byte) 1; + public static final byte MINOR_VERSION = (byte) 2; + + /** + * The length of the JFIF field not including thumbnail data. + */ + public static final short JFIF_FIXED_LENGTH = 16; + + /** + * The length of the JFIF extension field not including extension + * data. + */ + public static final short JFXX_FIXED_LENGTH = 8; + + private JPEGImageInputStream jpegStream; + + ArrayList jpegFrames = new ArrayList(); + + JPEGHuffmanTable[] dcTables = new JPEGHuffmanTable[4]; + JPEGHuffmanTable[] acTables = new JPEGHuffmanTable[4]; + JPEGQTable[] qTables = new JPEGQTable[4]; + + public int getHeight() + { + return height; + } + + public int getWidth() + { + return width; + } + public JPEGDecoder(ImageInputStream in) + throws IOException, JPEGException + { + jpegStream = new JPEGImageInputStream(in); + jpegStream.setByteOrder(ByteOrder.LITTLE_ENDIAN); + + if (jpegStream.findNextMarker() != JPEGMarker.SOI) + throw new JPEGException("Failed to find SOI marker."); + + if (jpegStream.findNextMarker() != JPEGMarker.APP0) + throw new JPEGException("Failed to find APP0 marker."); + + int length = jpegStream.readShort(); + if (!(length >= JFIF_FIXED_LENGTH)) + throw new JPEGException("Failed to find JFIF field."); + + byte[] identifier = new byte[5]; + jpegStream.read(identifier); + if (identifier[0] != JPEGMarker.JFIF_J + || identifier[1] != JPEGMarker.JFIF_F + || identifier[2] != JPEGMarker.JFIF_I + || identifier[3] != JPEGMarker.JFIF_F + || identifier[4] != JPEGMarker.X00) + throw new JPEGException("Failed to read JFIF identifier."); + + majorVersion = jpegStream.readByte(); + minorVersion = jpegStream.readByte(); + if (majorVersion != MAJOR_VERSION + || (majorVersion == MAJOR_VERSION + && minorVersion < MINOR_VERSION)) + throw new JPEGException("Unsupported JFIF version."); + + units = jpegStream.readByte(); + if (units > (byte) 2) + throw new JPEGException("Units field is out of range."); + + Xdensity = jpegStream.readShort(); + Ydensity = jpegStream.readShort(); + Xthumbnail = jpegStream.readByte(); + Ythumbnail = jpegStream.readByte(); + + // 3 * for RGB data + int thumbnailLength = 3 * Xthumbnail * Ythumbnail; + if (length > JFIF_FIXED_LENGTH + && thumbnailLength != length - JFIF_FIXED_LENGTH) + throw new JPEGException("Invalid length, Xthumbnail" + + " or Ythumbnail field."); + + if (thumbnailLength > 0) + { + thumbnail = new byte[thumbnailLength]; + if (jpegStream.read(thumbnail) != thumbnailLength) + throw new IOException("Failed to read thumbnail."); + } + } + + public void decode() + throws IOException + { + System.out.println ("DECODE!!!"); + // The frames in this jpeg are loaded into a list. There is + // usually just one frame except in heirarchial progression where + // there are multiple frames. + JPEGFrame frame = null; + + // The restart interval defines how many MCU's we should have + // between the 8-modulo restart marker. The restart markers allow + // us to tell whether or not our decoding process is working + // correctly, also if there is corruption in the image we can + // recover with these restart intervals. (See RSTm DRI). + int resetInterval = 0; + + // The JPEGDecoder constructor parses the JFIF field. At this + // point jpegStream points to the first byte after the JFIF field. + + // Find the first marker after the JFIF field. + byte marker = jpegStream.findNextMarker(); + + // Check for a JFIF extension field directly following the JFIF + // header and advance the current marker to the next marker in the + // stream, if necessary. + decodeJFIFExtension(); + + // Loop through until there are no more markers to read in, at + // that point everything is loaded into the jpegFrames array and + // can be processed. + while (true) + { + switch (marker) + { + // APPn Application Reserved Information - Just throw this + // information away because we wont be using it. + case JPEGMarker.APP0: + case JPEGMarker.APP1: + case JPEGMarker.APP2: + case JPEGMarker.APP3: + case JPEGMarker.APP4: + case JPEGMarker.APP5: + case JPEGMarker.APP6: + case JPEGMarker.APP7: + case JPEGMarker.APP8: + case JPEGMarker.APP9: + case JPEGMarker.APP10: + case JPEGMarker.APP11: + case JPEGMarker.APP12: + case JPEGMarker.APP13: + case JPEGMarker.APP14: + case JPEGMarker.APP15: + jpegStream.skipBytes(jpegStream.readShort() - 2); + break; + + case JPEGMarker.SOF0: + // SOFn Start of Frame Marker, Baseline DCT - This is the start + // of the frame header that defines certain variables that will + // be carried out through the rest of the encoding. Multiple + // frames are used in a heirarchiel system, however most JPEG's + // only contain a single frame. + jpegFrames.add(new JPEGFrame()); + frame = (JPEGFrame) jpegFrames.get(jpegFrames.size() - 1); + // Skip the frame length. + jpegStream.readShort(); + // Bits percision, either 8 or 12. + frame.setPrecision(jpegStream.readByte()); + // Scan lines = to the height of the frame. + frame.setScanLines(jpegStream.readShort()); + // Scan samples per line = to the width of the frame. + frame.setSamplesPerLine(jpegStream.readShort()); + // Number of Color Components (or channels). + frame.setComponentCount(jpegStream.readByte()); + + // Set the color mode for this frame, so far only 2 color + // modes are supported. + if (frame.getComponentCount() == 1) + frame.setColorMode(JPEGFrame.JPEG_COLOR_GRAY); + else + frame.setColorMode(JPEGFrame.JPEG_COLOR_YCbCr); + // Add all of the necessary components to the frame. + for (int i = 0; i < frame.getComponentCount(); i++) + frame.addComponent(jpegStream.readByte(), jpegStream.readByte(), + jpegStream.readByte()); + break; + + case JPEGMarker.SOF2: + jpegFrames.add(new JPEGFrame()); + frame = (JPEGFrame) jpegFrames.get(jpegFrames.size() - 1); + // Skip the frame length. + jpegStream.readShort(); + // Bits percision, either 8 or 12. + frame.setPrecision(jpegStream.readByte()); + // Scan lines = to the height of the frame. + frame.setScanLines(jpegStream.readShort()); + // Scan samples per line = to the width of the frame. + frame.setSamplesPerLine(jpegStream.readShort()); + // Number of Color Components (or channels). + frame.setComponentCount(jpegStream.readByte()); + + // Set the color mode for this frame, so far only 2 color + // modes are supported. + if (frame.getComponentCount() == 1) + frame.setColorMode(JPEGFrame.JPEG_COLOR_GRAY); + else + frame.setColorMode(JPEGFrame.JPEG_COLOR_YCbCr); + + // Add all of the necessary components to the frame. + for (int i = 0; i < frame.getComponentCount(); i++) + frame.addComponent(jpegStream.readByte(), jpegStream.readByte(), + jpegStream.readByte()); + break; + + case JPEGMarker.DHT: + // DHT non-SOF Marker - Huffman Table is required for decoding + // the JPEG stream, when we receive a marker we load in first + // the table length (16 bits), the table class (4 bits), table + // identifier (4 bits), then we load in 16 bytes and each byte + // represents the count of bytes to load in for each of the 16 + // bytes. We load this into an array to use later and move on 4 + // huffman tables can only be used in an image. + int huffmanLength = (jpegStream.readShort() - 2); + + // Keep looping until we are out of length. + int index = huffmanLength; + + // Multiple tables may be defined within a DHT marker. This + // will keep reading until there are no tables left, most + // of the time there are just one tables. + while (index > 0) + { + // Read the identifier information and class + // information about the Huffman table, then read the + // 16 byte codelength in and read in the Huffman values + // and put it into table info. + byte huffmanInfo = jpegStream.readByte(); + byte tableClass = (byte) (huffmanInfo >> 4); + byte huffmanIndex = (byte) (huffmanInfo & 0x0f); + short[] codeLength = new short[16]; + jpegStream.readFully(codeLength, 0, codeLength.length); + int huffmanValueLen = 0; + for (int i = 0; i < 16; i++) + huffmanValueLen += codeLength[i]; + index -= (huffmanValueLen + 17); + short[] huffmanVal = new short[huffmanValueLen]; + for (int i = 0; i < huffmanVal.length; i++) + huffmanVal[i] = jpegStream.readByte(); + // Assign DC Huffman Table. + if (tableClass == HuffmanTable.JPEG_DC_TABLE) + dcTables[(int) huffmanIndex] = new JPEGHuffmanTable(codeLength, + huffmanVal); + // Assign AC Huffman Table. + else if (tableClass == HuffmanTable.JPEG_AC_TABLE) + acTables[(int) huffmanIndex] = new JPEGHuffmanTable(codeLength, + huffmanVal); + } + break; + case JPEGMarker.DQT: + // DQT non-SOF Marker - This defines the quantization + // coeffecients, this allows us to figure out the quality of + // compression and unencode the data. The data is loaded and + // then stored in to an array. + short quantizationLength = (short) (jpegStream.readShort() - 2); + for (int j = 0; j < quantizationLength / 65; j++) + { + byte quantSpecs = jpegStream.readByte(); + int[] quantData = new int[64]; + if ((byte) (quantSpecs >> 4) == 0) + // Precision 8 bit. + { + for (int i = 0; i < 64; i++) + quantData[i] = jpegStream.readByte(); + + } + else if ((byte) (quantSpecs >> 4) == 1) + // Precision 16 bit. + { + for (int i = 0; i < 64; i++) + quantData[i] = jpegStream.readShort(); + } + qTables[(int) (quantSpecs & 0x0f)] = new JPEGQTable (quantData); + } + break; + case JPEGMarker.SOS: + // SOS non-SOF Marker - Start Of Scan Marker, this is where the + // actual data is stored in a interlaced or non-interlaced with + // from 1-4 components of color data, if three components most + // likely a YCrCb model, this is a fairly complex process. + + // Read in the scan length. + jpegStream.readShort(); + // Number of components in the scan. + byte numberOfComponents = jpegStream.readByte(); + byte[] componentSelector = new byte[numberOfComponents]; + for (int i = 0; i < numberOfComponents; i++) + { + // Component ID, packed byte containing the Id for the + // AC table and DC table. + byte componentID = jpegStream.readByte(); + byte tableInfo = jpegStream.readByte(); + frame.setHuffmanTables(componentID, + acTables[(byte) (tableInfo >> 4)], + dcTables[(byte) (tableInfo & 0x0f)]); + componentSelector[i] = componentID; + } + byte startSpectralSelection = jpegStream.readByte(); + byte endSpectralSelection = jpegStream.readByte(); + byte successiveApproximation = jpegStream.readByte(); + + int mcuIndex = 0; + int mcuTotalIndex = 0; + // This loops through until a MarkerTagFound exception is + // found, if the marker tag is a RST (Restart Marker) it + // simply skips it and moves on this system does not handle + // corrupt data streams very well, it could be improved by + // handling misplaced restart markers. + while (true) + { + try + { + // Loop though capturing MCU, instruct each + // component to read in its necessary count, for + // scaling factors the components automatically + // read in how much they need + for (int compIndex = 0; compIndex < numberOfComponents; compIndex++) + { + JPEGComponent comp = frame.components.getComponentByID(componentSelector[compIndex]); + comp.readComponentMCU(jpegStream); + } + mcuIndex++; + mcuTotalIndex++; + } + // We've found a marker, see if the marker is a restart + // marker or just the next marker in the stream. If + // it's the next marker in the stream break out of the + // while loop, if it's just a restart marker skip it + catch (JPEGMarkerFoundException bse) + { + // Handle JPEG Restart Markers, this is where the + // count of MCU's per interval is compared with + // the count actually obtained, if it's short then + // pad on some MCU's ONLY for components that are + // greater than one. Also restart the DC prediction + // to zero. + if (marker == JPEGMarker.RST0 + || marker == JPEGMarker.RST1 + || marker == JPEGMarker.RST2 + || marker == JPEGMarker.RST3 + || marker == JPEGMarker.RST4 + || marker == JPEGMarker.RST5 + || marker == JPEGMarker.RST6 + || marker == JPEGMarker.RST7) + { + for (int compIndex = 0; compIndex < numberOfComponents; compIndex++) + { + JPEGComponent comp = frame.components.getComponentByID(componentSelector[compIndex]); + if (compIndex > 1) + comp.padMCU(mcuTotalIndex, resetInterval - mcuIndex); + comp.resetInterval(); + } + mcuTotalIndex += (resetInterval - mcuIndex); + mcuIndex = 0; + } + else + { + // We're at the end of our scan, exit out. + break; + } + } + } + break; + case JPEGMarker.DRI: + // DRI - This defines the restart interval, if we have a + // restart interval when we reach our restart modulo calculate + // whether the count of MCU's specified in the restart + // interval have been reached, if they havent then pad with + // whatever MCU was last used, this is supposed to be a form of + // error recovery but it turns out that some JPEG encoders + // purposely cause missing MCU's on repeating MCU's to compress + // data even more (even though it adds an extra layer of + // complexity.. But since when is JPEG easy? + jpegStream.skipBytes(2); + resetInterval = jpegStream.readShort(); + break; + case JPEGMarker.COM: + // COM - This is a comment that was inserted into the JPEG, we + // simply skip over the comment because it's really of no + // importance, usually contains a verbal description of the + // application or author who created the JPEG. + jpegStream.skipBytes(jpegStream.readShort() - 2); + break; + case JPEGMarker.DNL: + // DNL - This sets the height of the image. This is the Define + // Number Lines for the image, I'm not sure exactly why we need + // this but, whatever we'll abide. + frame.setScanLines(jpegStream.readShort()); + break; + case JPEGMarker.EOI: + // EOI - End of Image, this processes the frames and turns the + // frames into a buffered image. + + if (jpegFrames.size() == 0) + { + return; + } + else if (jpegFrames.size() == 1) + { + // Only one frame, JPEG Non-Heirarchial Frame. + + DCT myDCT = new DCT(); + WritableRaster raster = + Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, + frame.width, + frame.height, + frame.getComponentCount(), + new Point(0, 0)); + + // Unencode the data. + for (int i = 0; i < frame.getComponentCount(); i++) + { + JPEGComponent comp = frame.components.get(i); + comp.setQuantizationTable(qTables[comp.quant_id].getTable()); + comp.quantitizeData(); + comp.idctData(myDCT); + } + // Scale the image and write the data to the raster. + for (int i = 0; i < frame.getComponentCount(); i++) + { + JPEGComponent comp = frame.components.get(i); + comp.scaleByFactors(); + comp.writeData(raster, i); + // Ensure garbage collection. + comp = null; + } + // Grayscale Color Image (1 Component). + if (frame.getComponentCount() == 1) + { + ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY); + ComponentColorModel ccm = + new ComponentColorModel(cs, false, false, + Transparency.OPAQUE, + DataBuffer.TYPE_BYTE); + image = new BufferedImage(ccm, raster, false, + new Hashtable()); + } + // YCbCr Color Image (3 Components). + else if (frame.getComponentCount() == 3) + { + ComponentColorModel ccm = + new ComponentColorModel(new YCbCr_ColorSpace(), false, + false, Transparency.OPAQUE, + DataBuffer.TYPE_BYTE); + image = new BufferedImage(ccm, raster, false, + new Hashtable()); + } + // Possibly CMYK or RGBA ? + else + { + throw new JPEGException("Unsupported Color Mode: 4 " + + "Component Color Mode found."); + } + height = frame.height; + width = frame.width; + } + else + { + //JPEG Heirarchial Frame (progressive or baseline). + throw new JPEGException("Unsupported Codec Type:" + + " Hierarchial JPEG"); + } + break; + case JPEGMarker.SOF1: + // ERROR - If we encounter any of the following marker codes + // error out with a codec exception, progressive, heirarchial, + // differential, arithmetic, lossless JPEG's are not supported. + // This is where enhancements can be made for future versions. + // Thankfully 99% of all JPEG's are baseline DCT. + throw new JPEGException("Unsupported Codec Type: Extended " + + "Sequential DCT JPEG's Not-Supported"); + //case JPEGMarker.SOF2: + // throw new JPEGException("Unsupported Codec Type: Progressive DCT JPEG's Not-Supported"); + case JPEGMarker.SOF3: + throw new JPEGException("Unsupported Codec Type:" + + " Lossless (sequential)"); + case JPEGMarker.SOF5: + throw new JPEGException("Unsupported Codec Type:" + + " Differential sequential DCT"); + case JPEGMarker.SOF6: + throw new JPEGException("Unsupported Codec Type:" + + " Differential progressive DCT"); + case JPEGMarker.SOF7: + throw new JPEGException("Unsupported Codec Type:" + + " Differential lossless"); + case JPEGMarker.SOF9: + case JPEGMarker.SOF10: + case JPEGMarker.SOF11: + case JPEGMarker.SOF13: + case JPEGMarker.SOF14: + case JPEGMarker.SOF15: + throw new JPEGException("Unsupported Codec Type:" + + " Arithmetic Coding Frame"); + default: + // Unknown marker found, ignore it. + } + marker = jpegStream.findNextMarker(); + } + } + + // If the current marker is APP0, tries to decode a JFIF extension + // and advances the current marker to the next marker in the stream. + private void decodeJFIFExtension() throws IOException + { + if (marker == JPEGMarker.APP0) + { + int length = jpegStream.readShort(); + + if (length >= JFXX_FIXED_LENGTH) + { + byte[] identifier = new byte[5]; + jpegStream.read(identifier); + if (identifier[0] != JPEGMarker.JFIF_J + || identifier[1] != JPEGMarker.JFIF_F + || identifier[2] != JPEGMarker.JFIF_X + || identifier[3] != JPEGMarker.JFIF_X + || identifier[4] != JPEGMarker.X00) + // Not a JFXX field. Ignore it and continue. + jpegStream.skipBytes(length - 7); + else + { + byte extension_code = jpegStream.readByte(); + + switch (extension_code) + { + case JPEGMarker.JFXX_JPEG: + // FIXME: add support for JFIF Extension: + // Thumbnail coded using JPEG. + jpegStream.skipBytes(length - 8); + case JPEGMarker.JFXX_ONE_BPP: + // FIXME: add support for JFIF Extension: + // Thumbnail stored using 1 byte/pixel. + jpegStream.skipBytes(length - 8); + case JPEGMarker.JFXX_THREE_BPP: + // FIXME: add support for JFIF Extension: + // Thumbnail stored using 3 bytes/pixel. + jpegStream.skipBytes(length - 8); + } + } + } + else + { + // Unknown APP0 marker. Ignore it and continue. + jpegStream.skipBytes(length - 2); + } + marker = jpegStream.findNextMarker(); + } + } + + public BufferedImage getImage() + { + return image; + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/JPEGException.java b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGException.java new file mode 100644 index 000000000..a2c06e27e --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGException.java @@ -0,0 +1,48 @@ +/* JPEGException.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.javax.imageio.jpeg; + +import javax.imageio.*; + +public class JPEGException extends IIOException +{ + public JPEGException(String message) + { + super(message); + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/JPEGFrame.java b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGFrame.java new file mode 100644 index 000000000..35aed728a --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGFrame.java @@ -0,0 +1,108 @@ +/* JPEGFrame.java -- + 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.imageio.jpeg; + +import javax.imageio.plugins.jpeg.JPEGHuffmanTable; + +public class JPEGFrame +{ + public final static byte JPEG_COLOR_GRAY = 1; + public final static byte JPEG_COLOR_RGB = 2; + public final static byte JPEG_COLOR_YCbCr = 3; + public final static byte JPEG_COLOR_CMYK = 4; + + public byte precision = 8; + public byte colorMode = JPEGFrame.JPEG_COLOR_YCbCr; + public byte componentCount = 0; + + public short width=0, height=0; + + public JPEGScan components; + + public JPEGFrame() + { + components = new JPEGScan(); + } + + public void addComponent(byte componentID, byte sampleFactors, + byte quantizationTableID) + { + byte sampleHorizontalFactor = (byte)(sampleFactors >> 4); + byte sampleVerticalFactor = (byte)(sampleFactors & 0x0f); + components.addComponent(componentID, sampleHorizontalFactor, + sampleVerticalFactor, quantizationTableID); + } + + public void setPrecision(byte data) + { + precision = data; + } + + public void setScanLines(short data) + { + height = data; + } + + public void setSamplesPerLine(short data) + { + width = data; + } + + public void setColorMode(byte data) + { + colorMode = data; + } + + public void setComponentCount(byte data) + { + componentCount = data; + } + + public byte getComponentCount() + { + return componentCount; + } + + public void setHuffmanTables(byte componentID, JPEGHuffmanTable ACTable, + JPEGHuffmanTable DCTable) + { + JPEGComponent comp = components.getComponentByID(componentID); + comp.setACTable(ACTable); + comp.setDCTable(DCTable); + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageInputStream.java b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageInputStream.java new file mode 100644 index 000000000..f2c26d9d5 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageInputStream.java @@ -0,0 +1,188 @@ +/* JPEGImageInputStream.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.javax.imageio.jpeg; + +import java.io.IOException; +import javax.imageio.stream.ImageInputStream; +import javax.imageio.stream.ImageInputStreamImpl; + +public class JPEGImageInputStream + extends ImageInputStreamImpl +{ + private ImageInputStream in; + + byte marker; + + public JPEGImageInputStream(ImageInputStream in) + { + super(); + + this.in = in; + } + + public int read() + throws IOException + { + setBitOffset(0); + return in.read(); + } + + public int read(byte[] data, int offset, int len) + throws IOException + { + setBitOffset(0); + return in.read(data, offset, len); + } + + /** + * Pull a byte from the stream, this checks to see if the byte is 0xff + * and if the next byte isn't 0x00 (stuffed byte) it errors out. If it's + * 0x00 then it simply ignores the byte. + * + * @return the next byte in the buffer + * + * @throws IOException TODO + * @throws BitStreamException TODO + */ + private byte pullByte() throws IOException, JPEGMarkerFoundException + { + byte mybyte = readByte(); + // FIXME: handle multiple 0xff in a row + if(mybyte==(byte)(0xff)) + { + byte secondbyte = readByte(); + if(secondbyte != (byte)(0x00)) + { + marker = secondbyte; + throw new JPEGMarkerFoundException(); + } + } + return mybyte; + } + + /** + * This returns the marker that was last encountered. This should only be + * used if removeBit() throws a MarkerTagFound exception. + * + * @return marker as byte + */ + public byte getMarker() + { + return marker; + } + + /** + * Removes a bit from the buffer. (Removes from the top of a queue). This + * also checks for markers and throws MarkerTagFound exception if it does. + * If MarkerTagFound is thrown you can use getMarker() method to get the + * marker that caused the throw. + * + * @param l specifies how many bits you want to remove and add to the + * integer + * @return the amount of bits specified by l as an integer + * + * @throws IOException TODO + * @throws JPEGMarkerFoundException + * @throws BitStreamException TODO + */ + public int readBit() + throws IOException, JPEGMarkerFoundException +{ + checkClosed(); + + // Calc new bit offset here, readByte resets it. + int newOffset = (bitOffset + 1) & 0x7; + + byte data = pullByte(); + + if (bitOffset != 0) + { + seek(getStreamPosition() - 1); + data = (byte) (data >> (8 - newOffset)); + } + + bitOffset = newOffset; + return data & 0x1; +} + + + /** + * This method skips over the the data and finds the next position + * in the bit sequence with a X'FF' X'??' sequence. Multiple X'FF + * bytes in sequence are considered padding and interpreted as one + * X'FF byte. + * + * @return the next marker byte in the stream + * @throws IOException if the end of the stream is reached + * unexpectedly + */ + public byte findNextMarker() + throws IOException + { + boolean marked0xff = false; + byte byteinfo = JPEGMarker.X00; + + setBitOffset(0); + while (true) + { + byteinfo = readByte(); + if (!marked0xff) + { + if (byteinfo == JPEGMarker.XFF) + marked0xff = true; + } + else + { + if (byteinfo == JPEGMarker.XFF) + // Ignore the value 0xff when it is immediately + // followed by another 0xff byte. + continue; + else if (byteinfo == JPEGMarker.X00) + // The sequence 0xff 0x00 is used to encode the + // actual value 0xff. So restart our search for a + // marker. + marked0xff = false; + else + // One or more 0xff values were follwed by a + // non-0x00, non-0xff value so return this as the + // marker byte. + return byteinfo; + } + } + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageReader.java b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageReader.java new file mode 100644 index 000000000..5ecbe0f8c --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageReader.java @@ -0,0 +1,141 @@ +/* JPEGImageReader.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.javax.imageio.jpeg; + +import java.io.IOException; +import javax.imageio.*; +import javax.imageio.spi.*; +import javax.imageio.metadata.*; +import javax.imageio.stream.ImageInputStream; +import java.util.Iterator; +import java.awt.image.BufferedImage; + +public class JPEGImageReader extends ImageReader +{ + JPEGDecoder decoder; + + protected JPEGImageReader(ImageReaderSpi originatingProvider) + { + super(originatingProvider); + System.out.println("JPEGIMAGEREADER!!!"); + } + + // Abstract ImageReader methods. + public int getHeight(int imageIndex) + throws IOException + { + checkIndex(imageIndex); + decodeStream(); + return decoder.getHeight(); + } + + public IIOMetadata getImageMetadata(int imageIndex) + throws IOException + { + // FIXME: handle metadata + checkIndex(imageIndex); + return null; + } + + public Iterator getImageTypes(int imageIndex) + throws IOException + { + return null; + } + + public int getNumImages(boolean allowSearch) + throws IOException + { + return 1; + } + + public IIOMetadata getStreamMetadata() + throws IOException + { + // FIXME: handle metadata + return null; + } + + public int getWidth(int imageIndex) + throws IOException + { + checkIndex(imageIndex); + decodeStream(); + return decoder.getWidth(); + } + + public BufferedImage read(int imageIndex, ImageReadParam param) + throws IOException + { + checkIndex(imageIndex); + decodeStream(); + return decoder.getImage(); + } + + // private helper methods + private void checkIndex(int imageIndex) + throws IndexOutOfBoundsException + { + if (imageIndex != 0) + throw new IndexOutOfBoundsException(); + } + + private void checkStream() throws IOException + { + if (!(input instanceof ImageInputStream)) + throw new IllegalStateException("Input not an ImageInputStream."); + if(input == null) + throw new IllegalStateException("No input stream."); + } + + private void decodeStream() + throws IOException, IIOException + { + System.out.println("DECONDING 1"); + if (decoder != null) + return; + + System.out.println("DECONDING 2"); + checkStream(); + + System.out.println("DECONDING 3"); + decoder = new JPEGDecoder((ImageInputStream)input); + System.out.println("DECONDING 4"); + decoder.decode(); + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageReaderSpi.java b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageReaderSpi.java new file mode 100644 index 000000000..c45b818c7 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageReaderSpi.java @@ -0,0 +1,137 @@ +/* JPEGImageReaderSpi.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.javax.imageio.jpeg; + +import java.io.IOException; +import java.util.Locale; +import javax.imageio.ImageReader; +import javax.imageio.spi.ImageReaderSpi; +import javax.imageio.spi.IIORegistry; +import javax.imageio.stream.ImageInputStream; + +public class JPEGImageReaderSpi extends ImageReaderSpi +{ + static final String vendorName = "GNU"; + static final String version = "0.1"; + static final String readerClassName = + "gnu.javax.imageio.jpeg.JPEGImageReader"; + static final String[] names = { "JPEG" }; + static final String[] suffixes = { ".jpeg", ".jpg", ".jpe" }; + static final String[] MIMETypes = { "image/jpeg" }; + static final String[] writerSpiNames = + { "gnu.javax.imageio.jpeg.JPEGImageWriterSpi" }; + + static final boolean supportsStandardStreamMetadataFormat = false; + static final String nativeStreamMetadataFormatName = null; + static final String nativeStreamMetadataFormatClassName = null; + static final String[] extraStreamMetadataFormatNames = null; + static final String[] extraStreamMetadataFormatClassNames = null; + static final boolean supportsStandardImageMetadataFormat = false; + static final String nativeImageMetadataFormatName = null; + static final String nativeImageMetadataFormatClassName = null; + static final String[] extraImageMetadataFormatNames = null; + static final String[] extraImageMetadataFormatClassNames = null; + + private static JPEGImageReaderSpi readerSpi; + + public JPEGImageReaderSpi() + { + super(vendorName, version, + names, suffixes, MIMETypes, + readerClassName, + STANDARD_INPUT_TYPE, // Accept ImageInputStreams + writerSpiNames, + supportsStandardStreamMetadataFormat, + nativeStreamMetadataFormatName, + nativeStreamMetadataFormatClassName, + extraStreamMetadataFormatNames, + extraStreamMetadataFormatClassNames, + supportsStandardImageMetadataFormat, + nativeImageMetadataFormatName, + nativeImageMetadataFormatClassName, + extraImageMetadataFormatNames, + extraImageMetadataFormatClassNames); + System.out.println ("JPEGImageReaderSPI!!!"); + } + + public String getDescription(Locale locale) + { + return "JPEG ISO 10918-1, JFIF V1.02"; + } + + public boolean canDecodeInput(Object input) + throws IOException + { + if (!(input instanceof ImageInputStream)) + return false; + + ImageInputStream in = (ImageInputStream) input; + boolean retval; + + in.mark(); + try + { + new JPEGDecoder(in); + retval = true; + } + catch(JPEGException e) + { + retval = false; + } + in.reset(); + + return retval; + } + + public ImageReader createReaderInstance(Object extension) + { + return new JPEGImageReader(this); + } + + public static void registerSpis(IIORegistry reg) + { + reg.registerServiceProvider(getReaderSpi(), ImageReaderSpi.class); + } + + public static synchronized JPEGImageReaderSpi getReaderSpi() + { + if (readerSpi == null) + readerSpi = new JPEGImageReaderSpi(); + return readerSpi; + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/JPEGMarker.java b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGMarker.java new file mode 100644 index 000000000..bc6350fbc --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGMarker.java @@ -0,0 +1,205 @@ +/* JPEGMarker.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.javax.imageio.jpeg; + +public class JPEGMarker +{ + /** + * JFIF identifiers. + */ + public final static byte JFIF_J = (byte) 0x4a; + public final static byte JFIF_F = (byte) 0x46; + public final static byte JFIF_I = (byte) 0x49; + public final static byte JFIF_X = (byte) 0x46; + + /** + * JFIF extension codes. + */ + public final static byte JFXX_JPEG = (byte) 0x10; + public final static byte JFXX_ONE_BPP = (byte) 0x11; + public final static byte JFXX_THREE_BPP = (byte) 0x13; + + /** + * Marker prefix byte. + */ + public final static byte XFF = (byte) 0xff; + + /** + * Marker byte that represents a literal 0xff. + */ + public final static byte X00 = (byte) 0x00; + + /** + * Application Reserved Keyword. + */ + public final static byte APP0 = (byte) 0xe0; + + public final static byte APP1 = (byte) 0xe1; + public final static byte APP2 = (byte) 0xe2; + public final static byte APP3 = (byte) 0xe3; + public final static byte APP4 = (byte) 0xe4; + public final static byte APP5 = (byte) 0xe5; + public final static byte APP6 = (byte) 0xe6; + public final static byte APP7 = (byte) 0xe7; + public final static byte APP8 = (byte) 0xe8; + public final static byte APP9 = (byte) 0xe9; + public final static byte APP10 = (byte) 0xea; + public final static byte APP11 = (byte) 0xeb; + public final static byte APP12 = (byte) 0xec; + public final static byte APP13 = (byte) 0xed; + public final static byte APP14 = (byte) 0xee; + public final static byte APP15 = (byte) 0xef; + + /** + * Modulo Restart Interval. + */ + public final static byte RST0 = (byte) 0xd0; + + public final static byte RST1 = (byte) 0xd1; + public final static byte RST2 = (byte) 0xd2; + public final static byte RST3 = (byte) 0xd3; + public final static byte RST4 = (byte) 0xd4; + public final static byte RST5 = (byte) 0xd5; + public final static byte RST6 = (byte) 0xd6; + public final static byte RST7 = (byte) 0xd7; + + /** + * Nondifferential Huffman-coding frame (baseline dct). + */ + public final static byte SOF0 = (byte) 0xc0; + + /** + * Nondifferential Huffman-coding frame (extended dct). + */ + public final static byte SOF1 = (byte) 0xc1; + + /** + * Nondifferential Huffman-coding frame (progressive dct). + */ + public final static byte SOF2 = (byte) 0xc2; + + /** + * Nondifferential Huffman-coding frame Lossless (Sequential). + */ + public final static byte SOF3 = (byte) 0xc3; + + /** + * Differential Huffman-coding frame Sequential DCT. + */ + public final static byte SOF5 = (byte) 0xc5; + + /** + * Differential Huffman-coding frame Progressive DCT. + */ + public final static byte SOF6 = (byte) 0xc6; + + /** + * Differential Huffman-coding frame lossless. + */ + public final static byte SOF7 = (byte) 0xc7; + + /** + * Nondifferential Arithmetic-coding frame (extended dct). + */ + public final static byte SOF9 = (byte) 0xc9; + + /** + * Nondifferential Arithmetic-coding frame (progressive dct). + */ + public final static byte SOF10 = (byte) 0xca; + + /** + * Nondifferential Arithmetic-coding frame (lossless). + */ + public final static byte SOF11 = (byte) 0xcb; + + /** + * Differential Arithmetic-coding frame (sequential dct). + */ + public final static byte SOF13 = (byte) 0xcd; + + /** + * Differential Arithmetic-coding frame (progressive dct). + */ + public final static byte SOF14 = (byte) 0xce; + + /** + * Differential Arithmetic-coding frame (lossless). + */ + public final static byte SOF15 = (byte) 0xcf; + + /** + * Huffman Table. + */ + public final static byte DHT = (byte) 0xc4; + + /** + * Quantization Table. + */ + public final static byte DQT = (byte) 0xdb; + + /** + * Start of Scan. + */ + public final static byte SOS = (byte) 0xda; + + /** + * Defined Restart Interval. + */ + public final static byte DRI = (byte) 0xdd; + + /** + * Comment in JPEG. + */ + public final static byte COM = (byte) 0xfe; + + /** + * Start of Image. + */ + public final static byte SOI = (byte) 0xd8; + + /** + * End of Image. + */ + public final static byte EOI = (byte) 0xd9; + + /** + * Define Number of Lines. + */ + public final static byte DNL = (byte) 0xdc; +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/JPEGMarkerFoundException.java b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGMarkerFoundException.java new file mode 100644 index 000000000..2e72d495b --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGMarkerFoundException.java @@ -0,0 +1,50 @@ +/* JPEGMarkerFoundException.java -- FIXME: briefly describe file purpose + 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.imageio.jpeg; + +import java.io.IOException; + +public class JPEGMarkerFoundException + extends IOException +{ + public JPEGMarkerFoundException() + { + super(""); + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/JPEGScan.java b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGScan.java new file mode 100644 index 000000000..e07251021 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/JPEGScan.java @@ -0,0 +1,151 @@ +/* JPEGScan.java -- + 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.imageio.jpeg; + +import java.util.ArrayList; + +public class JPEGScan +{ + private int maxHeight = 0, maxWidth = 0, maxV = 0, maxH = 0; + private int numOfComponents = 0, numOfComponentBlocks = 0; + private ArrayList components = new ArrayList(); + + public JPEGScan() + { + // Nothing to do here. + } + + public JPEGScan(int h, int w) + { + maxHeight=h; + maxWidth=w; + } + + private void recalculateDimensions() + { + JPEGComponent comp; + + // Compute the maximum H, maximum V factors defined in Annex A of the ISO + // DIS 10918-1. + for(int i=0; i < components.size() ; i++) + { + comp = (JPEGComponent)components.get(i); + if(comp.factorH > maxH) + maxH=comp.factorH; + if(comp.factorV > maxV) + maxV=comp.factorV; + } + + for(int i=0; i < components.size() ; i++) + { + comp = (JPEGComponent)components.get(i); + comp.maxH = maxH; + comp.maxV = maxV; + } + + } + + public void addComponent(byte id, byte factorHorizontal, byte factorVertical, + byte quantizationID) + { + JPEGComponent component = new JPEGComponent(id, factorHorizontal, factorVertical, quantizationID); + components.add((Object)component); + recalculateDimensions(); + numOfComponents++; + numOfComponentBlocks += factorHorizontal*factorVertical; + } + + public JPEGComponent getComponentByID(byte id) + { + JPEGComponent comp = (JPEGComponent)components.get(0); + for(int i=0; i < components.size() ; i++) + { + comp=(JPEGComponent)components.get(i); + if(comp.component_id==id) + break; + } + return(comp); + } + + public JPEGComponent get(int id) + { + return((JPEGComponent)components.get(id)); + } + + public int getX(byte id) + { + JPEGComponent comp = getComponentByID(id); + return(comp.width); + } + + public int getY(byte id) + { + JPEGComponent comp = getComponentByID(id); + return(comp.height); + } + + public int getMaxV() + { + return(maxV); + } + + public int getMaxH() + { + return(maxH); + } + + public void setWidth(int w) + { + maxWidth=w; + } + + public void setHeight(int h) + { + maxHeight=h; + } + + public int size() + { + return(numOfComponents); + } + + public int sizeComponentBlocks() + { + return(numOfComponentBlocks); + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/YCbCr_ColorSpace.java b/libjava/classpath/gnu/javax/imageio/jpeg/YCbCr_ColorSpace.java new file mode 100644 index 000000000..a3970b7fa --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/YCbCr_ColorSpace.java @@ -0,0 +1,113 @@ +/* YCbCr_ColorSpace.java -- + 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.imageio.jpeg; + +import java.awt.color.ColorSpace; + +public class YCbCr_ColorSpace extends ColorSpace { + public YCbCr_ColorSpace() { + super(ColorSpace.TYPE_YCbCr, 3); + } + + public float[] fromCIEXYZ(float[] data) { + return(new float[data.length]); + } + + public float[] toCIEXYZ(float[] data) { + return(new float[data.length]); + } + + public float[] fromRGB(float[] data) { + return(new float[data.length]); + } + + /* YCbCr to RGB range 0 to 1 */ + public float[] toRGB(float[] data) { + float[] dest = new float[3]; + + data[0] *= 255; + data[1] *= 255; + data[2] *= 255; + + dest[0] = (float)data[0] + (float)1.402*((float)data[2]-(float)128); + dest[1] = (float)data[0] - (float)0.34414*((float)data[1]-(float)128) - (float)0.71414*((float)data[2]-(float)128); + dest[2] = (float)data[0] + (float)1.772*((float)data[1]-(float)128); + + dest[0] /= 255; + dest[1] /= 255; + dest[2] /= 255; + + //dest[0] = ((float)1.164*((float)data[0]*(float)255 - (float)16) + (float)1.596*((float)data[2]*(float)255 - (float)128))/(float)255; + //dest[1] = ((float)1.164*((float)data[0]*(float)255 - (float)16) - (float)0.813*((float)data[2]*(float)255 - (float)128) - (float)0.392*(data[1]*255 - 128))/(float)255; + //dest[2] = ((float)1.164*((float)data[0]*(float)255 - (float)16) + (float)2.017*((float)data[1]*(float)255 - (float)128))/(float)255; + + //System.err.println("toRGB values received: 0: "+data[0]+" 1: "+data[1]+" 2: "+data[2]+" sent: 0: "+dest[0]+" 1: "+dest[1]+" 2: "+dest[2]); + if(dest[0] < (float)0) + dest[0] = 0; + if(dest[1] < (float)0) + dest[1] = 0; + if(dest[2] < (float)0) + dest[2] = 0; + + if(dest[0] > (float)1) + dest[0] = 1; + if(dest[1] > (float)1) + dest[1] = 1; + if(dest[2] > (float)1) + dest[2] = 1; + + + return(dest); + } + + /* RGB to YCbCr range 0-255 */ + public static float[] toYCbCr(float[] data) { + float[] dest = new float[3]; + //dest[0] = (float)0.257*data[0] + (float)0.504*data[1] + (float)0.098*data[2] + 16; + //dest[1] = (float)-0.148*data[0] - (float)0.291*data[1] + (float)0.439*data[2] + 128; + //dest[2] = (float)0.439*data[0] - (float)0.368*data[1] - (float)0.071*data[2] + 128; + + dest[0] = (float)((0.299 * (float)data[0] + 0.587 * (float)data[1] + 0.114 * (float)data[2])); + dest[1] = 128 + (float)((-0.16874 * (float)data[0] - 0.33126 * (float)data[1] + 0.5 * (float)data[2])); + dest[2] = 128 + (float)((0.5 * (float)data[0] - 0.41869 * (float)data[1] - 0.08131 * (float)data[2])); + + + return(dest); + + } +} diff --git a/libjava/classpath/gnu/javax/imageio/jpeg/ZigZag.java b/libjava/classpath/gnu/javax/imageio/jpeg/ZigZag.java new file mode 100644 index 000000000..9aac0df40 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/jpeg/ZigZag.java @@ -0,0 +1,520 @@ +/* ZigZag.java -- + 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.imageio.jpeg; + +/** + * This class implements the Zig Zag Algorithm on any array with + * the same amount of rows and columns. It takes a matrix and in turn builds an + * encoded byte array (or double array) from it. The adverse is also true, this + * will take a byte or double array and build a matrix based on the zig zag + * algorithm. + *

    This is used exclusively in the JPEG DCT encoding.

    + */ +public class ZigZag +{ + public final static boolean ZIGZAG_FORWARD = true; + public final static boolean ZIGZAG_BACKWARD = false; + public final static int ZIGZAG_8X8_MAP[] = + { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 + }; + + /** + * Encodes a matrix of equal width and height to a byte array. + * + * @param matrix + * + * @return + */ + public static byte[] encode(byte[][] matrix) + { + byte[] buffer = new byte[matrix.length ^ 2]; + boolean direction = ZigZag.ZIGZAG_FORWARD; + int x = 0, y = 0, index = 0; + for (int zigIndex = 0; zigIndex < (matrix.length * 2 - 1); + zigIndex++, direction = !direction) + { + if (direction == ZigZag.ZIGZAG_FORWARD) + { + while (x >= 0 && y != matrix.length) + { + if (x == matrix.length) + { + x--; + y++; + } + buffer[index] = matrix[x][y]; + y++; + x--; + index++; + } + x++; + } + else + { + while (y >= 0 && x != matrix.length) + { + if (y == matrix.length) + { + y--; + x++; + } + buffer[index] = matrix[x][y]; + y--; + x++; + index++; + } + y++; + } + } + return (buffer); + } + + /** + * Encodes a matrix of equal width and height to a double array + * + * @param matrix + * + * @return + */ + public static double[] encode(double[][] matrix) + { + double[] buffer = new double[matrix.length * matrix.length]; + boolean direction = ZigZag.ZIGZAG_FORWARD; + int x = 0, y = 0, index = 0; + for (int zigIndex = 0; zigIndex < (matrix.length * 2 - 1); + zigIndex++, direction = !direction) + { + if (direction == ZigZag.ZIGZAG_FORWARD) + { + while (x >= 0 && y != matrix.length) + { + if (x == matrix.length) + { + x--; + y++; + } + buffer[index] = matrix[x][y]; + y++; + x--; + index++; + } + x++; + } + else + { + while (y >= 0 && x != matrix.length) + { + if (y == matrix.length) + { + y--; + x++; + } + buffer[index] = matrix[x][y]; + y--; + x++; + index++; + } + y++; + } + } + return (buffer); + } + + /** + * Encodes a matrix of equal width and height to a float array + * + * @param matrix + * + * @return + */ + public static float[] encode(float[][] matrix) + { + float[] buffer = new float[matrix.length * matrix.length]; + boolean direction = ZigZag.ZIGZAG_FORWARD; + int x = 0, y = 0, index = 0; + for (int zigIndex = 0; zigIndex < (matrix.length * 2 - 1); + zigIndex++, direction = !direction) + { + if (direction == ZigZag.ZIGZAG_FORWARD) + { + while (x >= 0 && y != matrix.length) + { + if (x == matrix.length) + { + x--; + y++; + } + buffer[index] = matrix[x][y]; + y++; + x--; + index++; + } + x++; + } + else + { + while (y >= 0 && x != matrix.length) + { + if (y == matrix.length) + { + y--; + x++; + } + buffer[index] = matrix[x][y]; + y--; + x++; + index++; + } + y++; + } + } + return (buffer); + } + + /** + * Encodes a matrix of equal width and height to a float array + * + * @param matrix + * + * @return + */ + public static short[] encode(short[][] matrix) + { + short[] buffer = new short[matrix.length * matrix.length]; + boolean direction = ZigZag.ZIGZAG_FORWARD; + int x = 0, y = 0, index = 0; + for (int zigIndex = 0; zigIndex < (matrix.length * 2 - 1); + zigIndex++, direction = !direction) + { + if (direction == ZigZag.ZIGZAG_FORWARD) + { + while (x >= 0 && y != matrix.length) + { + if (x == matrix.length) + { + x--; + y++; + } + buffer[index] = matrix[x][y]; + y++; + x--; + index++; + } + x++; + } + else + { + while (y >= 0 && x != matrix.length) + { + if (y == matrix.length) + { + y--; + x++; + } + buffer[index] = matrix[x][y]; + y--; + x++; + index++; + } + y++; + } + } + return (buffer); + } + + /** + * Convert a double array into a matrix with the same amount of columns and + * rows with length sqrt(double array length) + * + * @param data + * + * @return + */ + public static double[][] decode(double[] data) + { + return decode(data, (int) Math.sqrt(data.length), + (int) Math.sqrt(data.length)); + } + + /** + * Convert a byte array into a matrix with the same amount of columns and + * rows with length sqrt(double array length) + * + * @param data + * + * @return + */ + public static byte[][] decode(byte[] data) + { + return decode(data, (int) Math.sqrt(data.length), + (int) Math.sqrt(data.length)); + } + + public static int[][] decode(int[] data) + { + return decode(data, (int) Math.sqrt(data.length), + (int) Math.sqrt(data.length)); + } + + public static byte[][] decode(byte[] data, int width, int height) + { + byte[][] buffer = new byte[height][width]; + + for (int v = 0; v < height; v++) + for (int z = 0; z < width; z++) + buffer[v][z] = 11; + + boolean dir = ZigZag.ZIGZAG_FORWARD; + int xindex = 0, yindex = 0, dataindex = 0; + + while (xindex < width && yindex < height && dataindex < data.length) + { + buffer[yindex][xindex] = data[dataindex]; + dataindex++; + + if (dir == ZigZag.ZIGZAG_FORWARD) + { + if (yindex == 0 || xindex == (width - 1)) + { + dir = ZigZag.ZIGZAG_BACKWARD; + if (xindex == (width - 1)) + yindex++; + else + xindex++; + } + else + { + yindex--; + xindex++; + } + } + else + { /* Backwards */ + if (xindex == 0 || yindex == (height - 1)) + { + dir = ZigZag.ZIGZAG_FORWARD; + if (yindex == (height - 1)) + xindex++; + else + yindex++; + } + else + { + yindex++; + xindex--; + } + } + } + return (buffer); + } + + public static double[][] decode(double[] data, int width, int height) + { + double[][] buffer = new double[height][width]; + + for (int v = 0; v < height; v++) + for (int z = 0; z < width; z++) + buffer[v][z] = 11; + + boolean dir = ZigZag.ZIGZAG_FORWARD; + int xindex = 0, yindex = 0, dataindex = 0; + + while (xindex < width && yindex < height && dataindex < data.length) + { + buffer[yindex][xindex] = data[dataindex]; + dataindex++; + System.err.println("Setting " + dataindex + " to row: " + yindex + + " column: " + xindex + " yourval:" + + (yindex*8+xindex)); + if (dir == ZigZag.ZIGZAG_FORWARD) + { + if (yindex == 0 || xindex == (width - 1)) + { + dir = ZigZag.ZIGZAG_BACKWARD; + if (xindex == (width - 1)) + yindex++; + else + xindex++; + } + else + { + yindex--; + xindex++; + } + } + else + { /* Backwards */ + if (xindex == 0 || yindex == (height - 1)) + { + dir = ZigZag.ZIGZAG_FORWARD; + if (yindex == (height - 1)) + xindex++; + else + yindex++; + } + else + { + yindex++; + xindex--; + } + } + } + return (buffer); + } + + public static float[][] decode(float[] data, int width, int height) + { + float[][] buffer = new float[height][width]; + + for (int v = 0; v < height; v++) + for (int z = 0; z < width; z++) + buffer[v][z] = 11; + + boolean dir = ZigZag.ZIGZAG_FORWARD; + int xindex = 0, yindex = 0, dataindex = 0; + + while (xindex < width && yindex < height && dataindex < data.length) + { + buffer[yindex][xindex] = data[dataindex]; + dataindex++; + + if (dir == ZigZag.ZIGZAG_FORWARD) + { + if (yindex == 0 || xindex == (width - 1)) + { + dir = ZigZag.ZIGZAG_BACKWARD; + if (xindex == (width - 1)) + yindex++; + else + xindex++; + } + else + { + yindex--; + xindex++; + } + } + else + { /* Backwards */ + if (xindex == 0 || yindex == (height - 1)) + { + dir = ZigZag.ZIGZAG_FORWARD; + if (yindex == (height - 1)) + xindex++; + else + yindex++; + } + else + { + yindex++; + xindex--; + } + } + } + return (buffer); + } + + public static int[][] decode(int[] data, int width, int height) + { + int[][] buffer = new int[height][width]; + + for (int v = 0; v < height; v++) + for (int z = 0; z < width; z++) + buffer[v][z] = 11; + + boolean dir = ZigZag.ZIGZAG_FORWARD; + int xindex = 0, yindex = 0, dataindex = 0; + + while (xindex < width && yindex < height && dataindex < data.length) + { + buffer[yindex][xindex] = data[dataindex]; + dataindex++; + + if (dir == ZigZag.ZIGZAG_FORWARD) + { + if (yindex == 0 || xindex == (width - 1)) + { + dir = ZigZag.ZIGZAG_BACKWARD; + if (xindex == (width - 1)) + yindex++; + else + xindex++; + } + else + { + yindex--; + xindex++; + } + } + else + { /* Backwards */ + if (xindex == 0 || yindex == (height - 1)) + { + dir = ZigZag.ZIGZAG_FORWARD; + if (yindex == (height - 1)) + xindex++; + else + yindex++; + } + else + { + yindex++; + xindex--; + } + } + } + return (buffer); + } + + public static double[][] decode8x8_map(double input[]) + { + double[][] output = new double[8][8]; + for(int i=0; i < 64 ; i++) + output[ZIGZAG_8X8_MAP[i]/8][ZIGZAG_8X8_MAP[i]%8] = input[i]; + return (output); + } + +} diff --git a/libjava/classpath/gnu/javax/imageio/png/PNGChunk.java b/libjava/classpath/gnu/javax/imageio/png/PNGChunk.java new file mode 100644 index 000000000..ade0999fe --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/png/PNGChunk.java @@ -0,0 +1,283 @@ +/* PNGChunk.java -- Generic PNG chunk + Copyright (C) 2006 Free Software Foundation + +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.imageio.png; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; + +/** + * Class to load and validate a generic PNG chunk. + */ +public class PNGChunk +{ + + /** + * CRC table and initialization code. + */ + private static long[] crcTable; + + static + { + long c; + crcTable = new long[256]; + + for(int i = 0; i < 256; i++) + { + c = i; + for(int j = 0; j < 8; j++) + if( (c & 1) == 1 ) + c = 0xEDB88320L ^ (c >> 1); + else + c = c >> 1; + crcTable[i] = c; + } + } + + /** + * (recognized) PNG chunk types. + */ + public static final int TYPE_HEADER = 0x49484452; // 'IHDR' + public static final int TYPE_PALETTE = 0x504c5445;// 'PLTE' + public static final int TYPE_DATA = 0x49444154; // 'IDAT' + public static final int TYPE_TIME = 0x74494d45; // 'tIME' + public static final int TYPE_END = 0x49454e44; // 'IEND' + public static final int TYPE_PHYS = 0x70485973; // 'pHYS' + public static final int TYPE_GAMMA = 0x67414d41; // 'gAMA' + public static final int TYPE_PROFILE = 0x69434350; // 'iCCP' + + /** + * The chunk type - Represented in the file as 4 ASCII bytes, + */ + private int type; + + /** + * The chunk data + */ + protected byte[] data; + + /** + * The chunk's crc + */ + private int crc; + + /** + * Constructor for reading a generic chunk. + */ + protected PNGChunk( int type, byte[] data, int crc ) + { + this.type = type; + this.data = data; + this.crc = crc; + } + + /** + * Constructor for creating new chunks. + * (only used by subclasses - creating a generic chunk is rather useless) + */ + protected PNGChunk( int type ) + { + this.type = type; + } + + /** + * Loads a chunk from an InputStream. Does not perform validation, + * but will throw an IOException if the read fails. + * @param in - th einputstream to read from + * @param strict - if true, a PNGException is thrown on all invalid chunks, + * if false, only critical chunks will throw PNGExceptions. + */ + public static PNGChunk readChunk(InputStream in, boolean strict) + throws IOException, PNGException + { + byte data[] = new byte[4]; + if( in.read( data ) != 4 ) + throw new IOException("Could not read chunk length."); + int length = ((data[0] & 0xFF) << 24) | ((data[1] & 0xFF) << 16 ) | + ((data[2] & 0xFF) << 8) | (data[3] & 0xFF); + + if( in.read( data ) != 4 ) + throw new IOException("Could not read chunk type."); + int type = ((data[0] & 0xFF) << 24) | ((data[1] & 0xFF) << 16 ) | + ((data[2] & 0xFF) << 8) | (data[3] & 0xFF); + + byte[] chkdata = new byte[ length ]; + if( in.read( chkdata ) != length ) + throw new IOException("Could not read chunk data."); + + if( in.read( data ) != 4 ) + throw new IOException("Could not read chunk CRC."); + + int crc = ((data[0] & 0xFF) << 24) | ( (data[1] & 0xFF) << 16 ) | + ((data[2] & 0xFF) << 8) | (data[3] & 0xFF); + + if( strict ) + return getChunk( type, chkdata, crc ); + else + { + try + { + return getChunk( type, chkdata, crc ); + } + catch(PNGException pnge) + { + if( isEssentialChunk( type ) ) + throw pnge; + return null; + } + } + } + + /** + * Returns a specialied object for a chunk, if we have one. + */ + private static PNGChunk getChunk( int type, byte[] data, int crc ) + throws PNGException + { + switch( type ) + { + case TYPE_HEADER: + return new PNGHeader( type, data, crc ); + case TYPE_DATA: + return new PNGData( type, data, crc ); + case TYPE_PALETTE: + return new PNGPalette( type, data, crc ); + case TYPE_TIME: + return new PNGTime( type, data, crc ); + case TYPE_PHYS: + return new PNGPhys( type, data, crc ); + case TYPE_GAMMA: + return new PNGGamma( type, data, crc ); + case TYPE_PROFILE: + return new PNGICCProfile( type, data, crc ); + default: + return new PNGChunk( type, data, crc ); + } + } + + /** + * Returns whether the chunk is essential or not + */ + private static boolean isEssentialChunk( int type ) + { + switch( type ) + { + case TYPE_HEADER: + case TYPE_DATA: + case TYPE_PALETTE: + case TYPE_END: + return true; + default: + return false; + } + } + + /** + * Validates the chunk + */ + public boolean isValidChunk() + { + return (crc == calcCRC()); + } + + /** + * Returns the chunk type. + */ + public int getType() + { + return type; + } + + /** + * Writes a PNG chunk to an output stream, + * performing the CRC calculation as well. + */ + public void writeChunk(OutputStream out) throws IOException + { + out.write( getInt(data.length) ); + out.write( getInt(type) ); + out.write( data ); + out.write( getInt(calcCRC()) ); + } + + /** + * Return whether the chunk contains any data. + */ + public boolean isEmpty() + { + return ( data.length == 0 ); + } + + /** + * Convenience method. Cast an int to four bytes (big endian). + * (Now why doesn't java have a simple way of doing this?) + */ + public static byte[] getInt(int intValue) + { + long i = (intValue & 0xFFFFFFFFL); + byte[] b = new byte[4]; + b[0] = (byte)((i & 0xFF000000L) >> 24); + b[1] = (byte)((i & 0x00FF0000L) >> 16); + b[2] = (byte)((i & 0x0000FF00L) >> 8); + b[3] = (byte)(i & 0x000000FFL); + return b; + } + + /** + * Calculates this chunk's CRC value. + */ + private int calcCRC() + { + long c = 0xFFFFFFFFL; + byte[] t = getInt( type ); + for(int i = 0; i < 4; i++) + c = crcTable[ (int)((c ^ t[i]) & 0xFF) ] ^ (c >> 8); + + for(int i = 0; i < data.length; i++) + c = crcTable[ (int)((c ^ data[i]) & 0xFF) ] ^ (c >> 8); + + return (int)(c ^ 0xFFFFFFFFL); + } + + public String toString() + { + return "PNG Chunk. Type: " + new String( getInt(type) ) + " , CRC: " + + crc + " , calculated CRC: "+calcCRC(); + } + +} diff --git a/libjava/classpath/gnu/javax/imageio/png/PNGData.java b/libjava/classpath/gnu/javax/imageio/png/PNGData.java new file mode 100644 index 000000000..08d765f66 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/png/PNGData.java @@ -0,0 +1,104 @@ +/* PNGData.java -- PNG IDAT chunk. + Copyright (C) 2006 Free Software Foundation + +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.imageio.png; + +import java.util.zip.Inflater; +import java.util.zip.Deflater; + +/** + * A PNG IDAT (data) chunk. + */ +public class PNGData extends PNGChunk +{ + private int offset; + + protected PNGData( int type, byte[] data, int crc ) + { + super( type, data, crc ); + } + + protected PNGData( int chunkSize ) + { + super( PNGChunk.TYPE_DATA ); + data = new byte[ chunkSize ]; + offset = 0; + } + + /** + * Deflates the available data in def to the chunk. + * + * @return true if the chunk is filled and no more data can be written, + * false otherwise. + */ + public void deflateToChunk( Deflater def ) + { + offset += def.deflate( data, offset, data.length - offset ); + } + + /** + * Returns true if the chunk is filled. + */ + public boolean chunkFull() + { + return (offset >= data.length); + } + + /** + * Shrink the chunk to offset size, used for the last chunk in a stream + * (no trailing data!) + */ + public void shrink() + { + byte[] newData = new byte[ offset ]; + System.arraycopy( data, 0, newData, 0, offset ); + data = newData; + } + + /** + * Feeds the data in the chunk to a ZIP inflater object. + */ + public void feedToInflater( Inflater inf ) + { + inf.setInput( data ); + } + + public String toString() + { + return "PNG Data chunk. Length = "+data.length; + } +} diff --git a/libjava/classpath/gnu/javax/imageio/png/PNGDecoder.java b/libjava/classpath/gnu/javax/imageio/png/PNGDecoder.java new file mode 100644 index 000000000..4481107c4 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/png/PNGDecoder.java @@ -0,0 +1,331 @@ +/* PNGDecoder.java + Copyright (C) 2006 Free Software Foundation + +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.imageio.png; + +import java.util.zip.Inflater; +import java.util.zip.DataFormatException; +import java.awt.image.ColorModel; +import java.awt.image.ComponentColorModel; +import java.awt.image.ComponentSampleModel; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.DataBufferUShort; +import java.awt.image.IndexColorModel; +import java.awt.image.MultiPixelPackedSampleModel; +import java.awt.image.Raster; +import java.awt.image.SampleModel; +import java.awt.image.SinglePixelPackedSampleModel; +import java.awt.image.WritableRaster; +import java.awt.color.ColorSpace; + +public class PNGDecoder +{ + private PNGHeader header; + private byte[] raster; + private byte[] scanline, lastScanline; + private byte[] filterType; + private int offset, length; + private int currentScanline; + private final int stride; + private Inflater inflater; + private boolean readFilter; + private int bpp; // bytes per pixel + + /** + * Constructs a filter object for + */ + public PNGDecoder(PNGHeader header) + { + this.header = header; + offset = 0; + inflater = new Inflater(); + stride = header.getScanlineStride(); + length = stride * header.getHeight(); + + // Allocate the output raster + raster = new byte[ length ]; + scanline = new byte[ stride ]; + lastScanline = new byte[ stride ]; + currentScanline = 0; + readFilter = true; + bpp = header.bytesPerPixel(); + filterType = new byte[1]; + inflater = new Inflater(); + } + + private int getBytes( byte[] buf, int offset ) throws PNGException + { + try + { + return inflater.inflate( buf, offset, buf.length - offset); + } + catch(DataFormatException dfe) + { + throw new PNGException("Error inflating data."); + } + } + + /** + * Decodes a data chunk. + */ + public void addData( PNGData chunk ) throws PNGException + { + int n = 0; + if( isFinished() ) + return; + chunk.feedToInflater( inflater ); + do + { + if( readFilter ) + if( getBytes( filterType, 0 ) < 1 ) + return; + + n = getBytes( scanline, offset ); + + if( offset + n < stride ) + { + offset += n; + readFilter = false; + } + else + { + scanline = PNGFilter.unFilterScanline( filterType[0], scanline, + lastScanline, bpp ); + System.arraycopy( scanline, 0, + raster, currentScanline * stride, stride ); + lastScanline = scanline; + scanline = new byte[scanline.length]; + currentScanline++; + readFilter = true; + offset = 0; + } + } + while( n > 0 && currentScanline < header.getHeight() ); + } + + /** + * Parse the appropriate color type and create an AWT raster for it. + * @param header - the file header. + */ + public WritableRaster getRaster( PNGHeader header ) + { + SampleModel sm = null; + DataBuffer db = null; + int t; + int width = header.getWidth(); + int height = header.getHeight(); + int depth = header.getDepth(); + + switch( header.getColorType() ) + { + case PNGHeader.GRAYSCALE_WITH_ALPHA: + if( depth == 8 ) + { + t = DataBuffer.TYPE_BYTE; + db = getByteBuffer(); + } + else + { + t = DataBuffer.TYPE_USHORT; + db = getShortBuffer(); + } + sm = new ComponentSampleModel(t, width, height, 2, width * 2, + new int[]{0, 1}); + break; + + case PNGHeader.GRAYSCALE: + switch( depth ) + { + case 16: + sm = new ComponentSampleModel(DataBuffer.TYPE_USHORT, + width, height, 1, width, + new int[]{ 0 }); + db = getShortBuffer(); + break; + + case 8: + sm = new ComponentSampleModel(DataBuffer.TYPE_BYTE, + width, height, 1, width, + new int[]{ 0 }); + db = getByteBuffer(); + break; + + default: + sm = new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE, + width, height, depth); + db = getByteBuffer(); + break; + } + break; + + case PNGHeader.RGB: + if( depth == 8 ) + { + t = DataBuffer.TYPE_BYTE; + db = getByteBuffer(); + } + else + { + t = DataBuffer.TYPE_USHORT; + db = getShortBuffer(); + } + sm = new ComponentSampleModel(t, width, height, 3, 3 * width, + new int[]{0, 1, 2}); + break; + + case PNGHeader.RGB_WITH_ALPHA: + if( depth == 8 ) + { + t = DataBuffer.TYPE_BYTE; + db = getByteBuffer(); + } + else + { + t = DataBuffer.TYPE_USHORT; + db = getShortBuffer(); + } + + sm = new ComponentSampleModel(t, width, height, 4, width * 4, + new int[]{0, 1, 2, 3}); + break; + + case PNGHeader.INDEXED: + if( depth == 8 ) + sm = new SinglePixelPackedSampleModel(DataBuffer.TYPE_BYTE, + width, height, + new int[] {0xFF}); + else + sm = new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE, + width, height, depth); + db = getByteBuffer(); + break; + } + + return Raster.createWritableRaster(sm, db, null); + } + + /** + * Wrap the raster with a DataBufferUShort, + * conversion is big-endian (PNG native). + */ + private DataBuffer getShortBuffer() + { + short[] data = new short[(raster.length >> 1)]; + for( int i = 0; i < data.length; i++ ) + data[i] = (short)(((raster[i * 2] & 0xFF) << 8) | + (raster[i * 2 + 1] & 0xFF)); + return new DataBufferUShort( data, data.length ); + } + + /** + * Wrap the raster with a DataBufferByte + */ + private DataBuffer getByteBuffer() + { + return new DataBufferByte( raster, raster.length ); + } + + public ColorModel getColorModel( ColorSpace cs, + int colorType, int depth ) + { + int[] bits; + boolean hasAlpha = false; + int transferType; + + switch( colorType ) + { + case PNGHeader.GRAYSCALE_WITH_ALPHA: + if( cs == null ) + cs = ColorSpace.getInstance( ColorSpace.CS_GRAY ); + hasAlpha = true; + bits = new int[]{ depth, depth }; + break; + + case PNGHeader.RGB: + bits = new int[]{ depth, depth, depth }; + break; + + case PNGHeader.RGB_WITH_ALPHA: + hasAlpha = true; + bits = new int[]{ depth, depth, depth, depth }; + break; + + case PNGHeader.GRAYSCALE: + if( depth < 8 ) + return grayPalette( depth ); + + if( cs == null ) + cs = ColorSpace.getInstance( ColorSpace.CS_GRAY ); + bits = new int[]{ depth }; + break; + + default: + case PNGHeader.INDEXED: + return null; // Handled by the palette chunk. + } + + if( cs == null ) + cs = ColorSpace.getInstance( ColorSpace.CS_sRGB ); + + + return new ComponentColorModel(cs, bits, hasAlpha, false, + (hasAlpha ? + ComponentColorModel.TRANSLUCENT : + ComponentColorModel.OPAQUE), + ((depth == 16) ? DataBuffer.TYPE_USHORT : + DataBuffer.TYPE_BYTE)); + } + + private IndexColorModel grayPalette(int depth) + { + byte[] c = new byte[ (1 << depth) ]; + for(int i = 0; i < c.length; i++) + c[i] = (byte)(255.0 * (((double)i) / ((double)c.length - 1.0))); + return new IndexColorModel(8, c.length, c, c, c); + } + + public byte[] getRaster() + { + return raster; + } + + public boolean isFinished() + { + return currentScanline >= header.getHeight(); + } +} diff --git a/libjava/classpath/gnu/javax/imageio/png/PNGEncoder.java b/libjava/classpath/gnu/javax/imageio/png/PNGEncoder.java new file mode 100644 index 000000000..b31787635 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/png/PNGEncoder.java @@ -0,0 +1,233 @@ +/* PNGEncoder.java -- + Copyright (C) 2006 Free Software Foundation + +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.imageio.png; + +import java.util.Vector; +import java.util.zip.Deflater; +import java.awt.color.ColorSpace; +import java.awt.color.ICC_ColorSpace; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.DataBufferUShort; +import java.awt.image.IndexColorModel; +import java.awt.image.WritableRaster; + +public class PNGEncoder +{ + /** + * The default data chunk size. 8 kb. + */ + private static final int defaultChunkSize = 8192; + + private PNGHeader header; + private PNGPalette palette; + private int stride, bpp; + private byte[] rawData; + private PNGICCProfile profile; + + public PNGEncoder( BufferedImage bi ) throws PNGException + { + ColorModel c = bi.getColorModel(); + int width = bi.getWidth(); + int height = bi.getHeight(); + int depth = 0; + int colorType; + boolean interlace = false; + + if( c instanceof IndexColorModel ) + { + colorType = PNGHeader.INDEXED; + int n = ((IndexColorModel)c).getMapSize(); + if( n <= 2 ) + depth = 1; + else if( n <= 4 ) + depth = 2; + else if( n <= 16 ) + depth = 4; + else if( n <= 256 ) + depth = 8; + else + throw new PNGException("Depth must be <= 8 bits for indexed color."); + palette = new PNGPalette( ((IndexColorModel)c) ); + } + else + { + ColorSpace cs = c.getColorSpace(); + ColorSpace grayCS = ColorSpace.getInstance( ColorSpace.CS_GRAY ); + if( cs == grayCS || bi.getType() == BufferedImage.TYPE_BYTE_GRAY + || bi.getType() == BufferedImage.TYPE_USHORT_GRAY ) + colorType = c.hasAlpha() ? PNGHeader.GRAYSCALE_WITH_ALPHA : + PNGHeader.GRAYSCALE; + else + colorType = c.hasAlpha() ? PNGHeader.RGB_WITH_ALPHA : PNGHeader.RGB; + // Figure out the depth + int[] bits = c.getComponentSize(); + depth = bits[0]; + for(int i = 1; i < bits.length; i++ ) + if( bits[i] > depth ) depth = bits[i]; + if( (cs != grayCS && !cs.isCS_sRGB()) && cs instanceof ICC_ColorSpace ) + profile = new PNGICCProfile( ((ICC_ColorSpace)cs).getProfile() ); + } + + header = new PNGHeader(width, height, depth, colorType, interlace); + + stride = header.getScanlineStride(); // scanline stride + bpp = header.bytesPerPixel(); // bytes per pixel + getRawData( bi ); + } + + /** + * Returns the generated header. + */ + public PNGHeader getHeader() + { + return header; + } + + /** + * Returns the generated palette. + */ + public PNGPalette getPalette() + { + return palette; + } + + /** + * Returns the associated ICC profile, if any. + */ + public PNGICCProfile getProfile() + { + return profile; + } + + /** + * Encodes the raster and returns a Vector of PNGData chunks. + */ + public Vector encodeImage() + { + Deflater deflater = new Deflater(); // The deflater + boolean useFilter = PNGFilter.useFilter( header ); + byte[] lastScanline = new byte[ stride ]; + + byte[] data = new byte[ rawData.length + header.getHeight() ]; + + byte filterByte = PNGFilter.FILTER_NONE; + for( int i = 0; i < header.getHeight(); i++) + { + byte[] scanline = new byte[ stride ]; + System.arraycopy(rawData, (i * stride), scanline, 0, stride); + if( useFilter && i > 0) + filterByte = PNGFilter.chooseFilter( scanline, lastScanline, bpp); + + byte[] filtered = PNGFilter.filterScanline( filterByte, scanline, + lastScanline, bpp ); + data[i * (stride + 1)] = filterByte; + System.arraycopy(filtered, 0, data, 1 + (i * (stride + 1)), stride); + + lastScanline = scanline; + } + + deflater.setInput( data ); + deflater.finish(); + + PNGData chunk; + Vector chunks = new Vector(); + do + { + chunk = new PNGData( defaultChunkSize ); + chunk.deflateToChunk( deflater ); + chunks.add( chunk ); + } + while( chunk.chunkFull() ); + chunk.shrink(); // Shrink the last chunk. + return chunks; + } + + /** + * Get the image's raw data. + * FIXME: This may need improving on. + */ + private void getRawData( BufferedImage bi ) throws PNGException + { + WritableRaster raster = bi.getRaster(); + rawData = new byte[ stride * header.getHeight() ]; + if( header.isIndexed() ) + { + DataBuffer db = raster.getDataBuffer(); + if( !( db instanceof DataBufferByte ) ) + throw new PNGException("Unexpected DataBuffer for an IndexColorModel."); + byte[] data = ((DataBufferByte)db).getData(); + for(int i = 0; i < header.getHeight(); i++ ) + System.arraycopy( data, i * stride, rawData, i * stride, stride ); + return; + } + + if( header.getDepth() == 16 ) + { + DataBuffer db = raster.getDataBuffer(); + if( !( db instanceof DataBufferUShort ) ) + throw new PNGException("Unexpected DataBuffer for 16-bit."); + short[] data = ((DataBufferUShort)db).getData(); + for(int i = 0; i < header.getHeight(); i++ ) + for(int j = 0; j < ( stride >> 1); j++) + { + rawData[ j * 2 + i * stride ] = (byte)((data[j + i * (stride >> 1 )] & 0xFF00) >> 8); + rawData[ j * 2 + i * stride + 1 ] = (byte)(data[j + i * (stride >> 1 )] & 0xFF); + } + return; + } + + int size = ( header.getColorType() == PNGHeader.RGB_WITH_ALPHA ) ? 4 : 3; + int width = header.getWidth(); + int height = header.getHeight(); + int[] pixels = bi.getRGB( 0, 0, width, height, null, 0, width ); + + for( int i = 0; i < width * height; i++ ) + { + rawData[ i * size ] = (byte)((pixels[i] & 0xFF0000) >> 16); + rawData[ i * size + 1 ] = (byte)((pixels[i] & 0xFF00) >> 8); + rawData[ i * size + 2 ] = (byte)(pixels[i] & 0xFF); + } + + if( size == 4 ) + for( int i = 0; i < width * height; i++ ) + rawData[ i * size + 3 ] = (byte)((pixels[i] & 0xFF000000) >> 24); + } +} diff --git a/libjava/classpath/gnu/javax/imageio/png/PNGException.java b/libjava/classpath/gnu/javax/imageio/png/PNGException.java new file mode 100644 index 000000000..ef5342cf8 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/png/PNGException.java @@ -0,0 +1,48 @@ +/* PNGException.java -- + Copyright (C) 2006 Free Software Foundation + +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.imageio.png; + +import java.io.IOException; + +public class PNGException extends IOException +{ + public PNGException(String msg) + { + super( msg ); + } +} diff --git a/libjava/classpath/gnu/javax/imageio/png/PNGFile.java b/libjava/classpath/gnu/javax/imageio/png/PNGFile.java new file mode 100644 index 000000000..76154cc66 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/png/PNGFile.java @@ -0,0 +1,257 @@ +/* PNGFile.java -- High-level representation of a PNG file. + Copyright (C) 2006 Free Software Foundation + +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.imageio.png; + +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; +import java.util.Vector; +import java.awt.image.BufferedImage; +import java.awt.image.WritableRaster; +import java.awt.image.ColorModel; +import java.awt.color.ColorSpace; + +public class PNGFile +{ + /** + * The PNG file signature. + */ + private static final byte[] signature = new byte[] + { (byte)137, 80, 78, 71, 13, 10, 26, 10 }; + + /** + * The end chunk in raw form, no need for anything fancy here, it's just + * 0 bytes of length, the "IEND" tag and its CRC. + */ + private static final byte[] endChunk = new byte[] + { 0, 0, 0, 0, (byte)0x49, (byte)0x45, (byte)0x4E, (byte)0x44, + (byte)0xAE, (byte)0x42, (byte)0x60, (byte)0x82 }; + + /** + * The loaded data. + */ + private Vector chunks; + + /** + * The Header chunk + */ + private PNGHeader header; + + /** + * Whether this file has a palette chunk or not. + */ + private boolean hasPalette; + + /** + * Image width and height. + */ + private int width, height; + + /** + * The decoder, if any. + */ + private PNGDecoder decoder; + + /** + * The encoder, if any. (Either this or the above must exist). + */ + private PNGEncoder encoder; + + /** + * The source of this PNG (if encoding) + */ + private BufferedImage sourceImage; + + /** + * Creates a PNGFile object from an InputStream. + */ + public PNGFile(InputStream in) throws IOException, PNGException + { + PNGChunk chunk; + byte[] fileHdr = new byte[8]; + chunks = new Vector(); + hasPalette = false; + + if( in.read( fileHdr ) != 8 ) + throw new IOException("Could not read file header."); + if( !validateHeader( fileHdr ) ) + throw new PNGException("Invalid file header. Not a PNG file."); + + chunk = PNGChunk.readChunk( in, false ); + if( !(chunk instanceof PNGHeader) ) + throw new PNGException("First chunk not a header chunk."); + header = (PNGHeader)chunk; + if( !header.isValidChunk() ) + throw new PNGException("First chunk not a valid header."); + System.out.println(header); + + decoder = new PNGDecoder( header ); + // Read chunks. + do + { + chunk = PNGChunk.readChunk( in, false ); + /* + * We could exit here or output some kind of warning. + * But in the meantime, we'll just silently drop invalid chunks. + */ + if( chunk.isValidChunk() ) + { + if( chunk instanceof PNGData ) + decoder.addData( (PNGData)chunk ); + else // Silently ignore multiple headers, and use only the first. + if( chunk.getType() != PNGChunk.TYPE_END ) + { + chunks.add( chunk ); + hasPalette |= ( chunk instanceof PNGPalette ); + } + } + else + System.out.println("WARNING: Invalid chunk!"); + } + while( chunk.getType() != PNGChunk.TYPE_END ); + + if( header.isIndexed() && !hasPalette ) + throw new PNGException("File is indexed color and has no palette."); + + width = header.getWidth(); + height = header.getHeight(); + } + + /** + * Creates a PNG file from an existing BufferedImage. + */ + public PNGFile(BufferedImage bi) throws PNGException + { + sourceImage = bi; + width = bi.getWidth(); + height = bi.getHeight(); + chunks = new Vector(); + encoder = new PNGEncoder( bi ); + header = encoder.getHeader(); + if( header.isIndexed() ) + chunks.add( encoder.getPalette() ); + + // Do the compression and put the data chunks in the list. + chunks.addAll( encoder.encodeImage() ); + } + + /** + * Writes a PNG file to an OutputStream + */ + public void writePNG(OutputStream out) throws IOException + { + out.write( signature ); // write the signature. + header.writeChunk( out ); + for( int i = 0; i < chunks.size(); i++ ) + { + PNGChunk chunk = ((PNGChunk)chunks.elementAt(i)); + chunk.writeChunk( out ); + } + out.write( endChunk ); + } + + /** + * Check 8 bytes to see if it's a valid PNG header. + */ + private boolean validateHeader( byte[] hdr ) + { + if( hdr.length != 8 ) + return false; + for( int i = 0; i < 8; i++ ) + if( signature[i] != hdr[i] ) + return false; + return true; + } + + /** + * Return a loaded image as a bufferedimage. + */ + public BufferedImage getBufferedImage() + { + if( decoder == null ) + return sourceImage; + + WritableRaster r = decoder.getRaster( header ); + ColorModel cm; + if( header.isIndexed() ) + { + PNGPalette pngp = getPalette(); + cm = pngp.getPalette( getColorSpace() ); + } + else + cm = decoder.getColorModel( getColorSpace(), + header.getColorType(), + header.getDepth() ); + + return new BufferedImage(cm, r, false, null); + } + + /** + * Find the palette chunk and return it + */ + private PNGPalette getPalette() + { + for(int i = 0; i < chunks.size(); i++ ) + if( chunks.elementAt(i) instanceof PNGPalette ) + return ((PNGPalette)chunks.elementAt(i)); + return null; + } + + /** + * Return the Color space to use, first preference is ICC profile, then + * a gamma chunk, or returns null for the default sRGB. + */ + private ColorSpace getColorSpace() + { + PNGICCProfile icc = null; + PNGGamma gamma = null; + for(int i = 0; i < chunks.size(); i++ ) + { + if( chunks.elementAt(i) instanceof PNGICCProfile ) + icc = ((PNGICCProfile)chunks.elementAt(i)); + else if(chunks.elementAt(i) instanceof PNGGamma ) + gamma = ((PNGGamma)chunks.elementAt(i)); + } + + if( icc != null ) + return icc.getColorSpace(); +// if( gamma != null && !header.isGrayscale()) +// return gamma.getColorSpace( header.isGrayscale() ); + return null; + } +} diff --git a/libjava/classpath/gnu/javax/imageio/png/PNGFilter.java b/libjava/classpath/gnu/javax/imageio/png/PNGFilter.java new file mode 100644 index 000000000..9be7b9127 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/png/PNGFilter.java @@ -0,0 +1,237 @@ +/* PNGFilter.java -- PNG image filters. + Copyright (C) 2006 Free Software Foundation + +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.imageio.png; + +/** + * A utility class of static methods implementing the PNG filtering algorithms. + */ +public class PNGFilter +{ + + public static final byte FILTER_NONE = 0; + public static final byte FILTER_SUB = 1; + public static final byte FILTER_UP = 2; + public static final byte FILTER_AVERAGE = 3; + public static final byte FILTER_PAETH = 4; + + /** + * Return whether a filter should be used or FILTER_NONE, + * following the recommendations in the PNG spec. + */ + public static boolean useFilter( PNGHeader header ) + { + switch( header.getColorType() ) + { + case PNGHeader.INDEXED: + return false; + + case PNGHeader.GRAYSCALE: + case PNGHeader.RGB: + if( header.bytesPerPixel() <= 1 ) + return false; + case PNGHeader.GRAYSCALE_WITH_ALPHA: + case PNGHeader.RGB_WITH_ALPHA: + default: + return true; + } + } + + /** + * Heuristic for adaptively choosing a filter, following the scheme + * suggested in the PNG spec. + * @return a fiter type. + */ + public static byte chooseFilter( byte[] scanline, byte[] lastScanline, + int bpp) + + { + long[] values = new long[5]; + int idx = 0; + for( int i = 0; i < 5; i++ ) + { + byte[] filtered = filterScanline((byte)i, scanline, lastScanline, bpp); + values[i] = 0; + for(int j = 0; j < filtered.length; j++ ) + values[i] += (int)(filtered[j] & 0xFF); + if( values[ idx ] > values[i] ) + idx = i; + } + return (byte)idx; + } + + /** + * Filter a scanline. + */ + public static byte[] filterScanline( byte filtertype, byte[] scanline, + byte[] lastScanline, int bpp) + { + int stride = scanline.length; + byte[] out = new byte[ stride ]; + switch( filtertype ) + { + case FILTER_SUB: + for( int i = 0; i < bpp; i++) + out[ i ] = scanline[ i ]; + + for( int i = bpp; i < stride; i++ ) + out[i] = (byte)(scanline[ i ] - + scanline[ i - bpp ]); + break; + + case FILTER_UP: + for( int i = 0; i < stride; i++ ) + out[ i ] = (byte)(scanline[ i ] - lastScanline[ i ]); + break; + + case FILTER_AVERAGE: + for( int i = 0; i < bpp; i++) + out[ i ] = (byte)((scanline[ i ] & 0xFF) - ((lastScanline[ i ] & 0xFF) >> 1)); + for( int i = bpp; i < stride; i++ ) + out[ i ] = (byte)((scanline[ i ] & 0xFF) - + (((scanline[ i - bpp ] & 0xFF) + + (lastScanline[ i ] & 0xFF)) >> 1)); + break; + + case FILTER_PAETH: + for( int i = 0; i < stride; i++ ) + { + int x; + { + int a, b, c; + if( i >= bpp ) + { + a = (scanline[ i - bpp ] & 0xFF); // left + c = (lastScanline[ i - bpp ] & 0xFF); // upper-left + } + else + a = c = 0; + b = (lastScanline[ i ] & 0xFF); // up + + int p = (a + b - c); // initial estimate + // distances to a, b, c + int pa = (p > a) ? p - a : a - p; + int pb = (p > b) ? p - b : b - p; + int pc = (p > c) ? p - c : c - p; + // return nearest of a,b,c, + // breaking ties in order a,b,c. + if( pa <= pb && pa <= pc ) x = a; + else { if( pb <= pc ) x = b; + else x = c; + } + } + out[ i ] = (byte)(scanline[ i ] - x); + } + break; + default: + case FILTER_NONE: + return scanline; + } + return out; + } + + /** + * Unfilter a scanline. + */ + public static byte[] unFilterScanline( int filtertype, byte[] scanline, + byte[] lastScanline, int bpp) + { + int stride = scanline.length; + byte[] out = new byte[ stride ]; + switch( filtertype ) + { + + case FILTER_NONE: + System.arraycopy( scanline, 0, out, 0, stride ); + break; + + case FILTER_SUB: + for( int i = 0; i < bpp; i++) + out[ i ] = scanline[ i ]; + + for( int i = bpp; i < stride; i++ ) + out[ i ] = (byte)(scanline[ i ] + + out[ i - bpp ]); + break; + + case FILTER_UP: + for( int i = 0; i < stride; i++ ) + out[ i ] = (byte)(scanline[ i ] + lastScanline[ i ]); + break; + + case FILTER_AVERAGE: + for( int i = 0; i < bpp; i++) + out[ i ] = (byte)((scanline[ i ] & 0xFF) + ((lastScanline[ i ] & 0xFF) >> 1)); + for( int i = bpp; i < stride; i++ ) + out[ i ] = (byte)((scanline[ i ] & 0xFF) + + (((out[ i - bpp ] & 0xFF) + (lastScanline[ i ] & 0xFF)) >> 1)); + break; + + case FILTER_PAETH: + for( int i = 0; i < stride; i++ ) + { + int x; + { + int a, b, c; + if( i >= bpp ) + { + a = (out[ i - bpp ] & 0xFF); // left + c = (lastScanline[ i - bpp ] & 0xFF); // upper-left + } + else + a = c = 0; + b = (lastScanline[ i ] & 0xFF); // up + + int p = (a + b - c); // initial estimate + // distances to a, b, c + int pa = (p > a) ? p - a : a - p; + int pb = (p > b) ? p - b : b - p; + int pc = (p > c) ? p - c : c - p; + // return nearest of a,b,c, + // breaking ties in order a,b,c. + if( pa <= pb && pa <= pc ) x = a; + else { if( pb <= pc ) x = b; + else x = c; + } + } + out[ i ] = (byte)(scanline[ i ] + x); + } + break; + } + return out; + } +} diff --git a/libjava/classpath/gnu/javax/imageio/png/PNGGamma.java b/libjava/classpath/gnu/javax/imageio/png/PNGGamma.java new file mode 100644 index 000000000..b9c3f21c3 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/png/PNGGamma.java @@ -0,0 +1,85 @@ +/* PNGGamma.java -- GAMA chunk. + Copyright (C) 2006 Free Software Foundation + +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.imageio.png; + +import java.awt.color.ColorSpace; + +/** + * A PNG gAMA (gamma) chunk. + */ +public class PNGGamma extends PNGChunk +{ + private double gamma; + + protected PNGGamma( int type, byte[] data, int crc ) throws PNGException + { + super( type, data, crc ); + if( data.length < 4 ) + throw new PNGException("Unexpectedly short time chunk. ("+data.length+" bytes)"); + long g = ((data[0] & 0xFF) << 24) | ( (data[1] & 0xFF) << 16 ) | + ((data[2] & 0xFF) << 8) | (data[3] & 0xFF); + gamma = (double)g; + gamma = 100000.0/gamma; + } + + public PNGGamma( double g ) + { + super( TYPE_GAMMA ); + data = new byte[ 4 ]; + gamma = g; + long tmp = (long)(100000.0/gamma); + data[0] = (byte)((tmp & 0xFF000000) >> 24); + data[1] = (byte)((tmp & 0xFF0000) >> 16); + data[2] = (byte)((tmp & 0xFF00) >> 8); + data[3] = (byte)(tmp & 0xFF); + } + + /** + * Returns a ColorSpace object corresponding to this gamma value. + */ + public ColorSpace getColorSpace(boolean grayscale) + { + // FIXME. + return null; + } + + public String toString() + { + return "PNG Gamma chunk, value: "+gamma; + } +} diff --git a/libjava/classpath/gnu/javax/imageio/png/PNGHeader.java b/libjava/classpath/gnu/javax/imageio/png/PNGHeader.java new file mode 100644 index 000000000..115e50311 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/png/PNGHeader.java @@ -0,0 +1,257 @@ +/* PNGHeader.java -- PNG Header + Copyright (C) 2006 Free Software Foundation + +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.imageio.png; + +/** + * A PNG Header chunk. + */ +public class PNGHeader extends PNGChunk +{ + private int width, height, depth; + private int colorType, compression, filter, interlace; + + /** + * The valid interlace types. + */ + public static final int INTERLACE_NONE = 0; + public static final int INTERLACE_ADAM7 = 1; + + /** + * The valid color types. + */ + public static final int GRAYSCALE = 0; + public static final int RGB = 2; + public static final int INDEXED = 3; + public static final int GRAYSCALE_WITH_ALPHA = 4; + public static final int RGB_WITH_ALPHA = 6; + + /** + * Parses a PNG Header chunk. + */ + protected PNGHeader( int type, byte[] data, int crc ) throws PNGException + { + super( type, data, crc ); + if( data.length < 13 ) + throw new PNGException("Unexpectedly short header chunk. (" + data.length + + " bytes)"); + + width = ((data[0] & 0xFF) << 24) | ( (data[1] & 0xFF) << 16 ) | + ((data[2] & 0xFF) << 8) | (data[3] & 0xFF); + height = ((data[4] & 0xFF) << 24) | ( (data[5] & 0xFF) << 16 ) | + ((data[6] & 0xFF) << 8) | (data[7] & 0xFF); + depth = (data[8] & 0xFF); + colorType = (data[9] & 0xFF); + compression = (data[10] & 0xFF); + filter = (data[11] & 0xFF); + interlace = (data[12] & 0xFF); + } + + /** + * Create a PNG header chunk. + * Warning: This trusts that the parameters are valid. + */ + public PNGHeader(int width, int height, int depth, + int colorType, boolean interlace) + { + super( TYPE_HEADER ); + data = new byte[ 13 ]; + + this.width = width; + this.height = height; + this.depth = depth; + compression = filter = 0; + this.colorType = colorType; + this.interlace = interlace ? 1 : 0; + + // Build the data chunk. + byte[] a = getInt( width ); + byte[] b = getInt( height ); + data[0] = a[0]; data[1] = a[1]; data[2] = a[2]; data[3] = a[3]; + data[4] = b[0]; data[5] = b[1]; data[6] = b[2]; data[7] = b[3]; + data[8] = (byte)depth; + data[9] = (byte)colorType; + data[10] = (byte)compression; + data[11] = (byte)filter; + data[12] = (byte)this.interlace; + } + + /** + * Validates the header fields + */ + public boolean isValidChunk() + { + if( !super.isValidChunk() ) + return false; + + // width and height must be nonzero + if( width == 0 || height == 0 ) + return false; + // colorType can be 0,2,3,4,6 + if( (colorType & 0xFFFFFFF8) != 0 || colorType == 5 || colorType == 1) + return false; + // Possible valid depths are 1,2,4,8,16 + if( !((depth == 1) || (depth == 2) || (depth == 4) || + (depth == 8) || (depth == 16)) ) + return false; + if( colorType == INDEXED && depth == 16 ) + return false; + if( ( colorType == RGB || colorType == GRAYSCALE_WITH_ALPHA || + colorType == RGB_WITH_ALPHA ) && + depth < 8 ) + return false; + // Only compression and filter methods zero are defined + if( compression != 0 || filter != 0 ) + return false; + // Interlace methods, 0 and 1 are valid values. + if( (interlace & 0xFFFFFFFE) != 0 ) + return false; + + return true; + } + + /** + * Returns true if this PNG is indexed-color + */ + public boolean isIndexed() + { + return (colorType == INDEXED); + } + + /** + * Returns true if this PNG is grayscale + */ + public boolean isGrayscale() + { + return ((colorType == GRAYSCALE) || (colorType == GRAYSCALE_WITH_ALPHA)); + } + + /** + * Returns the color type of the image. + */ + public int getColorType() + { + return colorType; + } + + /** + * Returns whether the image is interlaced or not. + */ + public boolean isInterlaced() + { + return (interlace != 0); + } + + /** + * Returns the number of bytes per pixel. + */ + public int bytesPerPixel() + { + switch( colorType ) + { + case GRAYSCALE_WITH_ALPHA: + return ((depth * 2) >> 3); + case RGB: + return ((depth * 3) >> 3); + case RGB_WITH_ALPHA: + return ((depth * 4) >> 3); + + default: + case GRAYSCALE: + case INDEXED: + int i = (depth >> 3); + if( i > 0 ) return i; + return 1; // if bytes per pixel < 1, return 1 anyway. + } + } + + /** + * Returns the stride of one scanline, in bytes. + */ + public int getScanlineStride() + { + long nBits = 0; // bits per scanline - scanlines are on byte offsets. + switch( colorType ) + { + case GRAYSCALE: + nBits = width * depth; + break; + case RGB: + nBits = width * depth * 3; + break; + case INDEXED: + nBits = depth * width; + break; + case GRAYSCALE_WITH_ALPHA: + nBits = depth * width * 2; + break; + case RGB_WITH_ALPHA: + nBits = depth * width * 4; + break; + } + // Round up number of bits to the nearest byte + if( (nBits & 0x07) != 0 ) + nBits += (8 - (nBits & 0x07)); + + return (int)(nBits >> 3); // return # of bytes. + } + + public int getWidth() + { + return width; + } + + public int getHeight() + { + return height; + } + + public int getDepth() + { + return depth; + } + + /** + * Debugging string. + */ + public String toString() + { + return "Header Chunk. Image width:"+width+" height:"+height+ + " depth:"+depth+" color type:"+colorType+" compression type:"+ + compression+" filter type:"+ filter+" interlace:"+interlace; + } +} diff --git a/libjava/classpath/gnu/javax/imageio/png/PNGICCProfile.java b/libjava/classpath/gnu/javax/imageio/png/PNGICCProfile.java new file mode 100644 index 000000000..9ecea7166 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/png/PNGICCProfile.java @@ -0,0 +1,116 @@ +/* PNGICCProfile.java -- + Copyright (C) 2006 Free Software Foundation + +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.imageio.png; + +import java.awt.color.ICC_Profile; +import java.awt.color.ICC_ColorSpace; +import java.awt.color.ColorSpace; +import java.io.UnsupportedEncodingException; +import java.io.IOException; +import java.io.ByteArrayInputStream; +import java.util.zip.InflaterInputStream; +import java.util.zip.Deflater; + +/** + * A PNG iCCP (ICC Profile) chunk. + */ +public class PNGICCProfile extends PNGChunk +{ + private String name; + private ICC_Profile profile; + // A generic profile name to use "ICC Profile" + private static final byte[] genericName = new byte[] + { 0x49, 0x43, 0x43, 0x20, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65 }; + + protected PNGICCProfile( int type, byte[] data, int crc ) throws PNGException + { + super( type, data, crc ); + int i = 0; + while( data[i++] != 0 ) + ; + + try + { + name = new String(data, 0, i, "8859_1"); + } + catch(UnsupportedEncodingException e) + { + name = ""; // shouldn't really happen. + } + if( data[i++] != 0 ) + throw new PNGException("Can't handle nonzero compression types with iCCP chunks."); + try + { + ByteArrayInputStream bos = new ByteArrayInputStream( data, i, + data.length - i ); + profile = ICC_Profile.getInstance( new InflaterInputStream( bos ) ); + } + catch(IOException ioe) + { + throw new PNGException("Couldn't read iCCP profile chunk."); + } + System.out.println("Got profile:"+profile); + } + + public PNGICCProfile( ICC_Profile profile ) + { + super( TYPE_PROFILE ); + this.profile = profile; + byte[] profData = profile.getData(); + byte[] outData = new byte[ profData.length * 2 ]; + Deflater deflater = new Deflater(); + deflater.setInput( profData ); + deflater.finish(); + int n = deflater.deflate( outData ); + data = new byte[ n + 11 + 2 ]; + System.arraycopy(genericName, 0, data, 0, 11 ); + data[11] = data[12] = 0; // null separator and compression type. + // Copy compressed data + System.arraycopy(outData, 0, data, 13, n ); + } + + public ColorSpace getColorSpace() + { + return new ICC_ColorSpace( profile ); + } + + public String toString() + { + return "PNG ICC Profile, name: "+name; + } +} diff --git a/libjava/classpath/gnu/javax/imageio/png/PNGImageReader.java b/libjava/classpath/gnu/javax/imageio/png/PNGImageReader.java new file mode 100644 index 000000000..3209baa26 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/png/PNGImageReader.java @@ -0,0 +1,224 @@ +/* PNGImageReader.java -- The ImageIO ImageReader for PNG + 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.imageio.png; + +import gnu.javax.imageio.IIOInputStream; + +import java.awt.image.BufferedImage; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Iterator; + +import javax.imageio.ImageReadParam; +import javax.imageio.ImageReader; +import javax.imageio.ImageTypeSpecifier; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.stream.ImageInputStream; + +/** + * The ImageIO ImageReader for PNG images. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class PNGImageReader + extends ImageReader +{ + + /** + * The PNG file. + */ + private PNGFile pngFile; + + /** + * The decoded image. + */ + private BufferedImage image; + + /** + * The supported image types for PNG. + */ + private ArrayList imageTypes; + + /** + * Creates a new instance. + * + * @param spi the corresponding ImageReaderSpi + */ + public PNGImageReader(PNGImageReaderSpi spi) + { + super(spi); + } + + /** + * Returns the height of the image. + */ + public int getHeight(int imageIndex) + throws IOException + { + checkIndex(imageIndex); + readImage(); + return image.getHeight(); + } + + /** + * Returns the width of the image. + * + * @param imageIndex the index of the image + * + * @return the width of the image + */ + public int getWidth(int imageIndex) throws IOException + { + checkIndex(imageIndex); + readImage(); + return image.getWidth(); + } + + /** + * Returns the image types for the image. + * + * @see ImageReader#getImageTypes(int) + */ + public Iterator getImageTypes(int imageIndex) + throws IOException + { + checkIndex(imageIndex); + readImage(); + if (imageTypes == null) + { + imageTypes = new ArrayList(); + imageTypes.add(new ImageTypeSpecifier(image.getColorModel(), + image.getSampleModel())); + } + return imageTypes.iterator(); + } + + /** + * Returns the number of images in the stream. + * + * @return the number of images in the stream + * + * @see ImageReader#getNumImages(boolean) + */ + public int getNumImages(boolean allowSearch) + throws IOException + { + return 1; + } + + /** + * Reads the image. + * + * @param imageIndex the index of the image to read + * @param param additional parameters + */ + public BufferedImage read(int imageIndex, ImageReadParam param) + throws IOException + { + checkIndex(imageIndex); + readImage(); + return image; + } + + /** + * Sets the input and checks the input parameter. + * + * @see ImageReader#setInput(Object, boolean, boolean) + */ + public void setInput(Object input, + boolean seekForwardOnly, + boolean ignoreMetadata) + { + super.setInput(input, seekForwardOnly, ignoreMetadata); + if (! (input instanceof InputStream || input instanceof ImageInputStream)) + throw new IllegalArgumentException("Input not an ImageInputStream"); + } + + public IIOMetadata getImageMetadata(int imageIndex) + throws IOException + { + // TODO: Not (yet) supported. + checkIndex(imageIndex); + return null; + } + + public IIOMetadata getStreamMetadata() + throws IOException + { + // TODO: Not (yet) supported. + return null; + } + + /** + * Checks the image indexa and throws and IndexOutOfBoundsException if + * appropriate. + * + * @param index the index to check + */ + private void checkIndex(int index) + { + if (index > 0) + throw new IndexOutOfBoundsException("Image index out of bounds"); + } + + /** + * Makes sure that the image is read. + * + * @throws IOException if something goes wrong + */ + private void readImage() + throws IOException + { + if (pngFile == null) + { + if (input instanceof InputStream) + pngFile = new PNGFile((InputStream) input); + else if (input instanceof ImageInputStream) + pngFile = new PNGFile(new IIOInputStream((ImageInputStream) input)); + else + assert false : "Must not happen"; + } + + if (pngFile != null && image == null) + { + image = pngFile.getBufferedImage(); + } + } +} diff --git a/libjava/classpath/gnu/javax/imageio/png/PNGImageReaderSpi.java b/libjava/classpath/gnu/javax/imageio/png/PNGImageReaderSpi.java new file mode 100644 index 000000000..0092ab558 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/png/PNGImageReaderSpi.java @@ -0,0 +1,128 @@ +/* PNGImageReaderSpi.java -- The ImageReader service provider for PNG + 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.imageio.png; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Locale; + +import javax.imageio.ImageReader; +import javax.imageio.spi.ImageReaderSpi; +import javax.imageio.stream.ImageInputStream; + +/** + * The ImageIO ImageReader service provider for PNG images. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class PNGImageReaderSpi + extends ImageReaderSpi +{ + + /** + * The PNG file signature. + */ + private static final byte[] SIGNATURE = new byte[] + { (byte) 137, 80, 78, 71, 13, 10, 26, 10 }; + + private static final String VENDOR_NAME = "GNU"; + static final String VERSION = "1.0"; + static final String READER_CLASSNAME = + "gnu.javax.imageio.png.PNGImageReader"; + static final String[] NAMES = { "Portable Network Graphics" }; + static final String[] SUFFIXES = { ".png" , ".PNG" }; + static final String[] MIME_TYPES = { "image/png" }; + static final String[] WRITER_SPI_NAMES = + new String[] { "gnu.javax.imageio.png.PNGWriterSpi" }; + static final Class[] INPUT_TYPES = new Class[]{ InputStream.class, + ImageInputStream.class}; + public PNGImageReaderSpi() + { + super(VENDOR_NAME, VERSION, NAMES, SUFFIXES, MIME_TYPES, READER_CLASSNAME, + INPUT_TYPES, WRITER_SPI_NAMES, false, null, null, null, null, false, + null, null, null, null); + } + + /** + * Determines if the PNG ImageReader can decode the specified input. + * + * @param source the source to decode + */ + public boolean canDecodeInput(Object source) throws IOException + { + boolean canDecode = false; + if (source instanceof ImageInputStream) + { + ImageInputStream in = (ImageInputStream) source; + in.mark(); + canDecode = true; + for (int i = 0; i < SIGNATURE.length && canDecode; i++) + { + byte sig = (byte) in.read(); + if (sig != SIGNATURE[i]) { + canDecode = false; + } + } + in.reset(); + } + return canDecode; + } + + /** + * Returns a new PNGImageReader instance. + * + * @param extension the extension, ignored + */ + public ImageReader createReaderInstance(Object extension) + throws IOException + { + return new PNGImageReader(this); + } + + /** + * Returns a description. + * + * @param locale the locale + */ + public String getDescription(Locale locale) + { + return "Portable Network Graphics"; + } + +} diff --git a/libjava/classpath/gnu/javax/imageio/png/PNGPalette.java b/libjava/classpath/gnu/javax/imageio/png/PNGPalette.java new file mode 100644 index 000000000..197cad846 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/png/PNGPalette.java @@ -0,0 +1,127 @@ +/* PNGPalette.java -- + Copyright (C) 2006 Free Software Foundation + +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.imageio.png; + +import java.awt.color.ColorSpace; +import java.awt.image.IndexColorModel; + +/** + * A PNG Palette chunk. + */ +public class PNGPalette extends PNGChunk +{ + private int[] red,green,blue; + + protected PNGPalette( int type, byte[] data, int crc ) throws PNGException + { + super( type, data, crc ); + double l = data.length; + l /= 3.0; + // Check if it's divisible by 3. (Yuck.) + if( l - Math.floor(l) != 0.0 ) + throw new PNGException("Invalid size of palette chunk."); + int nEntries = (int)l; + + red = new int[ nEntries ]; + green = new int[ nEntries ]; + blue = new int[ nEntries ]; + for( int i = 0; i < nEntries; i++ ) + { + red[i] = (data[ i * 3 ] & 0xFF); + green[i] = (data[ i * 3 + 1 ] & 0xFF); + blue[i] = (data[ i * 3 + 2] & 0xFF); + } + } + + public PNGPalette( IndexColorModel cm ) + { + super( TYPE_PALETTE ); + int n = cm.getMapSize(); + data = new byte[ n * 3 ]; + red = new int[ n ]; + green = new int[ n ]; + blue = new int[ n ]; + for(int i = 0; i < n; i++ ) + { + red[i] = data[i * 3] = (byte)cm.getRed(i); + green[i] = data[i * 3 + 1] = (byte)cm.getGreen(i); + blue[i] = data[i * 3 + 2] = (byte)cm.getBlue(i); + } + } + + public IndexColorModel getPalette( ColorSpace cs ) + { + int nc = red.length; + byte[] r = new byte[nc]; + byte[] g = new byte[nc]; + byte[] b = new byte[nc]; + + if( cs == null ) + { + for(int i = 0; i < nc; i ++ ) + { + r[i] = (byte)red[i]; + g[i] = (byte)green[i]; + b[i] = (byte)blue[i]; + } + } + else + { + for(int i = 0; i < nc; i ++ ) + { + float[] in = new float[3]; + in[0] = (((float)red[i]) / 255f); + in[1] = (((float)green[i]) / 255f); + in[2] = (((float)blue[i]) / 255f); + float[] out = cs.toRGB( in ); + r[i] = (byte)( Math.round(out[0] * 255.0) ); + g[i] = (byte)( Math.round(out[1] * 255.0) ); + b[i] = (byte)( Math.round(out[2] * 255.0) ); + } + } + return new IndexColorModel(8, nc, r, g, b); + } + + public String toString() + { + String s = "PNG Palette:\n"; + for( int i = 0; i < red.length; i++) + s = s + "Index " + i + ": ["+ red[i] +", "+green[i]+", "+blue[i]+"]\n"; + return s; + } +} diff --git a/libjava/classpath/gnu/javax/imageio/png/PNGPhys.java b/libjava/classpath/gnu/javax/imageio/png/PNGPhys.java new file mode 100644 index 000000000..d15f09e88 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/png/PNGPhys.java @@ -0,0 +1,112 @@ +/* PNGPhys.java -- + Copyright (C) 2006 Free Software Foundation + +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.imageio.png; + +/** + * A PNG "pHYS" chunk - pixel physical dimensions + */ +public class PNGPhys extends PNGChunk +{ + long x, y; + double ratio; + boolean usesRatio; + + protected PNGPhys( int type, byte[] data, int crc ) throws PNGException + { + super( type, data, crc ); + if( data.length < 9 ) + throw new PNGException("Unexpected size of pHYS chunk."); + x = ((data[0] & 0xFF) << 24) | ( (data[1] & 0xFF) << 16 ) | + ((data[2] & 0xFF) << 8) | (data[3] & 0xFF); + y = ((data[4] & 0xFF) << 24) | ( (data[5] & 0xFF) << 16 ) | + ((data[6] & 0xFF) << 8) | (data[7] & 0xFF); + if(data[8] == 0) + { + ratio = ((double)x)/((double)y); + usesRatio = true; + } + } + + public PNGPhys( double ratio ) + { + super( TYPE_PHYS ); + + this.ratio = ratio; + usesRatio = true; + + if( ratio < 1.0 ) + { + y = 0xFFFFFFFF; + x = (long)(0xFFFFFFFFL * ratio); + } + else + { + x = 0xFFFFFFFF; + y = (long)(0xFFFFFFFFL * ratio); + } + makeData(); + } + + public PNGPhys( int x, int y ) + { + super( TYPE_PHYS ); + usesRatio = false; + this.x = x; + this.y = y; + makeData(); + } + + private void makeData() + { + data = new byte[ 9 ]; + byte[] a = getInt( (int)x ); + byte[] b = getInt( (int)y ); + data[0] = a[0]; data[1] = a[1]; data[2] = a[2]; data[3] = a[3]; + data[4] = b[0]; data[5] = b[1]; data[6] = b[2]; data[7] = b[3]; + data[7] = (usesRatio) ? 0 : (byte)0xFF; + } + + public String toString() + { + String s = "PNG Physical pixel size chunk."; + if( usesRatio ) + return s + " Aspect ratio (x/y): " + ratio; + else + return s + " " + x + " by " + y + " pixels per meter. (x, y)."; + } +} diff --git a/libjava/classpath/gnu/javax/imageio/png/PNGTime.java b/libjava/classpath/gnu/javax/imageio/png/PNGTime.java new file mode 100644 index 000000000..824f06f83 --- /dev/null +++ b/libjava/classpath/gnu/javax/imageio/png/PNGTime.java @@ -0,0 +1,83 @@ +/* PNGTime.java -- + Copyright (C) 2006 Free Software Foundation + +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.imageio.png; + +import java.util.Date; + +/** + * A PNG tIME chunk. + */ +public class PNGTime extends PNGChunk +{ + private Date date; + + protected PNGTime( int type, byte[] data, int crc ) throws PNGException + { + super( type, data, crc ); + if( data.length < 7 ) + throw new PNGException("Unexpectedly short time chunk. ("+data.length+" bytes)"); + + // PNG value is absolute (2006, not 106 or 06), java is from 1900. + int year = ( (data[0] & 0xFF) << 8 ) | (data[1] & 0xFF); + int month = (data[2] & 0xFF); // java counts from 0. PNG from 1. + int day = (data[3] & 0xFF); + int hour = (data[4] & 0xFF); + int minute = (data[5] & 0xFF); + int second = (data[6] & 0xFF); + date = new Date( year - 1900, month - 1, day, hour, minute, second ); + } + + public PNGTime( Date d ) + { + super( TYPE_TIME ); + data = new byte[ 7 ]; + int tmp = d.getYear() + 1900; + data[0] = (byte)((tmp & 0xFF00) >> 8); + data[1] = (byte)(tmp & 0x00FF); + data[2] = (byte)(d.getMonth() + 1); + data[3] = (byte)(d.getDay()); + data[4] = (byte)(d.getHours()); + data[5] = (byte)(d.getMinutes()); + data[6] = (byte)(d.getSeconds()); + } + + public String toString() + { + return "PNG Time chunk: "+date; + } +} diff --git a/libjava/classpath/gnu/javax/management/ListenerData.java b/libjava/classpath/gnu/javax/management/ListenerData.java new file mode 100644 index 000000000..31fdeccf0 --- /dev/null +++ b/libjava/classpath/gnu/javax/management/ListenerData.java @@ -0,0 +1,136 @@ +/* ListenerData.java - Class to contain data about management bean listeners + Copyright (C) 2006 Free Software Foundation + +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.management; + +import javax.management.NotificationFilter; +import javax.management.NotificationListener; + +/** + * Container for data on management listeners. Wraps + * a {@link javax.management.NotificationListener}, + * {@link javax.management.NotificationFilter} and + * passback object in one class. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public class ListenerData +{ + /** + * The listener itself. + */ + private NotificationListener listener; + + /** + * A filter to apply to incoming events. + */ + private NotificationFilter filter; + + /** + * An object to pass back to the listener on an + * event occurring. + */ + private Object passback; + + /** + * Constructs a new {@link ListenerData} with the specified + * listener, filter and passback object. + * + * @param listener the listener itself. + * @param filter the filter for incoming events. + * @param passback the object to passback on an incoming event. + */ + public ListenerData(NotificationListener listener, + NotificationFilter filter, Object passback) + { + this.listener = listener; + this.filter = filter; + this.passback = passback; + } + + /** + * Returns the listener. + * + * @return the listener. + */ + public NotificationListener getListener() + { + return listener; + } + + /** + * Returns the filter. + * + * @return the filter. + */ + public NotificationFilter getFilter() + { + return filter; + } + + /** + * Returns the passback object. + * + * @return the passback object. + */ + public Object getPassback() + { + return passback; + } + + /** + * Returns true if the supplied object is an instance of + * {@link ListenerData} and has the same listener, filter + * and passback object. + * + * @param obj the object to check. + * @return true if obj is equal to this. + */ + public boolean equals(Object obj) + { + if (obj instanceof ListenerData) + { + ListenerData data = (ListenerData) obj; + return (data.getListener() == listener && + data.getFilter() == filter && + data.getPassback() == passback); + } + return false; + } + +} diff --git a/libjava/classpath/gnu/javax/management/Server.java b/libjava/classpath/gnu/javax/management/Server.java new file mode 100644 index 000000000..50252d4dd --- /dev/null +++ b/libjava/classpath/gnu/javax/management/Server.java @@ -0,0 +1,2233 @@ +/* Server.java -- A GNU Classpath management server. + 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.management; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectStreamClass; +import java.io.StreamCorruptedException; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.ConcurrentHashMap; + +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.AttributeNotFoundException; +import javax.management.BadAttributeValueExpException; +import javax.management.BadBinaryOpValueExpException; +import javax.management.BadStringOperationException; +import javax.management.DynamicMBean; +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.IntrospectionException; +import javax.management.InvalidApplicationException; +import javax.management.InvalidAttributeValueException; +import javax.management.ListenerNotFoundException; +import javax.management.MalformedObjectNameException; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.MBeanPermission; +import javax.management.MBeanRegistration; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServer; +import javax.management.MBeanServerDelegate; +import javax.management.MBeanServerNotification; +import javax.management.MBeanTrustPermission; +import javax.management.NotCompliantMBeanException; +import javax.management.Notification; +import javax.management.NotificationBroadcaster; +import javax.management.NotificationEmitter; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.OperationsException; +import javax.management.QueryExp; +import javax.management.ReflectionException; +import javax.management.RuntimeOperationsException; +import javax.management.StandardMBean; + +import javax.management.loading.ClassLoaderRepository; + +/** + * This class provides an {@link javax.management.MBeanServer} + * implementation for GNU Classpath. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public class Server + implements MBeanServer +{ + + /** + * The name of the delegate bean. + */ + private static final ObjectName DELEGATE_NAME; + + /** + * The registered beans, represented as a map of + * {@link javax.management.ObjectName}s to + * {@link gnu.javax.management.Server.ServerInfo}s. + */ + private final ConcurrentHashMap beans = + new ConcurrentHashMap(); + + /** + * The default domain. + */ + private final String defaultDomain; + + /** + * The outer server. + */ + private final MBeanServer outer; + + /** + * The class loader repository. + */ + private ClassLoaderRepository repository; + + /** + * The map of listener delegates to the true + * listener. We wrap this in an inner class + * to delay initialisation until a listener + * is actually added. + */ + private static class LazyListenersHolder + { + private static final Map listeners = + new ConcurrentHashMap(); + } + + /** + * An MBean that emits notifications when an MBean is registered and + * unregistered with this server. + * + */ + private final MBeanServerDelegate delegate; + + /** + * Provides sequencing for notifications about registrations. + */ + private static final AtomicLong sequenceNumber = new AtomicLong(1); + + /** + * Initialise the delegate name. + */ + static + { + try + { + DELEGATE_NAME = + new ObjectName("JMImplementation:type=MBeanServerDelegate"); + } + catch (MalformedObjectNameException e) + { + throw (Error) + (new InternalError("Failed to construct " + + "the delegate's object name.").initCause(e)); + } + } + + /** + * Constructs a new management server using the specified + * default domain, delegate bean and outer server. + * + * @param defaultDomain the default domain to use for beans constructed + * with no specified domain. + * @param outer an {@link javax.management.MBeanServer} to pass + * to beans implementing the {@link MBeanRegistration} + * interface, or null if this + * should be passed. + * @param delegate the delegate bean for this server. + */ + public Server(String defaultDomain, MBeanServer outer, + MBeanServerDelegate delegate) + { + this.defaultDomain = defaultDomain; + this.outer = outer; + this.delegate = delegate; + try + { + registerMBean(delegate, DELEGATE_NAME); + } + catch (InstanceAlreadyExistsException e) + { + throw (Error) + (new InternalError("The delegate bean is " + + "already registered.").initCause(e)); + } + catch (MBeanRegistrationException e) + { + throw (Error) + (new InternalError("The delegate bean's preRegister " + + "methods threw an exception.").initCause(e)); + } + catch (NotCompliantMBeanException e) + { + throw (Error) + (new InternalError("The delegate bean is " + + "not compliant.").initCause(e)); + } + } + + /** + * Checks for the necessary security privileges to perform an + * operation. + * + * @param name the name of the bean being accessed. + * @param member the name of the operation or attribute being + * accessed, or null if one is not + * involved. + * @param action the action being performed. + * @throws SecurityException if the action is denied. + */ + private void checkSecurity(ObjectName name, String member, + String action) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + try + { + MBeanInfo info = null; + if (name != null) + { + Object bean = getBean(name); + Method method = bean.getClass().getMethod("getMBeanInfo"); + info = (MBeanInfo) method.invoke(bean); + } + sm.checkPermission(new MBeanPermission((info == null) ? + null : info.getClassName(), + member, name, action)); + } + catch (InstanceNotFoundException e) + { + throw (Error) + (new InternalError("Failed to get bean.").initCause(e)); + } + catch (NoSuchMethodException e) + { + throw (Error) + (new InternalError("Failed to get bean info.").initCause(e)); + } + catch (IllegalAccessException e) + { + throw (Error) + (new InternalError("Failed to get bean info.").initCause(e)); + } + catch (IllegalArgumentException e) + { + throw (Error) + (new InternalError("Failed to get bean info.").initCause(e)); + } + catch (InvocationTargetException e) + { + throw (Error) + (new InternalError("Failed to get bean info.").initCause(e)); + } + } + + /** + * Retrieves the specified bean. + * + * @param name the name of the bean. + * @return the bean. + * @throws InstanceNotFoundException if the name of the management bean + * could not be resolved. + */ + private Object getBean(ObjectName name) + throws InstanceNotFoundException + { + ServerInfo bean = beans.get(name); + if (bean == null) + throw new InstanceNotFoundException("The bean, " + name + + ", was not found."); + return bean.getObject(); + } + + /** + * Registers the supplied listener with the specified management + * bean. Notifications emitted by the management bean are forwarded + * to the listener via the server, which will convert an MBean + * references in the source to a portable {@link ObjectName} + * instance. The notification is otherwise unchanged. + * + * @param name the name of the management bean with which the listener + * should be registered. + * @param listener the listener which will handle notifications from + * the bean. + * @param filter the filter to apply to incoming notifications, or + * null if no filtering should be applied. + * @param passback an object to be passed to the listener when a + * notification is emitted. + * @throws InstanceNotFoundException if the name of the management bean + * could not be resolved. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, name, + * "addNotificationListener")}. + * @see #removeNotificationListener(ObjectName, NotificationListener) + * @see #removeNotificationListener(ObjectName, NotificationListener, + * NotificationFilter, Object) + * @see NotificationBroadcaster#addNotificationListener(NotificationListener, + * NotificationFilter, + * Object) + */ + public void addNotificationListener(ObjectName name, NotificationListener listener, + NotificationFilter filter, Object passback) + throws InstanceNotFoundException + { + Object bean = getBean(name); + checkSecurity(name, null, "addNotificationListener"); + if (bean instanceof NotificationBroadcaster) + { + NotificationBroadcaster bbean = (NotificationBroadcaster) bean; + NotificationListener indirection = new ServerNotificationListener(bean, name, + listener); + bbean.addNotificationListener(indirection, filter, passback); + LazyListenersHolder.listeners.put(listener, indirection); + } + } + + /** + *

    + * Registers the supplied listener with the specified management + * bean. Notifications emitted by the management bean are forwarded + * to the listener via the server, which will convert any MBean + * references in the source to portable {@link ObjectName} + * instances. The notification is otherwise unchanged. + *

    + *

    + * The listener that receives notifications will be the one that is + * registered with the given name at the time this method is called. + * Even if it later unregisters and ceases to use that name, it will + * still receive notifications. + *

    + * + * @param name the name of the management bean with which the listener + * should be registered. + * @param listener the name of the listener which will handle + * notifications from the bean. + * @param filter the filter to apply to incoming notifications, or + * null if no filtering should be applied. + * @param passback an object to be passed to the listener when a + * notification is emitted. + * @throws InstanceNotFoundException if the name of the management bean + * could not be resolved. + * @throws RuntimeOperationsException if the bean associated with the given + * object name is not a + * {@link NotificationListener}. This + * exception wraps an + * {@link IllegalArgumentException}. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, name, + * "addNotificationListener")}. + * @see #removeNotificationListener(ObjectName, NotificationListener) + * @see #removeNotificationListener(ObjectName, NotificationListener, + * NotificationFilter, Object) + * @see NotificationBroadcaster#addNotificationListener(NotificationListener, + * NotificationFilter, + * Object) + */ + public void addNotificationListener(ObjectName name, ObjectName listener, + NotificationFilter filter, Object passback) + throws InstanceNotFoundException + { + Object lbean = getBean(listener); + if (!(lbean instanceof NotificationListener)) + { + RuntimeException e = + new IllegalArgumentException("The supplied listener name does not " + + "correspond to a notification listener."); + throw new RuntimeOperationsException(e); + } + addNotificationListener(name, ((NotificationListener) lbean), filter, passback); + } + + /** + *

    + * Instantiates a new instance of the specified management bean + * using the default constructor and registers it with the server + * under the supplied name. The class is loaded using the + * {@link javax.management.loading.ClassLoaderRepository default + * loader repository} of the server. + *

    + *

    + * If the name supplied is null, then the bean is + * expected to implement the {@link MBeanRegistration} interface. + * The {@link MBeanRegistration#preRegister preRegister} method + * of this interface will be used to obtain the name in this case. + *

    + *

    + * This method is equivalent to calling {@link + * #createMBean(String, ObjectName, Object[], String[]) + * createMBean(className, name, (Object[]) null, + * (String[]) null)} with null parameters + * and signature. + *

    + * + * @param className the class of the management bean, of which + * an instance should be created. + * @param name the name to register the new bean with. + * @return an {@link ObjectInstance} containing the {@link ObjectName} + * and Java class name of the created instance. + * @throws ReflectionException if an exception occurs in creating + * an instance of the bean. + * @throws InstanceAlreadyExistsException if a matching instance + * already exists. + * @throws MBeanRegistrationException if an exception occurs in + * calling the preRegister + * method. + * @throws MBeanException if the bean's constructor throws an exception. + * @throws NotCompliantMBeanException if the created bean is not + * compliant with the JMX specification. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * null class name or object + * name or if the object name is a pattern. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply the + * use of the instantiate + * and registerMBean methods. + * @see #createMBean(String, ObjectName, Object[], String[]) + */ + public ObjectInstance createMBean(String className, ObjectName name) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException + { + return createMBean(className, name, (Object[]) null, (String[]) null); + } + + /** + *

    + * Instantiates a new instance of the specified management bean + * using the given constructor and registers it with the server + * under the supplied name. The class is loaded using the + * {@link javax.management.loading.ClassLoaderRepository default + * loader repository} of the server. + *

    + *

    + * If the name supplied is null, then the bean is + * expected to implement the {@link MBeanRegistration} interface. + * The {@link MBeanRegistration#preRegister preRegister} method + * of this interface will be used to obtain the name in this case. + *

    + * + * @param className the class of the management bean, of which + * an instance should be created. + * @param name the name to register the new bean with. + * @param params the parameters for the bean's constructor. + * @param sig the signature of the constructor to use. + * @return an {@link ObjectInstance} containing the {@link ObjectName} + * and Java class name of the created instance. + * @throws ReflectionException if an exception occurs in creating + * an instance of the bean. + * @throws InstanceAlreadyExistsException if a matching instance + * already exists. + * @throws MBeanRegistrationException if an exception occurs in + * calling the preRegister + * method. + * @throws MBeanException if the bean's constructor throws an exception. + * @throws NotCompliantMBeanException if the created bean is not + * compliant with the JMX specification. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * null class name or object + * name or if the object name is a pattern. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply the + * use of the instantiate + * and registerMBean methods. + */ + public ObjectInstance createMBean(String className, ObjectName name, + Object[] params, String[] sig) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException + { + return registerMBean(instantiate(className, params, sig), name); + } + + /** + *

    + * Instantiates a new instance of the specified management bean + * using the default constructor and registers it with the server + * under the supplied name. The class is loaded using the + * given class loader. If this argument is null, + * then the same class loader as was used to load the server + * is used. + *

    + *

    + * If the name supplied is null, then the bean is + * expected to implement the {@link MBeanRegistration} interface. + * The {@link MBeanRegistration#preRegister preRegister} method + * of this interface will be used to obtain the name in this case. + *

    + *

    + * This method is equivalent to calling {@link + * #createMBean(String, ObjectName, ObjectName, Object[], String) + * createMBean(className, name, loaderName, (Object[]) null, + * (String) null)} with null parameters + * and signature. + *

    + * + * @param className the class of the management bean, of which + * an instance should be created. + * @param name the name to register the new bean with. + * @param loaderName the name of the class loader. + * @return an {@link ObjectInstance} containing the {@link ObjectName} + * and Java class name of the created instance. + * @throws ReflectionException if an exception occurs in creating + * an instance of the bean. + * @throws InstanceAlreadyExistsException if a matching instance + * already exists. + * @throws MBeanRegistrationException if an exception occurs in + * calling the preRegister + * method. + * @throws MBeanException if the bean's constructor throws an exception. + * @throws NotCompliantMBeanException if the created bean is not + * compliant with the JMX specification. + * @throws InstanceNotFoundException if the specified class loader is not + * registered with the server. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * null class name or object + * name or if the object name is a pattern. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply the + * use of the instantiate + * and registerMBean methods. + * @see #createMBean(String, ObjectName, ObjectName, Object[], String[]) + */ + public ObjectInstance createMBean(String className, ObjectName name, + ObjectName loaderName) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, InstanceNotFoundException + { + return createMBean(className, name, loaderName, (Object[]) null, + (String[]) null); + } + + /** + *

    + * Instantiates a new instance of the specified management bean + * using the given constructor and registers it with the server + * under the supplied name. The class is loaded using the + * given class loader. If this argument is null, + * then the same class loader as was used to load the server + * is used. + *

    + *

    + * If the name supplied is null, then the bean is + * expected to implement the {@link MBeanRegistration} interface. + * The {@link MBeanRegistration#preRegister preRegister} method + * of this interface will be used to obtain the name in this case. + *

    + * + * @param className the class of the management bean, of which + * an instance should be created. + * @param name the name to register the new bean with. + * @param loaderName the name of the class loader. + * @param params the parameters for the bean's constructor. + * @param sig the signature of the constructor to use. + * @return an {@link ObjectInstance} containing the {@link ObjectName} + * and Java class name of the created instance. + * @throws ReflectionException if an exception occurs in creating + * an instance of the bean. + * @throws InstanceAlreadyExistsException if a matching instance + * already exists. + * @throws MBeanRegistrationException if an exception occurs in + * calling the preRegister + * method. + * @throws MBeanException if the bean's constructor throws an exception. + * @throws NotCompliantMBeanException if the created bean is not + * compliant with the JMX specification. + * @throws InstanceNotFoundException if the specified class loader is not + * registered with the server. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * null class name or object + * name or if the object name is a pattern. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply the + * use of the instantiate + * and registerMBean methods. + */ + public ObjectInstance createMBean(String className, ObjectName name, + ObjectName loaderName, Object[] params, + String[] sig) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, InstanceNotFoundException + { + return registerMBean(instantiate(className, loaderName, params, sig), + name); + } + + /** + * Deserializes a byte array using the class loader of the specified + * management bean as its context. + * + * @param name the name of the bean whose class loader should be used. + * @param data the byte array to be deserialized. + * @return the deserialized object stream. + * @deprecated {@link #getClassLoaderFor(ObjectName)} should be used + * to obtain the class loader of the bean, which can then + * be used to perform deserialization in the user's code. + * @throws InstanceNotFoundException if the specified bean is not + * registered with the server. + * @throws OperationsException if any I/O error is thrown by the + * deserialization process. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, name, + * "getClassLoaderFor") + */ + public ObjectInputStream deserialize(ObjectName name, byte[] data) + throws InstanceNotFoundException, OperationsException + { + try + { + return new ServerInputStream(new ByteArrayInputStream(data), + getClassLoaderFor(name)); + } + catch (IOException e) + { + throw new OperationsException("An I/O error occurred: " + e); + } + } + + /** + * Deserializes a byte array using the same class loader for its context + * as was used to load the given class. This class loader is obtained by + * loading the specified class using the {@link + * javax.management.loading.ClassLoaderRepository Class Loader Repository} + * and then using the class loader of the resulting {@link Class} instance. + * + * @param name the name of the class which should be loaded to obtain the + * class loader. + * @param data the byte array to be deserialized. + * @return the deserialized object stream. + * @deprecated {@link #getClassLoaderRepository} should be used + * to obtain the class loading repository, which can then + * be used to obtain the {@link Class} instance and deserialize + * the array using its class loader. + * @throws OperationsException if any I/O error is thrown by the + * deserialization process. + * @throws ReflectionException if an error occurs in obtaining the + * {@link Class} instance. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(null, null, null, + * "getClassLoaderRepository") + */ + public ObjectInputStream deserialize(String name, byte[] data) + throws OperationsException, ReflectionException + { + try + { + Class c = getClassLoaderRepository().loadClass(name); + return new ServerInputStream(new ByteArrayInputStream(data), + c.getClassLoader()); + } + catch (IOException e) + { + throw new OperationsException("An I/O error occurred: " + e); + } + catch (ClassNotFoundException e) + { + throw new ReflectionException(e, "The class could not be found."); + } + } + + /** + * Deserializes a byte array using the same class loader for its context + * as was used to load the given class. The name of the class loader to + * be used is supplied, and may be null if the server's + * class loader should be used instead. + * + * @param name the name of the class which should be loaded to obtain the + * class loader. + * @param loader the name of the class loader to use, or null + * if the class loader of the server should be used. + * @param data the byte array to be deserialized. + * @return the deserialized object stream. + * @deprecated {@link #getClassLoader(ObjectName} can be used to obtain + * the named class loader and deserialize the array. + * @throws InstanceNotFoundException if the specified class loader is not + * registered with the server. + * @throws OperationsException if any I/O error is thrown by the + * deserialization process. + * @throws ReflectionException if an error occurs in obtaining the + * {@link Class} instance. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, loader, + * "getClassLoader") + */ + public ObjectInputStream deserialize(String name, ObjectName loader, byte[] data) + throws InstanceNotFoundException, ReflectionException, + OperationsException + { + try + { + Class c = getClassLoader(loader).loadClass(name); + return new ServerInputStream(new ByteArrayInputStream(data), + c.getClassLoader()); + } + catch (IOException e) + { + throw new OperationsException("An I/O error occurred: " + e); + } + catch (ClassNotFoundException e) + { + throw new ReflectionException(e, "The class could not be found."); + } + } + + /** + * Returns the value of the supplied attribute from the specified + * management bean. + * + * @param bean the bean to retrieve the value from. + * @param name the name of the attribute to retrieve. + * @return the value of the attribute. + * @throws AttributeNotFoundException if the attribute could not be + * accessed from the bean. + * @throws MBeanException if the management bean's accessor throws + * an exception. + * @throws InstanceNotFoundException if the bean can not be found. + * @throws ReflectionException if an exception was thrown in trying + * to invoke the bean's accessor. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * null bean or attribute + * name. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, name, bean, + * "getAttribute")}. + * @see DynamicMBean#getAttribute(String) + */ + public Object getAttribute(ObjectName bean, String name) + throws MBeanException, AttributeNotFoundException, + InstanceNotFoundException, ReflectionException + { + if (bean == null || name == null) + { + RuntimeException e = + new IllegalArgumentException("One of the supplied arguments was null."); + throw new RuntimeOperationsException(e); + } + Object abean = getBean(bean); + checkSecurity(bean, name, "getAttribute"); + if (abean instanceof DynamicMBean) + return ((DynamicMBean) abean).getAttribute(name); + else + try + { + return new StandardMBean(abean, null).getAttribute(name); + } + catch (NotCompliantMBeanException e) + { + throw (Error) + (new InternalError("Failed to create dynamic bean.").initCause(e)); + } + } + + + /** + * Returns the values of the named attributes from the specified + * management bean. + * + * @param bean the bean to retrieve the value from. + * @param names the names of the attributes to retrieve. + * @return the values of the attributes. + * @throws InstanceNotFoundException if the bean can not be found. + * @throws ReflectionException if an exception was thrown in trying + * to invoke the bean's accessor. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * null bean or attribute + * name. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, bean, + * "getAttribute")}. Additionally, + * for an attribute name, n, the + * caller's permission must imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, n, bean, + * "getAttribute")} or that attribute will + * not be included. + * + * @see DynamicMBean#getAttributes(String[]) + */ + public AttributeList getAttributes(ObjectName bean, String[] names) + throws InstanceNotFoundException, ReflectionException + { + if (bean == null || names == null) + { + RuntimeException e = + new IllegalArgumentException("One of the supplied arguments was null."); + throw new RuntimeOperationsException(e); + } + Object abean = getBean(bean); + checkSecurity(bean, null, "getAttribute"); + AttributeList list = new AttributeList(names.length); + for (int a = 0; a < names.length; ++a) + { + if (names[a] == null) + { + RuntimeException e = + new IllegalArgumentException("Argument " + a + " was null."); + throw new RuntimeOperationsException(e); + } + checkSecurity(bean, names[a], "getAttribute"); + try + { + Object value; + if (abean instanceof DynamicMBean) + value = ((DynamicMBean) abean).getAttribute(names[a]); + else + try + { + value = new StandardMBean(abean, null).getAttribute(names[a]); + } + catch (NotCompliantMBeanException e) + { + throw (Error) + (new InternalError("Failed to create dynamic bean.").initCause(e)); + } + list.add(new Attribute(names[a], value)); + } + catch (AttributeNotFoundException e) + { + /* Ignored */ + } + catch (MBeanException e) + { + /* Ignored */ + } + } + return list; + } + + + /** + * Returns the specified class loader. If the specified value is + * null, then the class loader of the server will be + * returned. If l is the requested class loader, + * and r is the actual class loader returned, then + * either l and r will be identical, + * or they will at least return the same class from + * {@link ClassLoader#loadClass(String)} for any given string. + * They may not be identical due to one or the other + * being wrapped in another class loader (e.g. for security). + * + * @param name the name of the class loader to return. + * @return the class loader. + * @throws InstanceNotFoundException if the class loader can not + * be found. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, name, + * "getClassLoader") + */ + public ClassLoader getClassLoader(ObjectName name) + throws InstanceNotFoundException + { + if (name == null) + { + checkSecurity(null, null, "getClassLoader"); + return getClass().getClassLoader(); + } + Object bean = getBean(name); + checkSecurity(name, null, "getClassLoader"); + return (ClassLoader) bean; + } + + /** + * Returns the class loader of the specified management bean. If + * l is the requested class loader, and r + * is the actual class loader returned, then either l + * and r will be identical, or they will at least + * return the same class from {@link ClassLoader#loadClass(String)} + * for any given string. They may not be identical due to one or + * the other being wrapped in another class loader (e.g. for + * security). + * + * @param name the name of the bean whose class loader should be + * returned. + * @return the class loader. + * @throws InstanceNotFoundException if the bean is not registered + * with the server. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, name, + * "getClassLoaderFor") + */ + public ClassLoader getClassLoaderFor(ObjectName name) + throws InstanceNotFoundException + { + Object bean = getBean(name); + checkSecurity(name, null, "getClassLoaderFor"); + return bean.getClass().getClassLoader(); + } + + /** + * Returns the class loader repository used by this server. + * + * @return the class loader repository. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(null, null, null, + * "getClassLoaderRepository") + */ + public ClassLoaderRepository getClassLoaderRepository() + { + return repository; + } + + /** + * Returns the default domain this server applies to beans that have + * no specified domain. + * + * @return the default domain. + */ + public String getDefaultDomain() + { + return defaultDomain; + } + + /** + * Returns an array containing all the domains used by beans registered + * with this server. The ordering of the array is undefined. + * + * @return the list of domains. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(null, null, name, + * "getDomains")}. Additionally, + * for an domain, d, the + * caller's permission must imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(null, null, + * new ObjectName("d:x=x"), "getDomains")} + * or that domain will not be included. Note + * that "x=x" is an arbitrary key-value pair + * provided to satisfy the constructor. + * @see ObjectName#getDomain() + */ + public String[] getDomains() + { + checkSecurity(null, null, "getDomains"); + Set domains = new HashSet(); + Iterator iterator = beans.keySet().iterator(); + while (iterator.hasNext()) + { + String d = iterator.next().getDomain(); + try + { + checkSecurity(new ObjectName(d + ":x=x"), null, "getDomains"); + domains.add(d); + } + catch (MalformedObjectNameException e) + { + /* Ignored */ + } + } + return domains.toArray(new String[domains.size()]); + } + + /** + * Returns the number of management beans registered with this server. + * This may be less than the real number if the caller's access is + * restricted. + * + * @return the number of registered beans. + */ + public Integer getMBeanCount() + { + return Integer.valueOf(beans.size()); + } + + /** + * Returns information on the given management bean. + * + * @param name the name of the management bean. + * @return an instance of {@link MBeanInfo} for the bean. + * @throws IntrospectionException if an exception occurs in examining + * the bean. + * @throws InstanceNotFoundException if the bean can not be found. + * @throws ReflectionException if an exception occurs when trying + * to invoke {@link DynamicMBean#getMBeanInfo()} + * on the bean. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, name, + * "getMBeanInfo")}. + * @see DynamicMBean#getMBeanInfo() + */ + public MBeanInfo getMBeanInfo(ObjectName name) + throws InstanceNotFoundException, IntrospectionException, + ReflectionException + { + Object bean = getBean(name); + checkSecurity(name, null, "getMBeanInfo"); + try + { + Method method = bean.getClass().getMethod("getMBeanInfo"); + return (MBeanInfo) method.invoke(bean); + } + catch (NoSuchMethodException e) + { + try + { + return new StandardMBean(bean, null).getMBeanInfo(); + } + catch (NotCompliantMBeanException ex) + { + throw new IntrospectionException("An error occurred in executing " + + "getMBeanInfo on the bean: " + ex + "."); + } + } + catch (IllegalAccessException e) + { + throw new ReflectionException(e, "Failed to call getMBeanInfo"); + } + catch (IllegalArgumentException e) + { + throw new ReflectionException(e, "Failed to call getMBeanInfo"); + } + catch (InvocationTargetException e) + { + throw new ReflectionException(e, "The method threw an exception"); + } + } + + /** + * Returns the {@link ObjectInstance} created for the specified + * management bean on registration. + * + * @param name the name of the bean. + * @return the corresponding {@link ObjectInstance} instance. + * @throws InstanceNotFoundException if the bean can not be found. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, name, + * "getObjectInstance") + * @see #createMBean(String, ObjectName) + */ + public ObjectInstance getObjectInstance(ObjectName name) + throws InstanceNotFoundException + { + ServerInfo bean = beans.get(name); + if (bean == null) + throw new InstanceNotFoundException("The bean, " + name + + ", was not found."); + return bean.getInstance(); + } + + /** + *

    + * Creates an instance of the specified class using the list of + * class loaders from the {@link + * javax.management.loading.ClassLoaderRepository Class Loader + * Repository}. The class should have a public constructor + * with no arguments. A reference to the new instance is returned, + * but the instance is not yet registered with the server. + *

    + *

    + * This method is equivalent to calling {@link + * #instantiate(String, Object[], String[]) + * instantiate(name, (Object[]) null, (String[]) null)} + * with null parameters and signature. + *

    + * + * @param name the name of the class of bean to be instantiated. + * @return an instance of the given class. + * @throws ReflectionException if an exception is thrown during + * loading the class or calling the + * constructor. + * @throws MBeanException if the constructor throws an exception. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * null name. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, null, + * "instantiate")}. + * @see #instantiate(String, Object[], String[]) + */ + public Object instantiate(String name) + throws ReflectionException, MBeanException + { + return instantiate(name, (Object[]) null, (String[]) null); + } + + /** + * Creates an instance of the specified class using the list of + * class loaders from the {@link + * javax.management.loading.ClassLoaderRepository Class Loader + * Repository}. The class should have a public constructor + * matching the supplied signature. A reference to the new + * instance is returned, but the instance is not yet + * registered with the server. + * + * @param name the name of the class of bean to be instantiated. + * @param params the parameters for the constructor. + * @param sig the signature of the constructor. + * @return an instance of the given class. + * @throws ReflectionException if an exception is thrown during + * loading the class or calling the + * constructor. + * @throws MBeanException if the constructor throws an exception. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * null name. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, null, + * "instantiate")}. + */ + public Object instantiate(String name, Object[] params, String[] sig) + throws ReflectionException, MBeanException + { + checkSecurity(null, null, "instantiate"); + if (name == null) + { + RuntimeException e = + new IllegalArgumentException("The name was null."); + throw new RuntimeOperationsException(e); + } + Class[] sigTypes = new Class[sig.length]; + for (int a = 0; a < sigTypes.length; ++a) + { + try + { + sigTypes[a] = repository.loadClass(sig[a]); + } + catch (ClassNotFoundException e) + { + throw new ReflectionException(e, "The class, " + sigTypes[a] + + ", in the method signature " + + "could not be loaded."); + } + } + try + { + Constructor cons = + repository.loadClass(name).getConstructor(sigTypes); + return cons.newInstance(params); + } + catch (ClassNotFoundException e) + { + throw new ReflectionException(e, "The class, " + name + + ", of the constructor " + + "could not be loaded."); + } + catch (NoSuchMethodException e) + { + throw new ReflectionException(e, "The method, " + name + + ", could not be found."); + } + catch (IllegalAccessException e) + { + throw new ReflectionException(e, "Failed to instantiate the object"); + } + catch (InstantiationException e) + { + throw new ReflectionException(e, "Failed to instantiate the object"); + } + catch (InvocationTargetException e) + { + throw new MBeanException((Exception) e.getCause(), "The constructor " + + name + " threw an exception"); + } + } + + /** + *

    + * Creates an instance of the specified class using the supplied + * class loader. If the class loader given is null, + * then the class loader of the server will be used. The class + * should have a public constructor with no arguments. A reference + * to the new instance is returned, but the instance is not yet + * registered with the server. + *

    + *

    + * This method is equivalent to calling {@link + * #instantiate(String, ObjectName, Object[], String[]) + * instantiate(name, loaderName, (Object[]) null, + * (String[]) null)} with null parameters + * and signature. + *

    + * + * @param name the name of the class of bean to be instantiated. + * @param loaderName the name of the class loader to use. + * @return an instance of the given class. + * @throws InstanceNotFoundException if the class loader is not + * registered with the server. + * @throws ReflectionException if an exception is thrown during + * loading the class or calling the + * constructor. + * @throws MBeanException if the constructor throws an exception. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * null name. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, null, + * "instantiate")}. + * @see #instantiate(String, Object[], String[]) + */ + public Object instantiate(String name, ObjectName loaderName) + throws InstanceNotFoundException, ReflectionException, + MBeanException + { + return instantiate(name, loaderName); + } + + /** + * Creates an instance of the specified class using the supplied + * class loader. If the class loader given is null, + * then the class loader of the server will be used. The class + * should have a public constructor matching the supplied + * signature. A reference to the new instance is returned, + * but the instance is not yet registered with the server. + * + * @param name the name of the class of bean to be instantiated. + * @param loaderName the name of the class loader to use. + * @param params the parameters for the constructor. + * @param sig the signature of the constructor. + * @return an instance of the given class. + * @throws InstanceNotFoundException if the class loader is not + * registered with the server. + * @throws ReflectionException if an exception is thrown during + * loading the class or calling the + * constructor. + * @throws MBeanException if the constructor throws an exception. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * null name. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, null, + * "instantiate")}. + */ + public Object instantiate(String name, ObjectName loaderName, + Object[] params, String[] sig) + throws InstanceNotFoundException, ReflectionException, + MBeanException + { + checkSecurity(null, null, "instantiate"); + if (name == null) + { + RuntimeException e = + new IllegalArgumentException("The name was null."); + throw new RuntimeOperationsException(e); + } + ClassLoader loader = getClassLoader(loaderName); + Class[] sigTypes = new Class[sig.length]; + for (int a = 0; a < sig.length; ++a) + { + try + { + sigTypes[a] = Class.forName(sig[a], true, loader); + } + catch (ClassNotFoundException e) + { + throw new ReflectionException(e, "The class, " + sig[a] + + ", in the method signature " + + "could not be loaded."); + } + } + try + { + Constructor cons = + Class.forName(name, true, loader).getConstructor(sigTypes); + return cons.newInstance(params); + } + catch (ClassNotFoundException e) + { + throw new ReflectionException(e, "The class, " + name + + ", of the constructor " + + "could not be loaded."); + } + catch (NoSuchMethodException e) + { + throw new ReflectionException(e, "The method, " + name + + ", could not be found."); + } + catch (IllegalAccessException e) + { + throw new ReflectionException(e, "Failed to instantiate the object"); + } + catch (InstantiationException e) + { + throw new ReflectionException(e, "Failed to instantiate the object"); + } + catch (InvocationTargetException e) + { + throw new MBeanException((Exception) e.getCause(), "The constructor " + + name + " threw an exception"); + } + } + + /** + * Invokes the supplied operation on the specified management + * bean. The class objects specified in the signature are loaded + * using the same class loader as was used for the management bean. + * + * @param bean the management bean whose operation should be invoked. + * @param name the name of the operation to invoke. + * @param params the parameters of the operation. + * @param sig the signature of the operation. + * @return the return value of the method. + * @throws InstanceNotFoundException if the bean can not be found. + * @throws MBeanException if the method invoked throws an exception. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * null name. + * @throws ReflectionException if an exception is thrown in invoking the + * method. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, name, bean, + * "invoke")}. + * @see DynamicMBean#invoke(String, Object[], String[]) + */ + public Object invoke(ObjectName bean, String name, Object[] params, String[] sig) + throws InstanceNotFoundException, MBeanException, + ReflectionException + { + if (bean == null) + { + RuntimeException e = + new IllegalArgumentException("The bean was null."); + throw new RuntimeOperationsException(e); + } + Object abean = getBean(bean); + checkSecurity(bean, name, "invoke"); + if (abean instanceof DynamicMBean) + return ((DynamicMBean) abean).invoke(name, params, sig); + else + try + { + return new StandardMBean(abean, null).invoke(name, params, sig); + } + catch (NotCompliantMBeanException e) + { + throw (Error) + (new InternalError("Failed to create dynamic bean.").initCause(e)); + } + } + + /** + *

    + * Returns true if the specified management bean is an instance + * of the supplied class. + *

    + *

    + * A bean, B, is an instance of a class, C, if either of the following + * conditions holds: + *

    + *
      + *
    • The class name in B's {@link MBeanInfo} is equal to the supplied + * name.
    • + *
    • Both the class of B and C were loaded by the same class loader, + * and B is assignable to C.
    • + *
    + * + * @param name the name of the management bean. + * @param className the name of the class to test if name is + * an instance of. + * @return true if either B is directly an instance of the named class, + * or B is assignable to the class, given that both it and B's + * current class were loaded using the same class loader. + * @throws InstanceNotFoundException if the bean can not be found. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, name, + * "isInstanceOf") + */ + public boolean isInstanceOf(ObjectName name, String className) + throws InstanceNotFoundException + { + Object bean = getBean(name); + checkSecurity(name, null, "isInstanceOf"); + MBeanInfo info; + if (bean instanceof DynamicMBean) + info = ((DynamicMBean) bean).getMBeanInfo(); + else + try + { + info = new StandardMBean(bean, null).getMBeanInfo(); + } + catch (NotCompliantMBeanException e) + { + throw (Error) + (new InternalError("Failed to create dynamic bean.").initCause(e)); + } + if (info.getClassName().equals(className)) + return true; + Class bclass = bean.getClass(); + try + { + Class oclass = Class.forName(className); + return (bclass.getClassLoader().equals(oclass.getClassLoader()) && + oclass.isAssignableFrom(bclass)); + } + catch (ClassNotFoundException e) + { + return false; + } + } + + /** + * Returns true if the specified management bean is registered with + * the server. + * + * @param name the name of the management bean. + * @return true if the bean is registered. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * null bean name. + */ + public boolean isRegistered(ObjectName name) + { + if (name == null) + { + RuntimeException e = + new IllegalArgumentException("The name was null."); + throw new RuntimeOperationsException(e); + } + return beans.containsKey(name); + } + + /** + *

    + * Returns a set of {@link ObjectInstance}s matching the specified + * criteria. The full set of beans registered with the server + * are passed through two filters: + *

    + *
      + *
    1. Pattern matching is performed using the supplied + * {@link ObjectName}.
    2. + *
    3. The supplied query expression is applied.
    4. + *
    + *

    + * If both the object name and the query expression are null, + * or the object name has no domain and no key properties, + * no filtering will be performed and all beans are returned. + *

    + * + * @param name an {@link ObjectName} to use as a filter. + * @param query a query expression to apply to each of the beans that match + * the given object name. + * @return a set of {@link ObjectInstance}s matching the filtered beans. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(null, null, name, + * "queryMBeans")}. Additionally, + * for an bean, b, the + * caller's permission must imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, b, name, + * "queryMBeans")} or that bean will + * not be included. Such an exception may also + * arise from the execution of the query, in which + * case that particular bean will again be excluded. + */ + public Set queryMBeans(ObjectName name, QueryExp query) + { + checkSecurity(name, null, "queryMBeans"); + Set results = new HashSet(); + for (Map.Entry entry : beans.entrySet()) + { + ObjectName nextName = entry.getKey(); + checkSecurity(name, nextName.toString(), "queryMBeans"); + try + { + if ((name == null || name.apply(nextName)) && + (query == null || query.apply(nextName))) + results.add(entry.getValue().getInstance()); + } + catch (BadStringOperationException e) + { + /* Ignored -- assume false result */ + } + catch (BadBinaryOpValueExpException e) + { + /* Ignored -- assume false result */ + } + catch (BadAttributeValueExpException e) + { + /* Ignored -- assume false result */ + } + catch (InvalidApplicationException e) + { + /* Ignored -- assume false result */ + } + } + return results; + } + + /** + *

    + * Returns a set of {@link ObjectName}s matching the specified + * criteria. The full set of beans registered with the server + * are passed through two filters: + *

    + *
      + *
    1. Pattern matching is performed using the supplied + * {@link ObjectName}.
    2. + *
    3. The supplied query expression is applied.
    4. + *
    + *

    + * If both the object name and the query expression are null, + * or the object name has no domain and no key properties, + * no filtering will be performed and all beans are returned. + *

    + * + * @param name an {@link ObjectName} to use as a filter. + * @param query a query expression to apply to each of the beans that match + * the given object name. + * @return a set of {@link ObjectName}s matching the filtered beans. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(null, null, name, + * "queryNames")}. Additionally, + * for an name, n, the + * caller's permission must imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, n, name, + * "queryNames")} or that name will + * not be included. Such an exception may also + * arise from the execution of the query, in which + * case that particular bean will again be excluded. + * Note that these permissions are implied if the + * queryMBeans permissions are available. + */ + public Set queryNames(ObjectName name, QueryExp query) + { + checkSecurity(name, null, "queryNames"); + Set results = new HashSet(); + for (ObjectName nextName : beans.keySet()) + { + checkSecurity(name, nextName.toString(), "queryNames"); + try + { + if ((name == null || name.apply(nextName)) && + (query == null || query.apply(nextName))) + results.add(nextName); + } + catch (BadStringOperationException e) + { + /* Ignored -- assume false result */ + } + catch (BadBinaryOpValueExpException e) + { + /* Ignored -- assume false result */ + } + catch (BadAttributeValueExpException e) + { + /* Ignored -- assume false result */ + } + catch (InvalidApplicationException e) + { + /* Ignored -- assume false result */ + } + } + return results; + } + + /** + * Registers the supplied instance with the server, using the specified + * {@link ObjectName}. If the name given is null, then + * the bean supplied is expected to implement the {@link MBeanRegistration} + * interface and provide the name via the + * {@link MBeanRegistration#preRegister preRegister} method + * of this interface. + * + * @param obj the object to register with the server. + * @param name the name under which to register the object, + * or null if the {@link MBeanRegistration} + * interface should be used. + * @return an {@link ObjectInstance} containing the supplied + * {@link ObjectName} along with the name of the bean's class. + * @throws InstanceAlreadyExistsException if a matching instance + * already exists. + * @throws MBeanRegistrationException if an exception occurs in + * calling the preRegister + * method. + * @throws NotCompliantMBeanException if the created bean is not + * compliant with the JMX specification. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * null object. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, name, + * "registerMBean")}. className + * here corresponds to the result of + * {@link MBeanInfo#getClassName()} for objects of + * this class. If this check succeeds, a check + * is also made on its + * {@link java.security.ProtectionDomain} to ensure + * it implies {@link MBeanTrustPermission(String) + * MBeanTrustPermission("register")}. + * The use of the {@link MBeanRegistration} interface + * results in another {@link MBeanPermission} check + * being made on the returned {@link ObjectName}. + */ + public ObjectInstance registerMBean(Object obj, ObjectName name) + throws InstanceAlreadyExistsException, MBeanRegistrationException, + NotCompliantMBeanException + { + SecurityManager sm = System.getSecurityManager(); + Class cl = obj.getClass(); + String className = cl.getName(); + if (sm != null) + { + sm.checkPermission(new MBeanPermission(className, null, name, + "registerMBean")); + if (!(cl.getProtectionDomain().implies(new MBeanTrustPermission("register")))) + throw new SecurityException("The protection domain of the object's class" + + "does not imply the trust permission," + + "register"); + } + if (obj == null) + { + RuntimeException e = + new IllegalArgumentException("The object was null."); + throw new RuntimeOperationsException(e); + } + MBeanRegistration register = null; + if (obj instanceof MBeanRegistration) + register = (MBeanRegistration) obj; + if (name == null && register == null) + { + RuntimeException e = + new IllegalArgumentException("The name was null and " + + "the bean does not implement " + + "MBeanRegistration."); + throw new RuntimeOperationsException(e); + } + if (register != null) + { + try + { + name = register.preRegister(this, name); + if (name == null) + { + RuntimeException e = + new NullPointerException("The name returned by " + + "MBeanRegistration.preRegister() " + + "was null"); + throw e; + } + if (sm != null) + sm.checkPermission(new MBeanPermission(className, null, name, + "registerMBean")); + } + catch (SecurityException e) + { + register.postRegister(Boolean.FALSE); + throw e; + } + catch (Exception e) + { + register.postRegister(Boolean.FALSE); + throw new MBeanRegistrationException(e, "Pre-registration failed."); + } + } + ObjectInstance obji = new ObjectInstance(name, className); + if (beans.putIfAbsent(name, new ServerInfo(obji, obj)) != null) + { + if (register != null) + register.postRegister(Boolean.FALSE); + throw new InstanceAlreadyExistsException(name + "is already registered."); + } + if (register != null) + register.postRegister(Boolean.TRUE); + notify(name, MBeanServerNotification.REGISTRATION_NOTIFICATION); + return obji; + } + + /** + * Removes the specified listener from the list of recipients + * of notifications from the supplied bean. This includes all + * combinations of filters and passback objects registered for + * this listener. For more specific removal of listeners, see + * {@link #removeNotificationListener(ObjectName, + * NotificationListener,NotificationFilter,Object)} + * + * @param name the name of the management bean from which the + * listener should be removed. + * @param listener the listener to remove. + * @throws InstanceNotFoundException if the bean can not be found. + * @throws ListenerNotFoundException if the specified listener + * is not registered with the bean. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, name, + * "removeNotificationListener")}. + * @see #addNotificationListener(NotificationListener, NotificationFilter, + * java.lang.Object) + * @see NotificationBroadcaster#removeNotificationListener(NotificationListener) + */ + public void removeNotificationListener(ObjectName name, + NotificationListener listener) + throws InstanceNotFoundException, ListenerNotFoundException + { + Object bean = getBean(name); + checkSecurity(name, null, "removeNotificationListener"); + if (bean instanceof NotificationBroadcaster) + { + NotificationBroadcaster bbean = (NotificationBroadcaster) bean; + bbean.removeNotificationListener(listener); + LazyListenersHolder.listeners.remove(listener); + } + } + + /** + * Removes the specified listener from the list of recipients + * of notifications from the supplied bean. Only the first instance with + * the supplied filter and passback object is removed. + * null is used as a valid value for these parameters, + * rather than as a way to remove all registration instances for + * the specified listener; for this behaviour instead, see + * {@link #removeNotificationListener(ObjectName, NotificationListener)}. + * + * @param name the name of the management bean from which the + * listener should be removed. + * @param listener the listener to remove. + * @param filter the filter of the listener to remove. + * @param passback the passback object of the listener to remove. + * @throws InstanceNotFoundException if the bean can not be found. + * @throws ListenerNotFoundException if the specified listener + * is not registered with the bean. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, name, + * "removeNotificationListener")}. + * @see #addNotificationListener(ObjectName, NotificationListener, + * NotificationFilter, Object) + * @see NotificationEmitter#removeNotificationListener(NotificationListener, + * NotificationFilter, + * Object) + */ + public void removeNotificationListener(ObjectName name, + NotificationListener listener, + NotificationFilter filter, + Object passback) + throws InstanceNotFoundException, ListenerNotFoundException + { + Object bean = getBean(name); + checkSecurity(name, null, "removeNotificationListener"); + if (bean instanceof NotificationEmitter) + { + NotificationEmitter bbean = (NotificationEmitter) bean; + bbean.removeNotificationListener(listener, filter, passback); + LazyListenersHolder.listeners.remove(listener); + } + } + + /** + * Removes the specified listener from the list of recipients + * of notifications from the supplied bean. This includes all + * combinations of filters and passback objects registered for + * this listener. For more specific removal of listeners, see + * {@link #removeNotificationListener(ObjectName, + * ObjectName,NotificationFilter,Object)} + * + * @param name the name of the management bean from which the + * listener should be removed. + * @param listener the name of the listener to remove. + * @throws InstanceNotFoundException if a name doesn't match a registered + * bean. + * @throws ListenerNotFoundException if the specified listener + * is not registered with the bean. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, name, + * "removeNotificationListener")}. + * @see #addNotificationListener(NotificationListener, NotificationFilter, + * java.lang.Object) + * @see NotificationBroadcaster#removeNotificationListener(NotificationListener) + */ + public void removeNotificationListener(ObjectName name, ObjectName listener) + throws InstanceNotFoundException, ListenerNotFoundException + { + Object lbean = getBean(listener); + if (!(lbean instanceof NotificationListener)) + { + RuntimeException e = + new IllegalArgumentException("The supplied listener name does not " + + "correspond to a notification listener."); + throw new RuntimeOperationsException(e); + } + removeNotificationListener(name, ((NotificationListener) lbean)); + } + + /** + * Removes the specified listener from the list of recipients + * of notifications from the supplied bean. Only the first instance with + * the supplied filter and passback object is removed. + * null is used as a valid value for these parameters, + * rather than as a way to remove all registration instances for + * the specified listener; for this behaviour instead, see + * {@link #removeNotificationListener(ObjectName, ObjectName)}. + * + * @param name the name of the management bean from which the + * listener should be removed. + * @param listener the name of the listener to remove. + * @param filter the filter of the listener to remove. + * @param passback the passback object of the listener to remove. + * @throws InstanceNotFoundException if a name doesn't match a registered + * bean. + * @throws ListenerNotFoundException if the specified listener + * is not registered with the bean. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, name, + * "removeNotificationListener")}. + * @see #addNotificationListener(ObjectName, NotificationListener, + * NotificationFilter, Object) + * @see NotificationEmitter#removeNotificationListener(NotificationListener, + * NotificationFilter, + * Object) + */ + public void removeNotificationListener(ObjectName name, + ObjectName listener, + NotificationFilter filter, + Object passback) + throws InstanceNotFoundException, ListenerNotFoundException + { + Object lbean = getBean(listener); + if (!(lbean instanceof NotificationListener)) + { + RuntimeException e = + new IllegalArgumentException("The supplied listener name does not " + + "correspond to a notification listener."); + throw new RuntimeOperationsException(e); + } + removeNotificationListener(name, ((NotificationListener) lbean), filter, + passback); + } + + /** + * Sets the value of the specified attribute of the supplied + * management bean. + * + * @param name the name of the management bean. + * @param attribute the attribute to set. + * @throws InstanceNotFoundException if the bean can not be found. + * @throws AttributeNotFoundException if the attribute does not + * correspond to an attribute + * of the bean. + * @throws InvalidAttributeValueException if the value is invalid + * for this particular + * attribute of the bean. + * @throws MBeanException if setting the attribute causes + * the bean to throw an exception (which + * becomes the cause of this exception). + * @throws ReflectionException if an exception occurred in trying + * to use the reflection interface + * to lookup the attribute. The + * thrown exception is the cause of + * this exception. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * null bean or attribute + * name. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, name, bean, + * "setAttribute")}. + * @see #getAttribute(ObjectName, String) + * @see DynamicMBean#setAttribute(Attribute) + */ + public void setAttribute(ObjectName name, Attribute attribute) + throws InstanceNotFoundException, AttributeNotFoundException, + InvalidAttributeValueException, MBeanException, + ReflectionException + { + if (attribute == null || name == null) + { + RuntimeException e = + new IllegalArgumentException("One of the supplied arguments was null."); + throw new RuntimeOperationsException(e); + } + Object bean = getBean(name); + checkSecurity(name, attribute.getName(), "setAttribute"); + if (bean instanceof DynamicMBean) + ((DynamicMBean) bean).setAttribute(attribute); + else + try + { + new StandardMBean(bean, null).setAttribute(attribute); + } + catch (NotCompliantMBeanException e) + { + throw (Error) + (new InternalError("Failed to create dynamic bean.").initCause(e)); + } + } + + /** + * Sets the value of each of the specified attributes + * of the supplied management bean to that specified by + * the {@link Attribute} object. The returned list contains + * the attributes that were set and their new values. + * + * @param name the name of the management bean. + * @param attributes the attributes to set. + * @return a list of the changed attributes. + * @throws InstanceNotFoundException if the bean can not be found. + * @throws ReflectionException if an exception occurred in trying + * to use the reflection interface + * to lookup the attribute. The + * thrown exception is the cause of + * this exception. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * null bean or attribute + * list. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, bean, + * "setAttribute")}. Additionally, + * for an attribute name, n, the + * caller's permission must imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, n, bean, + * "setAttribute")} or that attribute will + * not be included. + * @see #getAttributes(ObjectName, String[]) + * @see DynamicMBean#setAttributes(AttributeList) + */ + public AttributeList setAttributes(ObjectName name, AttributeList attributes) + throws InstanceNotFoundException, ReflectionException + { + if (name == null || attributes == null) + { + RuntimeException e = + new IllegalArgumentException("One of the supplied arguments was null."); + throw new RuntimeOperationsException(e); + } + Object abean = getBean(name); + checkSecurity(name, null, "setAttribute"); + AttributeList list = new AttributeList(attributes.size()); + Iterator it = attributes.iterator(); + while (it.hasNext()) + { + try + { + Attribute attrib = (Attribute) it.next(); + if (attrib == null) + { + RuntimeException e = + new IllegalArgumentException("An attribute was null."); + throw new RuntimeOperationsException(e); + } + checkSecurity(name, attrib.getName(), "setAttribute"); + if (abean instanceof DynamicMBean) + ((DynamicMBean) abean).setAttribute(attrib); + else + try + { + new StandardMBean(abean, null).setAttribute(attrib); + } + catch (NotCompliantMBeanException e) + { + throw (Error) + (new InternalError("Failed to create dynamic bean.").initCause(e)); + } + list.add(attrib); + } + catch (AttributeNotFoundException e) + { + /* Ignored */ + } + catch (InvalidAttributeValueException e) + { + /* Ignored */ + } + catch (MBeanException e) + { + /* Ignored */ + } + } + return list; + } + + /** + * Unregisters the specified management bean. Following this operation, + * the bean instance is no longer accessible from the server via this + * name. Prior to unregistering the bean, the + * {@link MBeanRegistration#preDeregister()} method will be called if + * the bean implements the {@link MBeanRegistration} interface. + * + * @param name the name of the management bean. + * @throws InstanceNotFoundException if the bean can not be found. + * @throws MBeanRegistrationException if an exception occurs in + * calling the preDeregister + * method. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * null bean name or a + * request being made to unregister the + * {@link MBeanServerDelegate} bean. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * MBeanPermission(className, null, name, + * "unregisterMBean")}. + */ + public void unregisterMBean(ObjectName name) + throws InstanceNotFoundException, MBeanRegistrationException + { + if (name == null) + { + RuntimeException e = + new IllegalArgumentException("The name was null."); + throw new RuntimeOperationsException(e); + } + if (name.equals(DELEGATE_NAME)) + { + RuntimeException e = + new IllegalArgumentException("The delegate can not be unregistered."); + throw new RuntimeOperationsException(e); + } + Object bean = getBean(name); + checkSecurity(name, null, "unregisterMBean"); + MBeanRegistration register = null; + if (bean instanceof MBeanRegistration) + { + register = (MBeanRegistration) bean; + try + { + register.preDeregister(); + } + catch (Exception e) + { + throw new MBeanRegistrationException(e, "Pre-deregistration failed."); + } + } + beans.remove(name); + notify(name, MBeanServerNotification.UNREGISTRATION_NOTIFICATION); + if (register != null) + register.postDeregister(); + } + + /** + * Notifies the delegate of beans being registered + * and unregistered. + * + * @param name the bean being registered. + * @param type the type of notification; + * {@code REGISTRATION_NOTIFICATION} or + * {@code UNREGISTRATION_NOTIFICATION}. + */ + private void notify(ObjectName name, String type) + { + delegate.sendNotification + (new MBeanServerNotification + (type, DELEGATE_NAME, sequenceNumber.getAndIncrement(), name)); + } + + /** + * Input stream which deserializes using the given classloader. + */ + private class ServerInputStream + extends ObjectInputStream + { + + private ClassLoader cl; + + public ServerInputStream(InputStream is, ClassLoader cl) + throws IOException, StreamCorruptedException + { + super(is); + this.cl = cl; + } + + protected Class resolveClass(ObjectStreamClass osc) + throws ClassNotFoundException, IOException + { + try + { + return Class.forName(osc.getName(), true, cl); + } + catch (ClassNotFoundException e) + { + return super.resolveClass(osc); + } + } + + } + + /** + * Holder for information on registered beans. + */ + private class ServerInfo + { + private ObjectInstance instance; + + private Object object; + + public ServerInfo(ObjectInstance instance, Object object) + { + this.instance = instance; + this.object = object; + } + + public Object getObject() + { + return object; + } + + public ObjectInstance getInstance() + { + return instance; + } + } + + /** + * Notification listener which removes direct references + * to beans. + */ + private class ServerNotificationListener + implements NotificationListener + { + + /** + * The bean from which notifications are emitted. + */ + Object bean; + + /** + * The {@link ObjectName} of the emitting bean. + */ + ObjectName name; + + /** + * The real {@link NotificationListener}. + */ + NotificationListener listener; + + /** + * Constructs a new {@link ServerNotificationListener} replacing + * occurrences of bean with its name. + * + * @param bean the bean emitting notifications. + * @param name the object name of the emitting bean. + * @param listener the listener events eventually reach. + */ + public ServerNotificationListener(Object bean, ObjectName name, + NotificationListener listener) + { + this.bean = bean; + this.name = name; + this.listener = listener; + } + + /** + * Replace a direct reference to bean with its + * object reference, if necessary, before calling the listener. + * + * @param notif the notification being emitted. + * @param handback an object that will be returned to the notification + * listener when an event occurs. + */ + public void handleNotification(Notification notif, Object handback) + { + if (notif.getSource() == bean) + notif.setSource(name); + listener.handleNotification(notif, handback); + } + + } + +} diff --git a/libjava/classpath/gnu/javax/management/Translator.java b/libjava/classpath/gnu/javax/management/Translator.java new file mode 100644 index 000000000..38d575aca --- /dev/null +++ b/libjava/classpath/gnu/javax/management/Translator.java @@ -0,0 +1,550 @@ +/* Translator.java -- Performs MXBean data type translation. + Copyright (C) 2007 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.management; + +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Proxy; +import java.lang.reflect.Type; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; +import java.util.SortedSet; + +import javax.management.JMX; +import javax.management.MBeanServerInvocationHandler; + +import javax.management.openmbean.ArrayType; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenMBeanParameterInfo; +import javax.management.openmbean.OpenMBeanParameterInfoSupport; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; + +/** + * Translates Java data types to their equivalent + * open data type, and vice versa, according to the + * {@link javax.management.MXBean} rules. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ +public final class Translator +{ + + /** + * Translates the input Java data types to the equivalent + * open data types. + * + * @param jtypes the Java types supplied as parameters. + * @param method the method that was called. + * @return the equivalent open types required by the {@link MXBean}. + * @throws Throwable if an exception is thrown in performing the + * conversion. + */ + public static final Object[] fromJava(Object[] jtypes, Method method) + throws Throwable + { + Type[] gtypes = method.getGenericParameterTypes(); + Object[] otypes = new Object[jtypes.length]; + for (int a = 0; a < jtypes.length; ++a) + otypes[a] = fromJava(jtypes[a], gtypes[a]); + return otypes; + } + + /** + * Translates the input Java data type to the equivalent + * open data type. + * + * @param jtype the Java type supplied as a parameter. + * @param type the type of the parameter. + * @return the equivalent open type required by the {@link MXBean}. + * @throws Throwable if an exception is thrown in performing the + * conversion. + */ + public static final Object fromJava(Object jtype, Type type) + throws Throwable + { + if (jtype == null) + return null; + Class jclass = jtype.getClass(); + if (OpenType.ALLOWED_CLASSNAMES_LIST.contains(jclass.getName())) + return jtype; + if (jclass.isArray()) + { + Class ctype = jclass.getComponentType(); + if (ctype.isPrimitive()) + return jtype; + if (OpenType.ALLOWED_CLASSNAMES_LIST.contains(ctype.getName())) + return jtype; + Object[] elems = (Object[]) jtype; + Object[] celems = new Object[elems.length]; + for (int a = 0; a < elems.length; ++a) + celems[a] = fromJava(elems[a], elems[a].getClass()); + return makeArraySpecific(celems); + } + String tName = getTypeName(type); + if (jtype instanceof List || jtype instanceof Set || + jtype instanceof SortedSet) + { + if (jtype instanceof SortedSet) + { + ParameterizedType ptype = (ParameterizedType) type; + Class elemClass = (Class) ptype.getActualTypeArguments()[0]; + if (!Comparable.class.isAssignableFrom(elemClass)) + throw new IllegalArgumentException(jtype + " has a " + + "non-comparable element " + + "type, " + elemClass); + if (((SortedSet) jtype).comparator() != null) + throw new IllegalArgumentException(jtype + " does not " + + "use natural ordering."); + } + Collection elems = (Collection) jtype; + int numElems = elems.size(); + Object[] celems = new Object[numElems]; + Iterator i = elems.iterator(); + for (int a = 0; a < numElems; ++a) + { + Object elem = i.next(); + celems[a] = fromJava(elem, elem.getClass()); + } + return makeArraySpecific(celems); + } + if (jtype instanceof Enum) + return ((Enum) jtype).name(); + if (jtype instanceof Map || jtype instanceof SortedMap) + { + int lparam = tName.indexOf("<"); + int comma = tName.indexOf(",", lparam); + int rparam = tName.indexOf(">", comma); + String key = tName.substring(lparam + 1, comma).trim(); + String value = tName.substring(comma + 1, rparam).trim(); + String typeName = null; + if (jtype instanceof Map) + typeName = "java.util.Map" + tName.substring(lparam); + else + { + Class keyClass = Class.forName(key); + if (!Comparable.class.isAssignableFrom(keyClass)) + throw new IllegalArgumentException(jtype + " has a " + + "non-comparable element " + + "type, " + keyClass); + if (((SortedMap) jtype).comparator() != null) + throw new IllegalArgumentException(jtype + " does not " + + "use natural ordering."); + typeName = "java.util.SortedMap" + tName.substring(lparam); + } + OpenType k = translate(key).getOpenType(); + OpenType v = translate(value).getOpenType(); + CompositeType rowType = new CompositeType(typeName, typeName, + new String[] { "key", "value" }, + new String[] { "Map key", "Map value"}, + new OpenType[] {k,v}); + TabularType tabType = new TabularType(typeName, typeName, rowType, + new String[]{"key"}); + TabularData data = new TabularDataSupport(tabType); + for (Map.Entry entry : ((Map) jtype).entrySet()) + { + try + { + data.put(new CompositeDataSupport(rowType, + new String[] { + "key", + "value" + }, + new Object[] { + entry.getKey(), + entry.getValue() + })); + } + catch (OpenDataException e) + { + throw (InternalError) (new InternalError("A problem occurred " + + "converting the map " + + "to a composite data " + + "structure.").initCause(e)); + } + } + return data; + } + if (JMX.isMXBeanInterface(jclass)) + { + try + { + MBeanServerInvocationHandler ih = (MBeanServerInvocationHandler) + Proxy.getInvocationHandler(jtype); + return ih.getObjectName(); + } + catch (IllegalArgumentException e) + { + throw new IllegalArgumentException("For a MXBean to be translated " + + "to an open type, it must be a " + + "proxy.", e); + } + catch (ClassCastException e) + { + throw new IllegalArgumentException("For a MXBean to be translated " + + "to an open type, it must have a " + + "MBeanServerInvocationHandler.", e); + } + } + /* FIXME: Handle other types */ + throw new IllegalArgumentException("The type, " + jtype + + ", is not convertible."); + } + + /** + * Translates the returned open data type to the value + * required by the interface. + * + * @param otype the open type returned by the method call. + * @param method the method that was called. + * @return the equivalent return type required by the interface. + * @throws Throwable if an exception is thrown in performing the + * conversion. + */ + public static final Object toJava(Object otype, Method method) + throws Throwable + { + Class returnType = method.getReturnType(); + if (returnType.isEnum()) + { + String ename = (String) otype; + Enum[] constants = (Enum[]) returnType.getEnumConstants(); + for (Enum c : constants) + if (c.name().equals(ename)) + return c; + } + if (List.class.isAssignableFrom(returnType)) + { + Object[] elems = (Object[]) otype; + List l = new ArrayList(elems.length); + for (Object elem : elems) + l.add(elem); + return l; + } + if (Map.class.isAssignableFrom(returnType)) + { + TabularData data = (TabularData) otype; + Map m = new HashMap(data.size()); + for (Object val : data.values()) + { + CompositeData vals = (CompositeData) val; + m.put(vals.get("key"), vals.get("value")); + } + return m; + } + try + { + Method m = returnType.getMethod("from", + new Class[] + { CompositeData.class }); + return m.invoke(null, (CompositeData) otype); + } + catch (NoSuchMethodException e) + { + /* Ignored; we expect this if this + isn't a from(CompositeData) class */ + } + return otype; + } + + /** + * Creates a new array which has the specific type + * used by the elements of the original {@link Object} + * array supplied. + * + * @param arr a series of elements in an {@link Object} + * array. + * @return the same elements in a new array of the specific + * type. + */ + private static final Object[] makeArraySpecific(Object[] arr) + { + Object[] rcelems = (Object[]) Array.newInstance(arr[0].getClass(), + arr.length); + System.arraycopy(arr, 0, rcelems, 0, arr.length); + return rcelems; + } + + /** + * Translates the name of a type into an equivalent + * {@link javax.management.openmbean.OpenMBeanParameterInfo} + * that describes it. + * + * @param type the type to describe. + * @return an instance of + * {@link javax.management.openmbean.OpenMBeanParameterInfo}, + * describing the translated type and limits of the given type. + * @throws OpenDataException if a type is not open. + */ + public static final OpenMBeanParameterInfo translate(String type) + throws OpenDataException + { + if (type.equals("boolean") || type.equals(Boolean.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.BOOLEAN, + null, + new Boolean[] { + Boolean.TRUE, + Boolean.FALSE + }); + if (type.equals("byte") || type.equals(Byte.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.BYTE, + null, + Byte.valueOf(Byte.MIN_VALUE), + Byte.valueOf(Byte.MAX_VALUE)); + if (type.equals("char") || type.equals(Character.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.CHARACTER, + null, + Character.valueOf(Character.MIN_VALUE), + Character.valueOf(Character.MAX_VALUE)); + if (type.equals("double") || type.equals(Double.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.DOUBLE, + null, + Double.valueOf(Double.MIN_VALUE), + Double.valueOf(Double.MAX_VALUE)); + if (type.equals("float") || type.equals(Float.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.FLOAT, + null, + Float.valueOf(Float.MIN_VALUE), + Float.valueOf(Float.MAX_VALUE)); + if (type.equals("int") || type.equals(Integer.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.INTEGER, + null, + Integer.valueOf(Integer.MIN_VALUE), + Integer.valueOf(Integer.MAX_VALUE)); + if (type.equals("long") || type.equals(Long.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.LONG, + null, + Long.valueOf(Long.MIN_VALUE), + Long.valueOf(Long.MAX_VALUE)); + if (type.equals("short") || type.equals(Short.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.SHORT, + null, + Short.valueOf(Short.MIN_VALUE), + Short.valueOf(Short.MAX_VALUE)); + if (type.equals(String.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.STRING); + if (type.equals("void")) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.VOID); + if (type.startsWith("java.util.Map")) + { + int lparam = type.indexOf("<"); + int comma = type.indexOf(",", lparam); + int rparam = type.indexOf(">", comma); + String key = type.substring(lparam + 1, comma).trim(); + OpenType k = translate(key).getOpenType(); + OpenType v = translate(type.substring(comma + 1, rparam).trim()).getOpenType(); + CompositeType ctype = new CompositeType(Map.class.getName(), Map.class.getName(), + new String[] { "key", "value" }, + new String[] { "Map key", "Map value"}, + new OpenType[] { k, v}); + TabularType ttype = new TabularType(key, key, ctype, + new String[] { "key" }); + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + ttype); + } + if (type.startsWith("java.util.List")) + { + int lparam = type.indexOf("<"); + int rparam = type.indexOf(">"); + OpenType e = translate(type.substring(lparam + 1, rparam).trim()).getOpenType(); + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + new ArrayType>(1, e) + ); + } + Class c; + try + { + c = Class.forName(type); + } + catch (ClassNotFoundException e) + { + throw (InternalError) + (new InternalError("The class for a type used in a management bean " + + "could not be loaded.").initCause(e)); + } + if (c.isEnum()) + { + Object[] values = c.getEnumConstants(); + String[] names = new String[values.length]; + for (int a = 0; a < values.length; ++a) + names[a] = values[a].toString(); + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.STRING, + null, names); + } + if (c.isArray()) + { + int depth; + for (depth = 0; c.getName().charAt(depth) == '['; ++depth) + ; + OpenType ot = getTypeFromClass(c.getComponentType()); + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + new ArrayType>(depth, ot) + ); + } + Method[] methods = c.getDeclaredMethods(); + List names = new ArrayList(); + List> types = new ArrayList>(); + for (int a = 0; a < methods.length; ++a) + { + String name = methods[a].getName(); + if (Modifier.isPublic(methods[a].getModifiers())) + { + if (name.startsWith("get")) + { + names.add(name.substring(3)); + types.add(getTypeFromClass(methods[a].getReturnType())); + } + else if (name.startsWith("is")) + { + names.add(name.substring(2)); + types.add(getTypeFromClass(methods[a].getReturnType())); + } + } + } + if (names.isEmpty()) + throw new OpenDataException("The type used does not have an open type translation."); + String[] fields = names.toArray(new String[names.size()]); + CompositeType ctype = new CompositeType(c.getName(), c.getName(), + fields, fields, + types.toArray(new OpenType[types.size()])); + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + ctype); + } + + /** + * Obtains the {@link javax.management.openmbean.OpenType} + * for a particular class. + * + * @param c the class to obtain the type for. + * @return the appropriate instance. + * @throws OpenDataException if the type is not open. + */ + private static final OpenType getTypeFromClass(Class c) + throws OpenDataException + { + return Translator.translate(c.getName()).getOpenType(); + } + + /** + *

    + * Returns the type name according to the rules described + * in {@link javax.management.MXBean}. Namely, for a type, + * {@code T}, {@code typename(T)} is computed as follows: + *

    + *
      + *
    • If T is non-generic and not an array, then the value + * of {@link java.lang.Class#getName()} is returned.
    • + *
    • If T is an array type, {@code{E[]}, then the type name + * is {@code typename(E)} followed by an occurrence + * of {@code '[]'} for each dimension.
    • + *
    • If T is a generic or parameterized type, the type name + * is composed of {@code typename(P)}, where {@code P} is the + * parameterized type name, followed by {@code '<'}, the resulting + * list of type names of the parameters after applying {@code typename} + * to each, separated by commas, and {@code '>'}.
    • + *
    + * + * @param type the type to return the type name of. + * @return the type name computed according to the rules above. + */ + private static final String getTypeName(Type type) + { + if (type instanceof Class) + { + Class c = (Class) type; + if (c.isArray()) + { + StringBuilder b = + new StringBuilder(c.getComponentType().getName()); + String normName = c.getName(); + for (int a = 0; a < normName.length(); ++a) + { + if (normName.charAt(a) == '[') + b.append("[]"); + else + break; + } + return b.toString(); + } + return c.getName(); + } + return type.toString(); + } + +} diff --git a/libjava/classpath/gnu/javax/naming/giop/ContextContinuation.java b/libjava/classpath/gnu/javax/naming/giop/ContextContinuation.java new file mode 100644 index 000000000..e952393cc --- /dev/null +++ b/libjava/classpath/gnu/javax/naming/giop/ContextContinuation.java @@ -0,0 +1,956 @@ +/* ContextContinuation.java -- handles corbaname: urls + 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.naming.giop; + +import gnu.CORBA.NamingService.Ext; +import gnu.CORBA.NamingService.NameTransformer; + +import java.util.Hashtable; + +import javax.naming.Binding; +import javax.naming.Context; +import javax.naming.ContextNotEmptyException; +import javax.naming.InvalidNameException; +import javax.naming.Name; +import javax.naming.NameAlreadyBoundException; +import javax.naming.NameClassPair; +import javax.naming.NameNotFoundException; +import javax.naming.NameParser; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.OperationNotSupportedException; +import javax.naming.directory.InvalidAttributesException; + +import org.omg.CORBA.ORB; +import org.omg.CORBA.portable.Delegate; +import org.omg.CORBA.portable.ObjectImpl; +import org.omg.CosNaming.BindingIteratorHolder; +import org.omg.CosNaming.BindingListHolder; +import org.omg.CosNaming.NameComponent; +import org.omg.CosNaming.NamingContext; +import org.omg.CosNaming.NamingContextExt; +import org.omg.CosNaming.NamingContextExtHelper; +import org.omg.CosNaming.NamingContextHelper; +import org.omg.CosNaming._NamingContextExtStub; +import org.omg.CosNaming._NamingContextStub; +import org.omg.CosNaming.NamingContextPackage.AlreadyBound; +import org.omg.CosNaming.NamingContextPackage.CannotProceed; +import org.omg.CosNaming.NamingContextPackage.InvalidName; +import org.omg.CosNaming.NamingContextPackage.NotFound; + +/** + * The context to represent the corba naming service. Being the naming service, + * the returned context supports creating the subcontexts, forwarding this task + * to the existing naming service. When listing bindings, it uses the + * {@link Context#BATCHSIZE} property to determine, how many bindings should + * be returned at once (the process is transparend) + * + * @author Audrius Meskauskas (audriusa@Bioinformatics.org) + */ +public class ContextContinuation implements Context +{ + /** + * This number of bindings will be requested from the naming server at once, + * while the subsequent bindings will be requested via binding iterator one by + * one. Use {@link Context#BATCHSIZE} to override the value of this constant. + */ + public int DEFAULT_BATCH_SIZE = 20; + + /** + * The actual CORBA naming service. + */ + NamingContextExt service; + + /** + * The object request broker, used to access the naming service. This field + * is only initialised when the context is constructed from the URL. + */ + ORB orb; + + /** + * The properties. + */ + Hashtable properties; + + /** + * The parent factory. + */ + GiopNamingServiceFactory factory; + + /** + * The name transformer to obtain the name from its string representation. The + * to_name method of the naming service is avoided as it may be remote and + * hence expensive. The conversion rules are standard and cannot be service + * specific. + */ + static NameTransformer transformer = new NameTransformer(); + + /** + * The batch size for list operations - how many to return at once. + */ + public final int howMany; + + /** + * Creates a new naming context that uses naming service, represented by the + * given CORBA object. + * + * @param nsObject + * the naming service object. It must be possible to narrow it into + * the NamingContextExt. + * @param props + * the environment table. + * @param anOrb + * the associated ORB. This reference is used during cleanup. + * @param aFactory + * parent factory. This reference is used during cleanup. + */ + public ContextContinuation(org.omg.CORBA.Object nsObject, + Hashtable props, ORB anOrb, + GiopNamingServiceFactory aFactory) + { + factory = aFactory; + orb = anOrb; + + Delegate delegate = ((ObjectImpl) nsObject)._get_delegate(); + + // If the IOR provides the IDL ID, we can check if our name + // service is old NamingContext or new NamingContextExt. + // Not all forms of the URL always provide the IDL id. + if (!nsObject._is_a(NamingContextExtHelper.id()) + && nsObject._is_a(NamingContextHelper.id())) + { + // We are surely working with the old version. + _NamingContextStub stub = new _NamingContextStub(); + stub._set_delegate(delegate); + // The Ext object will add the necessary extensions. + service = new Ext(stub); + } + else + { + // We expecte the service to be the NamingContextExt (this is true + // for both Sun's and our implementations). There is no easy way + // to check the version. + _NamingContextExtStub stub = new _NamingContextExtStub(); + stub._set_delegate(delegate); + service = stub; + } + properties = props; + howMany = getBatchSize(); + } + + /** + * Give the specified name for the specified object. The passed name must not + * be already bound to some other object. The components of the name are + * mapped into the components of the CORBA name. + * + * @param name + * the name that will be given to the object (in the scope of this + * context). + * @param obj + * the object being named. + * @throws NameAlreadyBoundException + * if this name is already used to name some object. + * @throws InvalidAttributesException + * if the object does not supply all required attributes. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void bind(Name name, Object obj) throws NamingException + { + try + { + org.omg.CORBA.Object object = (org.omg.CORBA.Object) obj; + service.bind(toGiop(name), object); + } + catch (ClassCastException e) + { + throw new NamingException(org.omg.CORBA.Object.class + " required "); + } + catch (InvalidName e) + { + throw new InvalidNameException(); + } + catch (AlreadyBound e) + { + throw new NameAlreadyBoundException(); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Give the specified name for the specified object. The passed name must not + * be already bound to some other object. + * + * @param name + * the name that will be given to the object (in the scope of this + * context). + * @param obj + * the object being named. + * @throws NameAlreadyBoundException + * if this name is already used to name some object. + * @throws InvalidAttributesException + * if the object does not supply all required attributes. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void bind(String name, Object obj) throws NamingException + { + try + { + org.omg.CORBA.Object object = (org.omg.CORBA.Object) obj; + service.bind(transformer.toName(name), object); + } + catch (ClassCastException e) + { + throw new NamingException(org.omg.CORBA.Object.class + " required "); + } + catch (InvalidName e) + { + throw new InvalidNameException(); + } + catch (AlreadyBound e) + { + throw new NameAlreadyBoundException(); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Releases all resources, associated with this context. The close() method + * can be called several times, but after it has been once invoked, it is not + * allowed to call any other method of this context. This method destroys + * the ORB, if we have one. + * + * @throws NamingException + */ + public void close() throws NamingException + { + if (orb != null && factory !=null) + { + factory.checkIfReferenced(orb); + } + } + + /** + * Not supported. + */ + public Name composeName(Name name, Name prefix) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported + */ + public String composeName(String name1, String name2) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Creates the new naming subcontext and binds it to the current (this) + * context. The returned object will wrap around the newly created CORBA + * subcontext + * + * @param subContext + * the name of the new context being created + * @return the newly created context, bound to the instance of the context on + * that the method has been called + * @throws NameAlreadyBoundException + * if this name is already bound + * @throws InvalidAttributesException + * if the creation of the new context requires the missing mandatory + * attributes + * @throws NamingException + */ + public Context createSubcontext(Name subContext) throws NamingException + { + try + { + org.omg.CORBA.Object subcontext = service.bind_new_context( + toGiop(subContext)); + Hashtable clonedProps = new Hashtable(); + clonedProps.putAll(properties); + + // Nulls are passed both for orb and factory, as the child contexts + // need not to do any cleanup. + return new ContextContinuation(subcontext, clonedProps, null, null); + } + catch (AlreadyBound e) + { + throw new NameAlreadyBoundException(); + } + catch (InvalidName e) + { + throw new InvalidNameException(); + } + catch (Exception ex) + { + throw new NamingException(ex.toString()); + } + } + + /** + * Creates the new naming subcontext and binds it to the current (this) + * context. The returned object will wrap around the newly created CORBA + * subcontext + * + * @param subContext + * the name of the new context being created + * @return the newly created context, bound to the instance of the context on + * that the method has been called + * @throws NameAlreadyBoundException + * if this name is already bound + * @throws InvalidAttributesException + * if the creation of the new context requires the missing mandatory + * attributes + * @throws NamingException + */ + public Context createSubcontext(String subContext) throws NamingException + { + try + { + org.omg.CORBA.Object subcontext = + service.bind_new_context(transformer.toName(subContext)); + Hashtable clonedProps = new Hashtable(); + clonedProps.putAll(properties); + + // Nulls are passed both for orb and factory, as the child contexts + // need not to do any cleanup. + return new ContextContinuation(subcontext, clonedProps, null, + null); + } + catch (AlreadyBound e) + { + throw new NameAlreadyBoundException(subContext); + } + catch (InvalidName e) + { + throw new InvalidNameException(subContext); + } + catch (Exception ex) + { + throw new NamingException(ex.toString()); + } + } + + /** + * Removes the naming subcontext from this naming context. Returns without + * action if such subcontext does not exist. The context being destroyed must + * be empty. + * + * @param subContext + * the name of the subcontext beig removed. + * @throws ContextNotEmptyException + * if the named context is not empty. + * @throws NamingException + */ + public void destroySubcontext(Name subContext) throws NamingException + { + unbind(subContext); + } + + /** + * Removes the naming subcontext from this naming context. Returns without + * action if such subcontext does not exist. The context being destroyed must + * be empty. + * + * @param subContext + * the name of the subcontext beig removed. + * @throws ContextNotEmptyException + * if the named context is not empty. + * @throws NamingException + */ + public void destroySubcontext(String subContext) throws NamingException + { + unbind(subContext); + } + + /** + * Returs the full name of this naming context. The returned string is not a + * JNDI composite name and should not be passed directly to the methods of the + * naming context. This implementation returns the IOR. + * + * @return the full name of this naming context, in its own namespace. + * @throws OperationNotSupportedException + * if the naming system, represented by this context, does not + * support the notation of the full name. + * @throws NamingException + */ + public String getNameInNamespace() throws NamingException + { + if (orb != null) + return orb.object_to_string(service); + else + { + try + { + ObjectImpl impl = (ObjectImpl) service; + return impl._orb().object_to_string(impl); + } + catch (ClassCastException e) + { + throw new UnsupportedOperationException(); + } + } + } + + /** + * Not supported. + */ + public NameParser getNameParser(Name name) throws NamingException + { + throw new UnsupportedOperationException(); + } + + /** + * Not supported. + */ + public NameParser getNameParser(String name) throws NamingException + { + throw new UnsupportedOperationException(); + } + + /** + * Creates and returns the enumeration over the name bindings that are present + * the given subcontext. The enumeration elements have the type of + * {@link NameClassPair}, providing also information about the class of the + * bound object. The behaviour in the case if the bindings are added or + * removed later is not defined. The contents of the subcontexts are not + * included. + * + * @param name + * the name of the subcontext + * @return the enumeration over the names, known for the given subcontext. + * @throws NamingException + */ + public NamingEnumeration list(Name name) throws NamingException + { + BindingIteratorHolder bi = new BindingIteratorHolder(); + BindingListHolder bl = new BindingListHolder(); + + NamingContext subcontext; + + if (name.size() == 0) + subcontext = service; + else + { + try + { + subcontext = (NamingContextHelper.narrow(service.resolve(toGiop(name)))); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + + } + + subcontext.list(howMany, bl, bi); + + return new ListEnumeration(bl, bi, howMany); + } + + /** + * Creates and returns the enumeration over the name bindings that are present + * the given subcontext. The enumeration elements have the type of + * {@link NameClassPair}, providing also information about the class of the + * bound object. The behaviour in the case if the bindings are added or + * removed later is not defined. The contents of the subcontexts are not + * included. + * + * @param name + * the name of the subcontext + * @return the enumeration over the names, known for the given subcontext. + * @throws NamingException + */ + public NamingEnumeration list(String name) throws NamingException + { + BindingIteratorHolder bi = new BindingIteratorHolder(); + BindingListHolder bl = new BindingListHolder(); + + NamingContext subcontext; + + if (name.length() == 0) + subcontext = service; + else + { + try + { + subcontext = (NamingContextHelper.narrow(service.resolve_str(name))); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + + } + + subcontext.list(howMany, bl, bi); + + return new ListEnumeration(bl, bi, howMany); + } + + /** + * Creates and returns the enumeration over the name - object bindings that + * are present the given subcontext. The enumeration elements have the type of + * {@link Binding}, providing also information about the class of the bound + * object. The behaviour in the case if the bindings are added or removed + * later is not defined. The contents of the subcontexts are not included. + * + * @param name + * the name of the subcontext + * @return the enumeration over the names, known for the given subcontext. + * @throws NamingException + */ + public NamingEnumeration listBindings(Name name) throws NamingException + { + BindingIteratorHolder bi = new BindingIteratorHolder(); + BindingListHolder bl = new BindingListHolder(); + + NamingContext subcontext; + + if (name.size() == 0) + subcontext = service; + else + { + try + { + subcontext = (NamingContextHelper.narrow(service.resolve(toGiop(name)))); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + subcontext.list(howMany, bl, bi); + + return new ListBindingsEnumeration(bl, bi, howMany, subcontext); + } + + /** + * Creates and returns the enumeration over the name - object bindings that + * are present the given subcontext. The enumeration elements have the type of + * {@link Binding}, providing also information about the class of the bound + * object. The behaviour in the case if the bindings are added or removed + * later is not defined. The contents of the subcontexts are not included. + * + * @param name + * the name of the subcontext + * @return the enumeration over the names, known for the given subcontext. + * @throws NamingException + */ + public NamingEnumeration listBindings(String name) throws NamingException + { + BindingIteratorHolder bi = new BindingIteratorHolder(); + BindingListHolder bl = new BindingListHolder(); + + NamingContext subcontext; + + if (name.length() == 0) + subcontext = service; + else + { + try + { + subcontext = (NamingContextHelper.narrow(service.resolve_str(name))); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + + } + + subcontext.list(howMany, bl, bi); + + return new ListBindingsEnumeration(bl, bi, howMany, subcontext); + } + + /** + * Gets the previously named object by name. If the passed name is empty, the + * method should return a cloned instance of this naming context. + * + * @param name + * the name of the object being searched in this context + * @return the named object + * @throws NameNotFountException + * if the name is not found + */ + public Object lookup(Name name) throws NamingException + { + try + { + return service.resolve(toGiop(name)); + } + catch (NotFound e) + { + throw new NameNotFoundException(); + } + catch (InvalidName e) + { + throw new InvalidNameException(); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Gets the previously named object by name. If the passed name is empty, the + * method should return a cloned instance of this naming context. + * + * @param name + * the name of the object being searched in this context + * @return the named object + * @throws NamingException + * if the naming fails. + */ + public Object lookup(String name) throws NamingException + { + try + { + return service.resolve_str(name); + } + catch (NotFound e) + { + throw new NameNotFoundException(); + } + catch (InvalidName e) + { + throw new InvalidNameException(); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Not supported. + */ + public Object lookupLink(Name name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported. + */ + public Object lookupLink(String name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Give the specified name for the specified object. Unlike bind, this method + * silently replaces the existing binding for this name, if one exists. + * + * @param name + * the name that will be given to the object (in the scope of this + * context). + * @param obj + * the object being named. + * @throws InvalidAttributesException + * if the object does not supply all required attributes. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void rebind(Name name, Object obj) throws NamingException + { + try + { + org.omg.CORBA.Object object = (org.omg.CORBA.Object) obj; + service.rebind(toGiop(name), object); + } + catch (ClassCastException e) + { + throw new NamingException(org.omg.CORBA.Object.class + " required "); + } + catch (InvalidName e) + { + throw new InvalidNameException(); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Give the specified name for the specified object. Unlike bind, this method + * silently replaces the existing binding for this name, if one exists. + * + * @param name + * the name that will be given to the object (in the scope of this + * context). + * @param obj + * the object being named. + * @throws InvalidAttributesException + * if the object does not supply all required attributes. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void rebind(String name, Object obj) throws NamingException + { + try + { + org.omg.CORBA.Object object = (org.omg.CORBA.Object) obj; + service.rebind(transformer.toName(name), object); + } + catch (ClassCastException e) + { + throw new NamingException(org.omg.CORBA.Object.class + " required "); + } + catch (InvalidName e) + { + throw new InvalidNameException(); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Renames the existing binding, removing the existing and giving the new name + * for the same object. + * + * @param oldName + * the existing name of the known object + * @param newName + * the new name of the same object + * @throws NameNotFoundException + * if the oldName is unknown for this context + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void rename(Name oldName, Name newName) throws NamingException + { + Object object = lookup(oldName); + unbind(oldName); + bind(newName, object); + } + + /** + * Renames the existing binding, removing the existing and giving the new name + * for the same object. + * + * @param oldName + * the existing name of the known object + * @param newName + * the new name of the same object + * @throws NameNotFoundException + * if the oldName is unknown for this context + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void rename(String oldName, String newName) throws NamingException + { + Object object = lookup(oldName); + unbind(oldName); + bind(newName, object); + } + + /** + * Removes the name - object mapping from the current context. This method + * returns without action if the name is not bound to an object in the + * terminal context, but throws {@link NameNotFoundException} if one of the + * intermadiate contexts does not exist. + * + * @param name + * the name to be removed + * @throws NameNotFoundException + * if one of the intermediate naming contexts does not exist. Will + * not be thrown if just the terminal binding is missing. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void unbind(Name name) throws NamingException + { + try + { + service.unbind(toGiop(name)); + } + catch (NotFound e) + { + throw new NameNotFoundException(); + } + catch (CannotProceed e) + { + throw new ContextNotEmptyException(); + } + catch (InvalidName e) + { + throw new InvalidNameException(); + } + } + + /** + * Removes the name - object mapping from the current context. This method + * returns without action if the name is not bound to an object in the + * terminal context, but throws {@link NameNotFoundException} if one of the + * intermadiate contexts does not exist. + * + * @param name + * the name to be removed + * @throws NameNotFoundException + * if one of the intermediate naming contexts does not exist. Will + * not be thrown if just the terminal binding is missing. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void unbind(String name) throws NamingException + { + try + { + service.unbind(transformer.toName(name)); + } + catch (NotFound e) + { + throw new NameNotFoundException(name); + } + catch (CannotProceed e) + { + throw new ContextNotEmptyException(name); + } + catch (InvalidName e) + { + throw new InvalidNameException(name); + } + } + + /** + * Add new environment property to the environment of this context. Both name + * and value of the new property must not be null. If the property is already + * defined, is current value is replaced by the propVal. + * + * @param key + * the name of the new property + * @param value + * the value of the new property + * @return the previous value of this property or null if the property has not + * been previously defined + * @throws NamingException + */ + public Object addToEnvironment(String key, Object value) + throws NamingException + { + if (key == null || value == null) + throw new NullPointerException(); + return properties.put(key, value); + } + + /** + * Returns the environment, associated with this naming context. The returned + * table should never be modified by the caller. Use {@link #addToEnvironment} + * and {@link #removeFromEnvironment} to modify the environement, if needed. + * + * @return the table, representing the environment of this context + * @throws NamingException + */ + public Hashtable getEnvironment() throws NamingException + { + return properties; + } + + /** + * Removes the property with the given name from the environment. Returns + * without action if this property is not defined. + * + * @param propName + * the name of the property being removed. + * @return the value of the property that has been removed or null if the + * property was not defined. + * @throws NamingException + */ + public Object removeFromEnvironment(String propName) throws NamingException + { + return properties.remove(propName); + } + + /** + * Convert the {@link Name} into array of the name components, required to the + * CORBA naming service. First the string representation is obtained, then + * it is converted using parsing rules of the CORBA name. + * + * @param name + * then name to convert + * @return the converted array of components. + */ + public NameComponent[] toGiop(Name name) throws InvalidName + { + return transformer.toName(name.toString()); + } + + /** + * Get the batch size from the environment properties. The batch size is used + * for listing operations. + * + * @return the batch size, or some default value if not specified. + */ + public int getBatchSize() + { + int batchSize = DEFAULT_BATCH_SIZE; + Object bs = properties.get(Context.BATCHSIZE); + if (bs != null) + { + try + { + int b = Integer.parseInt(bs.toString()); + if (b >= 0) + batchSize = b; + } + catch (NumberFormatException e) + { + // OK, use default value. + } + } + return batchSize; + } + + +} diff --git a/libjava/classpath/gnu/javax/naming/giop/CorbalocParser.java b/libjava/classpath/gnu/javax/naming/giop/CorbalocParser.java new file mode 100644 index 000000000..4b7883969 --- /dev/null +++ b/libjava/classpath/gnu/javax/naming/giop/CorbalocParser.java @@ -0,0 +1,441 @@ +/* CorbalocParser.java -- handles corbaname: urls + 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.naming.giop; + +import gnu.CORBA.IOR; +import gnu.CORBA.Minor; +import gnu.CORBA.Unexpected; +import gnu.CORBA.Version; +import gnu.CORBA.NamingService.NameTransformer; + +import gnu.java.lang.CPStringBuilder; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLDecoder; +import java.util.StringTokenizer; + +import javax.naming.InvalidNameException; + +import org.omg.CORBA.BAD_PARAM; +import org.omg.CORBA.DATA_CONVERSION; +import org.omg.CORBA.ORB; +import org.omg.CORBA.Object; +import org.omg.CORBA.ORBPackage.InvalidName; + +/** + * Parses the alternative IOR representations into our IOR structure. + * + * TODO This parser currently supports only one address per target string. A + * string with the multiple addresses will be accepted, but only the last + * address will be taken into consideration. The fault tolerance is not yet + * implemented. + * + * The key string is filtered using {@link java.net.URLDecoder} that replaces + * the agreed escape sequences by the corresponding non alphanumeric characters. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class CorbalocParser + extends NameTransformer +{ + /** + * The corbaloc prefix. + */ + public static final String pxCORBALOC = "corbaloc"; + + /** + * The corbaname prefix. + */ + public static final String pxCORBANAME = "corbaname"; + + /** + * The IOR prefix. + */ + public static final String pxIOR = "ior"; + + /** + * The file:// prefix. + */ + public static final String pxFILE = "file://"; + + /** + * The ftp:// prefix. + */ + public static final String pxFTP = "ftp://"; + + /** + * The http:// prefix. + */ + public static final String pxHTTP = "http://"; + + /** + * Marks iiop protocol. + */ + public static final String IIOP = "iiop"; + + /** + * Marks rir protocol. + */ + public static final String RIR = "rir"; + + /** + * The default port value, as specified in OMG documentation. + */ + public static final int DEFAULT_PORT = 2809; + + /** + * The default name. + */ + public static final String DEFAULT_NAME = "NameService"; + + /** + * The string to name converter, initialized on demand. + */ + static NameTransformer converter; + + /** + * The current position. + */ + int p; + + /** + * The address being parsed, splitted into tokens. + */ + String[] t; + + /** + * Parse CORBALOC. + * + * The expected format is:
    + * 1. corbaloc:[iiop][version.subversion@]:host[:port]/key
    + * 2. corbaloc:rir:[/key]
    + * 3. corbaname:[iiop][version.subversion@]:host[:port]/key
    + * 4. corbaname:rir:[/key]
    + * 5. file://[file name]
    + * 6. http://[url]
    + * 7. ftp://[url]
    + * + * Protocol defaults to IOP, the object key defaults to the NameService. + * + * @param corbaloc the string to parse. + * @param orb the ORB, needed to create IORs and resolve rir references. + * + * @return the arrey of strings, first member being the IOR of the + * naming service, second member the name in the naming service. + */ + public synchronized String[] corbaloc(String corbaloc, + ORB orb) + throws InvalidNameException + { + return corbaloc(corbaloc, orb, 0); + } + + /** + * Parse controlling against the infinite recursion loop. + */ + private String[] corbaloc(String corbaloc, + ORB orb, int recursion) throws InvalidNameException + { + // The used CORBA specification does not state how many times we should to + //redirect, but the infinite loop may be used to knock out the system. + // by malicious attempt. + if (recursion > 10) + throw new DATA_CONVERSION("More than 10 redirections"); + + if (corbaloc.startsWith(pxFILE)) + return corbaloc(readFile(corbaloc.substring(pxFILE.length())), orb, recursion+1); + else if (corbaloc.startsWith(pxHTTP)) + return corbaloc(readUrl(corbaloc), orb, recursion+1); + else if (corbaloc.startsWith(pxFTP)) + return corbaloc(readUrl(corbaloc), orb, recursion+1); + + // The version numbers with default values. + int major = 1; + int minor = 0; + + // The host address. + String host; + + // The port. + int port = DEFAULT_PORT; + + // The object key as string. + String key; + + StringTokenizer st = new StringTokenizer(corbaloc, ":@/.,#", true); + + t = new String[st.countTokens()]; + + for (int i = 0; i < t.length; i++) + { + t[i] = st.nextToken(); + } + + p = 0; + + if (!t[p].startsWith(pxCORBANAME)) + throw new InvalidNameException(corbaloc+" must start with "+pxCORBANAME); + + p++; + + if (!t[p++].equals(":")) + throw new BAD_PARAM("Syntax (':' expected after name prefix)"); + + // Check for rir: + if (t[p].equals(RIR)) + { + p++; + if (!t[p++].equals(":")) + throw new BAD_PARAM("':' expected after 'rir'"); + + key = readKey("/"); + + Object object; + try + { + object = orb.resolve_initial_references(key); + return resolve(orb.object_to_string(object)); + } + catch (InvalidName e) + { + throw new BAD_PARAM("Unknown initial reference '" + key + "'"); + } + } + else + // Check for iiop. + if (t[p].equals(IIOP) || t[p].equals(":")) + { + IOR ior = new IOR(); + + Addresses: do + { // Read addresses. + if (t[p].equals(":")) + { + p++; + } + else + { + p++; + if (!t[p++].equals(":")) + throw new BAD_PARAM("':' expected after 'iiop'"); + // Check if version is present. + if (t[p + 1].equals(".")) + if (t[p + 3].equals("@")) + { + // Version info present. + try + { + major = Integer.parseInt(t[p++]); + } + catch (NumberFormatException e) + { + throw new BAD_PARAM("Major version number '" + + t[p - 1] + "'"); + } + p++; // '.' at this point. + try + { + minor = Integer.parseInt(t[p++]); + } + catch (NumberFormatException e) + { + throw new BAD_PARAM("Major version number '" + + t[p - 1] + "'"); + } + p++; // '@' at this point. + } + } + + ior.Internet.version = new Version(major, minor); + + // Then host data goes till '/' or ':'. + CPStringBuilder bhost = new CPStringBuilder(corbaloc.length()); + while (!t[p].equals(":") && !t[p].equals("/") && !t[p].equals(",")) + bhost.append(t[p++]); + + host = bhost.toString(); + + ior.Internet.host = host; + + if (t[p].equals(":")) + { + // Port specified. + p++; + try + { + port = Integer.parseInt(t[p++]); + } + catch (NumberFormatException e) + { + throw new BAD_PARAM("Invalid port '" + t[p - 1] + "'"); + } + } + + ior.Internet.port = port; + + // Id is not listed. + ior.Id = ""; + + if (t[p].equals(",")) + p++; + else + break Addresses; + } + while (true); + + key = readKey("/"); + ior.key = key.getBytes(); + + return resolve(ior.toStringifiedReference()); + } + + else + throw new InvalidNameException("Unsupported protocol '" + t[p] + + "' (iiop expected)"); + } + + /** + * Read IOR from the file in the local file system. + */ + String readFile(String file) + { + File f = new File(file); + if (!f.exists()) + { + DATA_CONVERSION err = new DATA_CONVERSION(f.getAbsolutePath() + + " does not exist."); + err.minor = Minor.Missing_IOR; + } + try + { + char[] c = new char[(int) f.length()]; + FileReader fr = new FileReader(f); + fr.read(c); + fr.close(); + return new String(c).trim(); + } + catch (IOException ex) + { + DATA_CONVERSION d = new DATA_CONVERSION(); + d.initCause(ex); + d.minor = Minor.Missing_IOR; + throw (d); + } + } + + /** + * Read IOR from the remote URL. + */ + String readUrl(String url) + { + URL u; + try + { + u = new URL(url); + } + catch (MalformedURLException mex) + { + throw new BAD_PARAM("Malformed URL: '" + url + "'"); + } + + try + { + InputStreamReader r = new InputStreamReader(u.openStream()); + + CPStringBuilder b = new CPStringBuilder(); + int c; + + while ((c = r.read()) > 0) + b.append((char) c); + + return b.toString().trim(); + } + catch (Exception exc) + { + DATA_CONVERSION d = new DATA_CONVERSION("Reading " + url + " failed."); + d.minor = Minor.Missing_IOR; + throw d; + } + } + + private String[] resolve(String nsIor) + { + String [] n = new String[2]; + n[0] = nsIor; + n[1] = readKey("#"); + return n; + } + + private String readKey(String delimiter) + throws BAD_PARAM + { + if (p < t.length) + if (!t[p].equals(delimiter)) + { + if (t[p].equals("#")) + return DEFAULT_NAME; + else + throw new BAD_PARAM("'" + delimiter + "String' expected '" + t[p] + + "' found"); + } + + CPStringBuilder bKey = new CPStringBuilder(); + p++; + + while (p < t.length && !t[p].equals("#")) + bKey.append(t[p++]); + + if (bKey.length() == 0) + return DEFAULT_NAME; + + try + { + return URLDecoder.decode(bKey.toString(), "UTF-8"); + } + catch (UnsupportedEncodingException e) + { + throw new Unexpected("URLDecoder does not support UTF-8", e); + } + } +} diff --git a/libjava/classpath/gnu/javax/naming/giop/GiopNamingEnumeration.java b/libjava/classpath/gnu/javax/naming/giop/GiopNamingEnumeration.java new file mode 100644 index 000000000..c2de75b38 --- /dev/null +++ b/libjava/classpath/gnu/javax/naming/giop/GiopNamingEnumeration.java @@ -0,0 +1,187 @@ +/* GiopNamingEnumeration.java -- handles corbaname: urls + 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.naming.giop; + +import java.util.NoSuchElementException; + +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; + +import org.omg.CosNaming.Binding; +import org.omg.CosNaming.BindingIterator; +import org.omg.CosNaming.BindingIteratorHolder; +import org.omg.CosNaming.BindingListHolder; + +/** + * Iterates over name class pairs, obtaining values first from the binding list + * and then from the binding iterator. + * + * @author Audrius Meskauskas + */ +public abstract class GiopNamingEnumeration implements NamingEnumeration +{ + /** + * The array of bindings, returned at once. + */ + Binding[] list; + + /** + * The binding iterator to obtain the subsequent bindings. May be null, + * if all values are stored in the list. + */ + BindingIterator iterator; + + /** + * The batch size. + */ + int batch; + + /** + * The position of the element in the binding list, that must be returned + * during the subsequent call of the next(). If this field is grater or equal + * to the lenght of the list, the subsequent values must be requested from the + * iterator. + */ + int p; + + GiopNamingEnumeration(BindingListHolder bh, BindingIteratorHolder bih, int batchSize) + { + list = bh.value; + iterator = bih.value; + batch = batchSize; + } + + /** + * Convert from the CORBA binding into that this enumeration should return. + * + * @param binding + * the binding to convert + * @return the value, that must be returned by the {@link #next()}. + */ + public abstract Object convert(Binding binding); + + public void close() throws NamingException + { + if (iterator != null) + { + iterator.destroy(); + iterator = null; + } + } + + /** + * Checks if there are more elements to return. + * + * @throws NamingException + * never + */ + public boolean hasMore() throws NamingException + { + return hasMoreElements(); + } + + /** + * Returns the next element. + * + * @throws NamingException + * never + */ + public Object next() throws NamingException + { + return nextElement(); + } + + /** + * Checks if there are more elements to return. + */ + public boolean hasMoreElements() + { + if (p < 0) + return false; + else if (p < list.length) + return true; + else + return getMore(); + } + + /** + * Returns the next element. + */ + public Object nextElement() + { + if (p < 0) + throw new NoSuchElementException(); + else if (p < list.length) + return convert(list[p++]); + else if (getMore()) + // getMore updates p + return convert(list[p++]); + else + throw new NoSuchElementException(); + } + + /** + * Tries to obtain more elements, return true on success. Updates the fields + * accordingly. + */ + boolean getMore() + { + if (iterator != null) + { + BindingListHolder holder = new BindingListHolder(); + boolean rt = iterator.next_n(batch, holder); + if (rt) + { + // The new pack of the bindings arrived. + p = 0; + list = holder.value; + return true; + } + else + { + iterator.destroy(); + iterator = null; + p = -1; + return false; + } + } + else + return false; + } +} diff --git a/libjava/classpath/gnu/javax/naming/giop/GiopNamingServiceFactory.java b/libjava/classpath/gnu/javax/naming/giop/GiopNamingServiceFactory.java new file mode 100644 index 000000000..e8aac3b65 --- /dev/null +++ b/libjava/classpath/gnu/javax/naming/giop/GiopNamingServiceFactory.java @@ -0,0 +1,179 @@ +/* GiopNamingServiceFactory.java -- handles corbaname: urls + 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.naming.giop; + +import gnu.CORBA.OrbFunctional; + +import gnu.java.lang.CPStringBuilder; + +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; +import java.util.TreeMap; + +import javax.naming.Context; +import javax.naming.Name; + +import org.omg.CORBA.ORB; + +/** + * The context factory to represent the corbaname: style urls. Such URL states + * that the CORBA naming service exists on the given host. This service can + * return the required object, finding it by the given name. The names are + * parsed using the specification of the corbaname urls. Being the naming + * service, the returned context supports creating the subcontexts, forwarding + * this task to the existing naming service. + * + * @author Audrius Meskauskas (audriusa@Bioinformatics.org) + */ +public class GiopNamingServiceFactory +{ + /** + * The default naming service provider. It is assumed, that the naming service + * is running on the port 900 of the local host, using the GIOP version 1.2 + */ + public static final String DEFAULT_PROVIDER = + "corbaloc:iiop:1.2@127.0.0.1:900/NameService"; + + /** + * The table of all instantiated ORB's that are found by they ORB + * properties signatures. If all ORB related properties are the same, + * the ORB's are shared. + */ + public static Hashtable orbs = new Hashtable(); + + + /** + * Create a new instance of the corbaname URL context. + */ + public Object getObjectInstance(Object refObj, Name name, Context nameCtx, + Hashtable environment) + { + String provider = (String) environment.get(Context.PROVIDER_URL); + if (provider == null) + provider = DEFAULT_PROVIDER; + + String orbSignature = getOrbSignature(environment); + + ORB orb; + synchronized (orbs) + { + orb = (ORB) orbs.get(orbSignature); + if (orb == null) + { + Properties props = new Properties(); + props.putAll(environment); + orb = ORB.init(new String[0], props); + orbs.put(orbSignature, orb); + final ORB runIt = orb; + new Thread() + { + public void run() + { + runIt.run(); + } + }.start(); + } + } + + return new GiopNamingServiceURLContext(environment, this, orb); + } + + /** + * Check if this ORB is still in use (maybe it is time to shutdown it). This + * method only works when the Classpath CORBA implementation is used + * (otherwise it return without action). The method is called from the close() + * method of the created context. + * + * @param orb + * the ORB that maybe is no longer referenced. + */ + public void checkIfReferenced(ORB orb) + { + synchronized (orbs) + { + // We can only do this with the Classpath implementation. + if (orb instanceof OrbFunctional) + { + OrbFunctional cOrb = (OrbFunctional) orb; + // If there are no connected objects, we can destroy the orb. + if (cOrb.countConnectedObjects() == 0) + { + cOrb.shutdown(false); + cOrb.destroy(); + + Enumeration keys = orbs.keys(); + Object key; + Remove: while (keys.hasMoreElements()) + { + key = keys.nextElement(); + if (orbs.get(key) == orb) + { + orbs.remove(key); + break Remove; + } + } + } + } + } + } + + /** + * Get all properties. + */ + public String getOrbSignature(Map props) + { + TreeMap map = new TreeMap(); + map.putAll(props); + CPStringBuilder b = new CPStringBuilder(50*props.size()); + + Iterator iter = map.entrySet().iterator(); + Map.Entry m; + while (iter.hasNext()) + { + m = (Map.Entry) iter.next(); + b.append(m.getKey()); + b.append('='); + b.append(m.getValue()); + } + return b.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/naming/giop/GiopNamingServiceURLContext.java b/libjava/classpath/gnu/javax/naming/giop/GiopNamingServiceURLContext.java new file mode 100644 index 000000000..0d2e290b4 --- /dev/null +++ b/libjava/classpath/gnu/javax/naming/giop/GiopNamingServiceURLContext.java @@ -0,0 +1,840 @@ +/* GiopNamingServiceURLContext.java -- handles corbaname: urls + 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.naming.giop; + +import gnu.CORBA.NamingService.Ext; +import gnu.CORBA.NamingService.NameTransformer; + +import java.util.Hashtable; + +import javax.naming.Binding; +import javax.naming.Context; +import javax.naming.ContextNotEmptyException; +import javax.naming.InvalidNameException; +import javax.naming.Name; +import javax.naming.NameAlreadyBoundException; +import javax.naming.NameClassPair; +import javax.naming.NameNotFoundException; +import javax.naming.NameParser; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.OperationNotSupportedException; +import javax.naming.directory.InvalidAttributesException; + +import org.omg.CORBA.ORB; +import org.omg.CORBA.portable.Delegate; +import org.omg.CORBA.portable.ObjectImpl; +import org.omg.CosNaming.BindingIteratorHolder; +import org.omg.CosNaming.BindingListHolder; +import org.omg.CosNaming.NameComponent; +import org.omg.CosNaming.NamingContext; +import org.omg.CosNaming.NamingContextExt; +import org.omg.CosNaming.NamingContextExtHelper; +import org.omg.CosNaming.NamingContextHelper; +import org.omg.CosNaming._NamingContextExtStub; +import org.omg.CosNaming._NamingContextStub; +import org.omg.CosNaming.NamingContextPackage.AlreadyBound; +import org.omg.CosNaming.NamingContextPackage.CannotProceed; +import org.omg.CosNaming.NamingContextPackage.InvalidName; +import org.omg.CosNaming.NamingContextPackage.NotFound; + +/** + * The context to represent the corba naming service. Being the naming service, + * the returned context supports creating the subcontexts, forwarding this task + * to the existing naming service. When listing bindings, it uses the + * {@link Context#BATCHSIZE} property to determine, how many bindings should + * be returned at once (the process is transparend) + * + * @author Audrius Meskauskas (audriusa@Bioinformatics.org) + */ +public class GiopNamingServiceURLContext extends CorbalocParser implements + Context +{ + /** + * This number of bindings will be requested from the naming server at once, + * while the subsequent bindings will be requested via binding iterator one by + * one. Use {@link Context#BATCHSIZE} to override the value of this constant. + */ + public int DEFAULT_BATCH_SIZE = 20; + + /** + * The object request broker, used to access the naming service. This field + * is only initialised when the context is constructed from the URL. + */ + ORB orb; + + /** + * The properties. + */ + Hashtable properties; + + /** + * The parent factory. + */ + GiopNamingServiceFactory factory; + + /** + * The name transformer to obtain the name from its string representation. The + * to_name method of the naming service is avoided as it may be remote and + * hence expensive. The conversion rules are standard and cannot be service + * specific. + */ + static NameTransformer transformer = new NameTransformer(); + + /** + * The batch size for list operations - how many to return at once. + */ + public final int howMany; + + /** + * Creates a new naming context that uses naming service, represented by the + * given CORBA object. + * + * @param props + * the environment table. + * @param aFactory + * parent factory. This reference is used during cleanup. + * @param anOrb + * the associated ORB. This reference is used during cleanup. + */ + public GiopNamingServiceURLContext(Hashtable props, + GiopNamingServiceFactory aFactory, + ORB anOrb) + { + factory = aFactory; + orb = anOrb; + + properties = props; + howMany = getBatchSize(); + } + + public NamingContextExt getService(String address) + { + org.omg.CORBA.Object nsObject = orb.string_to_object(address); + Delegate delegate = ((ObjectImpl) nsObject)._get_delegate(); + + // If the IOR provides the IDL ID, we can check if our name + // service is old NamingContext or new NamingContextExt. + // Not all forms of the URL always provide the IDL id. + if (!nsObject._is_a(NamingContextExtHelper.id()) + && nsObject._is_a(NamingContextHelper.id())) + { + // We are surely working with the old version. + _NamingContextStub stub = new _NamingContextStub(); + stub._set_delegate(delegate); + // The Ext object will add the necessary extensions. + return new Ext(stub); + } + else + { + // We expecte the service to be the NamingContextExt (this is true + // for both Sun's and our implementations). There is no easy way + // to check the version. + _NamingContextExtStub stub = new _NamingContextExtStub(); + stub._set_delegate(delegate); + return stub; + } + } + + /** + * Split the corbaname name into the address of the naming service (first + * part) and the name of the object in the naming service (second part) + */ + public String[] split(String corbaloc) throws InvalidNameException + { + if (corbaloc.endsWith("#")) + corbaloc = corbaloc.substring(0, corbaloc.length() - 1); + + // No name part - parse as corbaname. + if (corbaloc.indexOf('#') < 0) + { + if (!corbaloc.regionMatches(true, 0, pxCORBANAME, 0, + pxCORBANAME.length())) + throw new InvalidNameException(corbaloc + " must start with " + + pxCORBANAME); + corbaloc = pxCORBALOC + corbaloc.substring(pxCORBANAME.length()); + return new String[] { corbaloc, "" }; + } + + return corbaloc(corbaloc, orb); + } + + /** + * Give the specified name for the specified object. The passed name must not + * be already bound to some other object. The components of the name are + * mapped into the components of the CORBA name. + * + * @param name + * the name that will be given to the object (in the scope of this + * context). + * @param obj + * the object being named. + * @throws NameAlreadyBoundException + * if this name is already used to name some object. + * @throws InvalidAttributesException + * if the object does not supply all required attributes. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void bind(Name name, Object obj) throws NamingException + { + bind(name.toString(), obj); + } + + /** + * Give the specified name for the specified object. The passed name must not + * be already bound to some other object. + * + * @param name + * the name that will be given to the object (in the scope of this + * context). + * @param obj + * the object being named. + * @throws NameAlreadyBoundException + * if this name is already used to name some object. + * @throws InvalidAttributesException + * if the object does not supply all required attributes. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void bind(String name, Object obj) throws NamingException + { + try + { + String[] n = split(name); + org.omg.CORBA.Object object = (org.omg.CORBA.Object) obj; + getService(n[0]).bind(transformer.toName(n[1]), object); + } + catch (ClassCastException e) + { + throw new NamingException(org.omg.CORBA.Object.class + " required "); + } + catch (InvalidName e) + { + throw new InvalidNameException(); + } + catch (AlreadyBound e) + { + throw new NameAlreadyBoundException(); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Releases all resources, associated with this context. The close() method + * can be called several times, but after it has been once invoked, it is not + * allowed to call any other method of this context. This method destroys + * the ORB, if we have one. + * + * @throws NamingException + */ + public void close() throws NamingException + { + if (orb != null && factory != null) + { + factory.checkIfReferenced(orb); + } + } + + /** + * Not supported. + */ + public Name composeName(Name name, Name prefix) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported + */ + public String composeName(String name1, String name2) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Creates the new naming subcontext and binds it to the current (this) + * context. The returned object will wrap around the newly created CORBA + * subcontext + * + * @param subContext + * the name of the new context being created + * @return the newly created context, bound to the instance of the context on + * that the method has been called + * @throws NameAlreadyBoundException + * if this name is already bound + * @throws InvalidAttributesException + * if the creation of the new context requires the missing mandatory + * attributes + * @throws NamingException + */ + public Context createSubcontext(Name subContext) throws NamingException + { + return createSubcontext(subContext.toString()); + } + + /** + * Creates the new naming subcontext and binds it to the current (this) + * context. The returned object will wrap around the newly created CORBA + * subcontext + * + * @param subContext + * the name of the new context being created + * @return the newly created context, bound to the instance of the context on + * that the method has been called + * @throws NameAlreadyBoundException + * if this name is already bound + * @throws InvalidAttributesException + * if the creation of the new context requires the missing mandatory + * attributes + * @throws NamingException + */ + public Context createSubcontext(String subContext) throws NamingException + { + try + { + String[] n = split(subContext); + org.omg.CORBA.Object subcontext = getService(n[0]).bind_new_context( + transformer.toName(n[1])); + Hashtable clonedProps = new Hashtable(); + clonedProps.putAll(properties); + + // Nulls are passed both for orb and factory, as the child contexts + // need not to do any cleanup. + return new ContextContinuation(subcontext, clonedProps, null, null); + } + catch (AlreadyBound e) + { + throw new NameAlreadyBoundException(subContext); + } + catch (InvalidName e) + { + throw new InvalidNameException(subContext); + } + catch (Exception ex) + { + throw new NamingException(ex.toString()); + } + } + + /** + * Removes the naming subcontext from this naming context. Returns without + * action if such subcontext does not exist. The context being destroyed must + * be empty. + * + * @param subContext + * the name of the subcontext beig removed. + * @throws ContextNotEmptyException + * if the named context is not empty. + * @throws NamingException + */ + public void destroySubcontext(Name subContext) throws NamingException + { + unbind(subContext); + } + + /** + * Removes the naming subcontext from this naming context. Returns without + * action if such subcontext does not exist. The context being destroyed must + * be empty. + * + * @param subContext + * the name of the subcontext beig removed. + * @throws ContextNotEmptyException + * if the named context is not empty. + * @throws NamingException + */ + public void destroySubcontext(String subContext) throws NamingException + { + unbind(subContext); + } + + /** + * Returs the empty string. + */ + public String getNameInNamespace() throws NamingException + { + return ""; + } + + /** + * Not supported. + */ + public NameParser getNameParser(Name name) throws NamingException + { + throw new UnsupportedOperationException(); + } + + /** + * Not supported. + */ + public NameParser getNameParser(String name) throws NamingException + { + throw new UnsupportedOperationException(); + } + + /** + * Creates and returns the enumeration over the name bindings that are present + * the given subcontext. The enumeration elements have the type of + * {@link NameClassPair}, providing also information about the class of the + * bound object. The behaviour in the case if the bindings are added or + * removed later is not defined. The contents of the subcontexts are not + * included. + * + * @param name + * the name of the subcontext + * @return the enumeration over the names, known for the given subcontext. + * @throws NamingException + */ + public NamingEnumeration list(Name name) throws NamingException + { + return list(name.toString()); + } + + /** + * Creates and returns the enumeration over the name bindings that are present + * the given subcontext. The enumeration elements have the type of + * {@link NameClassPair}, providing also information about the class of the + * bound object. The behaviour in the case if the bindings are added or + * removed later is not defined. The contents of the subcontexts are not + * included. + * + * @param name + * the name of the subcontext + * @return the enumeration over the names, known for the given subcontext. + * @throws NamingException + */ + public NamingEnumeration list(String name) throws NamingException + { + BindingIteratorHolder bi = new BindingIteratorHolder(); + BindingListHolder bl = new BindingListHolder(); + + NamingContext subcontext; + + String [] n = split(name); + NamingContextExt service = getService(n[0]); + + if (n[1].length() == 0) + subcontext = service; + else + { + try + { + subcontext = (NamingContextHelper.narrow(service.resolve_str(n[1]))); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + + } + + subcontext.list(howMany, bl, bi); + + return new ListEnumeration(bl, bi, howMany); + } + + /** + * Creates and returns the enumeration over the name - object bindings that + * are present the given subcontext. The enumeration elements have the type of + * {@link Binding}, providing also information about the class of the bound + * object. The behaviour in the case if the bindings are added or removed + * later is not defined. The contents of the subcontexts are not included. + * + * @param name + * the name of the subcontext + * @return the enumeration over the names, known for the given subcontext. + * @throws NamingException + */ + public NamingEnumeration listBindings(Name name) throws NamingException + { + return listBindings(name.toString()); + } + + /** + * Creates and returns the enumeration over the name - object bindings that + * are present the given subcontext. The enumeration elements have the type of + * {@link Binding}, providing also information about the class of the bound + * object. The behaviour in the case if the bindings are added or removed + * later is not defined. The contents of the subcontexts are not included. + * + * @param name + * the name of the subcontext + * @return the enumeration over the names, known for the given subcontext. + * @throws NamingException + */ + public NamingEnumeration listBindings(String name) throws NamingException + { + BindingIteratorHolder bi = new BindingIteratorHolder(); + BindingListHolder bl = new BindingListHolder(); + + NamingContext subcontext; + + String [] n = split(name); + NamingContextExt service = getService(n[0]); + + if (n[1].length() == 0) + subcontext = service; + else + { + try + { + subcontext = (NamingContextHelper.narrow(service.resolve_str(n[1]))); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + + } + + subcontext.list(howMany, bl, bi); + + return new ListBindingsEnumeration(bl, bi, howMany, subcontext); + } + + /** + * Gets the previously named object by name. If the passed name is empty, the + * method should return a cloned instance of this naming context. + * + * @param name + * the name of the object being searched in this context + * @return the named object + * @throws NameNotFoundException + * if the name is not found + */ + public Object lookup(Name name) throws NamingException + { + return lookup(name.toString()); + } + + /** + * Gets the previously named object by name. If the passed name is empty, the + * method should return a cloned instance of this naming context. + * + * @param name + * the name of the object being searched in this context + * @return the named object + * @throws NamingException + * if the naming fails. + */ + public Object lookup(String name) throws NamingException + { + try + { + String [] n = split(name); + NamingContextExt service = getService(n[0]); + return service.resolve_str(n[1]); + } + catch (NotFound e) + { + throw new NameNotFoundException(); + } + catch (InvalidName e) + { + throw new InvalidNameException(); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Not supported. + */ + public Object lookupLink(Name name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported. + */ + public Object lookupLink(String name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Give the specified name for the specified object. Unlike bind, this method + * silently replaces the existing binding for this name, if one exists. + * + * @param name + * the name that will be given to the object (in the scope of this + * context). + * @param obj + * the object being named. + * @throws InvalidAttributesException + * if the object does not supply all required attributes. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void rebind(Name name, Object obj) throws NamingException + { + rebind(name.toString(), obj); + } + + /** + * Give the specified name for the specified object. Unlike bind, this method + * silently replaces the existing binding for this name, if one exists. + * + * @param name + * the name that will be given to the object (in the scope of this + * context). + * @param obj + * the object being named. + * @throws InvalidAttributesException + * if the object does not supply all required attributes. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void rebind(String name, Object obj) throws NamingException + { + try + { + String[] n = split(name); + NamingContextExt service = getService(n[0]); + + org.omg.CORBA.Object object = (org.omg.CORBA.Object) obj; + service.rebind(transformer.toName(n[1]), object); + } + catch (ClassCastException e) + { + throw new NamingException(org.omg.CORBA.Object.class + " required "); + } + catch (InvalidName e) + { + throw new InvalidNameException(); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Renames the existing binding, removing the existing and giving the new name + * for the same object. + * + * @param oldName + * the existing name of the known object + * @param newName + * the new name of the same object + * @throws NameNotFoundException + * if the oldName is unknown for this context + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void rename(Name oldName, Name newName) throws NamingException + { + Object object = lookup(oldName); + unbind(oldName); + bind(newName, object); + } + + /** + * Renames the existing binding, removing the existing and giving the new name + * for the same object. + * + * @param oldName + * the existing name of the known object + * @param newName + * the new name of the same object + * @throws NameNotFoundException + * if the oldName is unknown for this context + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void rename(String oldName, String newName) throws NamingException + { + Object object = lookup(oldName); + unbind(oldName); + bind(newName, object); + } + + /** + * Removes the name - object mapping from the current context. This method + * returns without action if the name is not bound to an object in the + * terminal context, but throws {@link NameNotFoundException} if one of the + * intermadiate contexts does not exist. + * + * @param name + * the name to be removed + * @throws NameNotFoundException + * if one of the intermediate naming contexts does not exist. Will + * not be thrown if just the terminal binding is missing. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void unbind(Name name) throws NamingException + { + unbind(name.toString()); + } + + /** + * Removes the name - object mapping from the current context. This method + * returns without action if the name is not bound to an object in the + * terminal context, but throws {@link NameNotFoundException} if one of the + * intermadiate contexts does not exist. + * + * @param name + * the name to be removed + * @throws NameNotFoundException + * if one of the intermediate naming contexts does not exist. Will + * not be thrown if just the terminal binding is missing. + * @throws NamingException + * if the naming operation has failed due other reasons. + */ + public void unbind(String name) throws NamingException + { + try + { + String[] n = split(name); + NamingContextExt service = getService(n[0]); + + service.unbind(transformer.toName(n[1])); + } + catch (NotFound e) + { + throw new NameNotFoundException(name); + } + catch (CannotProceed e) + { + throw new ContextNotEmptyException(name); + } + catch (InvalidName e) + { + throw new InvalidNameException(name); + } + } + + /** + * Add new environment property to the environment of this context. Both name + * and value of the new property must not be null. If the property is already + * defined, is current value is replaced by the propVal. + * + * @param key + * the name of the new property + * @param value + * the value of the new property + * @return the previous value of this property or null if the property has not + * been previously defined + * @throws NamingException + */ + public Object addToEnvironment(String key, Object value) + throws NamingException + { + if (key == null || value == null) + throw new NullPointerException(); + return properties.put(key, value); + } + + /** + * Returns the environment, associated with this naming context. The returned + * table should never be modified by the caller. Use {@link #addToEnvironment} + * and {@link #removeFromEnvironment} to modify the environement, if needed. + * + * @return the table, representing the environment of this context + * @throws NamingException + */ + public Hashtable getEnvironment() throws NamingException + { + return properties; + } + + /** + * Removes the property with the given name from the environment. Returns + * without action if this property is not defined. + * + * @param propName + * the name of the property being removed. + * @return the value of the property that has been removed or null if the + * property was not defined. + * @throws NamingException + */ + public Object removeFromEnvironment(String propName) throws NamingException + { + return properties.remove(propName); + } + + /** + * Convert the {@link Name} into array of the name components, required to the + * CORBA naming service. First the string representation is obtained, then + * it is converted using parsing rules of the CORBA name. + * + * @param name + * then name to convert + * @return the converted array of components. + */ + public NameComponent[] toGiop(Name name) throws InvalidName + { + return transformer.toName(name.toString()); + } + + /** + * Get the batch size from the environment properties. The batch size is used + * for listing operations. + * + * @return the batch size, or some default value if not specified. + */ + public int getBatchSize() + { + int batchSize = DEFAULT_BATCH_SIZE; + Object bs = properties.get(Context.BATCHSIZE); + if (bs != null) + { + try + { + int b = Integer.parseInt(bs.toString()); + if (b >= 0) + batchSize = b; + } + catch (NumberFormatException e) + { + // OK, use default value. + } + } + return batchSize; + } + +} diff --git a/libjava/classpath/gnu/javax/naming/giop/ListBindingsEnumeration.java b/libjava/classpath/gnu/javax/naming/giop/ListBindingsEnumeration.java new file mode 100644 index 000000000..dd9ed0265 --- /dev/null +++ b/libjava/classpath/gnu/javax/naming/giop/ListBindingsEnumeration.java @@ -0,0 +1,118 @@ +/* ListBindingsEnumeration.java -- handles corbaname: urls + 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.naming.giop; + +import gnu.java.lang.CPStringBuilder; + +import javax.naming.NamingEnumeration; + +import org.omg.CosNaming.Binding; +import org.omg.CosNaming.BindingIteratorHolder; +import org.omg.CosNaming.BindingListHolder; +import org.omg.CosNaming.NamingContext; + +/** + * Iterates over bindings, obtaining values first from the binding list and then + * from the binding iterator. + * + * @author Audrius Meskauskas + */ +public class ListBindingsEnumeration extends GiopNamingEnumeration implements + NamingEnumeration +{ + /** + * The naming service, to resolve the objects. + */ + NamingContext service; + + /** + * Create the new enumeration + * + * @param bh + * holder, containing the first portion of the bindings + * @param bih + * the iterator, containing the remaining bindings + * @param batchSize + * the number of bindings the the iterator will be requested to + * return as a single pack + * @param aService + * the naming service, used to obtain the objects, bound to the + * names. + */ + public ListBindingsEnumeration(BindingListHolder bh, + BindingIteratorHolder bih, int batchSize, + NamingContext aService) + { + super(bh, bih, batchSize); + service = aService; + } + + /** + * Convert from the CORBA binding into the javax.naming binding. As the CORBA + * naming service binding does not contain the object itself, this method + * makes the additional calls to the naming service. + * + * @param binding + * the binding to convert + * @return the value, that must be returned by the {@link #next()}. + */ + public Object convert(Binding binding) + { + CPStringBuilder name = new CPStringBuilder(); + + for (int i = 0; i < binding.binding_name.length; i++) + { + name.append(binding.binding_name[i]); + if (i < binding.binding_name.length - 1) + name.append('/'); + } + + try + { + Object object = service.resolve(binding.binding_name); + return new javax.naming.Binding(name.toString(), object); + } + catch (Exception e) + { + // Probably was removed by the concurent thread. + return null; + } + } + +} diff --git a/libjava/classpath/gnu/javax/naming/giop/ListEnumeration.java b/libjava/classpath/gnu/javax/naming/giop/ListEnumeration.java new file mode 100644 index 000000000..68a40fcf0 --- /dev/null +++ b/libjava/classpath/gnu/javax/naming/giop/ListEnumeration.java @@ -0,0 +1,118 @@ +/* ListEnumeration.java -- handles corbaname: urls + 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 +odule. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.javax.naming.giop; + +import gnu.java.lang.CPStringBuilder; + +import javax.naming.NameClassPair; +import javax.naming.NamingEnumeration; + +import org.omg.CosNaming.Binding; +import org.omg.CosNaming.BindingIteratorHolder; +import org.omg.CosNaming.BindingListHolder; +import org.omg.CosNaming.BindingType; +import org.omg.CosNaming.NamingContext; + +/** + * Iterates over name class pairs, obtaining values first from the binding list + * and then from the binding iterator. + * + * @author Audrius Meskauskas + */ +public class ListEnumeration extends GiopNamingEnumeration implements + NamingEnumeration +{ + /** + * Create the new enumeration + * + * @param bh + * holder, containing the first portion of the bindings + * @param bih + * the iterator, containing the remaining bindings + * @param batchSize + * the number of bindings the the iterator will be requested to + * return as a single pack + */ + public ListEnumeration(BindingListHolder bh, + BindingIteratorHolder bih, int batchSize) + { + super(bh, bih, batchSize); + } + + /** + * Convert from the CORBA binding into the {@link NameClassPair} that this + * enumeration should return. This method converts into NameClassPair, + * connecting the name components with slashes and setting the class name + * to either NamingContext or GIOP Object. + * + * @param binding + * the binding to convert + * @return the value, that must be returned by the {@link #next()}. + */ + public Object convert(Binding binding) + { + CPStringBuilder name = new CPStringBuilder(); + + for (int i = 0; i < binding.binding_name.length; i++) + { + name.append(binding.binding_name[i]); + if (i < binding.binding_name.length - 1) + name.append('/'); + } + + String className; + + switch (binding.binding_type.value()) + { + case BindingType._ncontext: + className = NamingContext.class.getName(); + break; + case BindingType._nobject: + className = org.omg.CORBA.Object.class.getName(); + break; + default: + className = Object.class.getName(); + break; + } + + NameClassPair pair = new NameClassPair(name.toString(), className); + return pair; + } + +} diff --git a/libjava/classpath/gnu/javax/naming/ictxImpl/trans/GnuName.java b/libjava/classpath/gnu/javax/naming/ictxImpl/trans/GnuName.java new file mode 100644 index 000000000..f37f8022d --- /dev/null +++ b/libjava/classpath/gnu/javax/naming/ictxImpl/trans/GnuName.java @@ -0,0 +1,469 @@ +/* GnuName.java -- implementation of the javax.naming.Name + 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.naming.ictxImpl.trans; + +import gnu.java.lang.CPStringBuilder; + +import java.util.Enumeration; +import java.util.NoSuchElementException; + +import javax.naming.InvalidNameException; +import javax.naming.Name; + +/** + * The implementation of the {@link Name}. + * + * @author Audrius Meskauskas + */ +public class GnuName + implements Name +{ + /** + * The enumeration to traverse over name components. + */ + class GnuNameEnum + implements Enumeration + { + /** + * Get the new enumeration that enumerates from the given position forward + * + * @param position the position of the first name component to enumerate (0 + * means first element) + */ + GnuNameEnum(int position) + { + nxt = from + position; + } + + /** + * The position of the next enumeration component to be returned or -1 if + * the end has been reached. + */ + int nxt; + + /** + * Check if there are more elements in this enumeration. + */ + public boolean hasMoreElements() + { + return nxt >= 0; + } + + /** + * Return the next element or throw a NoSuchElementException if there is no + * any. + */ + public Object nextElement() + { + if (nxt < 0) + throw new NoSuchElementException(); + Object r = content[nxt++]; + + if (nxt - from == length) + nxt = - 1; + + return r; + } + } + + private static final long serialVersionUID = - 3617482732056931635L; + + /** + * The hashcode + */ + int hash; + + /** + * The content buffer of the name. This buffer may be shared, so the array + * member content should never be modified. + */ + String[] content; + + /** + * The place, inclusive, where the name content starts in the content buffer. + */ + int from; + + /** + * The length of the name. + */ + int length; + + /** + * Creates the unitialised name. + */ + protected GnuName() + { + + } + + /** + * Creates the name, containing from the given chain of the atomic components. + * + * @param name the array, containing the name components. + */ + public GnuName(String[] name) + { + this(name, 0, name.length); + } + + /** + * Creates the name that uses the given portion of the array for its + * components. + */ + public GnuName(String[] buffer, int useFrom, int useLength) + { + content = buffer; + from = useFrom; + length = useLength; + } + + /** + * Inserts the given String component to this Name + * at the given index. The method modifies the current Name and + * then returns it. + * + * @exception ArrayIndexOutOfBoundsException if the given index is smaller + * then zero or greater then or equal to size(). + * @exception InvalidNameException if the given String is not a + * valid component for this Name. + */ + public Name add(int posn, String comp) throws InvalidNameException + { + String[] nc = new String[content.length + 1]; + System.arraycopy(content, from, nc, 0, posn); + nc[posn] = comp; + System.arraycopy(content, from + posn, nc, posn + 1, length - posn); + + content = nc; + from = 0; + length = content.length; + hash = 0; + return this; + } + + /** + * Adds the given String component to the end of this + * Name. The method modifies the current Name + * and then returns it. + * + * @exception InvalidNameException if the given String is not a + * valid component for this Name. + */ + public Name add(String comp) throws InvalidNameException + { + String[] nc = new String[content.length + 1]; + System.arraycopy(content, from, nc, 0, length); + nc[nc.length - 1] = comp; + + content = nc; + from = 0; + length = content.length; + hash = 0; + return this; + } + + /** + * Inserts all the components of the given Name to this + * Name at the given index. Components after this index (if + * any) are shifted up. The method modifies the current Name + * and then returns it. + * + * @exception ArrayIndexOutOfBoundsException if the given index is smaller + * then zero or greater then or equal to size(). + * @exception InvalidNameException if any of the given components is not a + * valid component for this Name. + */ + public Name addAll(int posn, Name n) throws InvalidNameException + { + String[] nc = new String[length + n.size()]; + System.arraycopy(content, from, nc, 0, posn); + + int i = posn; + for (int p = 0; p < n.size(); i++, p++) + nc[i] = n.get(p); + + System.arraycopy(content, from + posn, nc, i, length - posn); + + length = length + n.size(); + hash = 0; + content = nc; + return this; + } + + /** + * Adds all the components of the given Name to the end of this + * Name. The method modifies the current Name + * and then returns it. + * + * @exception InvalidNameException if any of the given components is not a + * valid component for this Name. + */ + public Name addAll(Name suffix) throws InvalidNameException + { + String[] nc = new String[length + suffix.size()]; + System.arraycopy(content, from, nc, 0, length); + + for (int i = length, p = 0; i < nc.length; i++, p++) + nc[i] = suffix.get(p); + + length = length + suffix.size(); + hash = 0; + content = nc; + return this; + } + + /** + * Compares the given object to this Name. Returns a negative + * value if the given Object is smaller then this + * Name, a positive value if the Object is + * bigger, and zero if the are equal. If the Object is not of a + * class that can be compared to the class of this Name then a + * ClassCastException is thrown. Note that it is not guaranteed + * that Names implemented in different classes can be + * compared. The definition of smaller, bigger and equal is up to the actual + * implementing class. + */ + public int compareTo(Object obj) + { + Name n = (Name) obj; + + int l = Math.min(length, n.size()); + int c; + + for (int i = 0; i < l; i++) + { + c = content[from + i].compareTo(n.get(i)); + if (c != 0) + return c; + } + return length - n.size(); + } + + /** + * Returns true if this Name ends with the + * components of the given Name, false + * otherwise. + */ + public boolean endsWith(Name n) + { + if (n.size() > length) + return false; + + int ofs = length - n.size() + from; + + for (int i = 0; i < n.size(); i++, ofs++) + if (! content[ofs].equals(n.get(i))) + return false; + + return true; + } + + /** + * Gets the component at the given index. + * + * @exception ArrayIndexOutOfBoundsException if the given index is smaller + * then zero or greater then or equal to size(). + */ + public String get(int posn) + { + return content[from + posn]; + } + + /** + * Returns a non-null (but possibly empty) Enumeration of the + * components of the Name as Strings. + */ + public Enumeration getAll() + { + return new GnuNameEnum(0); + } + + /** + * Returns the components till the given index as a Name. The + * returned Name can be modified without changing the original. + * + * @param posn the ending position, exclusive + * @exception ArrayIndexOutOfBoundsException if the given index is smaller + * then zero or greater then or equal to size(). + */ + public Name getPrefix(int posn) + { + return new GnuName(content, from, posn); + } + + /** + * Returns the components from the given index till the end as a + * Name. The returned Name can be modified + * without changing the original. + * + * @param posn the starting position, inclusive. If it is equal to the size of + * the name, the empty name is returned. + * @exception ArrayIndexOutOfBoundsException if the given index is smaller + * then zero or greater then or equal to size(). + */ + public Name getSuffix(int posn) + { + return new GnuName(content, from + posn, length - posn); + } + + /** + * Returns true if the number of components of this + * Name is zero, false otherwise. + */ + public boolean isEmpty() + { + return length == 0; + } + + /** + * Removes the component at the given index from this Name. + * The method modifies the current Name and then returns it. + * + * @exception InvalidNameException if the name size reduces below zero. + */ + public Object remove(int posn) throws InvalidNameException + { + if (length == 0) + throw new InvalidNameException("negative size"); + else + { + length--; + if (posn == 0) + from++; + else if (posn < length) + { + String[] nc = new String[length]; + System.arraycopy(content, from, nc, 0, posn); + System.arraycopy(content, from + posn + 1, nc, posn, length - posn); + content = nc; + from = 0; + } + } + hash = 0; + return this; + } + + /** + * Returns the number of components of this Name. The returned + * number can be zero. + */ + public int size() + { + return length; + } + + /** + * Returns true if this Name starts with the + * components of the given Name, false + * otherwise. + */ + public boolean startsWith(Name n) + { + if (n.size() > length) + return false; + + for (int i = 0; i < n.size(); i++) + if (! content[from + i].equals(n.get(i))) + return false; + + return true; + } + + /** + * Returns a clone of this Name. It will be a deep copy of all + * the components of the Name so that changes to components of + * the components does not change the component in this Name. + */ + public Object clone() + { + return new GnuName(content, from, length); + } + + /** + * The name is equal to other name if they contents are equal. + */ + public boolean equals(Object arg0) + { + if (this == arg0) + return true; + else if (arg0 instanceof Name) + { + Name n = (Name) arg0; + if (length != n.size()) + return false; + + for (int i = 0; i < length; i++) + if (! content[from + i].equals(n.get(i))) + return false; + return true; + } + else + return false; + } + + /** + * Overridden to make consistent with equals. + */ + public int hashCode() + { + if (hash == 0 && length > 0) + { + int s = 0; + for (int i = from; i < from + length; i++) + s ^= content[i].hashCode(); + hash = s; + } + return hash; + } + + /** + * Get the string representation, separating the name components by slashes + */ + public String toString() + { + CPStringBuilder b = new CPStringBuilder(); + for (int i = 0; i < length; i++) + { + b.append(get(i)); + if (i < length - 1) + b.append('/'); + } + return b.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/naming/jndi/url/corbaname/corbanameURLContextFactory.java b/libjava/classpath/gnu/javax/naming/jndi/url/corbaname/corbanameURLContextFactory.java new file mode 100644 index 000000000..c6fb8481f --- /dev/null +++ b/libjava/classpath/gnu/javax/naming/jndi/url/corbaname/corbanameURLContextFactory.java @@ -0,0 +1,53 @@ +/* corbanameURLContextFactory.java -- handles corbaname: urls + 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.naming.jndi.url.corbaname; + +import gnu.javax.naming.giop.GiopNamingServiceFactory; + +import javax.naming.spi.ObjectFactory; + +/** + * The GIOP URL context factory. + * + * @author Audrius Meskauskas (audriusa@Bioinformatics.org) + */ +public class corbanameURLContextFactory extends GiopNamingServiceFactory + implements ObjectFactory +{ + // Nothing to override here. +} diff --git a/libjava/classpath/gnu/javax/naming/jndi/url/rmi/ContextContinuation.java b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/ContextContinuation.java new file mode 100644 index 000000000..a94ae6d65 --- /dev/null +++ b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/ContextContinuation.java @@ -0,0 +1,597 @@ +/* ContextContinuation.java -- RMI naming context + 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.naming.jndi.url.rmi; + +import java.rmi.AccessException; +import java.rmi.AlreadyBoundException; +import java.rmi.NotBoundException; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.util.Hashtable; +import java.util.Map; +import java.util.Properties; + +import javax.naming.CommunicationException; +import javax.naming.Context; +import javax.naming.InvalidNameException; +import javax.naming.Name; +import javax.naming.NameAlreadyBoundException; +import javax.naming.NameNotFoundException; +import javax.naming.NameParser; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.OperationNotSupportedException; + +/** + * The implementation of the RMI URL context. This context connects + * + * @author Audrius Meskauskas + */ +public class ContextContinuation implements Context +{ + /** + * The default registry location. + */ + public static final String DEFAULT_REGISTRY_LOCATION = "rmi://localhost:1099"; + + /** + * The local or remote RMI registry, performing the actual work for this + * context. + */ + Registry registry; + + /** + * The properties. + */ + Properties properties; + + /** + * The flag, indicating, that the lookup methods were called before. + * If the lookup methods were called before, the existing ORB cannot be + * destroyed, as references to the existing objects will become + * unfunctional. + */ + boolean lookupCalled; + + /** + * Add new environment property to the environment of this context. Both name + * and value of the new property must not be null. If the property is already + * defined, is current value is replaced by the propVal. This method replaces + * the registry. The new registry will be lazily instantiated on the first + * call. + * + * @param key + * the name of the new property + * @param value + * the value of the new property + * @return the previous value of this property or null if the property has not + * been previously defined + */ + public Object addToEnvironment(String key, Object value) + { + removeRegistry(); + if (key == null || value == null) + throw new NullPointerException(); + return properties.put(key, value); + } + + /** + * Returns the environment, associated with this naming context. The returned + * table should never be modified by the caller (the registry would not be updated + * in such case). Use {@link #addToEnvironment} and + * {@link #removeFromEnvironment} to modify the environement, if needed. + * + * @return the table, representing the environment of this context + * @throws NamingException + */ + public Hashtable getEnvironment() throws NamingException + { + return properties; + } + + /** + * Removes the property with the given name from the environment. Returns + * without action if this property is not defined. Replaces the ORB, + * constructing the new ORB with the changes set of properties (you can + * replace the CORBA implementation provider, for instance). The new ORB will + * be lazily instantiated on the first call. + * + * @param propName + * the name of the property being removed. + * @return the value of the property that has been removed or null if the + * property was not defined. + * @throws NamingException + */ + public Object removeFromEnvironment(String propName) throws NamingException + { + removeRegistry(); + return properties.remove(propName); + } + + /** + * Remove the current registry reference. + */ + public void removeRegistry() + { + registry = null; + } + + /** + * Get the cached or new registry reference. + * + * @return the registry reference, either cached or new. + */ + public Registry getRegistry() throws NamingException + { + if (registry == null) + { + String address = properties.getProperty(Context.PROVIDER_URL, + DEFAULT_REGISTRY_LOCATION); + + // The format like rmi://localhost:1099 is expected. Parse. + if (!address.startsWith("rmi://")) + throw new InvalidNameException(address); + + String a = address.substring("rmi://".length()); + + // The colon, if present, indicates the start of the port number. + int colon = a.lastIndexOf(':'); + int port; + + try + { + if (colon >=0) + { + port = Integer.parseInt(a.substring(colon+1)); + a = a.substring(0, colon); + } + else + port = Registry.REGISTRY_PORT; + } + catch (NumberFormatException e1) + { + throw new InvalidNameException(address); + } + + try + { + registry = LocateRegistry.getRegistry(a, port); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + } + return registry; + } + + /** + * Create the rmi url context that works, talking with the given RMI registry. + * + * @param props + * the properties for this context + * @param initialRegistry + * the initial value of the registry + */ + public ContextContinuation(Map props, Registry initialRegistry) + { + properties = new Properties(); + if (props != null) + properties.putAll(props); + registry = initialRegistry; + } + + /** + * Bind the given name into this context. The .toString() is called to + * convert into the string representation, required by RMI registry. + * + * @throws NamingException if the object is not an instance of Remote + */ + public void bind(Name name, Object obj) throws NamingException + { + bind(name.toString(), obj); + } + + /** + * Bind the given name into this context. + */ + public void bind(String name, Object obj) throws NamingException + { + try + { + getRegistry().bind(name, (Remote) obj); + } + catch (AccessException e) + { + throw new NamingException("access:"+e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (AlreadyBoundException e) + { + throw new NameAlreadyBoundException(name); + } + catch (ClassCastException c) + { + throw new NamingException("Only Remote can be bound:" + + obj.getClass().getName()); + } + } + + /** + * Not supported. + */ + public Name composeName(Name name, Name prefix) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported. + */ + public String composeName(String name, String prefix) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. The only supported case is an + * empty name (returns the cloned instance of self). + */ + public Context createSubcontext(Name name) throws NamingException + { + if (name.size() == 0) + return new rmiURLContext(properties); + else + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. The only supported case is an + * empty name (returns the cloned instance of self). + */ + public Context createSubcontext(String name) throws NamingException + { + if (name.length() == 0) + return new rmiURLContext(properties); + else + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. + */ + public void destroySubcontext(Name name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. + */ + public void destroySubcontext(String name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Returns the naming service URL, same that was passed vie + * {@link Context#PROVIDER_URL}. + */ + public String getNameInNamespace() throws NamingException + { + return properties.getProperty(Context.PROVIDER_URL, + DEFAULT_REGISTRY_LOCATION); + } + + /** + * Not supported, this context never parses any names. + */ + public NameParser getNameParser(Name name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported, this context never parses any names. + */ + public NameParser getNameParser(String name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * List existing bindings of this context (the parameter must be empty name, + * indicating the root context). The class name of the returned name class + * pairs is "Remote", as this "quick preview" method should probably not call + * the naming service again. Use listBindings if more details are required. + */ + public NamingEnumeration list(Name name) throws NamingException + { + if (name.size() > 0) + throw new OperationNotSupportedException("Only empty name is accepted"); + return list(""); + } + + /** + * List existing bindings of this context (the parameter must be empty string, + * indicating the root context). The class name of the returned name class + * pairs is "Remote", as this "quick preview" method should probably not call + * the naming service again. Use listBindings if more details are required. + */ + public NamingEnumeration list(String name) throws NamingException + { + if (name.length() > 0) + throw new OperationNotSupportedException("Only empty name is accepted"); + + try + { + return new ListEnumeration(getRegistry().list()); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * List existing bindings of this context (the parameter must be empty name, + * indicating the root context). + */ + public NamingEnumeration listBindings(Name name) throws NamingException + { + if (name.size() > 0) + throw new OperationNotSupportedException("Only empty name is accepted"); + return listBindings(""); + } + + /** + * List existing bindings of this context (the parameter must be empty name, + * indicating the root context). + */ + public NamingEnumeration listBindings(String name) throws NamingException + { + if (name.length() > 0) + throw new OperationNotSupportedException("Only empty name is accepted"); + + try + { + Registry r = getRegistry(); + return new ListBindingsEnumeration(r.list(), r); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Not supported. + */ + public Object lookupLink(Name name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported. + */ + public Object lookupLink(String name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Rebinds this object. + * + * @param name + * the object name (.toString()) is used to convert into string + * representation. + * @param obj + * object (must be an instance of Remote). + */ + public void rebind(Name name, Object obj) throws NamingException + { + rebind(name.toString(), obj); + } + + /** + * Rebinds this object. + * + * @param name + * the object name. + * @param obj + * object (must be an instance of Remote). + */ + public void rebind(String name, Object obj) throws NamingException + { + try + { + getRegistry().rebind(name, (Remote) obj); + } + catch (AccessException e) + { + throw new NamingException("access:"+e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (ClassCastException c) + { + throw new NamingException("Only Remote can be bound:" + + obj.getClass().getName()); + } + } + + /** + * Renames the object. If the new name is already bound in the given context, + * the {@link AlreadyBoundException} is thrown and the oldName binding is + * preserved. + */ + public void rename(Name oldName, Name newName) throws NamingException + { + rename(oldName.toString(), newName.toString()); + } + + /** + * Renames the object. If the new name is already bound in the given context, + * the {@link AlreadyBoundException} is thrown and the oldName binding is + * preserved. + */ + public synchronized void rename(String oldName, String newName) + throws NamingException + { + try + { + Registry r = getRegistry(); + Remote object = r.lookup(oldName); + r.unbind(oldName); + try + { + r.bind(newName, object); + } + catch (AlreadyBoundException e) + { + // Bind it back. + try + { + r.bind(oldName, object); + } + catch (AlreadyBoundException e1) + { + // We have just removed this name. + throw new InternalError(); + } + throw new NameAlreadyBoundException(newName); + } + } + catch (AccessException e) + { + throw new NamingException(e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (NotBoundException e) + { + throw new CommunicationException(e.toString()); + } + } + + /** + * Unbind the object. + */ + public void unbind(Name name) throws NamingException + { + unbind(name.toString()); + } + + /** + * Unbind the object. + */ + public void unbind(String name) throws NamingException + { + try + { + getRegistry().unbind(name); + } + catch (AccessException e) + { + throw new NamingException(e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (NotBoundException e) + { + throw new CommunicationException(e.toString()); + } + } + + /** + * Release the associated resources. + */ + public void close() throws NamingException + { + removeRegistry(); + } + + /** + * Resolve the object by name. + * + * @param name + * the object name, .toString() is used to get the string + * representation. + */ + public Object lookup(Name name) throws NamingException + { + return lookup(name.toString()); + } + + /** + * Resolve the object by name + * + * @param name the object name. + */ + public Object lookup(String name) throws NamingException + { + try + { + return getRegistry().lookup(name); + } + catch (AccessException e) + { + throw new NamingException(e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (NotBoundException e) + { + throw new NameNotFoundException(name); + } + } +} diff --git a/libjava/classpath/gnu/javax/naming/jndi/url/rmi/ListBindingsEnumeration.java b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/ListBindingsEnumeration.java new file mode 100644 index 000000000..6ac4788d0 --- /dev/null +++ b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/ListBindingsEnumeration.java @@ -0,0 +1,97 @@ +/* ListBindingsEnumeration.java -- handles rmi: urls + 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.naming.jndi.url.rmi; + +import java.rmi.registry.Registry; + +import javax.naming.NamingEnumeration; + +/** + * Iterates over bindings, obtaining values first from the binding list and then + * from the binding iterator. + * + * @author Audrius Meskauskas + */ +public class ListBindingsEnumeration extends RmiNamingEnumeration implements + NamingEnumeration +{ + /** + * The naming service, to resolve the objects. + */ + Registry service; + + /** + * Create the new enumeration + * + * @param bindings + * the list of the bound names + * @param aService + * the RMI naming service, used to get the bound values. + */ + public ListBindingsEnumeration(String [] bindings, + Registry aService) + { + super(bindings); + service = aService; + } + + /** + * Convert from the CORBA binding into the javax.naming binding. As the CORBA + * naming service binding does not contain the object itself, this method + * makes the additional calls to the naming service. + * + * @param binding + * the binding to convert + * @return the value, that must be returned by the {@link #next()}. + */ + public Object convert(String binding) + { + try + { + Object object = service.lookup(binding); + return new javax.naming.Binding(binding, object); + } + catch (Exception e) + { + // Probably was removed by the concurent thread. + return null; + } + } + +} diff --git a/libjava/classpath/gnu/javax/naming/jndi/url/rmi/ListEnumeration.java b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/ListEnumeration.java new file mode 100644 index 000000000..b64ca87ea --- /dev/null +++ b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/ListEnumeration.java @@ -0,0 +1,80 @@ +/* ListEnumeration.java -- handles rmi: urls + 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.naming.jndi.url.rmi; + +import java.rmi.Remote; + +import javax.naming.NameClassPair; +import javax.naming.NamingEnumeration; + +/** + * Iterates over name class pairs, obtaining values first from the binding list + * and then from the binding iterator. + * + * @author Audrius Meskauskas + */ +public class ListEnumeration extends RmiNamingEnumeration implements + NamingEnumeration +{ + /** + * Create the new enumeration + * + * @param bindings + * the array of the binding names, returned by the RMI registry. + */ + public ListEnumeration(String [] bindings) + { + super(bindings); + } + + /** + * Convert from the binding name into the {@link NameClassPair} that this + * enumeration should return. + * + * @param binding + * the binding to convert + * @return the value, that must be returned by the {@link #next()}. + */ + public Object convert(String binding) + { + NameClassPair pair = new NameClassPair(binding, Remote.class.getName()); + return pair; + } + +} diff --git a/libjava/classpath/gnu/javax/naming/jndi/url/rmi/RmiContinuation.java b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/RmiContinuation.java new file mode 100644 index 000000000..c8e6a158a --- /dev/null +++ b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/RmiContinuation.java @@ -0,0 +1,594 @@ +/* RmiContinuation.java -- RMI naming context + 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.naming.jndi.url.rmi; + +import java.rmi.AccessException; +import java.rmi.AlreadyBoundException; +import java.rmi.NotBoundException; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.util.Hashtable; +import java.util.Map; +import java.util.Properties; + +import javax.naming.CommunicationException; +import javax.naming.Context; +import javax.naming.InvalidNameException; +import javax.naming.Name; +import javax.naming.NameAlreadyBoundException; +import javax.naming.NameNotFoundException; +import javax.naming.NameParser; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.OperationNotSupportedException; + +/** + * The implementation of the RMI URL context. This context connects + * + * @author Audrius Meskauskas + */ +public class RmiContinuation implements Context +{ + /** + * The default registry location. + */ + public static final String DEFAULT_REGISTRY_LOCATION = "rmi://localhost:1099"; + + /** + * The local or remote RMI registry, performing the actual work for this + * context. + */ + Registry registry; + + /** + * The properties. + */ + Properties properties; + + /** + * The flag, indicating, that the lookup methods were called before. + * If the lookup methods were called before, the existing ORB cannot be + * destroyed, as references to the existing objects will become + * unfunctional. + */ + boolean lookupCalled; + + /** + * Add new environment property to the environment of this context. Both name + * and value of the new property must not be null. If the property is already + * defined, is current value is replaced by the propVal. This method replaces + * the registry. The new registry will be lazily instantiated on the first + * call. + * + * @param key + * the name of the new property + * @param value + * the value of the new property + * @return the previous value of this property or null if the property has not + * been previously defined + */ + public Object addToEnvironment(String key, Object value) + { + removeRegistry(); + if (key == null || value == null) + throw new NullPointerException(); + return properties.put(key, value); + } + + /** + * Returns the environment, associated with this naming context. The returned + * table should never be modified by the caller (the registry would not be updated + * in such case). Use {@link #addToEnvironment} and + * {@link #removeFromEnvironment} to modify the environement, if needed. + * + * @return the table, representing the environment of this context + * @throws NamingException + */ + public Hashtable getEnvironment() throws NamingException + { + return properties; + } + + /** + * Removes the property with the given name from the environment. Returns + * without action if this property is not defined. Replaces the ORB, + * constructing the new ORB with the changes set of properties (you can + * replace the CORBA implementation provider, for instance). The new ORB will + * be lazily instantiated on the first call. + * + * @param propName + * the name of the property being removed. + * @return the value of the property that has been removed or null if the + * property was not defined. + * @throws NamingException + */ + public Object removeFromEnvironment(String propName) throws NamingException + { + removeRegistry(); + return properties.remove(propName); + } + + /** + * Remove the current registry reference. + */ + public void removeRegistry() + { + registry = null; + } + + /** + * Get the cached or new registry reference. + * + * @return the registry reference, either cached or new. + */ + public Registry getRegistry() throws NamingException + { + if (registry == null) + { + String address = properties.getProperty(Context.PROVIDER_URL, + DEFAULT_REGISTRY_LOCATION); + + // The format like rmi://localhost:1099 is expected. Parse. + if (!address.startsWith("rmi://")) + throw new InvalidNameException(address); + + String a = address.substring("rmi://".length()); + + // The colon, if present, indicates the start of the port number. + int colon = a.lastIndexOf(':'); + int port; + + try + { + if (colon >=0) + { + port = Integer.parseInt(a.substring(colon+1)); + a = a.substring(0, colon); + } + else + port = Registry.REGISTRY_PORT; + } + catch (NumberFormatException e1) + { + throw new InvalidNameException(address); + } + + try + { + registry = LocateRegistry.getRegistry(a, port); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + } + return registry; + } + + /** + * Create the rmi url context that works, talking with the given RMI registry. + * + * @param props + * the properties for this context + */ + public RmiContinuation(Map props) + { + properties = new Properties(); + if (props != null) + properties.putAll(props); + } + + /** + * Bind the given name into this context. The .toString() is called to + * convert into the string representation, required by RMI registry. + * + * @throws NamingException if the object is not an instance of Remote + */ + public void bind(Name name, Object obj) throws NamingException + { + bind(name.toString(), obj); + } + + /** + * Bind the given name into this context. + */ + public void bind(String name, Object obj) throws NamingException + { + try + { + getRegistry().bind(name, (Remote) obj); + } + catch (AccessException e) + { + throw new NamingException("access:"+e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (AlreadyBoundException e) + { + throw new NameAlreadyBoundException(name); + } + catch (ClassCastException c) + { + throw new NamingException("Only Remote can be bound:" + + obj.getClass().getName()); + } + } + + /** + * Not supported. + */ + public Name composeName(Name name, Name prefix) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported. + */ + public String composeName(String name, String prefix) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. The only supported case is an + * empty name (returns the cloned instance of self). + */ + public Context createSubcontext(Name name) throws NamingException + { + if (name.size() == 0) + return new RmiContinuation(properties); + else + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. The only supported case is an + * empty name (returns the cloned instance of self). + */ + public Context createSubcontext(String name) throws NamingException + { + if (name.length() == 0) + return new RmiContinuation(properties); + else + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. + */ + public void destroySubcontext(Name name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. + */ + public void destroySubcontext(String name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Returns the naming service URL, same that was passed vie + * {@link Context#PROVIDER_URL}. + */ + public String getNameInNamespace() throws NamingException + { + return properties.getProperty(Context.PROVIDER_URL, + DEFAULT_REGISTRY_LOCATION); + } + + /** + * Not supported, this context never parses any names. + */ + public NameParser getNameParser(Name name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported, this context never parses any names. + */ + public NameParser getNameParser(String name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * List existing bindings of this context (the parameter must be empty name, + * indicating the root context). The class name of the returned name class + * pairs is "Remote", as this "quick preview" method should probably not call + * the naming service again. Use listBindings if more details are required. + */ + public NamingEnumeration list(Name name) throws NamingException + { + if (name.size() > 0) + throw new OperationNotSupportedException("Only empty name is accepted"); + return list(""); + } + + /** + * List existing bindings of this context (the parameter must be empty string, + * indicating the root context). The class name of the returned name class + * pairs is "Remote", as this "quick preview" method should probably not call + * the naming service again. Use listBindings if more details are required. + */ + public NamingEnumeration list(String name) throws NamingException + { + if (name.length() > 0) + throw new OperationNotSupportedException("Only empty name is accepted"); + + try + { + return new ListEnumeration(getRegistry().list()); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * List existing bindings of this context (the parameter must be empty name, + * indicating the root context). + */ + public NamingEnumeration listBindings(Name name) throws NamingException + { + if (name.size() > 0) + throw new OperationNotSupportedException("Only empty name is accepted"); + return listBindings(""); + } + + /** + * List existing bindings of this context (the parameter must be empty name, + * indicating the root context). + */ + public NamingEnumeration listBindings(String name) throws NamingException + { + if (name.length() > 0) + throw new OperationNotSupportedException("Only empty name is accepted"); + + try + { + Registry r = getRegistry(); + return new ListBindingsEnumeration(r.list(), r); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Not supported. + */ + public Object lookupLink(Name name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported. + */ + public Object lookupLink(String name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Rebinds this object. + * + * @param name + * the object name (.toString()) is used to convert into string + * representation. + * @param obj + * object (must be an instance of Remote). + */ + public void rebind(Name name, Object obj) throws NamingException + { + rebind(name.toString(), obj); + } + + /** + * Rebinds this object. + * + * @param name + * the object name. + * @param obj + * object (must be an instance of Remote). + */ + public void rebind(String name, Object obj) throws NamingException + { + try + { + getRegistry().rebind(name, (Remote) obj); + } + catch (AccessException e) + { + throw new NamingException("access:"+e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (ClassCastException c) + { + throw new NamingException("Only Remote can be bound:" + + obj.getClass().getName()); + } + } + + /** + * Renames the object. If the new name is already bound in the given context, + * the {@link AlreadyBoundException} is thrown and the oldName binding is + * preserved. + */ + public void rename(Name oldName, Name newName) throws NamingException + { + rename(oldName.toString(), newName.toString()); + } + + /** + * Renames the object. If the new name is already bound in the given context, + * the {@link AlreadyBoundException} is thrown and the oldName binding is + * preserved. + */ + public synchronized void rename(String oldName, String newName) + throws NamingException + { + try + { + Registry r = getRegistry(); + Remote object = r.lookup(oldName); + r.unbind(oldName); + try + { + r.bind(newName, object); + } + catch (AlreadyBoundException e) + { + // Bind it back. + try + { + r.bind(oldName, object); + } + catch (AlreadyBoundException e1) + { + // We have just removed this name. + throw new InternalError(); + } + throw new NameAlreadyBoundException(newName); + } + } + catch (AccessException e) + { + throw new NamingException(e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (NotBoundException e) + { + throw new CommunicationException(e.toString()); + } + } + + /** + * Unbind the object. + */ + public void unbind(Name name) throws NamingException + { + unbind(name.toString()); + } + + /** + * Unbind the object. + */ + public void unbind(String name) throws NamingException + { + try + { + getRegistry().unbind(name); + } + catch (AccessException e) + { + throw new NamingException(e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (NotBoundException e) + { + throw new CommunicationException(e.toString()); + } + } + + /** + * Release the associated resources. + */ + public void close() throws NamingException + { + removeRegistry(); + } + + /** + * Resolve the object by name. + * + * @param name + * the object name, .toString() is used to get the string + * representation. + */ + public Object lookup(Name name) throws NamingException + { + return lookup(name.toString()); + } + + /** + * Resolve the object by name + * + * @param name the object name. + */ + public Object lookup(String name) throws NamingException + { + try + { + return getRegistry().lookup(name); + } + catch (AccessException e) + { + throw new NamingException(e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (NotBoundException e) + { + throw new NameNotFoundException(name); + } + } +} diff --git a/libjava/classpath/gnu/javax/naming/jndi/url/rmi/RmiNamingEnumeration.java b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/RmiNamingEnumeration.java new file mode 100644 index 000000000..a75896272 --- /dev/null +++ b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/RmiNamingEnumeration.java @@ -0,0 +1,130 @@ +/* RmiNamingEnumeration.java -- handles rmi: urls + 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.naming.jndi.url.rmi; + +import java.util.NoSuchElementException; + +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; + +/** + * Iterates over name class pairs, obtaining values first from the binding list + * and then from the binding iterator. + * + * @author Audrius Meskauskas + */ +public abstract class RmiNamingEnumeration implements NamingEnumeration +{ + /** + * The array of bindings, returned at once. + */ + String[] list; + + /** + * The position of the element in the binding list, that must be returned + * during the subsequent call of the next(). If this field is grater or equal + * to the lenght of the list, the subsequent values must be requested from the + * iterator. + */ + int p; + + RmiNamingEnumeration(String[] bindingList) + { + list = bindingList; + } + + /** + * Convert from the CORBA binding into that this enumeration should return. + * + * @param binding + * the binding to convert + * @return the value, that must be returned by the {@link #next()}. + */ + public abstract Object convert(String binding); + + /** + * Checks if there are more elements to return. + * + * @throws NamingException + * never + */ + public boolean hasMore() throws NamingException + { + return hasMoreElements(); + } + + /** + * Returns the next element. + * + * @throws NamingException + * never + */ + public Object next() throws NamingException + { + return nextElement(); + } + + /** + * Checks if there are more elements to return. + */ + public boolean hasMoreElements() + { + return p < list.length; + } + + /** + * Returns the next element. + */ + public Object nextElement() + { + if (p < list.length) + return convert(list[p++]); + else + throw new NoSuchElementException(); + } + + /** + * Nothing to do in this method. + */ + public void close() + { + // Nothing to do here. + } + +} diff --git a/libjava/classpath/gnu/javax/naming/jndi/url/rmi/rmiURLContext.java b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/rmiURLContext.java new file mode 100644 index 000000000..11f7265a6 --- /dev/null +++ b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/rmiURLContext.java @@ -0,0 +1,637 @@ +/* rmiURLContext.java -- RMI naming context + 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.naming.jndi.url.rmi; + +import java.rmi.AccessException; +import java.rmi.AlreadyBoundException; +import java.rmi.NotBoundException; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.util.Hashtable; +import java.util.Map; +import java.util.Properties; +import java.util.WeakHashMap; + +import javax.naming.CommunicationException; +import javax.naming.Context; +import javax.naming.InvalidNameException; +import javax.naming.Name; +import javax.naming.NameAlreadyBoundException; +import javax.naming.NameNotFoundException; +import javax.naming.NameParser; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.OperationNotSupportedException; + +/** + * The implementation of the RMI URL context. This context connects + * + * @author Audrius Meskauskas + */ +public class rmiURLContext implements Context +{ + /** + * The default registry location. + */ + public static final String DEFAULT_REGISTRY_LOCATION = "rmi://localhost:1099"; + + /** + * The registry cache, maps the registry URL's to they instances. The + * obtained registries are reused, as newly obtaining them may cause the + * resource leak. + */ + static WeakHashMap registryCache = new WeakHashMap(); + + /** + * The properties. + */ + Properties properties; + + /** + * The flag, indicating, that the lookup methods were called before. + * If the lookup methods were called before, the existing ORB cannot be + * destroyed, as references to the existing objects will become + * unfunctional. + */ + boolean lookupCalled; + + /** + * Add new environment property to the environment of this context. Both name + * and value of the new property must not be null. If the property is already + * defined, is current value is replaced by the propVal. This method replaces + * the registry. The new registry will be lazily instantiated on the first + * call. + * + * @param key + * the name of the new property + * @param value + * the value of the new property + * @return the previous value of this property or null if the property has not + * been previously defined + */ + public Object addToEnvironment(String key, Object value) + { + if (key == null || value == null) + throw new NullPointerException(); + return properties.put(key, value); + } + + /** + * Returns the environment, associated with this naming context. The returned + * table should never be modified by the caller (the registry would not be updated + * in such case). Use {@link #addToEnvironment} and + * {@link #removeFromEnvironment} to modify the environement, if needed. + * + * @return the table, representing the environment of this context + * @throws NamingException + */ + public Hashtable getEnvironment() throws NamingException + { + return properties; + } + + /** + * Removes the property with the given name from the environment. Returns + * without action if this property is not defined. Replaces the ORB, + * constructing the new ORB with the changes set of properties (you can + * replace the CORBA implementation provider, for instance). The new ORB will + * be lazily instantiated on the first call. + * + * @param propName + * the name of the property being removed. + * @return the value of the property that has been removed or null if the + * property was not defined. + * @throws NamingException + */ + public Object removeFromEnvironment(String propName) throws NamingException + { + return properties.remove(propName); + } + + /** + * Get the cached or new registry reference. + * + * @return the registry reference, either cached or new. + */ + public Registry getRegistry(String netAddress) throws NamingException + { + Registry registry; + + synchronized (registryCache) + { + registry = (Registry) registryCache.get(netAddress); + } + + if (registry == null) + { + // The colon, if present, indicates the start of the port number. + int colon = netAddress.lastIndexOf(':'); + int port; + + try + { + if (colon >= 0) + { + port = Integer.parseInt(netAddress.substring(colon + 1)); + netAddress = netAddress.substring(0, colon); + } + else + port = Registry.REGISTRY_PORT; + } + catch (NumberFormatException e1) + { + throw new InvalidNameException(netAddress); + } + + try + { + registry = LocateRegistry.getRegistry(netAddress, port); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + + synchronized (registryCache) + { + registryCache.put(netAddress, registry); + } + } + return registry; + } + + /** + * Create the rmi url context that works, talking with the given RMI registry. + * + * @param props + * the properties for this context + */ + public rmiURLContext(Map props) + { + properties = new Properties(); + if (props != null) + properties.putAll(props); + } + + /** + * Bind the given name into this context. The .toString() is called to + * convert into the string representation, required by RMI registry. + * + * @throws NamingException if the object is not an instance of Remote + */ + public void bind(Name name, Object obj) throws NamingException + { + bind(name.toString(), obj); + } + + /** + * Bind the given name into this context. + */ + public void bind(String name, Object obj) throws NamingException + { + try + { + String [] n = split(name); + getRegistry(n[0]).bind(n[1], (Remote) obj); + } + catch (AccessException e) + { + throw new NamingException("access:"+e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (AlreadyBoundException e) + { + throw new NameAlreadyBoundException(name); + } + catch (ClassCastException c) + { + throw new NamingException("Only Remote can be bound:" + + obj.getClass().getName()); + } + } + + /** + * Not supported. + */ + public Name composeName(Name name, Name prefix) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported. + */ + public String composeName(String name, String prefix) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. The only supported case is an + * empty name (returns the cloned instance of self). + */ + public Context createSubcontext(Name name) throws NamingException + { + if (name.size() == 0) + return new rmiURLContext(properties); + else + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. The only supported case is an + * empty name (returns the cloned instance of self). + */ + public Context createSubcontext(String name) throws NamingException + { + if (name.length() == 0) + return new rmiURLContext(properties); + else + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. + */ + public void destroySubcontext(Name name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Subcontexts are not supporte by RMI registry. + */ + public void destroySubcontext(String name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Returns the naming service URL, same that was passed vie + * {@link Context#PROVIDER_URL}. + */ + public String getNameInNamespace() throws NamingException + { + return properties.getProperty(Context.PROVIDER_URL, + DEFAULT_REGISTRY_LOCATION); + } + + /** + * Not supported, this context never parses any names. + */ + public NameParser getNameParser(Name name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * Not supported, this context never parses any names. + */ + public NameParser getNameParser(String name) throws NamingException + { + throw new OperationNotSupportedException(); + } + + /** + * List existing bindings of this context (the parameter must be empty name, + * indicating the root context). The class name of the returned name class + * pairs is "Remote", as this "quick preview" method should probably not call + * the naming service again. Use listBindings if more details are required. + */ + public NamingEnumeration list(Name name) throws NamingException + { + return list(name); + } + + /** + * List existing bindings of thie given registry.The class name of the + * returned name class pairs is "Remote", as this "quick preview" method + * should probably not call the naming service again. Use listBindings if more + * details are required. + */ + public NamingEnumeration list(String name) throws NamingException + { + try + { + String [] n = split(name); + if (n[1].length() > 0) + throw new InvalidNameException(name+", the name part must be empty"); + return new ListEnumeration(getRegistry(n[0]).list()); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * List existing bindings of this context (the parameter must be empty name, + * indicating the root context). + */ + public NamingEnumeration listBindings(Name name) throws NamingException + { + return listBindings(name.toString()); + } + + /** + * List existing bindings of this context. + */ + public NamingEnumeration listBindings(String name) throws NamingException + { + try + { + String [] n = split(name); + if (n[1].length() > 0) + throw new InvalidNameException(name+", the name part must be empty"); + + Registry r = getRegistry(n[0]); + return new ListBindingsEnumeration(r.list(), r); + } + catch (Exception e) + { + throw new NamingException(e.toString()); + } + } + + /** + * Returns the naming service context under the given address, wrapped as + * Context. + */ + public Object lookupLink(Name name) throws NamingException + { + return lookupLink(name.toString()); + } + + /** + * Returns the naming service context under the given address, + * wrapped as Context. + */ + public Object lookupLink(String name) throws NamingException + { + return new ContextContinuation(properties, getRegistry(name)); + } + + /** + * Rebinds this object. + * + * @param name + * the object name (.toString()) is used to convert into string + * representation. + * @param obj + * object (must be an instance of Remote). + */ + public void rebind(Name name, Object obj) throws NamingException + { + rebind(name.toString(), obj); + } + + /** + * Rebinds this object. + * + * @param name + * the object name. + * @param obj + * object (must be an instance of Remote). + */ + public void rebind(String name, Object obj) throws NamingException + { + try + { + String [] n = split(name); + getRegistry(n[0]).rebind(n[1], (Remote) obj); + } + catch (AccessException e) + { + throw new NamingException("access:"+e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (ClassCastException c) + { + throw new NamingException("Only Remote can be bound:" + + obj.getClass().getName()); + } + } + + /** + * Renames the object. If the new name is already bound in the given context, + * the {@link AlreadyBoundException} is thrown and the oldName binding is + * preserved. + */ + public void rename(Name oldName, Name newName) throws NamingException + { + rename(oldName.toString(), newName.toString()); + } + + /** + * Renames the object. If the new name is already bound in the given context, + * the {@link AlreadyBoundException} is thrown and the oldName binding is + * preserved. + */ + public synchronized void rename(String oldName, String newName) + throws NamingException + { + try + { + String [] n = split(oldName); + Registry r = getRegistry(n[0]); + Remote object = r.lookup(n[1]); + r.unbind(oldName); + try + { + String [] n2 = split(newName); + Registry r2 = getRegistry(n2[0]); + r2.bind(n2[1], object); + } + catch (AlreadyBoundException e) + { + // Bind it back. + try + { + r.bind(oldName, object); + } + catch (AlreadyBoundException e1) + { + // We have just removed this name. + throw new InternalError(); + } + throw new NameAlreadyBoundException(newName); + } + } + catch (AccessException e) + { + throw new NamingException(e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (NotBoundException e) + { + throw new CommunicationException(e.toString()); + } + } + + /** + * Unbind the object. + */ + public void unbind(Name name) throws NamingException + { + unbind(name.toString()); + } + + /** + * Unbind the object. + */ + public void unbind(String name) throws NamingException + { + try + { + String [] n = split(name); + getRegistry(n[0]).unbind(n[1]); + } + catch (AccessException e) + { + throw new NamingException(e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (NotBoundException e) + { + throw new CommunicationException(e.toString()); + } + } + + /** + * Release the associated resources. + */ + public void close() throws NamingException + { + } + + /** + * Resolve the object by name. + * + * @param name + * the object name, .toString() is used to get the string + * representation. + */ + public Object lookup(Name name) throws NamingException + { + return lookup(name.toString()); + } + + /** + * Resolve the object by name + * + * @param name the object name. + */ + public Object lookup(String name) throws NamingException + { + try + { + String [] n = split(name); + return getRegistry(n[0]).lookup(n[1]); + } + catch (AccessException e) + { + throw new NamingException(e.toString()); + } + catch (RemoteException e) + { + throw new CommunicationException(e.toString()); + } + catch (NotBoundException e) + { + throw new NameNotFoundException(name); + } + } + + /** + * Split the given rmi address into the network address and naming service + * name. + * + * @param address + * the address to split + * @return the two member array, lower being the network address of the naming + * service and upper being the naming service name + * @throws NamingException + * if the name is invalid + */ + public String[] split(String address) throws NamingException + { + // The format like rmi://localhost:1099/name is expected. Parse. + if (!address.startsWith("rmi://")) + throw new InvalidNameException( + address + + " should be like 'rmi://localhost:1099/name'"); + + String a = address.substring("rmi://".length()); + + // The suffix starts after the first slash from the rmi:// + int sfx = a.indexOf('/'); + + // Handle the possible escape + while (sfx > 0 && a.charAt(sfx - 1) == '\\') + sfx = a.indexOf('/', sfx + 1); + + String net; + String name; + if (sfx >= 0) + { + net = a.substring(0, sfx); + name = a.substring(sfx + 1); + } + else + { + net = a; + name = ""; + } + + return new String[] { net, name }; + } +} diff --git a/libjava/classpath/gnu/javax/naming/jndi/url/rmi/rmiURLContextFactory.java b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/rmiURLContextFactory.java new file mode 100644 index 000000000..ce0471d36 --- /dev/null +++ b/libjava/classpath/gnu/javax/naming/jndi/url/rmi/rmiURLContextFactory.java @@ -0,0 +1,66 @@ +/* rmiURLContextFactory.java -- handles RMI naming context + 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.naming.jndi.url.rmi; + +import java.util.Hashtable; + +import javax.naming.Context; +import javax.naming.Name; +import javax.naming.spi.ObjectFactory; + +/** + * Find the RMI URL context. This factory checks the Context.PROVIDER_URL + * property for the address of the RMI naming service and creates the + * context that operates talking with this naming service. If such property + * is missing, "rmi://localhost:1099" is assumed. + * + * @author Audrius Meskauskas (audriusa@Bioinformatics.org) + */ +public class rmiURLContextFactory implements ObjectFactory +{ + + /** + * Create a new instance of the context. + */ + public Object getObjectInstance(Object refObj, Name name, Context nameCtx, + Hashtable environment) + { + return new rmiURLContext(environment); + } + +} diff --git a/libjava/classpath/gnu/javax/net/ssl/AbstractSessionContext.java b/libjava/classpath/gnu/javax/net/ssl/AbstractSessionContext.java new file mode 100644 index 000000000..96a4e6dd0 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/AbstractSessionContext.java @@ -0,0 +1,288 @@ +/* AbstractSessionContext -- stores SSL sessions, possibly persistently. + 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.java.security.Requires; + +import gnu.javax.net.ssl.provider.SimpleSessionContext; + +import java.util.Enumeration; + +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLPermission; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSessionContext; + +/** + * A skeletal implementation of {@link SSLSessionContext}. This class may + * be subclassed to add extended functionality to session contexts, such + * as by storing sessions in files on disk, or by sharing contexts + * across different JVM instances. + * + *

    In order to securely store sessions, along with private key data, + * the abstract methods {@lnk {@link #load(char[])} and {@link #store(char[])} + * come into play. When storing sessions, a session context implementation + * must pass this password to the {@link Session#prepare(char[])} method, + * before either writing the {@link java.io.Serializable} session to the + * underlying store, or getting the opaque {@link Session#privateData()} + * class from the session, and storing that. + * + *

    As a simple example, that writes sessions to some object output + * stream: + * + *

    +  char[] password = ...;
    +  ObjectOutputStream out = ...;
    +  ...
    +  for (Session s : this)
    +    {
    +      s.prepare(password);
    +      out.writeObject(s);
    +    }
    + * + *

    The reverse must be done when deserializing sessions, by using the + * {@link Session#repair(char[])} method, possibly by first calling + * {@link Session#setPrivateData(java.io.Serializable)} with the read, + * opaque private data type. Thus an example of reading may be: + * + *

    +  char[] password = ...;
    +  ObjectInputStream in = ...;
    +  ...
    +  while (hasMoreSessions(in))
    +    {
    +      Session s = (Session) in.readObject();
    +      s.repair(password);
    +      addToThisStore(s);
    +    }
    + * + * @author Casey Marshall (csm@gnu.org) + */ +public abstract class AbstractSessionContext implements SSLSessionContext +{ + protected long timeout; + private static Class + implClass = SimpleSessionContext.class; + + /** + * Create a new instance of a session context, according to the configured + * implementation class. + * + * @return The new session context. + * @throws SSLException If an error occurs in creating the instance. + */ + public static AbstractSessionContext newInstance () throws SSLException + { + try + { + return implClass.newInstance(); + } + catch (IllegalAccessException iae) + { + throw new SSLException(iae); + } + catch (InstantiationException ie) + { + throw new SSLException(ie); + } + } + + /** + * Reconfigure this instance to use a different session context + * implementation. + * + *

    Note: this method requires that the caller have + * {@link SSLPermission} with target + * gnu.javax.net.ssl.AbstractSessionContext and action + * setImplClass. + * + * @param clazz The new implementation class. + * @throws SecurityException If the caller does not have permission to + * change the session context. + */ + @Requires(permissionClass = SSLPermission.class, + target = "gnu.javax.net.ssl.AbstractSessionContext", + action = "setImplClass") + public static synchronized void setImplClass + (Class clazz) + throws SecurityException + { + SecurityManager sm = System.getSecurityManager (); + if (sm != null) + sm.checkPermission(new SSLPermission("gnu.javax.net.ssl.AbstractSessionContext", + "setImplClass")); + implClass = clazz; + } + + /** + * @param timeout The initial session timeout. + */ + protected AbstractSessionContext (final int timeout) + { + setSessionTimeout(timeout); + } + + /** + * Fetch a saved session by its ID. This method will (possibly) + * deserialize and return the SSL session with that ID, or null if + * the requested session does not exist, or has expired. + * + *

    Subclasses implementing this class must not + * perform any blocking operations in this method. If any blocking + * behavior is required, it must be done in the {@link load(char[])} + * method. + * + * @param sessionId The ID of the session to get. + * @return The found session, or null if no such session was found, + * or if that session has expired. + */ + public final SSLSession getSession (byte[] sessionId) + { + Session s = implGet (sessionId); + if (s != null + && System.currentTimeMillis () - s.getLastAccessedTime () > timeout) + { + remove (sessionId); + return null; + } + return s; + } + + public final SSLSession getSession(String host, int port) + { + for (Enumeration e = getIds(); e.hasMoreElements(); ) + { + byte[] id = (byte[]) e.nextElement(); + SSLSession s = getSession(id); + if (s == null) // session expired. + continue; + String host2 = s.getPeerHost(); + if (host == null) + { + if (host2 != null) + continue; + } + else if (!host.equals(host2)) + continue; + int port2 = s.getPeerPort(); + if (port != port2) + continue; + + // Else, a match. + return s; + } + + return null; + } + + /** + * To be implemented by subclasses. Subclasses do not need to check + * timeouts in this method. + * + * @param sessionId The session ID. + * @return The session, or null if the requested session + * was not found. + */ + protected abstract Session implGet (byte[] sessionId); + + public int getSessionTimeout() + { + return (int) (timeout / 1000); + } + + /** + * Load this session store from the underlying media, if supported + * by the implementation. + * + * @param password The password that protects the sensitive data in + * this store. + * @throws SessionStoreException If reading this store fails, such + * as when an I/O exception occurs, or if the password is incorrect. + */ + public abstract void load (char[] password) throws SessionStoreException; + + /** + * Add a new session to the store. The underlying implementation + * will add the session to its store, possibly overwriting any + * existing session with the same ID. + * + *

    Subclasses implementing this class must not + * perform any blocking operations in this method. If any blocking + * behavior is required, it must be done in the {@link + * #store(char[])} method. + * + * @param session The session to add. + * @throws NullPointerException If the argument is null. + */ + public abstract void put (Session session); + + /** + * Remove a session from this store. + * + *

    Subclasses implementing this class must not + * perform any blocking operations in this method. If any blocking + * behavior is required, it must be done in the {@link + * #store(char[])} method. + * + * @param sessionId The ID of the session to remove. + */ + public abstract void remove (byte[] sessionId); + + /** + * + */ + public final void setSessionTimeout(int seconds) + { + if (timeout < 0) + throw new IllegalArgumentException("timeout may not be negative"); + this.timeout = (long) seconds * 1000; + } + + /** + * Commit this session store to the underlying media. For session + * store implementations that support saving sessions across + * invocations of the JVM, this method will save any sessions that + * have not expired to some persistent media, so they may be loaded + * and used again later. + * + * @param password The password that will protect the sensitive data + * in this store. + */ + public abstract void store (char[] password) throws SessionStoreException; +} diff --git a/libjava/classpath/gnu/javax/net/ssl/EntropySource.java b/libjava/classpath/gnu/javax/net/ssl/EntropySource.java new file mode 100644 index 000000000..be840e5d6 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/NullManagerParameters.java b/libjava/classpath/gnu/javax/net/ssl/NullManagerParameters.java new file mode 100644 index 000000000..0e9337932 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/PreSharedKeyManager.java b/libjava/classpath/gnu/javax/net/ssl/PreSharedKeyManager.java new file mode 100644 index 000000000..2c9fd2aea --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/PreSharedKeyManager.java @@ -0,0 +1,54 @@ +/* PreSharedKeyManager.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.net.ssl; + +import java.security.KeyManagementException; + +import javax.crypto.SecretKey; +import javax.net.ssl.KeyManager; + +/** + * @author Casey Marshall (csm@gnu.org) + */ +public interface PreSharedKeyManager extends KeyManager +{ + SecretKey getKey(String name) throws KeyManagementException; + + String chooseIdentityHint(); +} diff --git a/libjava/classpath/gnu/javax/net/ssl/PreSharedKeyManagerParameters.java b/libjava/classpath/gnu/javax/net/ssl/PreSharedKeyManagerParameters.java new file mode 100644 index 000000000..fe3c9e89b --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/PreSharedKeyManagerParameters.java @@ -0,0 +1,83 @@ +/* PreSharedKeyManagerParameters.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.net.ssl; + +import java.util.Iterator; +import java.util.LinkedHashMap; + +import javax.crypto.SecretKey; +import javax.net.ssl.ManagerFactoryParameters; + +/** + * @author Casey Marshall (csm@gnu.org) + */ +public class PreSharedKeyManagerParameters + implements ManagerFactoryParameters +{ + private final LinkedHashMap keys; + + public PreSharedKeyManagerParameters() + { + keys = new LinkedHashMap(); + } + + public SecretKey getKey(String name) + { + name.getClass(); + return keys.get(name); + } + + public void putKey(String name, SecretKey key) + { + name.getClass(); + key.getClass(); + keys.put(name, key); + } + + public boolean removeKey(String name) + { + name.getClass(); + return keys.remove(name) != null; + } + + public Iterator identities() + { + return keys.keySet().iterator(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/PrivateCredentials.java b/libjava/classpath/gnu/javax/net/ssl/PrivateCredentials.java new file mode 100644 index 000000000..7fff253dd --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/PrivateCredentials.java @@ -0,0 +1,363 @@ +/* PrivateCredentials.java -- private key/certificate pairs. + Copyright (C) 2006, 2007 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.java.lang.CPStringBuilder; + +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.Certificate; +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; +import gnu.java.util.Base64; + +/** + * 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; + CPStringBuilder base64 = new CPStringBuilder(); + 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"); + CPStringBuilder str = new CPStringBuilder(); + 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/libjava/classpath/gnu/javax/net/ssl/SRPManagerParameters.java b/libjava/classpath/gnu/javax/net/ssl/SRPManagerParameters.java new file mode 100644 index 000000000..a2a745e1b --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/SRPTrustManager.java b/libjava/classpath/gnu/javax/net/ssl/SRPTrustManager.java new file mode 100644 index 000000000..664fa4cab --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/SSLCipherSuite.java b/libjava/classpath/gnu/javax/net/ssl/SSLCipherSuite.java new file mode 100644 index 000000000..80068e5cb --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/SSLCipherSuite.java @@ -0,0 +1,142 @@ +/* SSLCipherSuite.java -- an SSL cipher suite. + 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.java.security.Engine; + +import java.lang.reflect.InvocationTargetException; +import java.nio.ByteBuffer; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.Security; + +/** + * An SSL cipher suite. + */ +public abstract class SSLCipherSuite +{ + private static final String SERVICE = "SSLCipherSuite"; + private final String algorithm; + private final byte[] id; + private final SSLProtocolVersion version; + private Provider provider; + + protected SSLCipherSuite (final String algorithm, final byte[] id, + final SSLProtocolVersion version) + { + this.algorithm = algorithm; + if (id.length != 2) + throw new IllegalArgumentException ("cipher suite ID must be two bytes"); + this.id = (byte[]) id.clone (); + this.version = version; + } + + public static final SSLCipherSuite getInstance (SSLProtocolVersion version, byte[] id) + throws NoSuchAlgorithmException + { + return getInstance (version + "-" + ((id[0] & 0xFF) + "/" + (id[1] & 0xFF))); + } + + public static final SSLCipherSuite getInstance (SSLProtocolVersion version, + byte[] id, Provider provider) + throws NoSuchAlgorithmException + { + return getInstance (version + "-" + (id[0] & 0xFF) + "/" + (id[1] & 0xFF), provider); + } + + public static final SSLCipherSuite getInstance (String name) + throws NoSuchAlgorithmException + { + Provider[] providers = Security.getProviders (); + for (int i = 0; i < providers.length; i++) + { + try + { + return getInstance (name, providers[i]); + } + catch (NoSuchAlgorithmException nsae) + { + // Ignore. + } + } + + throw new NoSuchAlgorithmException (SERVICE + ": " + name); + } + + public static final SSLCipherSuite getInstance (String name, Provider provider) + throws NoSuchAlgorithmException + { + SSLCipherSuite suite = null; + try + { + suite = (SSLCipherSuite) Engine.getInstance (SERVICE, name, provider); + suite.provider = provider; + } + catch (InvocationTargetException ite) + { + // XXX + NoSuchAlgorithmException nsae = new NoSuchAlgorithmException (name); + nsae.initCause (ite); + throw nsae; + } + return suite; + } + + public final String getAlgorithm () + { + return algorithm; + } + + public final byte[] getId () + { + return (byte[]) id.clone (); + } + + public final Provider getProvider () + { + return provider; + } + + public final SSLProtocolVersion getProtocolVersion () + { + return version; + } + + public abstract void encipher (ByteBuffer in, ByteBuffer out); +} diff --git a/libjava/classpath/gnu/javax/net/ssl/SSLProtocolVersion.java b/libjava/classpath/gnu/javax/net/ssl/SSLProtocolVersion.java new file mode 100644 index 000000000..3998f936a --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/SSLProtocolVersion.java @@ -0,0 +1,54 @@ +/* SSLProtocolVersion.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.net.ssl; + +public enum SSLProtocolVersion +{ + SSLv3 (3, 0), + TLSv1 (3, 1); + + public final int major; + public final int minor; + + private SSLProtocolVersion (int major, int minor) + { + this.major = major; + this.minor = minor; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/SSLRecordHandler.java b/libjava/classpath/gnu/javax/net/ssl/SSLRecordHandler.java new file mode 100644 index 000000000..8a44245ce --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/SSLRecordHandler.java @@ -0,0 +1,100 @@ +/* SSLRecordHandler.java -- a class that handles SSL record layer messages. + 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.nio.ByteBuffer; +import javax.net.ssl.SSLException; + +public abstract class SSLRecordHandler +{ + private final byte contentType; + + /** + * Create a new record handler for the given content type. + */ + protected SSLRecordHandler (final byte contentType) + { + this.contentType = contentType; + } + + /** + * Handle an SSL record layer message, encapsulated in the supplied + * input buffer, and writing any output bytes to the output + * buffer. The input buffer is always only limited to the bytes that + * encapsulate the fragment of the record layer message + * — that is, the content-type, version, and length fields are + * not present in the input buffer, and the limit of the input + * buffer is always only as large as the fragment. If the message + * being read is not contained entirely within the given buffer, + * then the implementation should cache the bytes read as input, and + * wait until subsequent calls finish the object being read. + * + *

    Technically, we expect only APPLICATION messages to ever + * produce output, but do suppose that extensions to the SSL + * protocol could allow other channels that produce output. + * + * @param input The input buffer. + * @param output The output buffer. + */ + public abstract void handle (final ByteBuffer input, + final ByteBuffer output) + throws SSLException; + + /** + * Returns the record layer content type that this handler is for. + * + * @return The content type value. + */ + public final byte contentType () + { + return contentType; + } + + public boolean equals (final Object o) + { + if (!(o instanceof SSLRecordHandler)) + return false; + return ((SSLRecordHandler) o).contentType == contentType; + } + + public int hashCode () + { + return contentType & 0xFF; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/Session.java b/libjava/classpath/gnu/javax/net/ssl/Session.java new file mode 100644 index 000000000..3acf9932d --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/Session.java @@ -0,0 +1,366 @@ +/* SessionImpl.java -- concrete definition of SSLSession. + 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.java.lang.CPStringBuilder; + +import java.io.Serializable; + +import java.security.Principal; +import java.security.SecureRandom; +import java.security.cert.Certificate; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Set; + +import javax.crypto.SealedObject; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSessionBindingEvent; +import javax.net.ssl.SSLSessionBindingListener; +import javax.net.ssl.SSLSessionContext; +import javax.security.cert.X509Certificate; + +/** + * A concrete implementation of the {@link SSLSession} interface. This + * class is provided to allow pluggable {@link AbstractSessionContext} + * implementations. + */ +public abstract class Session implements SSLSession, Serializable +{ + protected final long creationTime; + protected long lastAccessedTime; + protected int applicationBufferSize; + + protected ID sessionId; + protected Certificate[] localCerts; + protected Certificate[] peerCerts; + protected X509Certificate[] peerCertChain; + protected String peerHost; + protected int peerPort; + protected boolean peerVerified; + protected HashMap values; + protected boolean valid; + protected boolean truncatedMac = false; + transient protected SecureRandom random; + transient protected SSLSessionContext context; + + protected Session() + { + creationTime = System.currentTimeMillis(); + values = new HashMap(); + applicationBufferSize = (1 << 14); + } + + public void access() + { + lastAccessedTime = System.currentTimeMillis (); + } + + public int getApplicationBufferSize() + { + return applicationBufferSize; + } + + public String getCipherSuite() + { + return null; + } + + public long getCreationTime() + { + return creationTime; + } + + public byte[] getId() + { + return sessionId.id(); + } + + public ID id() + { + return sessionId; + } + + public long getLastAccessedTime() + { + return lastAccessedTime; + } + + public Certificate[] getLocalCertificates() + { + if (localCerts == null) + return null; + return (Certificate[]) localCerts.clone(); + } + + public Principal getLocalPrincipal() + { + if (localCerts != null) + { + if (localCerts[0] instanceof java.security.cert.X509Certificate) + return ((java.security.cert.X509Certificate) localCerts[0]).getSubjectDN(); + } + return null; + } + + public int getPacketBufferSize() + { + return applicationBufferSize + 2048; + } + + public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException + { + if (!peerVerified) + throw new SSLPeerUnverifiedException("peer not verified"); + if (peerCerts == null) + return null; + return (Certificate[]) peerCerts.clone(); + } + + public X509Certificate[] getPeerCertificateChain() + throws SSLPeerUnverifiedException + { + if (!peerVerified) + throw new SSLPeerUnverifiedException("peer not verified"); + if (peerCertChain == null) + return null; + return (X509Certificate[]) peerCertChain.clone(); + } + + public String getPeerHost() + { + return peerHost; + } + + public int getPeerPort() + { + return peerPort; + } + + public Principal getPeerPrincipal() throws SSLPeerUnverifiedException + { + if (!peerVerified) + throw new SSLPeerUnverifiedException("peer not verified"); + if (peerCertChain == null) + return null; + return peerCertChain[0].getSubjectDN(); + } + + public SSLSessionContext getSessionContext() + { + return context; + } + + public String[] getValueNames() + { + Set keys = this.values.keySet(); + return keys.toArray(new String[keys.size()]); + } + + public Object getValue(String name) + { + return values.get(name); + } + + public void invalidate() + { + valid = false; + } + + public boolean isValid() + { + return valid; + } + + public void putValue(String name, Object value) + { + values.put(name, value); + try + { + if (value instanceof SSLSessionBindingListener) + ((SSLSessionBindingListener) value).valueBound + (new SSLSessionBindingEvent(this, name)); + } + catch (Exception x) + { + } + } + + public void removeValue(String name) + { + Object value = values.remove(name); + try + { + if (value instanceof SSLSessionBindingListener) + ((SSLSessionBindingListener) value).valueUnbound + (new SSLSessionBindingEvent(this, name)); + } + catch (Exception x) + { + } + } + + public final boolean isTruncatedMac() + { + return truncatedMac; + } + + /** + * Prepare this session for serialization. Private data will be encrypted + * with the given password, and this object will then be ready to be + * serialized. + * + * @param password The password to protect this session with. + * @throws SSLException If encrypting this session's private data fails. + */ + public abstract void prepare (char[] password) throws SSLException; + + /** + * Repair this session's private data after deserialization. This method + * will decrypt this session's private data, and prepare the session for + * use in new SSL connections. + * + * @param password The password to decrypt the private data with. + * @throws SSLException + */ + public abstract void repair(char[] password) throws SSLException; + + /** + * Get the private data of this session. This method may only be called + * after first calling {@link #prepare(char[])}. + * + * @return The sealed private data. + * @throws SSLException If the private data have not been sealed. + */ + public abstract SealedObject privateData() throws SSLException; + + /** + * Set the private data of this session. + * @param data + * @throws SSLException + */ + public abstract void setPrivateData(SealedObject data) throws SSLException; + + // Inner classes. + // ------------------------------------------------------------------------- + + /** + * An SSL or TLS session ID. + */ + public static final class ID implements Comparable, Serializable + { + + // Fields. + // ----------------------------------------------------------------------- + + static final long serialVersionUID = 7887036954666565936L; + /** The ID itself. */ + private final byte[] id; + + // Constructor. + // ----------------------------------------------------------------------- + + /** + * Creates a new ID. + * + * @param id The ID. The array is cloned. + */ + public ID (final byte[] id) + { + if (id.length > 32) + throw new IllegalArgumentException ("session ID's are limited to 32 bytes"); + this.id = (byte[]) id.clone(); + } + + // Instance methods. + // ----------------------------------------------------------------------- + + public byte[] id() + { + return (byte[]) id.clone(); + } + + public boolean equals(Object other) + { + if (!(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) + { + 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] & 0xFF) < (id2[i] & 0xFF)) + return -1; + if ((id[i] & 0xFF) > (id2[i] & 0xFF)) + return 1; + } + return 0; + } + + public String toString() + { + CPStringBuilder str = new CPStringBuilder (3 * id.length + 1); + for (int i = 0; i < id.length; i++) + { + int x = id[i] & 0xFF; + str.append (Character.forDigit ((x >>> 4) & 0xF, 16)); + str.append (Character.forDigit (x & 0xF, 16)); + if (i != id.length - 1) + str.append (':'); + } + return str.toString (); + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/SessionStoreException.java b/libjava/classpath/gnu/javax/net/ssl/SessionStoreException.java new file mode 100644 index 000000000..4d8ef97d0 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/SessionStoreException.java @@ -0,0 +1,59 @@ +/* SessionStoreException.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.net.ssl; + +import javax.net.ssl.SSLException; + +public class SessionStoreException extends SSLException +{ + public SessionStoreException (final String message) + { + super (message); + } + + public SessionStoreException (final String message, final Throwable cause) + { + super (message, cause); + } + + public SessionStoreException (final Throwable cause) + { + super (cause); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/StaticTrustAnchors.java b/libjava/classpath/gnu/javax/net/ssl/StaticTrustAnchors.java new file mode 100644 index 000000000..480f1c754 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/StaticTrustAnchors.java @@ -0,0 +1,1940 @@ +/* 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.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/libjava/classpath/gnu/javax/net/ssl/provider/AbstractHandshake.java b/libjava/classpath/gnu/javax/net/ssl/provider/AbstractHandshake.java new file mode 100644 index 000000000..bf03ed77f --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/AbstractHandshake.java @@ -0,0 +1,1205 @@ +/* AbstractHandshake.java -- abstract handshake handler. + 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.debug.Component; +import gnu.classpath.debug.SystemLogger; +import gnu.java.security.action.GetSecurityPropertyAction; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.ByteArray; +import gnu.javax.security.auth.callback.CertificateCallback; +import gnu.javax.security.auth.callback.DefaultCallbackHandler; + +import java.nio.ByteBuffer; +import java.security.AccessController; +import java.security.DigestException; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.KeyManagementException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.PrivilegedExceptionAction; +import java.security.SecureRandom; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.zip.Deflater; +import java.util.zip.Inflater; + +import javax.crypto.Cipher; +import javax.crypto.KeyAgreement; +import javax.crypto.Mac; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.interfaces.DHPrivateKey; +import javax.crypto.interfaces.DHPublicKey; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import javax.net.ssl.SSLEngineResult; +import javax.net.ssl.SSLException; +import javax.net.ssl.X509TrustManager; +import javax.net.ssl.SSLEngineResult.HandshakeStatus; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.ConfirmationCallback; + +/** + * The base interface for handshake implementations. Concrete + * subclasses of this class (one for the server, one for the client) + * handle the HANDSHAKE content-type in communications. + */ +public abstract class AbstractHandshake +{ + protected static final SystemLogger logger = SystemLogger.SYSTEM; + + /** + * "server finished" -- TLS 1.0 and later + */ + protected static final byte[] SERVER_FINISHED + = new byte[] { + 115, 101, 114, 118, 101, 114, 32, 102, 105, 110, 105, 115, + 104, 101, 100 + }; + + /** + * "client finished" -- TLS 1.0 and later + */ + protected static final byte[] CLIENT_FINISHED + = new byte[] { + 99, 108, 105, 101, 110, 116, 32, 102, 105, 110, 105, 115, + 104, 101, 100 + }; + + /** + * "key expansion" -- TLS 1.0 and later + */ + private static final byte[] KEY_EXPANSION = + new byte[] { 107, 101, 121, 32, 101, 120, 112, + 97, 110, 115, 105, 111, 110 }; + + /** + * "master secret" -- TLS 1.0 and later + */ + private static final byte[] MASTER_SECRET + = new byte[] { + 109, 97, 115, 116, 101, 114, 32, 115, 101, 99, 114, 101, 116 + }; + + /** + * "client write key" -- TLS 1.0 exportable whitener. + */ + private static final byte[] CLIENT_WRITE_KEY + = new byte[] { + 99, 108, 105, 101, 110, 116, 32, 119, 114, 105, 116, 101, 32, 107, + 101, 121 + }; + + /** + * "server write key" -- TLS 1.0 exportable whitener. + */ + private static final byte[] SERVER_WRITE_KEY + = new byte[] { + 115, 101, 114, 118, 101, 114, 32, 119, 114, 105, 116, 101, 32, 107, + 101, 121 + }; + + private static final byte[] IV_BLOCK + = new byte[] { + 73, 86, 32, 98, 108, 111, 99, 107 + }; + + /** + * SSL 3.0; the string "CLNT" + */ + private static final byte[] SENDER_CLIENT + = new byte[] { 0x43, 0x4C, 0x4E, 0x54 }; + + /** + * SSL 3.0; the string "SRVR" + */ + private static final byte[] SENDER_SERVER + = new byte[] { 0x53, 0x52, 0x56, 0x52 }; + + /** + * SSL 3.0; the value 0x36 40 (for SHA-1 hashes) or 48 (for MD5 hashes) + * times. + */ + protected static final byte[] PAD1 = new byte[48]; + + /** + * SSL 3.0; the value 0x5c 40 (for SHA-1 hashes) or 48 (for MD5 hashes) + * times. + */ + protected static final byte[] PAD2 = new byte[48]; + + static + { + Arrays.fill(PAD1, SSLHMac.PAD1); + Arrays.fill(PAD2, SSLHMac.PAD2); + } + + /** + * The currently-read handshake messages. There may be zero, or + * multiple, handshake messages in this buffer. + */ + protected ByteBuffer handshakeBuffer; + + /** + * The offset into `handshakeBuffer' where the first unread + * handshake message resides. + */ + protected int handshakeOffset; + + protected MessageDigest sha; + protected MessageDigest md5; + + protected final SSLEngineImpl engine; + protected KeyAgreement keyAgreement; + protected byte[] preMasterSecret; + protected InputSecurityParameters inParams; + protected OutputSecurityParameters outParams; + protected LinkedList tasks; + protected Random serverRandom; + protected Random clientRandom; + protected CompressionMethod compression; + + protected AbstractHandshake(SSLEngineImpl engine) + throws NoSuchAlgorithmException + { + this.engine = engine; + sha = MessageDigest.getInstance("SHA-1"); + md5 = MessageDigest.getInstance("MD5"); + tasks = new LinkedList(); + } + + /** + * Handles the next input message in the handshake. This is called + * in response to a call to {@link javax.net.ssl.SSLEngine#unwrap} + * for a message with content-type HANDSHAKE. + * + * @param record The input record. The callee should not assume that + * the record's buffer is writable, and should not try to use it for + * output or temporary storage. + * @return An {@link SSLEngineResult} describing the result. + */ + public final HandshakeStatus handleInput (ByteBuffer fragment) + throws SSLException + { + if (!tasks.isEmpty()) + return HandshakeStatus.NEED_TASK; + + HandshakeStatus status = status(); + if (status != HandshakeStatus.NEED_UNWRAP) + return status; + + // Try to read another... + if (!pollHandshake(fragment)) + return HandshakeStatus.NEED_UNWRAP; + + while (hasMessage() && status != HandshakeStatus.NEED_WRAP) + { + int pos = handshakeOffset; + status = implHandleInput(); + int len = handshakeOffset - pos; + if (len == 0) + { + // Don't bother; the impl is just telling us to go around + // again. + continue; + } + if (doHash()) + { + if (Debug.DEBUG) + logger.logv(Component.SSL_HANDSHAKE, "hashing output\n{0}", + Util.hexDump((ByteBuffer) handshakeBuffer + .duplicate().position(pos) + .limit(pos+len), " >> ")); + sha.update((ByteBuffer) handshakeBuffer.duplicate() + .position(pos).limit(pos+len)); + md5.update((ByteBuffer) handshakeBuffer.duplicate() + .position(pos).limit(pos+len)); + } + } + return status; + } + + /** + * Called to process more handshake data. This method will be called + * repeatedly while there is remaining handshake data, and while the + * status is + * @return + * @throws SSLException + */ + protected abstract HandshakeStatus implHandleInput() + throws SSLException; + + /** + * Produce more handshake output. This is called in response to a + * call to {@link javax.net.ssl.SSLEngine#wrap}, when the handshake + * is still in progress. + * + * @param record The output record; the callee should put its output + * handshake message (or a part of it) in the argument's + * fragment, and should set the record length + * appropriately. + * @return An {@link SSLEngineResult} describing the result. + */ + public final HandshakeStatus handleOutput (ByteBuffer fragment) + throws SSLException + { + if (!tasks.isEmpty()) + return HandshakeStatus.NEED_TASK; + + int orig = fragment.position(); + SSLEngineResult.HandshakeStatus status = implHandleOutput(fragment); + if (doHash()) + { + if (Debug.DEBUG) + logger.logv(Component.SSL_HANDSHAKE, "hashing output:\n{0}", + Util.hexDump((ByteBuffer) fragment.duplicate().flip().position(orig), " >> ")); + sha.update((ByteBuffer) fragment.duplicate().flip().position(orig)); + md5.update((ByteBuffer) fragment.duplicate().flip().position(orig)); + } + return status; + } + + /** + * Called to implement the underlying output handling. The callee should + * attempt to fill the given buffer as much as it can; this can include + * multiple, and even partial, handshake messages. + * + * @param fragment The buffer the callee should write handshake messages to. + * @return The new status of the handshake. + * @throws SSLException If an error occurs processing the output message. + */ + protected abstract SSLEngineResult.HandshakeStatus implHandleOutput (ByteBuffer fragment) + throws SSLException; + + /** + * Return a new instance of input security parameters, initialized with + * the session key. It is, of course, only valid to invoke this method + * once the handshake is complete, and the session keys established. + * + *

    In the presence of a well-behaving peer, this should be called once + * the ChangeCipherSpec message is recieved. + * + * @return The input parameters for the newly established session. + * @throws SSLException If the handshake is not complete. + */ + final InputSecurityParameters getInputParams() throws SSLException + { + checkKeyExchange(); + return inParams; + } + + /** + * Return a new instance of output security parameters, initialized with + * the session key. This should be called after the + * ChangeCipherSpec message is sent to the peer. + * + * @return The output parameters for the newly established session. + * @throws SSLException If the handshake is not complete. + */ + final OutputSecurityParameters getOutputParams() throws SSLException + { + checkKeyExchange(); + return outParams; + } + + /** + * Fetch a delegated task waiting to run, if any. + * + * @return The task. + */ + final Runnable getTask() + { + if (tasks.isEmpty()) + return null; + return tasks.removeFirst(); + } + + /** + * Used by the skeletal code to query the current status of the handshake. + * This should be the same value as returned by the previous call + * to {@link #implHandleOutput(ByteBuffer)} or {@link + * #implHandleInput(ByteBuffer)}. + * + * @return The current handshake status. + */ + abstract HandshakeStatus status(); + + /** + * Check if the key exchange completed successfully, throwing an exception + * if not. + * + *

    Note that we assume that the caller of our SSLEngine is correct, and + * that they did run the delegated tasks that encapsulate the key exchange. + * What we are primarily checking, therefore, is that no error occurred in the + * key exchange operation itself. + * + * @throws SSLException If the key exchange did not complete successfully. + */ + abstract void checkKeyExchange() throws SSLException; + + /** + * Handle an SSLv2 client hello. This is only used by SSL servers. + * + * @param hello The hello message. + */ + abstract void handleV2Hello(ByteBuffer hello) throws SSLException; + + /** + * Attempt to read the next handshake message from the given + * record. If only a partial handshake message is available, then + * this method saves the incoming bytes and returns false. If a + * complete handshake is read, or if there was one buffered in the + * handshake buffer, this method returns true, and `handshakeBuffer' + * can be used to read the handshake. + * + * @param record The input record. + * @return True if a complete handshake is present in the buffer; + * false if only a partial one. + */ + protected boolean pollHandshake (final ByteBuffer fragment) + { + // Allocate space for the new fragment. + if (handshakeBuffer == null + || handshakeBuffer.remaining() < fragment.remaining()) + { + // We need space for anything still unread in the handshake + // buffer... + int len = ((handshakeBuffer == null) ? 0 + : handshakeBuffer.position() - handshakeOffset); + + // Plus room for the incoming record. + len += fragment.remaining(); + reallocateBuffer(len); + } + + if (Debug.DEBUG) + logger.logv(Component.SSL_HANDSHAKE, "inserting {0} into {1}", + fragment, handshakeBuffer); + + // Put the fragment into the buffer. + handshakeBuffer.put(fragment); + + return hasMessage(); + } + + protected boolean doHash() + { + return true; + } + + /** + * Tell if the handshake buffer currently has a full handshake + * message. + */ + protected boolean hasMessage() + { + if (handshakeBuffer == null) + return false; + ByteBuffer tmp = handshakeBuffer.duplicate(); + tmp.flip(); + tmp.position(handshakeOffset); + if (Debug.DEBUG) + logger.logv(Component.SSL_HANDSHAKE, "current buffer: {0}; test buffer {1}", + handshakeBuffer, tmp); + if (tmp.remaining() < 4) + return false; + Handshake handshake = new Handshake(tmp.slice()); + if (Debug.DEBUG) + logger.logv(Component.SSL_HANDSHAKE, "handshake len:{0} remaining:{1}", + handshake.length(), tmp.remaining()); + return (handshake.length() <= tmp.remaining() - 4); + } + + /** + * Reallocate the handshake buffer so it can hold `totalLen' + * bytes. The smallest buffer allocated is 1024 bytes, and the size + * doubles from there until the buffer is sufficiently large. + */ + private void reallocateBuffer (final int totalLen) + { + int len = handshakeBuffer == null ? -1 + : handshakeBuffer.capacity() - (handshakeBuffer.limit() - handshakeOffset); + if (len >= totalLen) + { + // Big enough; no need to reallocate; but maybe shift the contents + // down. + if (handshakeOffset > 0) + { + handshakeBuffer.flip().position(handshakeOffset); + handshakeBuffer.compact(); + handshakeOffset = 0; + } + return; + } + + // Start at 1K (probably the system's page size). Double the size + // from there. + len = 1024; + while (len < totalLen) + len = len << 1; + ByteBuffer newBuf = ByteBuffer.allocate (len); + + // Copy the unread bytes from the old buffer. + if (handshakeBuffer != null) + { + handshakeBuffer.flip (); + handshakeBuffer.position(handshakeOffset); + newBuf.put(handshakeBuffer); + } + handshakeBuffer = newBuf; + + // We just put only unread handshake messages in the new buffer; + // the offset of the next one is now zero. + handshakeOffset = 0; + } + + /** + * Generate a certificate verify message for SSLv3. In SSLv3, a different + * algorithm was used to generate this value was subtly different than + * that used in TLSv1.0 and later. In TLSv1.0 and later, this value is + * just the digest over the handshake messages. + * + *

    SSLv3 uses the algorithm: + * + *

    +CertificateVerify.signature.md5_hash
    +  MD5(master_secret + pad_2 +
    +      MD5(handshake_messages + master_secret + pad_1));
    +Certificate.signature.sha_hash
    +  SHA(master_secret + pad_2 +
    +      SHA(handshake_messages + master_secret + pad_1));
    + * + * @param md5 The running MD5 hash of the handshake. + * @param sha The running SHA-1 hash of the handshake. + * @param session The current session being negotiated. + * @return The computed to-be-signed value. + */ + protected byte[] genV3CertificateVerify(MessageDigest md5, + MessageDigest sha, + SessionImpl session) + { + byte[] md5value = null; + if (session.suite.signatureAlgorithm() == SignatureAlgorithm.RSA) + { + md5.update(session.privateData.masterSecret); + md5.update(PAD1, 0, 48); + byte[] tmp = md5.digest(); + md5.reset(); + md5.update(session.privateData.masterSecret); + md5.update(PAD2, 0, 48); + md5.update(tmp); + md5value = md5.digest(); + } + + sha.update(session.privateData.masterSecret); + sha.update(PAD1, 0, 40); + byte[] tmp = sha.digest(); + sha.reset(); + sha.update(session.privateData.masterSecret); + sha.update(PAD2, 0, 40); + sha.update(tmp); + byte[] shavalue = sha.digest(); + + if (md5value != null) + return Util.concat(md5value, shavalue); + + return shavalue; + } + + /** + * Generate the session keys from the computed master secret. + * + * @param clientRandom The client's nonce. + * @param serverRandom The server's nonce. + * @param session The session being established. + * @return The derived keys. + */ + protected byte[][] generateKeys(Random clientRandom, Random serverRandom, + SessionImpl session) + { + int maclen = 20; // SHA-1. + if (session.suite.macAlgorithm() == MacAlgorithm.MD5) + maclen = 16; + int ivlen = 0; + if (session.suite.cipherAlgorithm() == CipherAlgorithm.DES + || session.suite.cipherAlgorithm() == CipherAlgorithm.DESede) + ivlen = 8; + if (session.suite.cipherAlgorithm() == CipherAlgorithm.AES) + ivlen = 16; + int keylen = session.suite.keyLength(); + + byte[][] keys = new byte[6][]; + keys[0] = new byte[maclen]; // client_write_MAC_secret + keys[1] = new byte[maclen]; // server_write_MAC_secret + keys[2] = new byte[keylen]; // client_write_key + keys[3] = new byte[keylen]; // server_write_key + keys[4] = new byte[ivlen]; // client_write_iv + keys[5] = new byte[ivlen]; // server_write_iv + + IRandom prf = null; + if (session.version == ProtocolVersion.SSL_3) + { + byte[] seed = new byte[clientRandom.length() + + serverRandom.length()]; + serverRandom.buffer().get(seed, 0, serverRandom.length()); + clientRandom.buffer().get(seed, serverRandom.length(), + clientRandom.length()); + prf = new SSLRandom(); + HashMap attr = new HashMap(2); + attr.put(SSLRandom.SECRET, session.privateData.masterSecret); + attr.put(SSLRandom.SEED, seed); + prf.init(attr); + } + else + { + byte[] seed = new byte[KEY_EXPANSION.length + + clientRandom.length() + + serverRandom.length()]; + System.arraycopy(KEY_EXPANSION, 0, seed, 0, KEY_EXPANSION.length); + serverRandom.buffer().get(seed, KEY_EXPANSION.length, + serverRandom.length()); + clientRandom.buffer().get(seed, (KEY_EXPANSION.length + + serverRandom.length()), + clientRandom.length()); + + prf = new TLSRandom(); + HashMap attr = new HashMap(2); + attr.put(TLSRandom.SECRET, session.privateData.masterSecret); + attr.put(TLSRandom.SEED, seed); + prf.init(attr); + } + + try + { + prf.nextBytes(keys[0], 0, keys[0].length); + prf.nextBytes(keys[1], 0, keys[1].length); + prf.nextBytes(keys[2], 0, keys[2].length); + prf.nextBytes(keys[3], 0, keys[3].length); + + if (session.suite.isExportable()) + { + if (session.version == ProtocolVersion.SSL_3) + { + MessageDigest md5 = MessageDigest.getInstance("MD5"); + md5.update(clientRandom.buffer()); + md5.update(serverRandom.buffer()); + byte[] d = md5.digest(); + System.arraycopy(d, 0, keys[4], 0, keys[4].length); + + md5.reset(); + md5.update(serverRandom.buffer()); + md5.update(clientRandom.buffer()); + d = md5.digest(); + System.arraycopy(d, 0, keys[5], 0, keys[5].length); + + md5.reset(); + md5.update(keys[2]); + md5.update(clientRandom.buffer()); + md5.update(serverRandom.buffer()); + keys[2] = Util.trim(md5.digest(), 8); + + md5.reset(); + md5.update(keys[3]); + md5.update(serverRandom.buffer()); + md5.update(clientRandom.buffer()); + keys[3] = Util.trim(md5.digest(), 8); + } + else + { + TLSRandom prf2 = new TLSRandom(); + HashMap attr = new HashMap(2); + attr.put(TLSRandom.SECRET, keys[2]); + byte[] seed = new byte[CLIENT_WRITE_KEY.length + + clientRandom.length() + + serverRandom.length()]; + System.arraycopy(CLIENT_WRITE_KEY, 0, seed, 0, + CLIENT_WRITE_KEY.length); + clientRandom.buffer().get(seed, CLIENT_WRITE_KEY.length, + clientRandom.length()); + serverRandom.buffer().get(seed, CLIENT_WRITE_KEY.length + + clientRandom.length(), + serverRandom.length()); + attr.put(TLSRandom.SEED, seed); + prf2.init(attr); + keys[2] = new byte[8]; + prf2.nextBytes(keys[2], 0, keys[2].length); + + attr.put(TLSRandom.SECRET, keys[3]); + seed = new byte[SERVER_WRITE_KEY.length + + serverRandom.length() + + clientRandom.length()]; + System.arraycopy(SERVER_WRITE_KEY, 0, seed, 0, + SERVER_WRITE_KEY.length); + serverRandom.buffer().get(seed, SERVER_WRITE_KEY.length, + serverRandom.length()); + clientRandom.buffer().get(seed, SERVER_WRITE_KEY.length + + serverRandom.length(), + + clientRandom.length()); + attr.put(TLSRandom.SEED, seed); + prf2.init(attr); + keys[3] = new byte[8]; + prf2.nextBytes(keys[3], 0, keys[3].length); + + attr.put(TLSRandom.SECRET, new byte[0]); + seed = new byte[IV_BLOCK.length + + clientRandom.length() + + serverRandom.length()]; + System.arraycopy(IV_BLOCK, 0, seed, 0, IV_BLOCK.length); + clientRandom.buffer().get(seed, IV_BLOCK.length, + clientRandom.length()); + serverRandom.buffer().get(seed, IV_BLOCK.length + + clientRandom.length(), + serverRandom.length()); + attr.put(TLSRandom.SEED, seed); + prf2.init(attr); + prf2.nextBytes(keys[4], 0, keys[4].length); + prf2.nextBytes(keys[5], 0, keys[5].length); + } + } + else + { + prf.nextBytes(keys[4], 0, keys[4].length); + prf.nextBytes(keys[5], 0, keys[5].length); + } + } + catch (LimitReachedException lre) + { + // Won't happen with our implementation. + throw new Error(lre); + } + catch (NoSuchAlgorithmException nsae) + { + throw new Error(nsae); + } + + if (Debug.DEBUG_KEY_EXCHANGE) + logger.logv(Component.SSL_KEY_EXCHANGE, + "keys generated;\n [0]: {0}\n [1]: {1}\n [2]: {2}\n" + + " [3]: {3}\n [4]: {4}\n [5]: {5}", + Util.toHexString(keys[0], ':'), + Util.toHexString(keys[1], ':'), + Util.toHexString(keys[2], ':'), + Util.toHexString(keys[3], ':'), + Util.toHexString(keys[4], ':'), + Util.toHexString(keys[5], ':')); + return keys; + } + + /** + * Generate a "finished" message. The hashes passed in are modified + * by this function, so they should be clone copies of the digest if + * the hash function needs to be used more. + * + * @param md5 The MD5 computation. + * @param sha The SHA-1 computation. + * @param isClient Whether or not the client-side finished message is + * being computed. + * @param session The current session. + * @return A byte buffer containing the computed finished message. + */ + protected ByteBuffer generateFinished(MessageDigest md5, + MessageDigest sha, + boolean isClient, + SessionImpl session) + { + ByteBuffer finishedBuffer = null; + if (session.version.compareTo(ProtocolVersion.TLS_1) >= 0) + { + finishedBuffer = ByteBuffer.allocate(12); + TLSRandom prf = new TLSRandom(); + byte[] md5val = md5.digest(); + byte[] shaval = sha.digest(); + if (Debug.DEBUG) + logger.logv(Component.SSL_HANDSHAKE, "finished md5:{0} sha:{1}", + Util.toHexString(md5val, ':'), + Util.toHexString(shaval, ':')); + byte[] seed = new byte[CLIENT_FINISHED.length + + md5val.length + + shaval.length]; + if (isClient) + System.arraycopy(CLIENT_FINISHED, 0, seed, 0, CLIENT_FINISHED.length); + else + System.arraycopy(SERVER_FINISHED, 0, seed, 0, SERVER_FINISHED.length); + System.arraycopy(md5val, 0, + seed, CLIENT_FINISHED.length, + md5val.length); + System.arraycopy(shaval, 0, + seed, CLIENT_FINISHED.length + md5val.length, + shaval.length); + HashMap params = new HashMap(2); + params.put(TLSRandom.SECRET, session.privateData.masterSecret); + params.put(TLSRandom.SEED, seed); + prf.init(params); + byte[] buf = new byte[12]; + prf.nextBytes(buf, 0, buf.length); + finishedBuffer.put(buf).position(0); + } + else + { + // The SSLv3 algorithm is: + // + // enum { client(0x434C4E54), server(0x53525652) } Sender; + // + // struct { + // opaque md5_hash[16]; + // opaque sha_hash[20]; + // } Finished; + // + // md5_hash MD5(master_secret + pad2 + + // MD5(handshake_messages + Sender + + // master_secret + pad1)); + // sha_hash SHA(master_secret + pad2 + + // SHA(handshake_messages + Sender + + // master_secret + pad1)); + // + + finishedBuffer = ByteBuffer.allocate(36); + + md5.update(isClient ? SENDER_CLIENT : SENDER_SERVER); + md5.update(session.privateData.masterSecret); + md5.update(PAD1); + + byte[] tmp = md5.digest(); + md5.reset(); + md5.update(session.privateData.masterSecret); + md5.update(PAD2); + md5.update(tmp); + finishedBuffer.put(md5.digest()); + + sha.update(isClient ? SENDER_CLIENT : SENDER_SERVER); + sha.update(session.privateData.masterSecret); + sha.update(PAD1, 0, 40); + + tmp = sha.digest(); + sha.reset(); + sha.update(session.privateData.masterSecret); + sha.update(PAD2, 0, 40); + sha.update(tmp); + finishedBuffer.put(sha.digest()).position(0); + } + return finishedBuffer; + } + + protected void initDiffieHellman(DHPrivateKey dhKey, SecureRandom random) + throws SSLException + { + try + { + keyAgreement = KeyAgreement.getInstance("DH"); + keyAgreement.init(dhKey, random); + } + catch (InvalidKeyException ike) + { + throw new SSLException(ike); + } + catch (NoSuchAlgorithmException nsae) + { + throw new SSLException(nsae); + } + } + + protected void generateMasterSecret(Random clientRandom, + Random serverRandom, + SessionImpl session) + throws SSLException + { + assert(clientRandom != null); + assert(serverRandom != null); + assert(session != null); + + if (Debug.DEBUG_KEY_EXCHANGE) + logger.logv(Component.SSL_KEY_EXCHANGE, "preMasterSecret:\n{0}", + new ByteArray(preMasterSecret)); + + if (session.version == ProtocolVersion.SSL_3) + { + try + { + MessageDigest _md5 = MessageDigest.getInstance("MD5"); + MessageDigest _sha = MessageDigest.getInstance("SHA"); + session.privateData.masterSecret = new byte[48]; + + _sha.update((byte) 'A'); + _sha.update(preMasterSecret); + _sha.update(clientRandom.buffer()); + _sha.update(serverRandom.buffer()); + _md5.update(preMasterSecret); + _md5.update(_sha.digest()); + _md5.digest(session.privateData.masterSecret, 0, 16); + + _sha.update((byte) 'B'); + _sha.update((byte) 'B'); + _sha.update(preMasterSecret); + _sha.update(clientRandom.buffer()); + _sha.update(serverRandom.buffer()); + _md5.update(preMasterSecret); + _md5.update(_sha.digest()); + _md5.digest(session.privateData.masterSecret, 16, 16); + + _sha.update((byte) 'C'); + _sha.update((byte) 'C'); + _sha.update((byte) 'C'); + _sha.update(preMasterSecret); + _sha.update(clientRandom.buffer()); + _sha.update(serverRandom.buffer()); + _md5.update(preMasterSecret); + _md5.update(_sha.digest()); + _md5.digest(session.privateData.masterSecret, 32, 16); + } + catch (DigestException de) + { + throw new SSLException(de); + } + catch (NoSuchAlgorithmException nsae) + { + throw new SSLException(nsae); + } + } + else // TLSv1.0 and later + { + byte[] seed = new byte[clientRandom.length() + + serverRandom.length() + + MASTER_SECRET.length]; + System.arraycopy(MASTER_SECRET, 0, seed, 0, MASTER_SECRET.length); + clientRandom.buffer().get(seed, MASTER_SECRET.length, + clientRandom.length()); + serverRandom.buffer().get(seed, + MASTER_SECRET.length + clientRandom.length(), + serverRandom.length()); + TLSRandom prf = new TLSRandom(); + HashMap attr = new HashMap(2); + attr.put(TLSRandom.SECRET, preMasterSecret); + attr.put(TLSRandom.SEED, seed); + prf.init(attr); + + session.privateData.masterSecret = new byte[48]; + prf.nextBytes(session.privateData.masterSecret, 0, 48); + } + + if (Debug.DEBUG_KEY_EXCHANGE) + logger.log(Component.SSL_KEY_EXCHANGE, "master_secret: {0}", + new ByteArray(session.privateData.masterSecret)); + + // Wipe out the preMasterSecret. + for (int i = 0; i < preMasterSecret.length; i++) + preMasterSecret[i] = 0; + } + + protected void setupSecurityParameters(byte[][] keys, boolean isClient, + SSLEngineImpl engine, + CompressionMethod compression) + throws SSLException + { + assert(keys.length == 6); + assert(engine != null); + assert(compression != null); + + try + { + CipherSuite s = engine.session().suite; + Cipher inCipher = s.cipher(); + Mac inMac = s.mac(engine.session().version); + Inflater inflater = (compression == CompressionMethod.ZLIB + ? new Inflater() : null); + inCipher.init(Cipher.DECRYPT_MODE, + new SecretKeySpec(keys[isClient ? 3 : 2], + s.cipherAlgorithm().toString()), + new IvParameterSpec(keys[isClient ? 5 : 4])); + inMac.init(new SecretKeySpec(keys[isClient ? 1 : 0], + inMac.getAlgorithm())); + inParams = new InputSecurityParameters(inCipher, inMac, + inflater, + engine.session(), s); + + Cipher outCipher = s.cipher(); + Mac outMac = s.mac(engine.session().version); + Deflater deflater = (compression == CompressionMethod.ZLIB + ? new Deflater() : null); + outCipher.init(Cipher.ENCRYPT_MODE, + new SecretKeySpec(keys[isClient ? 2 : 3], + s.cipherAlgorithm().toString()), + new IvParameterSpec(keys[isClient ? 4 : 5])); + outMac.init(new SecretKeySpec(keys[isClient ? 0 : 1], + outMac.getAlgorithm())); + outParams = new OutputSecurityParameters(outCipher, outMac, + deflater, + engine.session(), s); + } + catch (InvalidAlgorithmParameterException iape) + { + throw new SSLException(iape); + } + catch (InvalidKeyException ike) + { + throw new SSLException(ike); + } + catch (NoSuchAlgorithmException nsae) + { + throw new SSLException(nsae); + } + catch (NoSuchPaddingException nspe) + { + throw new SSLException(nspe); + } + } + + protected void generatePSKSecret(String identity, byte[] otherkey, + boolean isClient) + throws SSLException + { + SecretKey key = null; + try + { + key = engine.contextImpl.pskManager.getKey(identity); + } + catch (KeyManagementException kme) + { + } + if (key != null) + { + byte[] keyb = key.getEncoded(); + if (otherkey == null) + { + otherkey = new byte[keyb.length]; + } + preMasterSecret = new byte[otherkey.length + keyb.length + 4]; + preMasterSecret[0] = (byte) (otherkey.length >>> 8); + preMasterSecret[1] = (byte) otherkey.length; + System.arraycopy(otherkey, 0, preMasterSecret, 2, otherkey.length); + preMasterSecret[otherkey.length + 2] + = (byte) (keyb.length >>> 8); + preMasterSecret[otherkey.length + 3] + = (byte) keyb.length; + System.arraycopy(keyb, 0, preMasterSecret, + otherkey.length + 4, keyb.length); + } + else + { + // Generate a random, fake secret. + preMasterSecret = new byte[8]; + preMasterSecret[1] = 2; + preMasterSecret[5] = 2; + preMasterSecret[6] = (byte) engine.session().random().nextInt(); + preMasterSecret[7] = (byte) engine.session().random().nextInt(); + } + + if (Debug.DEBUG_KEY_EXCHANGE) + logger.logv(Component.SSL_KEY_EXCHANGE, "PSK identity {0} key {1}", + identity, key); + + generateMasterSecret(clientRandom, serverRandom, + engine.session()); + byte[][] keys = generateKeys(clientRandom, serverRandom, + engine.session()); + setupSecurityParameters(keys, isClient, engine, compression); + } + + protected class DHPhase extends DelegatedTask + { + private final DHPublicKey key; + private final boolean full; + + protected DHPhase(DHPublicKey key) + { + this(key, true); + } + + protected DHPhase(DHPublicKey key, boolean full) + { + this.key = key; + this.full = full; + } + + protected void implRun() throws InvalidKeyException, SSLException + { + keyAgreement.doPhase(key, true); + preMasterSecret = keyAgreement.generateSecret(); + if (full) + { + generateMasterSecret(clientRandom, serverRandom, engine.session()); + byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session()); + setupSecurityParameters(keys, engine.getUseClientMode(), engine, compression); + } + } + } + + protected class CertVerifier extends DelegatedTask + { + private final boolean clientSide; + private final X509Certificate[] chain; + private boolean verified; + + protected CertVerifier(boolean clientSide, X509Certificate[] chain) + { + this.clientSide = clientSide; + this.chain = chain; + } + + boolean verified() + { + return verified; + } + + protected void implRun() + { + X509TrustManager tm = engine.contextImpl.trustManager; + if (clientSide) + { + try + { + tm.checkServerTrusted(chain, null); + verified = true; + } + catch (CertificateException ce) + { + if (Debug.DEBUG) + logger.log(Component.SSL_DELEGATED_TASK, "cert verify", ce); + // For client connections, ask the user if the certificate is OK. + CallbackHandler verify = new DefaultCallbackHandler(); + GetSecurityPropertyAction gspa + = new GetSecurityPropertyAction("jessie.certificate.handler"); + String clazz = AccessController.doPrivileged(gspa); + try + { + ClassLoader cl = + AccessController.doPrivileged(new PrivilegedExceptionAction() + { + public ClassLoader run() throws Exception + { + return ClassLoader.getSystemClassLoader(); + } + }); + verify = (CallbackHandler) cl.loadClass(clazz).newInstance(); + } + catch (Exception x) + { + // Ignore. + if (Debug.DEBUG) + logger.log(Component.SSL_DELEGATED_TASK, + "callback handler loading", x); + } + // XXX Internationalize + CertificateCallback confirm = + new CertificateCallback(chain[0], + "The server's certificate could not be verified. There is no proof " + + "that this server is who it claims to be, or that their certificate " + + "is valid. Do you wish to continue connecting? "); + + try + { + verify.handle(new Callback[] { confirm }); + verified = confirm.getSelectedIndex() == ConfirmationCallback.YES; + } + catch (Exception x) + { + if (Debug.DEBUG) + logger.log(Component.SSL_DELEGATED_TASK, + "callback handler exception", x); + verified = false; + } + } + } + else + { + try + { + tm.checkClientTrusted(chain, null); + } + catch (CertificateException ce) + { + verified = false; + } + } + + if (verified) + engine.session().setPeerVerified(true); + } + } + + protected class DHE_PSKGen extends DelegatedTask + { + private final DHPublicKey dhKey; + private final SecretKey psKey; + private final boolean isClient; + + protected DHE_PSKGen(DHPublicKey dhKey, SecretKey psKey, boolean isClient) + { + this.dhKey = dhKey; + this.psKey = psKey; + this.isClient = isClient; + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.DelegatedTask#implRun() + */ + @Override protected void implRun() throws Throwable + { + keyAgreement.doPhase(dhKey, true); + byte[] dhSecret = keyAgreement.generateSecret(); + byte[] psSecret = null; + if (psKey != null) + psSecret = psKey.getEncoded(); + else + { + psSecret = new byte[8]; + engine.session().random().nextBytes(psSecret); + } + + preMasterSecret = new byte[dhSecret.length + psSecret.length + 4]; + preMasterSecret[0] = (byte) (dhSecret.length >>> 8); + preMasterSecret[1] = (byte) dhSecret.length; + System.arraycopy(dhSecret, 0, preMasterSecret, 2, dhSecret.length); + preMasterSecret[dhSecret.length + 2] = (byte) (psSecret.length >>> 8); + preMasterSecret[dhSecret.length + 3] = (byte) psSecret.length; + System.arraycopy(psSecret, 0, preMasterSecret, dhSecret.length + 4, + psSecret.length); + + generateMasterSecret(clientRandom, serverRandom, engine.session()); + byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session()); + setupSecurityParameters(keys, isClient, engine, compression); + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Alert.java b/libjava/classpath/gnu/javax/net/ssl/provider/Alert.java new file mode 100644 index 000000000..0ceb96bbb --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Alert.java @@ -0,0 +1,288 @@ +/* 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.PrintWriter; +import java.io.StringWriter; + +import java.nio.ByteBuffer; + +/** + * 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;
    + * }
    + * 
    + */ +public final class Alert implements Constructed +{ + + // Fields. + // ------------------------------------------------------------------------- + + /** The underlying byte buffer. */ + private final ByteBuffer buffer; + + // Constructor. + // ------------------------------------------------------------------------- + + public Alert (final ByteBuffer buffer) + { + this.buffer = buffer; + } + + public Alert (final Level level, final Description description) + { + level.getClass (); + description.getClass (); + ByteBuffer b = ByteBuffer.allocate (2); + b.put (0, (byte) level.getValue ()); + b.put (1, (byte) description.getValue ()); + this.buffer = b.asReadOnlyBuffer (); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public int length () + { + return 2; + } + + byte[] getEncoded() + { + byte[] buf = new byte[2]; + buffer.position (0); + buffer.get (buf); + return buf; + } + + public Level level() + { + return Level.forInteger (buffer.get (0) & 0xFF); + } + + public Description description() + { + return Description.forInteger (buffer.get (1) & 0xFF); + } + + public void setLevel (final Level level) + { + buffer.put (0, (byte) level.getValue ()); + } + + public void setDescription (final Description description) + { + buffer.put (1, (byte) description.getValue ()); + } + + public boolean equals (Object o) + { + if (!(o instanceof Alert)) + return false; + Alert that = (Alert) o; + return that.buffer.position (0).equals (buffer.position (0)); + } + + public int hashCode () + { + return buffer.getShort (0) & 0xFFFF; + } + + public String toString() + { + return toString (null); + } + + public String toString (final String prefix) + { + StringWriter str = new StringWriter (); + PrintWriter out = new PrintWriter (str); + if (prefix != null) out.print (prefix); + out.println ("struct {"); + if (prefix != null) out.print (prefix); + out.print (" level: "); + out.print (level ()); + out.println (";"); + if (prefix != null) out.print (prefix); + out.print (" description: "); + out.print (description ()); + out.println (";"); + if (prefix != null) out.print (prefix); + out.print ("} Alert;"); + return str.toString (); + } + + // Enumerations. + // ------------------------------------------------------------------------- + + /** + * The level enumeration. + * + *
    +   * enum { warning(1), fatal(2), (255) } AlertLevel;
    +   * 
    + */ + public static enum Level + { + + WARNING (1), FATAL (2); + + private final int value; + + private Level(int value) + { + this.value = value; + } + + public static Level forInteger (final int value) + { + switch (value & 0xFF) + { + case 1: return WARNING; + case 2: return FATAL; + default: throw new IllegalArgumentException ("invalid alert level: " + value); + } + } + + public int getValue() + { + return value; + } + } + + /** + * The description enumeration. + */ + public static enum Description + { + CLOSE_NOTIFY ( 0), + UNEXPECTED_MESSAGE ( 10), + BAD_RECORD_MAC ( 20), + DECRYPTION_FAILED ( 21), + RECORD_OVERFLOW ( 22), + DECOMPRESSION_FAILURE ( 30), + HANDSHAKE_FAILURE ( 40), + NO_CERTIFICATE ( 41), + BAD_CERTIFICATE ( 42), + UNSUPPORTED_CERTIFICATE ( 43), + CERTIFICATE_REVOKED ( 44), + CERTIFICATE_EXPIRED ( 45), + CERTIFICATE_UNKNOWN ( 46), + ILLEGAL_PARAMETER ( 47), + UNKNOWN_CA ( 48), + ACCESS_DENIED ( 49), + DECODE_ERROR ( 50), + DECRYPT_ERROR ( 51), + EXPORT_RESTRICTION ( 60), + PROTOCOL_VERSION ( 70), + INSUFFICIENT_SECURITY ( 71), + INTERNAL_ERROR ( 80), + USER_CANCELED ( 90), + NO_RENEGOTIATION (100), + UNSUPPORTED_EXTENSION (110), + CERTIFICATE_UNOBTAINABLE (111), + UNRECOGNIZED_NAME (112), + BAD_CERTIFICATE_STATUS_RESPONSE (113), + BAD_CERTIFICATE_HASH_VALUE (114), + UNKNOWN_SRP_USERNAME (120), + MISSING_SRP_USERNAME (121); + + private final int value; + + private Description(int value) + { + this.value = value; + } + + /** + * Return an alert description object based on the specified integer + * value. + * + * @param value The raw description value. + * @return The appropriate description object. + */ + public static Description forInteger (final int value) + { + switch (value & 0xFF) + { + 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: throw new IllegalArgumentException("unknown alert description: " + value); + } + } + + public int getValue() + { + return value; + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/AlertException.java b/libjava/classpath/gnu/javax/net/ssl/provider/AlertException.java new file mode 100644 index 000000000..90eaaf430 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/AlertException.java @@ -0,0 +1,101 @@ +/* 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; + +/** + * An exception generated by an SSL alert. + */ +public class AlertException extends SSLException +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final Alert alert; + private final boolean isLocal; + + // Constructor. + // ------------------------------------------------------------------------- + + public AlertException(Alert alert, boolean isLocal) + { + super(alert.description().toString()); + this.alert = alert; + this.isLocal = isLocal; + } + + public AlertException(Alert alert) + { + this(alert, true); + } + + public AlertException(Alert alert, boolean isLocal, Throwable cause) + { + super(alert.description().toString(), cause); + this.alert = alert; + this.isLocal = isLocal; + } + + public AlertException(Alert alert, Throwable cause) + { + this(alert, true, cause); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public String getMessage() + { + return alert.description() + ": " + + (isLocal ? "locally generated; " : "remotely generated; ") + + alert.level(); + } + + public Alert alert () + { + return alert; + } + + public boolean isLocal() + { + return isLocal; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Builder.java b/libjava/classpath/gnu/javax/net/ssl/provider/Builder.java new file mode 100644 index 000000000..070c51b76 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Builder.java @@ -0,0 +1,66 @@ +/* Builder.java -- builder interface for protocol objects. + 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.nio.ByteBuffer; + +/** + * The base interface for classes that build SSL protocol objects. The + * general contract for Builder implementations is that they maintain a + * buffer that grows to fit the object being built; the allocated size of + * this buffer may be larger than the built object needs, but the general + * effort will be not to allocate too large a buffer. + * + *

    Once the object is built, through various setters for + * the object's attributes, the final buffer may be retrieved with the + * {@link #buffer()} method. + * + * @author Casey Marshall (csm@gnu.org) + */ +public interface Builder extends Constructed +{ + /** + * Returns the final buffer, possibly containing the built object. The + * returned buffer will be "trimmed" to size: its position will be zero, + * and its limit and capacity set to the length of the built object. + * + * @return The underlying buffer. + */ + ByteBuffer buffer(); +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Certificate.java b/libjava/classpath/gnu/javax/net/ssl/provider/Certificate.java new file mode 100644 index 000000000..68de1304d --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Certificate.java @@ -0,0 +1,177 @@ +/* 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.ByteArrayInputStream; +import java.io.PrintWriter; +import java.io.StringWriter; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +/** + * The certificate object. This is used by both the client and the server + * to send their certificates (if any) to one another. + * + *

    opaque ASN.1Cert<1..2^24-1>;
    +
    +struct {
    +  ASN.1Cert certificate_list<0..2^24-1>;
    +} Certificate;
    + * + * @author Casey Marshall (csm@gnu.org) + */ +public class Certificate implements Handshake.Body +{ + + // Fields. + // ------------------------------------------------------------------------- + + protected ByteBuffer buffer; + protected final CertificateType type; + + // Constructors. + // ------------------------------------------------------------------------- + + public Certificate (final ByteBuffer buffer, final CertificateType type) + { + buffer.getClass (); + type.getClass (); + this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); + this.type = type; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public int length () + { + return (((buffer.get (0) & 0xFF) << 24) + | buffer.getShort (1)) + 3; + } + + public List certificates () + throws CertificateException, NoSuchAlgorithmException + { + LinkedList list + = new LinkedList(); + CertificateFactory factory = CertificateFactory.getInstance(type.toString()); + int length = (((buffer.get(0) & 0xFF) << 16) + | (buffer.getShort(1) & 0xFFFF)); + ByteBuffer b = (ByteBuffer) buffer.duplicate().position(3); + for (int i = 3; i < length; ) + { + int length2 = (((b.get () & 0xFF) << 16) + | (b.getShort () & 0xFFFF)); + byte[] buf = new byte[length2]; + b.position(i+3); + b.get (buf); + list.add(factory.generateCertificate (new ByteArrayInputStream (buf))); + i += length2 + 3; + b.position(i); + } + return list; + } + + public String toString () + { + return toString (null); + } + + public String toString (final String prefix) + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + if (prefix != null) + out.print (prefix); + out.println ("struct {"); + try + { + List certs = certificates (); + if (prefix != null) + out.print (prefix); + out.print (" certificateList: ["); + out.print (certs.size ()); + out.println ("] {"); + for (Iterator it = certs.iterator (); it.hasNext (); ) + { + java.security.cert.Certificate cert = + (java.security.cert.Certificate) it.next (); + if (prefix != null) + out.print (prefix); + out.print (" "); + if (cert instanceof X509Certificate) + out.print (((X509Certificate) cert).getSubjectDN ()); + else + out.print (cert); + out.println (";"); + } + if (prefix != null) + out.print (prefix); + out.println (" };"); + } + catch (CertificateException ce) + { + if (prefix != null) + out.print (prefix); + out.print (" "); + out.print (ce); + out.println (";"); + } + catch (NoSuchAlgorithmException nsae) + { + if (prefix != null) + out.print (prefix); + out.print (" "); + out.print (nsae); + out.println (";"); + } + out.print ("} Certificate;"); + return str.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CertificateBuilder.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateBuilder.java new file mode 100644 index 000000000..1126e6fcc --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateBuilder.java @@ -0,0 +1,94 @@ +/* CertificateBuilder.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.net.ssl.provider; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.List; +import java.security.cert.CertificateException; + +/** + * Builder for {@link Certificate} objects. + * + * @author Casey Marshall (csm@gnu.org) + */ +public class CertificateBuilder extends Certificate implements Builder +{ + public CertificateBuilder(final CertificateType certType) + { + super(ByteBuffer.allocate(1024), certType); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Builder#buffer() + */ + public ByteBuffer buffer() + { + return ((ByteBuffer) buffer.duplicate().position(0).limit(length())).slice(); + } + + public void setCertificates (final List certificates) + throws CertificateException + { + ByteArrayOutputStream out = new ByteArrayOutputStream(1024); + for (java.security.cert.Certificate cert : certificates) + { + byte[] encoded = cert.getEncoded(); + out.write((encoded.length >>> 16) & 0xFF); + out.write((encoded.length >>> 8) & 0xFF); + out.write( encoded.length & 0xFF); + try + { + out.write(encoded); + } + catch (IOException shouldNotHappen) + { + // ignore; this is a ByteArrayOutputStream. + } + } + byte[] certs = out.toByteArray(); + // There is only one field in Certificate; so it is easy to reallocate. + if (buffer.capacity() < certs.length + 3) + buffer = ByteBuffer.allocate(certs.length + 3); + buffer.put(0, (byte) (certs.length >>> 16)); + buffer.putShort(1, (short) certs.length); + ((ByteBuffer) buffer.duplicate().position(3)).put(certs); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequest.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequest.java new file mode 100644 index 000000000..fd9d65be5 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequest.java @@ -0,0 +1,155 @@ +/* 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.PrintWriter; +import java.io.StringWriter; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * A request by the server for a client certificate. + * + *
    +struct
    +{
    +  ClientCertificateType certificate_types<1..2^8-1>;
    +  DistinguishedName certificate_authorities<3..2^16-1>;
    +} CertificateRequest;
    +
    + */ +public class CertificateRequest implements Handshake.Body +{ + + // Fields. + // ------------------------------------------------------------------------- + + protected ByteBuffer buffer; + + // Constructor. + // ------------------------------------------------------------------------- + + public CertificateRequest(final ByteBuffer buffer) + { + this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public int length () + { + int o1 = (buffer.get (0) & 0xFF) + 1; + return o1 + (buffer.getShort (o1) & 0xFFFF) + 2; + } + + public ClientCertificateTypeList types () + { + return new ClientCertificateTypeList(buffer.duplicate()); + } + + public X500PrincipalList authorities () + { + int offset = (buffer.get (0) & 0xFF) + 1; + return new X500PrincipalList (((ByteBuffer) buffer.position(offset)).slice()); + } + + public String toString() + { + return toString (null); + } + + public String toString (final String prefix) + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + String subprefix = " "; + if (prefix != null) subprefix = prefix + " "; + if (prefix != null) out.print (prefix); + out.println("struct {"); + if (prefix != null) out.print (prefix); + out.println (" types ="); + out.println (types ().toString (subprefix)); + if (prefix != null) out.print (prefix); + out.println(" authorities ="); + out.println (authorities ().toString (subprefix)); + if (prefix != null) out.print (prefix); + out.print ("} CertificateRequest;"); + return str.toString(); + } + + public static enum ClientCertificateType + { + RSA_SIGN (1), + DSS_SIGN (2), + RSA_FIXED_DH (3), + DSS_FIXED_DH (4); + + private final int value; + + // Constructor. + // ----------------------------------------------------------------------- + + private ClientCertificateType (final int value) + { + this.value = value; + } + + // Class method. + // ----------------------------------------------------------------------- + + static ClientCertificateType forValue (final int value) + { + 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: throw new IllegalArgumentException("unknown client certificate type: " + value); + } + } + + public int getValue() + { + return value; + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequestBuilder.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequestBuilder.java new file mode 100644 index 000000000..f32c52acf --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequestBuilder.java @@ -0,0 +1,111 @@ +/* CertificateRequestBuilder.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.net.ssl.provider; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.List; + +import javax.security.auth.x500.X500Principal; + +/** + * Builder for {@link CertificateRequest} objects. + * + * @author Casey Marshall (csm@gnu.org) + */ +public class CertificateRequestBuilder extends CertificateRequest + implements Builder +{ + public CertificateRequestBuilder() + { + super(ByteBuffer.allocate(1024)); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Builder#buffer() + */ + public ByteBuffer buffer() + { + return ((ByteBuffer) buffer.duplicate().limit(length())).slice(); + } + + public void setTypes(List types) + { + ensureCapacity(types.size() + 3); + buffer.put(0, (byte) types.size()); + ByteBuffer b = (ByteBuffer) buffer.duplicate().position(1); + for (ClientCertificateType type : types) + b.put((byte) type.getValue()); + } + + public void setAuthorities(List authorities) + { + ByteArrayOutputStream out = new ByteArrayOutputStream(1024); + for (X500Principal auth : authorities) + { + byte[] encoded = auth.getEncoded(); + out.write((encoded.length >>> 8) & 0xFF); + out.write( encoded.length & 0xFF); + try + { + out.write(encoded); + } + catch (IOException ignored) + { + // Ignored; we use a ByteArrayOutputStream. + } + } + byte[] auths = out.toByteArray(); + int typesLen = 1 + (buffer.get(0) & 0xFF); + int len = typesLen + auths.length + 2; + ensureCapacity(len); + buffer.putShort(typesLen, (short) auths.length); + ((ByteBuffer) buffer.duplicate().position(typesLen + 2)).put(auths); + } + + public void ensureCapacity(final int capacity) + { + if (buffer.capacity() >= capacity) + return; + ByteBuffer newBuffer = ByteBuffer.allocate(capacity); + newBuffer.duplicate().put(buffer); + buffer = newBuffer; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CertificateStatusRequest.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateStatusRequest.java new file mode 100644 index 000000000..e66373620 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateStatusRequest.java @@ -0,0 +1,272 @@ +/* CertificateStatusRequest.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.net.ssl.provider; + +import gnu.javax.net.ssl.provider.Extension.Value; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.nio.ByteBuffer; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + +/** + *
    +struct {
    +  CertificateStatusType status_type;
    +  select (status_type) {
    +    case ocsp: OCSPStatusRequest;
    +  } request;
    +} CertificateStatusRequest;
    +
    +enum { ocsp(1), (255) } CertificateStatusType;
    +
    +struct {
    +  ResponderID responder_id_list<0..2^16-1>;
    +  Extensions  request_extensions;
    +} OCSPStatusRequest;
    +
    +opaque ResponderID<1..2^16-1>;
    +opaque Extensions<0..2^16-1>;
    + * + * @author csm + */ +public class CertificateStatusRequest extends Value implements Iterable +{ + private ByteBuffer buffer; + + public CertificateStatusRequest(final ByteBuffer buffer) + { + this.buffer = buffer; + } + + public CertificateStatusRequest(CertificateStatusType type, + List responderIdList, + byte[] requestExtensions) + { + if (type != CertificateStatusType.OCSP) + throw new IllegalArgumentException(); + int length = 3; + int idsLength = 0; + for (byte[] responderId : responderIdList) + { + length += 2 + responderId.length; + idsLength += 2 + responderId.length; + } + length += 2 + requestExtensions.length; + buffer = ByteBuffer.allocate(length); + buffer.put((byte) 1); + buffer.putShort((short) idsLength); + for (byte[] responderId : responderIdList) + buffer.putShort((short) responderId.length).put(responderId); + buffer.putShort((short) requestExtensions.length); + buffer.put(requestExtensions); + buffer.rewind(); + } + + public int length() + { + int l = 3 + (buffer.getShort(1) & 0xFFFF); + return l + (buffer.getShort(l) & 0xFFFF) + 2; + } + + public ByteBuffer buffer() + { + return (ByteBuffer) buffer.duplicate().limit(length()); + } + + public CertificateStatusType statusType() + { + int x = buffer.get(0) & 0xFF; + if (x == 1) + return CertificateStatusType.OCSP; + throw new IllegalArgumentException ("invalid type: " + x); + } + + public int size() + { + int len = buffer.getShort(1) & 0xFFFF; + int n = 0; + for (int i = 3; i < len; ) + { + int l = buffer.getShort(i); + i += l + 2; + n++; + } + return n; + } + + public byte[] responderId(int index) + { + int len = buffer.getShort(1) & 0xFFFF; + int n = 0; + int i = 3; + while (i < len && n <= index) + { + int l = buffer.getShort(i) & 0xFFFF; + if (n == index) + { + byte[] b = new byte[l]; + ((ByteBuffer) buffer.duplicate().position(i+2)).get(b); + return b; + } + i += l + 2; + n++; + } + throw new IndexOutOfBoundsException(); + } + + public byte[] requestExtensions() + { + int l = 2 + (buffer.getShort(0) & 0xFFFF); + int ll = buffer.getShort(l) & 0xFFFF; + byte[] b = new byte[ll]; + ((ByteBuffer) buffer.duplicate().position(ll+2)).get(b); + return b; + } + + public void setStatusType(CertificateStatusType type) + { + buffer.put(0, (byte) type.value); + } + + public void setRequestIdListLength(int newLength) + { + if (newLength < 0 || newLength > 0xFFFF) + throw new IllegalArgumentException("length out of range"); + buffer.putShort(1, (short) newLength); + } + + public void putRequestId(int index, byte[] id) + { + if (id.length > 0xFFFF) + throw new IllegalArgumentException("request ID too large"); + int len = buffer.getShort(1) & 0xFFFF; + int n = 0; + int i = 3; + while (i < len && n < index) + { + int l = buffer.getShort(i) & 0xFFFF; + i += l + 2; + n++; + } + if (n < index) + throw new IndexOutOfBoundsException(); + buffer.putShort(i, (short) id.length); + ((ByteBuffer) buffer.duplicate().position(i)).put(id); + } + + public void setRequestExtensions(int index, byte[] ext) + { + if (ext.length > 0xFFFF) + throw new IllegalArgumentException("exceptions too large"); + int off = 3 + (buffer.getShort(1) & 0xFFFF); + buffer.putShort(off, (short) ext.length); + ((ByteBuffer) buffer.duplicate().position(off+2)).put(ext); + } + + public Iterator iterator() + { + return new ResponderIdIterator(); + } + + public String toString() + { + return toString(null); + } + + public String toString(String prefix) + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + if (prefix != null) out.print(prefix); + out.println("struct {"); + if (prefix != null) out.print(prefix); + out.print(" status_type = "); + out.print(statusType()); + out.println(";"); + String subprefix = " "; + if (prefix != null) subprefix = prefix + subprefix; + if (prefix != null) out.print(prefix); + out.println(" responder_id_list = {"); + for (byte[] b : this) + out.print(Util.hexDump(b, subprefix)); + if (prefix != null) out.print(prefix); + out.println(" };"); + if (prefix != null) out.print(prefix); + out.println(" request_extensions ="); + out.print(Util.hexDump(requestExtensions(), subprefix)); + if (prefix != null) out.print(prefix); + out.print("} CertificateStatus;"); + return str.toString(); + } + + public class ResponderIdIterator implements Iterator + { + private int index; + + public ResponderIdIterator() + { + index = 0; + } + + public byte[] next() throws NoSuchElementException + { + try + { + return responderId(index++); + } + catch (IndexOutOfBoundsException ioobe) + { + throw new NoSuchElementException(); + } + } + + public boolean hasNext() + { + return index < size(); + } + + public void remove() + { + throw new UnsupportedOperationException(); + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CertificateStatusType.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateStatusType.java new file mode 100644 index 000000000..0d52b2778 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateStatusType.java @@ -0,0 +1,13 @@ +package gnu.javax.net.ssl.provider; + +public enum CertificateStatusType +{ + OCSP (1); + + public final int value; + + private CertificateStatusType (final int value) + { + this.value = value; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CertificateType.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateType.java new file mode 100644 index 000000000..ecba21b63 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateType.java @@ -0,0 +1,62 @@ +/* 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; + +public enum CertificateType +{ + X509 (0), + OPEN_PGP (1); + + private final int value; + + private CertificateType(int value) + { + this.value = value; + } + + public static CertificateType forValue (final int value) + { + switch (value) + { + case 0: return X509; + case 1: return OPEN_PGP; + default: throw new IllegalArgumentException ("unknown certificate type: " + value); + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CertificateURL.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateURL.java new file mode 100644 index 000000000..737efcacd --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateURL.java @@ -0,0 +1,388 @@ +/* CertificateURL.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.net.ssl.provider; + +import gnu.javax.net.ssl.provider.Extension.Value; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; +import java.util.List; +import java.util.NoSuchElementException; + +/** + * The CertificateURL extension value. + * + *
    +enum {
    +  individual_certs(0), pkipath(1), (255)
    +} CertChainType;
    +
    +enum {
    +  false(0), true(1)
    +} Boolean;
    +
    +struct {
    +  CertChainType type;
    +  URLAndOptionalHash url_and_hash_list<1..2^16-1>;
    +} CertificateURL;
    +
    +struct {
    +  opaque url<1..2^16-1>;
    +  Boolean hash_present;
    +  select (hash_present) {
    +    case false: struct {};
    +    case true: SHA1Hash;
    +  } hash;
    +} URLAndOptionalHash;
    +
    +opaque SHA1Hash[20];
    + * + * @author csm + * + */ +public class CertificateURL extends Value implements Iterable +{ + private ByteBuffer buffer; + + public CertificateURL(final ByteBuffer buffer) + { + this.buffer = buffer; + } + + public CertificateURL(CertChainType type, List urls) + { + int length = 3; + for (URLAndOptionalHash url : urls) + length += url.length(); + buffer = ByteBuffer.allocate(length); + buffer.put((byte) type.getValue()); + buffer.putShort((short) (length - 1)); + for (URLAndOptionalHash url : urls) + buffer.put(url.buffer()); + buffer.rewind(); + } + + public int length() + { + return 3 + (buffer.getShort(1) & 0xFFFF); + } + + public ByteBuffer buffer() + { + return (ByteBuffer) buffer.duplicate().limit(length()); + } + + public CertChainType type() + { + switch (buffer.get(0)) + { + case 0: return CertChainType.INDIVIDUAL_CERTS; + case 1: return CertChainType.PKIPATH; + } + throw new IllegalArgumentException("unknown certificate URL type"); + } + + public int size() + { + int len = buffer.getShort(1) & 0xFFFF; + int n = 0; + for (int i = 3; i < len; ) + { + URLAndOptionalHash u + = new URLAndOptionalHash((ByteBuffer) buffer.duplicate().position(i)); + int l = u.length(); + i += l; + n++; + } + return n; + } + + public URLAndOptionalHash get(int index) + { + int len = buffer.getShort(1) & 0xFFFF; + int n = 0; + int l = 0; + int i; + for (i = 3; i < len && n < index; ) + { + URLAndOptionalHash u + = new URLAndOptionalHash((ByteBuffer) buffer.duplicate().position(i)); + l = u.length(); + i += l; + n++; + } + if (n < index) + throw new IndexOutOfBoundsException(); + return new URLAndOptionalHash(((ByteBuffer) buffer.duplicate().position(i).limit(i+l)).slice()); + } + + public void set(int index, URLAndOptionalHash url) + { + int len = buffer.getShort(1) & 0xFFFF; + int n = 0; + int i; + for (i = 3; i < len && n < index-1; ) + { + URLAndOptionalHash u + = new URLAndOptionalHash((ByteBuffer) buffer.duplicate().position(i)); + int l = u.length(); + i += l; + n++; + } + if (n < index - 1) + throw new IndexOutOfBoundsException(); + int l = url.urlLength(); + buffer.putShort(i, (short) l); + ((ByteBuffer) buffer.duplicate().position(i+2)).put(url.urlBuffer()); + buffer.put(i+l+2, (byte) (url.hashPresent() ? 1 : 0)); + if (url.hashPresent()) + ((ByteBuffer) buffer.duplicate().position(i+l+3)).put (url.sha1Hash()); + } + + public void setLength(final int length) + { + if (length < 0 || length > 65535) + throw new IllegalArgumentException("length must be between 0 and 65535"); + buffer.putShort(1, (short) length); + } + + public String toString() + { + return toString(null); + } + + public String toString(String prefix) + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + if (prefix != null) out.print(prefix); + out.println ("struct {"); + if (prefix != null) out.print(prefix); + out.print(" type = "); + out.print(type()); + out.println(";"); + if (prefix != null) out.print(prefix); + out.println(" url_and_hash_list = {"); + String subprefix = " "; + if (prefix != null) subprefix = prefix + subprefix; + for (URLAndOptionalHash url : this) + { + out.println(url.toString(subprefix)); + } + if (prefix != null) out.print(prefix); + out.println(" };"); + if (prefix != null) out.print(prefix); + out.print("} CertificateURL;"); + return str.toString(); + } + + public java.util.Iterator iterator() + { + return new Iterator(); + } + + public class Iterator implements java.util.Iterator + { + private int index; + + public Iterator() + { + index = 0; + } + + public URLAndOptionalHash next() throws NoSuchElementException + { + try + { + return get(index++); + } + catch (IndexOutOfBoundsException ioobe) + { + throw new NoSuchElementException(); + } + } + + public boolean hasNext() + { + return index < size(); + } + + public void remove() + { + throw new UnsupportedOperationException(); + } + } + + public static enum CertChainType + { + INDIVIDUAL_CERTS (0), PKIPATH (1); + + private final int value; + + private CertChainType (final int value) + { + this.value = value; + } + + public int getValue() + { + return value; + } + } + + public static class URLAndOptionalHash implements Builder, Constructed + { + private ByteBuffer buffer; + + public URLAndOptionalHash (final ByteBuffer buffer) + { + this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); + } + + public URLAndOptionalHash(String url) + { + this(url, null); + } + + public URLAndOptionalHash(String url, byte[] hash) + { + if (hash != null && hash.length < 20) + throw new IllegalArgumentException(); + int length = 3 + url.length(); + if (hash != null) + length += 20; + buffer = ByteBuffer.allocate(length); + buffer.putShort((short) url.length()); + Charset cs = Charset.forName("US-ASCII"); + CharsetEncoder ascii = cs.newEncoder(); + ascii.encode(CharBuffer.wrap(url), buffer, true); + buffer.put((byte) (hash != null ? 1 : 0)); + if (hash != null) + buffer.put(hash, 0, 20); + buffer.rewind(); + } + + public int length() + { + return ((buffer.getShort(0) & 0xFFFF) + + (hashPresent() ? 23 : 3)); + } + + public ByteBuffer buffer() + { + return (ByteBuffer) buffer.duplicate().limit(length()); + } + + public String url() + { + Charset cs = Charset.forName("ASCII"); + return cs.decode(urlBuffer()).toString(); + } + + public int urlLength() + { + return buffer.getShort(0) & 0xFFFF; + } + + public ByteBuffer urlBuffer() + { + int len = urlLength(); + return ((ByteBuffer) buffer.duplicate().position(2).limit(2+len)).slice(); + } + + public boolean hashPresent() + { + int i = (buffer.getShort(0) & 0xFFFF) + 2; + byte b = buffer.get(i); + if (b == 0) + return false; + if (b == 1) + return true; + throw new IllegalArgumentException("expecting 0 or 1: " + (b & 0xFF)); + } + + public byte[] sha1Hash() + { + int i = (buffer.getShort(0) & 0xFFFF) + 2; + byte b = buffer.get(i); + if (b == 0) + return null; + byte[] buf = new byte[20]; + ((ByteBuffer) buffer.duplicate().position(i+1)).get(buf); + return buf; + } + + public String toString() + { + return toString(null); + } + + public String toString(final String prefix) + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + if (prefix != null) out.print(prefix); + out.println("struct {"); + if (prefix != null) out.print(prefix); + out.print(" url = "); + out.print(url()); + out.println(";"); + boolean has_hash = hashPresent(); + if (prefix != null) out.print(prefix); + out.print(" hash_present = "); + out.print(has_hash); + out.println(";"); + if (has_hash) + { + if (prefix != null) out.print(prefix); + out.print(" sha1Hash = "); + out.print(Util.toHexString(sha1Hash(), ':')); + out.println(";"); + } + if (prefix != null) out.print(prefix); + out.print("} URLAndOptionalHash;"); + return str.toString(); + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CertificateVerify.java b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateVerify.java new file mode 100644 index 000000000..dfa5f6028 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/CertificateVerify.java @@ -0,0 +1,83 @@ +/* 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.PrintWriter; +import java.io.StringWriter; +import java.nio.ByteBuffer; + +public class CertificateVerify extends Signature implements Handshake.Body +{ + + // Contstructor. + // ------------------------------------------------------------------------- + + public CertificateVerify(final ByteBuffer buffer, final SignatureAlgorithm sigAlg) + { + super(buffer, sigAlg); + } + + public CertificateVerify(final byte[] sigVal, final SignatureAlgorithm sigAlg) + { + super(sigVal, sigAlg); + } + + // Instance method. + // ------------------------------------------------------------------------- + + public String toString() + { + return toString (null); + } + + public String toString (final String prefix) + { + StringWriter str = new StringWriter (); + PrintWriter out = new PrintWriter (str); + if (prefix != null) out.print (prefix); + out.println("struct {"); + String subprefix = " "; + if (prefix != null) + subprefix = prefix + subprefix; + out.println (super.toString (subprefix)); + if (prefix != null) out.print (prefix); + out.print ("} CertificateVerify;"); + return str.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CipherAlgorithm.java b/libjava/classpath/gnu/javax/net/ssl/provider/CipherAlgorithm.java new file mode 100644 index 000000000..98e05af31 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/CipherAlgorithm.java @@ -0,0 +1,47 @@ +/* CipherAlgorithm.java -- Cipher algorithm enumeration. + 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; + +/** + * The set of cipher algorithms we support. + */ +public enum CipherAlgorithm +{ + NULL, RC4, DES, DESede, CAST5, AES +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CipherSuite.java b/libjava/classpath/gnu/javax/net/ssl/provider/CipherSuite.java new file mode 100644 index 000000000..1c5923129 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/CipherSuite.java @@ -0,0 +1,837 @@ +/* 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 gnu.java.security.action.GetSecurityPropertyAction; + +import java.io.IOException; +import java.io.OutputStream; + +import java.nio.ByteBuffer; + +import java.security.AccessController; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; + +import javax.crypto.Cipher; +import javax.crypto.Mac; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.NullCipher; + +public final class CipherSuite implements Constructed +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + private static final List tlsSuiteNames = new LinkedList(); + private static final HashMap namesToSuites = new HashMap(); + + // Core TLS cipher suites. + public static final CipherSuite TLS_NULL_WITH_NULL_NULL = + new CipherSuite (CipherAlgorithm.NULL, + KeyExchangeAlgorithm.NONE, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.NULL, 0, 0x00, 0x00, + "TLS_NULL_WITH_NULL_NULL"); + public static final CipherSuite TLS_RSA_WITH_NULL_MD5 = + new CipherSuite (CipherAlgorithm.NULL, + KeyExchangeAlgorithm.RSA, + SignatureAlgorithm.RSA, + MacAlgorithm.MD5, 0, 0x00, 0x01, + "TLS_RSA_WITH_NULL_MD5"); + public static final CipherSuite TLS_RSA_WITH_NULL_SHA = + new CipherSuite (CipherAlgorithm.NULL, + KeyExchangeAlgorithm.RSA, + SignatureAlgorithm.RSA, + MacAlgorithm.SHA, 0, 0x00, 0x02, + "TLS_RSA_WITH_NULL_SHA"); + public static final CipherSuite TLS_RSA_EXPORT_WITH_RC4_40_MD5 = + new CipherSuite (CipherAlgorithm.RC4, + KeyExchangeAlgorithm.RSA, + SignatureAlgorithm.RSA, + MacAlgorithm.MD5, 5, 0x00, 0x03, + "TLS_RSA_EXPORT_WITH_RC4_40_MD5"); + public static final CipherSuite TLS_RSA_WITH_RC4_128_MD5 = + new CipherSuite (CipherAlgorithm.RC4, + KeyExchangeAlgorithm.RSA, + SignatureAlgorithm.RSA, + MacAlgorithm.MD5, 16, 0x00, 0x04, + "TLS_RSA_WITH_RC4_128_MD5"); + public static final CipherSuite TLS_RSA_WITH_RC4_128_SHA = + new CipherSuite (CipherAlgorithm.RC4, + KeyExchangeAlgorithm.RSA, + SignatureAlgorithm.RSA, + MacAlgorithm.SHA, 16, 0x00, 0x05, + "TLS_RSA_WITH_RC4_128_SHA"); + public static final CipherSuite TLS_RSA_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite (CipherAlgorithm.DES, + KeyExchangeAlgorithm.RSA, + SignatureAlgorithm.RSA, + MacAlgorithm.SHA, 5, 0x00, 0x08, + "TLS_RSA_EXPORT_WITH_DES40_CBC_SHA"); + public static final CipherSuite TLS_RSA_WITH_DES_CBC_SHA = + new CipherSuite (CipherAlgorithm.DES, + KeyExchangeAlgorithm.RSA, + SignatureAlgorithm.RSA, + MacAlgorithm.SHA, 8, 0x00, 0x09, + "TLS_RSA_WITH_DES_CBC_SHA"); + public static final CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite (CipherAlgorithm.DESede, + KeyExchangeAlgorithm.RSA, + SignatureAlgorithm.RSA, + MacAlgorithm.SHA, 24, 0x00, 0x0A, + "TLS_RSA_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite (CipherAlgorithm.DES, + KeyExchangeAlgorithm.DH_DSS, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 5, 0x00, 0x0B, + "TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA"); + public static final CipherSuite TLS_DH_DSS_WITH_DES_CBC_SHA = + new CipherSuite (CipherAlgorithm.DES, + KeyExchangeAlgorithm.DH_DSS, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 8, 0x00, 0x0C, + "TLS_DH_DSS_WITH_DES_CBC_SHA"); + public static final CipherSuite TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = + new CipherSuite (CipherAlgorithm.DESede, + KeyExchangeAlgorithm.DH_DSS, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 24, 0x00, 0x0D, + "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite (CipherAlgorithm.DES, + KeyExchangeAlgorithm.DH_RSA, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 5, 0x00, 0x0E, + "TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA"); + public static final CipherSuite TLS_DH_RSA_WITH_DES_CBC_SHA = + new CipherSuite (CipherAlgorithm.DES, + KeyExchangeAlgorithm.DH_RSA, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 8, 0x00, 0x0F, + "TLS_DH_RSA_WITH_DES_CBC_SHA"); + public static final CipherSuite TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite (CipherAlgorithm.DESede, + KeyExchangeAlgorithm.DH_RSA, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 24, 0x00, 0x10, + "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite (CipherAlgorithm.DES, + KeyExchangeAlgorithm.DHE_DSS, true, + SignatureAlgorithm.DSA, + MacAlgorithm.SHA, 5, 0x00, 0x11, + "TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA"); + public static final CipherSuite TLS_DHE_DSS_WITH_DES_CBC_SHA = + new CipherSuite (CipherAlgorithm.DES, + KeyExchangeAlgorithm.DHE_DSS, true, + SignatureAlgorithm.DSA, + MacAlgorithm.SHA, 8, 0x00, 0x12, + "TLS_DHE_DSS_WITH_DES_CBC_SHA"); + public static final CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = + new CipherSuite (CipherAlgorithm.DESede, + KeyExchangeAlgorithm.DHE_DSS, true, + SignatureAlgorithm.DSA, + MacAlgorithm.SHA, 24, 0x00, 0x13, + "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA = + new CipherSuite (CipherAlgorithm.DES, + KeyExchangeAlgorithm.DHE_RSA, true, + SignatureAlgorithm.RSA, + MacAlgorithm.SHA, 5, 0x00, 0x14, + "TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA"); + public static final CipherSuite TLS_DHE_RSA_WITH_DES_CBC_SHA = + new CipherSuite (CipherAlgorithm.DES, + KeyExchangeAlgorithm.DHE_RSA, true, + SignatureAlgorithm.RSA, + MacAlgorithm.SHA, 8, 0x00, 0x15, + "TLS_DHE_RSA_WITH_DES_CBC_SHA"); + public static final CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite (CipherAlgorithm.DESede, + KeyExchangeAlgorithm.DHE_RSA, true, + SignatureAlgorithm.RSA, + MacAlgorithm.SHA, 24, 0x00, 0x16, + "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA"); + + // AES CipherSuites. + public static final CipherSuite TLS_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.RSA, + SignatureAlgorithm.RSA, + MacAlgorithm.SHA, 16, 0x00, 0x2F, + "TLS_RSA_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_DH_DSS_WITH_AES_128_CBC_SHA = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.DH_DSS, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 16, 0x00, 0x30, + "TLS_DH_DSS_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_DH_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.DH_RSA, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 16, 0x00, 0x31, + "TLS_DH_RSA_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_SHA = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.DHE_DSS, true, + SignatureAlgorithm.DSA, + MacAlgorithm.SHA, 16, 0x00, 0x32, + "TLS_DHE_DSS_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.DHE_RSA, true, + SignatureAlgorithm.RSA, + MacAlgorithm.SHA, 16, 0x00, 0x33, + "TLS_DHE_RSA_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.RSA, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 32, 0x00, 0x35, + "TLS_RSA_WITH_AES_256_CBC_SHA"); + public static final CipherSuite TLS_DH_DSS_WITH_AES_256_CBC_SHA = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.DH_DSS, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 32, 0x00, 0x36, + "TLS_DH_DSS_WITH_AES_256_CBC_SHA"); + public static final CipherSuite TLS_DH_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.DH_RSA, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 32, 0x00, 0x37, + "TLS_DH_RSA_WITH_AES_256_CBC_SHA"); + public static final CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_SHA = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.DHE_DSS, true, + SignatureAlgorithm.DSA, + MacAlgorithm.SHA, 32, 0x00, 0x38, + "TLS_DHE_DSS_WITH_AES_256_CBC_SHA"); + public static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.DHE_RSA, true, + SignatureAlgorithm.RSA, + MacAlgorithm.SHA, 32, 0x00, 0x39, + "TLS_DHE_RSA_WITH_AES_256_CBC_SHA"); + + // Secure remote password (SRP) ciphersuites + // Actual ID values are TBD, so these are omitted until they are specified. + /*public static final CipherSuite TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite (CipherAlgorithm.DESede, + KeyExchangeAlgorithm.SRP, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 24, 0x00, 0x50, + "TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA = + new CipherSuite (CipherAlgorithm.DESede, + KeyExchangeAlgorithm.SRP, + SignatureAlgorithm.RSA, + MacAlgorithm.SHA, 24, 0x00, 0x51, + "TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA = + new CipherSuite (CipherAlgorithm.DESede, + KeyExchangeAlgorithm.SRP, + SignatureAlgorithm.DSA, + MacAlgorithm.SHA, 24, 0x00, 0x52, + "TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_SRP_SHA_WITH_AES_128_CBC_SHA = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.SRP, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 16, 0x00, 0x53, + "TLS_SRP_SHA_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.SRP, + SignatureAlgorithm.RSA, + MacAlgorithm.SHA, 16, 0x00, 0x54, + "TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.SRP, + SignatureAlgorithm.DSA, + MacAlgorithm.SHA, 16, 0x00, 0x55, + "TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_SRP_SHA_WITH_AES_256_CBC_SHA = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.SRP, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 32, 0x00, 0x56, + "TLS_SRP_SHA_WITH_AES_256_CBC_SHA"); + public static final CipherSuite TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.SRP, + SignatureAlgorithm.RSA, + MacAlgorithm.SHA, 32, 0x00, 0x57, + "TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA"); + public static final CipherSuite TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.SRP, + SignatureAlgorithm.DSA, + MacAlgorithm.SHA, 32, 0x00, 0x58, + "TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA");*/ + + // Pre-shared key suites. + public static final CipherSuite TLS_PSK_WITH_RC4_128_SHA = + new CipherSuite(CipherAlgorithm.RC4, + KeyExchangeAlgorithm.PSK, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 16, 0x00, 0x8A, + "TLS_PSK_WITH_RC4_128_SHA"); + public static final CipherSuite TLS_PSK_WITH_3DES_EDE_CBC_SHA = + new CipherSuite(CipherAlgorithm.DESede, + KeyExchangeAlgorithm.PSK, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 24, 0x00, 0x8B, + "TLS_PSK_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_PSK_WITH_AES_128_CBC_SHA = + new CipherSuite(CipherAlgorithm.AES, + KeyExchangeAlgorithm.PSK, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 16, 0x00, 0x8C, + "TLS_PSK_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_PSK_WITH_AES_256_CBC_SHA = + new CipherSuite(CipherAlgorithm.AES, + KeyExchangeAlgorithm.PSK, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 32, 0x00, 0x8D, + "TLS_PSK_WITH_AES_256_CBC_SHA"); + + public static final CipherSuite TLS_DHE_PSK_WITH_RC4_128_SHA = + new CipherSuite(CipherAlgorithm.RC4, + KeyExchangeAlgorithm.DHE_PSK, true, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 16, 0x00, 0x8E, + "TLS_DHE_PSK_WITH_RC4_128_SHA"); + public static final CipherSuite TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA = + new CipherSuite(CipherAlgorithm.DESede, + KeyExchangeAlgorithm.DHE_PSK, true, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 24, 0x00, 0x8F, + "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_DHE_PSK_WITH_AES_128_CBC_SHA = + new CipherSuite(CipherAlgorithm.AES, + KeyExchangeAlgorithm.DHE_PSK, true, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 16, 0x00, 0x90, + "TLS_DHE_PSK_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_DHE_PSK_WITH_AES_256_CBC_SHA = + new CipherSuite(CipherAlgorithm.AES, + KeyExchangeAlgorithm.DHE_PSK, true, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 32, 0x00, 0x91, + "TLS_DHE_PSK_WITH_AES_256_CBC_SHA"); + + public static final CipherSuite TLS_RSA_PSK_WITH_RC4_128_SHA = + new CipherSuite(CipherAlgorithm.RC4, + KeyExchangeAlgorithm.RSA_PSK, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 16, 0x00, 0x92, + "TLS_RSA_PSK_WITH_RC4_128_SHA"); + public static final CipherSuite TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA = + new CipherSuite(CipherAlgorithm.DESede, + KeyExchangeAlgorithm.RSA_PSK, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 24, 0x00, 0x93, + "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA"); + public static final CipherSuite TLS_RSA_PSK_WITH_AES_128_CBC_SHA = + new CipherSuite(CipherAlgorithm.AES, + KeyExchangeAlgorithm.RSA_PSK, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 16, 0x00, 0x94, + "TLS_RSA_PSK_WITH_AES_128_CBC_SHA"); + public static final CipherSuite TLS_RSA_PSK_WITH_AES_256_CBC_SHA = + new CipherSuite(CipherAlgorithm.AES, + KeyExchangeAlgorithm.RSA_PSK, + SignatureAlgorithm.ANONYMOUS, + MacAlgorithm.SHA, 32, 0x00, 0x95, + "TLS_RSA_PSK_WITH_AES_256_CBC_SHA"); + + // Ciphersuites from the OpenPGP extension draft. + // These disappeared from a more recent draft. +/* public static final CipherSuite TLS_DHE_DSS_WITH_CAST_128_CBC_SHA = + new CipherSuite (CipherAlgorithm.CAST5, + KeyExchangeAlgorithm.DIFFIE_HELLMAN, true, + SignatureAlgorithm.DSA, + MacAlgorithm.SHA, 16, 0x00, 0x70, + "TLS_DHE_DSS_WITH_CAST_128_CBC_SHA"); + public static final CipherSuite TLS_DHE_DSS_WITH_CAST_128_CBC_RMD = + new CipherSuite (CipherAlgorithm.CAST5, + KeyExchangeAlgorithm.DIFFIE_HELLMAN, true, + SignatureAlgorithm.DSA, + MacAlgorithm.HMAC_RMD, 16, 0x00, 0x71, + "TLS_DHE_DSS_WITH_CAST_128_CBC_RMD"); + public static final CipherSuite TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD = + new CipherSuite (CipherAlgorithm.DESede, + KeyExchangeAlgorithm.DIFFIE_HELLMAN, true, + SignatureAlgorithm.DSA, + MacAlgorithm.HMAC_RMD, 24, 0x00, 0x72, + "TLS_DHE_DSS_WITH_3DES_EDE_CBC_RMD"); + public static final CipherSuite TLS_DHE_DSS_WITH_AES_128_CBC_RMD = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.DIFFIE_HELLMAN, true, + SignatureAlgorithm.DSA, + MacAlgorithm.HMAC_RMD, 16, 0x00, 0x73, + "TLS_DHE_DSS_WITH_AES_128_CBC_RMD"); + public static final CipherSuite TLS_DHE_DSS_WITH_AES_256_CBC_RMD = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.DIFFIE_HELLMAN, true, + SignatureAlgorithm.DSA, + MacAlgorithm.HMAC_RMD, 32, 0x00, 0x74, + "TLS_DHE_DSS_WITH_AES_256_CBC_RMD"); + public static final CipherSuite TLS_DHE_RSA_WITH_CAST_128_CBC_SHA = + new CipherSuite (CipherAlgorithm.CAST5, + KeyExchangeAlgorithm.DIFFIE_HELLMAN, true, + SignatureAlgorithm.RSA, + MacAlgorithm.SHA, 16, 0x00, 0x75, + "TLS_DHE_RSA_WITH_CAST_128_CBC_SHA"); + public static final CipherSuite TLS_DHE_RSA_WITH_CAST_128_CBC_RMD = + new CipherSuite (CipherAlgorithm.CAST5, + KeyExchangeAlgorithm.DIFFIE_HELLMAN, true, + SignatureAlgorithm.RSA, + MacAlgorithm.HMAC_RMD, 16, 0x00, 0x76, + "TLS_DHE_RSA_WITH_CAST_128_CBC_RMD"); + public static final CipherSuite TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD = + new CipherSuite (CipherAlgorithm.DESede, + KeyExchangeAlgorithm.DIFFIE_HELLMAN, true, + SignatureAlgorithm.RSA, + MacAlgorithm.HMAC_RMD, 24, 0x00, 0x77, + "TLS_DHE_RSA_WITH_3DES_EDE_CBC_RMD"); + public static final CipherSuite TLS_DHE_RSA_WITH_AES_128_CBC_RMD = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.DIFFIE_HELLMAN, true, + SignatureAlgorithm.RSA, + MacAlgorithm.HMAC_RMD, 16, 0x00, 0x78, + "TLS_DHE_RSA_WITH_AES_128_CBC_RMD"); + public static final CipherSuite TLS_DHE_RSA_WITH_AES_256_CBC_RMD = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.DIFFIE_HELLMAN, true, + SignatureAlgorithm.RSA, + MacAlgorithm.HMAC_RMD, 32, 0x00, 0x79, + "TLS_DHE_RSA_WITH_AES_256_CBC_RMD"); + public static final CipherSuite TLS_RSA_WITH_CAST_128_CBC_SHA = + new CipherSuite (CipherAlgorithm.CAST5, + KeyExchangeAlgorithm.RSA, + SignatureAlgorithm.RSA, + MacAlgorithm.SHA, 16, 0x00, 0x7A, + "TLS_RSA_WITH_CAST_128_CBC_SHA"); + public static final CipherSuite TLS_RSA_WITH_CAST_128_CBC_RMD = + new CipherSuite (CipherAlgorithm.CAST5, + KeyExchangeAlgorithm.RSA, + SignatureAlgorithm.RSA, + MacAlgorithm.HMAC_RMD, 16, 0x00, 0x7B, + "TLS_RSA_WITH_CAST_128_CBC_RMD"); + public static final CipherSuite TLS_RSA_WITH_3DES_EDE_CBC_RMD = + new CipherSuite (CipherAlgorithm.DESede, + KeyExchangeAlgorithm.RSA, + SignatureAlgorithm.RSA, + MacAlgorithm.HMAC_RMD, 24, 0x00, 0x7C, + "TLS_RSA_WITH_3DES_EDE_CBC_RMD"); + public static final CipherSuite TLS_RSA_WITH_AES_128_CBC_RMD = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.RSA, + SignatureAlgorithm.RSA, + MacAlgorithm.HMAC_RMD, 16, 0x00, 0x7D, + "TLS_RSA_WITH_AES_128_CBC_RMD"); + public static final CipherSuite TLS_RSA_WITH_AES_256_CBC_RMD = + new CipherSuite (CipherAlgorithm.AES, + KeyExchangeAlgorithm.RSA, + SignatureAlgorithm.RSA, + MacAlgorithm.HMAC_RMD, 32, 0x00, 0x7E, + "TLS_RSA_WITH_AES_256_CBC_RMD"); */ + + private final CipherAlgorithm cipherAlgorithm; + private final KeyExchangeAlgorithm keyExchangeAlgorithm; + private final SignatureAlgorithm signatureAlgorithm; + private final MacAlgorithm macAlgorithm; + private final boolean ephemeralDH; + private final boolean exportable; + private final boolean isStream; + private final int keyLength; + private final byte[] id; + private final String name; + private final boolean isResolved; + + // Constructors. + // ------------------------------------------------------------------------- + + private CipherSuite (final CipherAlgorithm cipherAlgorithm, + final KeyExchangeAlgorithm keyExchangeAlgorithm, + final SignatureAlgorithm signatureAlgorithm, + final MacAlgorithm macAlgorithm, + final int keyLength, + final int id1, + final int id2, + final String name) + { + this (cipherAlgorithm, keyExchangeAlgorithm, false, signatureAlgorithm, + macAlgorithm, keyLength, id1, id2, name); + } + + private CipherSuite (final CipherAlgorithm cipherAlgorithm, + final KeyExchangeAlgorithm keyExchangeAlgorithm, + final boolean ephemeralDH, + final SignatureAlgorithm signatureAlgorithm, + final MacAlgorithm macAlgorithm, + final int keyLength, + final int id1, + final int id2, + final String name) + { + this.cipherAlgorithm = cipherAlgorithm; + this.keyExchangeAlgorithm = keyExchangeAlgorithm; + this.ephemeralDH = ephemeralDH; + this.signatureAlgorithm = signatureAlgorithm; + this.macAlgorithm = macAlgorithm; + this.exportable = keyLength <= 5; + this.isStream = (cipherAlgorithm == CipherAlgorithm.NULL + || cipherAlgorithm == CipherAlgorithm.RC4); + this.keyLength = keyLength; + this.id = new byte[] { (byte) id1, (byte) id2 }; + this.name = name.intern(); + namesToSuites.put(name, this); + if (name.startsWith("TLS")) + { + tlsSuiteNames.add(name); + } + isResolved = true; + } + + private CipherSuite(byte[] id) + { + cipherAlgorithm = null; + keyExchangeAlgorithm = null; + signatureAlgorithm = null; + macAlgorithm = null; + ephemeralDH = false; + exportable = false; + isStream = false; + keyLength = 0; + this.id = id; + name = null; + isResolved = false; + } + + // Class methods. + // ------------------------------------------------------------------------- + + /** + * Returns the cipher suite for the given name, or null if there is no + * such suite. + * + * @return The named cipher suite. + */ + public static CipherSuite forName(String name) + { + if (name.startsWith("SSL_")) + name = "TLS_" + name.substring(4); + return namesToSuites.get(name); + } + + public static CipherSuite forValue(final short raw_value) + { + byte[] b = new byte[] { (byte) (raw_value >>> 8), (byte) raw_value }; + return new CipherSuite(b).resolve(); + } + + public static List availableSuiteNames() + { + return tlsSuiteNames; + } + + // Intance methods. + // ------------------------------------------------------------------------- + + public CipherAlgorithm cipherAlgorithm () + { + return cipherAlgorithm; + } + + public Cipher cipher () throws NoSuchAlgorithmException, NoSuchPaddingException + { + if (cipherAlgorithm == null) + throw new NoSuchAlgorithmException (toString () + ": unresolved cipher suite"); + if (cipherAlgorithm == CipherAlgorithm.NULL) + return new NullCipher (); + + String alg = null; + if (cipherAlgorithm == CipherAlgorithm.RC4) + alg = "RC4"; + else + alg = cipherAlgorithm + "/CBC/NoPadding"; + GetSecurityPropertyAction gspa = + new GetSecurityPropertyAction ("jessie.jce.provider"); + final String provider = (String) AccessController.doPrivileged (gspa); + if (provider != null) + { + try + { + return Cipher.getInstance (alg, provider); + } + catch (NoSuchProviderException nspe) + { + } + } + return Cipher.getInstance (alg); + } + + public MacAlgorithm macAlgorithm () + { + return macAlgorithm; + } + + public Mac mac(ProtocolVersion version) throws NoSuchAlgorithmException + { + if (macAlgorithm == null) + throw new NoSuchAlgorithmException(toString() + ": unresolved cipher suite"); + if (macAlgorithm == MacAlgorithm.NULL) + return null; + + String macAlg = null; + if (version == ProtocolVersion.SSL_3) + { + macAlg = "SSLv3HMac-" + macAlgorithm; + } + else + { + if (macAlgorithm == MacAlgorithm.MD5) + macAlg = "HMac-MD5"; + if (macAlgorithm == MacAlgorithm.SHA) + macAlg = "HMac-SHA1"; + } + + GetSecurityPropertyAction gspa = + new GetSecurityPropertyAction ("jessie.jce.provider"); + final String provider = AccessController.doPrivileged (gspa); + if (provider != null) + { + try + { + return Mac.getInstance(macAlg, provider); + } + catch (NoSuchProviderException nspe) + { + // Ignore; try any installed provider. + } + } + return Mac.getInstance(macAlg); + } + + public SignatureAlgorithm signatureAlgorithm () + { + return signatureAlgorithm; + } + + public KeyExchangeAlgorithm keyExchangeAlgorithm () + { + return keyExchangeAlgorithm; + } + + public boolean isEphemeralDH () + { + return ephemeralDH; + } + + public int length () + { + return 2; + } + + public void write(OutputStream out) throws IOException + { + out.write(id); + } + + public void put (final ByteBuffer buf) + { + buf.put (id); + } + + public CipherSuite resolve() + { + if (id[0] == 0x00) switch (id[1] & 0xFF) + { + 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;*/ + case 0x8A: return TLS_PSK_WITH_RC4_128_SHA; + case 0x8B: return TLS_PSK_WITH_3DES_EDE_CBC_SHA; + case 0x8C: return TLS_PSK_WITH_AES_128_CBC_SHA; + case 0x8D: return TLS_PSK_WITH_AES_256_CBC_SHA; + case 0x8E: return TLS_DHE_PSK_WITH_RC4_128_SHA; + case 0x8F: return TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA; + case 0x90: return TLS_DHE_PSK_WITH_AES_128_CBC_SHA; + case 0x91: return TLS_DHE_PSK_WITH_AES_256_CBC_SHA; + case 0x92: return TLS_RSA_PSK_WITH_RC4_128_SHA; + case 0x93: return TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA; + case 0x94: return TLS_RSA_PSK_WITH_AES_128_CBC_SHA; + case 0x95: return TLS_RSA_PSK_WITH_AES_256_CBC_SHA; + } + return this; + } + + public boolean isResolved() + { + return isResolved; + } + + public int keyLength() + { + return keyLength; + } + + public boolean isExportable() + { + return exportable; + } + + public boolean isStreamCipher() + { + return isStream; + } + +// String getAuthType() +// { +// if (keyExchangeAlgorithm == KeyExchangeAlgorithm.RSA) +// { +// if (isExportable()) +// { +// return "RSA_EXPORT"; +// } +// return "RSA"; +// } +// return kexName + "_" + sigName; +// } + + public byte[] id() + { + return id; + } + + public boolean equals(Object o) + { + if (!(o instanceof CipherSuite)) + { + return false; + } + if (o == this) + return true; + byte[] id = ((CipherSuite) o).id(); + return (id[0] == this.id[0] && + id[1] == this.id[1]); + } + + public int hashCode() + { + return 0xFFFF0000 | (id[0] & 0xFF) << 8 | (id[1] & 0xFF); + } + + public String toString (String prefix) + { + return toString (); + } + + public String toString() + { + if (name == null) + { + return "{ " + (id[0] & 0xFF) + ", " + (id[1] & 0xFF) + " }"; + } + return name; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CipherSuiteList.java b/libjava/classpath/gnu/javax/net/ssl/provider/CipherSuiteList.java new file mode 100644 index 000000000..a12304698 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/CipherSuiteList.java @@ -0,0 +1,283 @@ +/* CipherSuiteList.java -- A list of 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.PrintWriter; +import java.io.StringWriter; + +import java.nio.ByteBuffer; +import java.util.ConcurrentModificationException; +import java.util.ListIterator; +import java.util.NoSuchElementException; + +public final class CipherSuiteList implements Iterable +{ + private final ByteBuffer buffer; + private final ProtocolVersion version; + private int modCount; + + public CipherSuiteList (final ByteBuffer buffer) + { + this (buffer, ProtocolVersion.SSL_3); + } + + public CipherSuiteList (final ByteBuffer buffer, final ProtocolVersion version) + { + this.version = version; + this.buffer = buffer; + modCount = 0; + } + + /** + * Return the number of elements in this list. + * + * @return The size of this list. + */ + public int size () + { + return (buffer.getShort (0) & 0xFFFF) >>> 1; + } + + /** + * Get the cipher suite at the specified index. + * + * @param index The index of the suite to get. + * @return The cipher suite at that index. + * @throws IndexOutOfBoundsException If the index is negative or is + * not less than {@link size()}. + */ + public CipherSuite get (final int index) + { + int size = size (); + if (index < 0 || index >= size) + throw new IndexOutOfBoundsException ("limit: " + size + + "; requested: " + index); + return CipherSuite.forValue(buffer.getShort(2 + (index << 1))).resolve(); + } + + /** + * Set the CipherSuite at the specified index. The list must have + * sufficient size to hold the element (that is, index <= + * size ()). + * + * @param index The index to put the suite. + * @param suite The CipherSuite object. + * @throws IndexOutOfBoundsException If index is not + * less than @{link #size()}, or if it is negative. + * @throws NullPointerException If suite is + * null. + * @throws java.nio.ReadOnlyBufferException If the underlying buffer + * is not writable. + */ + public void put (final int index, final CipherSuite suite) + { + int size = size (); + if (index < 0 || index >= size) + throw new IndexOutOfBoundsException ("limit: " + size + + "; requested: " + index); + buffer.position (2 + (index << 1)); + buffer.put (suite.id ()); + modCount++; + } + + /** + * Sets the size of this list. You must call this if you are adding + * elements to the list; calling {@link + * #put(int,gnu.jessie.provider.CipherSuite)} does not expand the + * list size (the same goes for removing elements, as there is no + * remove method). + * + * @param newSize The new size of this list. + * @throws IllegalArgumentException If the new size is negative or + * greater than 32767, or if there is insufficient space for that + * many elements in the underlying buffer. + * @throws java.nio.ReadOnlyBufferException If the underlying buffer + * is not writable. + */ + public void setSize (final int newSize) + { + if (newSize < 0 || newSize > 32767) + throw new IllegalArgumentException ("size must be between 0 and 32767"); + if ((newSize << 1) + 2 > buffer.capacity ()) + throw new IllegalArgumentException ("limit: " + buffer.capacity () + + "; requested: " + newSize); + buffer.putShort (0, (short) (newSize << 1)); + modCount++; + } + + public String toString () + { + return toString (null); + } + + public String toString (final String prefix) + { + StringWriter str = new StringWriter (); + PrintWriter out = new PrintWriter (str); + if (prefix != null) + out.print (prefix); + out.print ("["); + out.print (size ()); + out.println ("] {"); + for (Iterator it = new Iterator (); it.hasNext (); ) + { + CipherSuite suite = (CipherSuite) it.next (); + if (prefix != null) + out.print (prefix); + out.print (" "); + out.print (suite); + if (it.hasNext ()) + out.print (","); + out.println (); + } + if (prefix != null) + out.print (prefix); + out.print ("};"); + return str.toString (); + } + + public boolean equals (Object o) + { + if (!(o instanceof CipherSuiteList)) + return false; + CipherSuiteList that = (CipherSuiteList) o; + + if (size () != that.size ()) + return false; + + for (Iterator it1 = new Iterator (), it2 = that.new Iterator (); + it1.hasNext () && it2.hasNext (); ) + { + if (!it1.next ().equals (it2.next ())) + return false; + } + return true; + } + + public java.util.Iterator iterator () + { + return new Iterator (); + } + + /** + * An iterator for the elements in this list. The iterator supports + * only the set method out of the optional methods, + * because elements in a CipherSuiteList may not be removed or + * added; only the size of the list can be changed, and elements at + * a specific index changed. + */ + public class Iterator implements ListIterator + { + private final int modCount; + private int index; + + Iterator () + { + this.modCount = CipherSuiteList.this.modCount; + index = 0; + } + + public void add (CipherSuite cs) + { + throw new UnsupportedOperationException (); + } + + public boolean hasNext () + { + return (index < size ()); + } + + public boolean hasPrevious () + { + return (index > 0); + } + + public CipherSuite next () throws NoSuchElementException + { + if (modCount != CipherSuiteList.this.modCount) + throw new ConcurrentModificationException (); + try + { + return get (index++); + } + catch (IndexOutOfBoundsException ioobe) + { + throw new NoSuchElementException (); + } + } + + public int nextIndex () + { + if (hasNext ()) + return (index + 1); + return -1; + } + + public CipherSuite previous () throws NoSuchElementException + { + if (index == 0) + throw new NoSuchElementException (); + if (modCount != CipherSuiteList.this.modCount) + throw new ConcurrentModificationException (); + try + { + return get (--index); + } + catch (IndexOutOfBoundsException ioobe) // on empty list + { + throw new NoSuchElementException (); + } + } + + public int previousIndex () + { + return (index - 1); + } + + public void remove () + { + throw new UnsupportedOperationException (); + } + + public void set (final CipherSuite cs) + { + put (index, cs); + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientCertificateTypeList.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientCertificateTypeList.java new file mode 100644 index 000000000..4dd64f09f --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientCertificateTypeList.java @@ -0,0 +1,227 @@ +/* ClientCertificateTypeList.java -- A list of certificate 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; + +import gnu.javax.net.ssl.provider.CertificateRequest.ClientCertificateType; + +import java.io.PrintWriter; +import java.io.StringWriter; + +import java.nio.ByteBuffer; + +import java.util.ConcurrentModificationException; +import java.util.ListIterator; +import java.util.NoSuchElementException; + +public class ClientCertificateTypeList implements Iterable +{ + private final ByteBuffer buffer; + private int modCount; + + public ClientCertificateTypeList (final ByteBuffer buffer) + { + this.buffer = buffer; + modCount = 0; + } + + public int size () + { + return (buffer.get (0) & 0xFF); + } + + public CertificateRequest.ClientCertificateType get (final int index) + { + int size = size (); + if (index < 0 || index >= size) + throw new IndexOutOfBoundsException ("limit: " + size + + "; requested: " + index); + return CertificateRequest.ClientCertificateType.forValue + (buffer.get (index + 1) & 0xFF); + } + + public java.util.Iterator iterator() + { + return new Iterator(); + } + + public void put (final int index, final CertificateRequest.ClientCertificateType type) + { + int size = size (); + if (index < 0 || index >= size) + throw new IndexOutOfBoundsException ("limit: " + size + + "; requested: " + index); + buffer.put (index + 1, (byte) type.getValue ()); + modCount++; + } + + public void setSize (final int newSize) + { + if (newSize < 0 || newSize > 255) + throw new IllegalArgumentException ("size must be between 0 and 255"); + if (newSize + 1 > buffer.capacity ()) + throw new IllegalArgumentException ("limit: " + (buffer.capacity () - 1) + + "; requested: " + newSize); + buffer.put (0, (byte) newSize); + modCount++; + } + + public String toString () + { + return toString (null); + } + + public String toString (final String prefix) + { + StringWriter str = new StringWriter (); + PrintWriter out = new PrintWriter (str); + if (prefix != null) out.print (prefix); + out.print ("["); + out.print (size ()); + out.println ("] {"); + for (Iterator it = new Iterator (); it.hasNext (); ) + { + if (prefix != null) out.print (prefix); + out.print (" "); + out.print (it.next ()); + if (it.hasNext ()) + out.print (","); + out.println (); + } + if (prefix != null) out.print (prefix); + out.println ("};"); + return str.toString (); + } + + public boolean equals (Object o) + { + if (!(o instanceof ClientCertificateTypeList)) + return false; + ClientCertificateTypeList that = (ClientCertificateTypeList) o; + + if (size () != that.size ()) + return false; + + for (Iterator it1 = new Iterator (), it2 = that.new Iterator (); + it1.hasNext () && it2.hasNext (); ) + { + if (!it1.next ().equals (it2.next ())) + return false; + } + return true; + } + + public class Iterator implements ListIterator + { + private int index; + private final int modCount; + + Iterator () + { + index = 0; + modCount = ClientCertificateTypeList.this.modCount; + } + + public void add (CertificateRequest.ClientCertificateType type) + { + throw new UnsupportedOperationException (); + } + + public boolean hasNext () + { + return (index < size ()); + } + + public boolean hasPrevious () + { + return (index > 0); + } + + public CertificateRequest.ClientCertificateType next () throws NoSuchElementException + { + if (modCount != ClientCertificateTypeList.this.modCount) + throw new ConcurrentModificationException (); + try + { + return get (index++); + } + catch (IndexOutOfBoundsException ioobe) + { + throw new NoSuchElementException (); + } + } + + public int nextIndex () + { + if (hasNext ()) + return (index + 1); + return -1; + } + + public CertificateRequest.ClientCertificateType previous () throws NoSuchElementException + { + if (index == 0) + throw new NoSuchElementException (); + if (modCount != ClientCertificateTypeList.this.modCount) + throw new ConcurrentModificationException (); + try + { + return get (--index); + } + catch (IndexOutOfBoundsException ioobe) + { + throw new NoSuchElementException (); + } + } + + public int previousIndex () + { + return (index - 1); + } + + public void remove () + { + throw new UnsupportedOperationException (); + } + + public void set (final CertificateRequest.ClientCertificateType type) + { + put (index, type); + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java new file mode 100644 index 000000000..e2362e029 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java @@ -0,0 +1,122 @@ +/* ClientDHE_PSKParameters.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.net.ssl.provider; + +import java.nio.ByteBuffer; +import java.nio.charset.Charset; + +/** + *
    +      struct {
    +          select (KeyExchangeAlgorithm) {
    +              /* other cases for rsa, diffie_hellman, etc. */
    +              case diffie_hellman_psk:   /* NEW */
    +                  opaque psk_identity<0..2^16-1>;
    +                  ClientDiffieHellmanPublic public;
    +          } exchange_keys;
    +      } ClientKeyExchange;
    + * + * @author Casey Marshall (csm@gnu.org) + */ +public class ClientDHE_PSKParameters extends ExchangeKeys implements Builder, Constructed +{ + public ClientDHE_PSKParameters(ByteBuffer buffer) + { + super(buffer); + } + + public ClientDHE_PSKParameters(String identity, ClientDiffieHellmanPublic dh) + { + super(null); + Charset utf8 = Charset.forName("UTF-8"); + ByteBuffer idBuf = utf8.encode(identity); + buffer = ByteBuffer.allocate(2 + idBuf.remaining() + dh.length()); + buffer.putShort((short) idBuf.remaining()); + buffer.put(idBuf); + buffer.put(dh.buffer()); + buffer.rewind(); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Builder#buffer() + */ + public ByteBuffer buffer() + { + return (ByteBuffer) buffer.duplicate().rewind().limit(length()); + } + + private int identityLength() + { + return (buffer.getShort(0) & 0xFFFF) + 2; + } + + public String identity() + { + Charset utf8 = Charset.forName("UTF-8"); + return utf8.decode((ByteBuffer) buffer.duplicate().position(2).limit + (identityLength())).toString(); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Constructed#length() + */ + public int length() + { + int length = (buffer.getShort(0) & 0xFFFF) + 2; + // XXX always explicit? + length += (buffer.getShort(length) & 0xFFFF) + 2; + return length; + } + + public ClientDiffieHellmanPublic params() + { + return new ClientDiffieHellmanPublic(((ByteBuffer) buffer.duplicate() + .position(identityLength()).limit(length())).slice()); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Constructed#toString(java.lang.String) + */ + public String toString(String prefix) + { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientDiffieHellmanPublic.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientDiffieHellmanPublic.java new file mode 100644 index 000000000..393313a2f --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientDiffieHellmanPublic.java @@ -0,0 +1,129 @@ +/* ClientDiffieHellmanPublic.java -- Client Diffie-Hellman value. + 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.PrintWriter; +import java.io.StringWriter; + +import java.math.BigInteger; + +import java.nio.ByteBuffer; + +/** + * The client's explicit Diffie Hellman value. + * + *
    +struct {
    +  select (PublicValueEncoding) {
    +    case implicit: struct { };
    +    case explicit: opaque dh_Yc<1..2^16-1>;
    +  } dh_public;
    +} ClientDiffieHellmanPublic;
    + */ +public class ClientDiffieHellmanPublic extends ExchangeKeys implements Builder +{ + public ClientDiffieHellmanPublic(final ByteBuffer buffer) + { + super(buffer); + } + + public ClientDiffieHellmanPublic(final BigInteger Yc) + { + super(wrap(Yc)); + } + + private static ByteBuffer wrap(BigInteger Yc) + { + byte[] b = Util.trim(Yc); + ByteBuffer ret = ByteBuffer.allocate(b.length + 2); + ret.putShort((short) b.length); + ret.put(b); + return (ByteBuffer) ret.rewind(); + } + + public ByteBuffer buffer() + { + return (ByteBuffer) buffer.duplicate().rewind().limit(length()); + } + + public BigInteger publicValue() + { + int len = length() - 2; + byte[] b = new byte[len]; + buffer.position(2); + buffer.get(b); + buffer.rewind(); + return new BigInteger(1, b); + } + + public void setPublicValue(final BigInteger Yc) + { + byte[] buf = Util.trim(Yc); + if (buffer.capacity() < buf.length + 2) + buffer = ByteBuffer.allocate(buf.length + 2); + buffer.putShort((short) buf.length); + buffer.put(buf); + buffer.rewind(); + } + + public int length () + { + return (buffer.getShort(0) & 0xFFFF) + 2; + } + + public String toString () + { + return toString (null); + } + + public String toString (final String prefix) + { + StringWriter str = new StringWriter (); + PrintWriter out = new PrintWriter (str); + if (prefix != null) out.print (prefix); + out.println ("struct {"); + if (prefix != null) out.print (prefix); + out.print (" dh_Yc = "); + out.print (publicValue ().toString (16)); + out.println (';'); + if (prefix != null) out.print (prefix); + out.print ("} ClientDiffieHellmanPublic;"); + return str.toString (); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientHandshake.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHandshake.java new file mode 100644 index 000000000..c938e284a --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHandshake.java @@ -0,0 +1,1153 @@ +/* ClientHandshake.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.net.ssl.provider; + +import static gnu.javax.net.ssl.provider.ClientHandshake.State.*; +import static gnu.javax.net.ssl.provider.KeyExchangeAlgorithm.*; + +import gnu.classpath.debug.Component; +import gnu.java.security.action.GetSecurityPropertyAction; +import gnu.javax.crypto.key.dh.GnuDHPublicKey; +import gnu.javax.net.ssl.AbstractSessionContext; +import gnu.javax.net.ssl.Session; +import gnu.javax.net.ssl.provider.Alert.Description; +import gnu.javax.net.ssl.provider.Alert.Level; +import gnu.javax.net.ssl.provider.CertificateRequest.ClientCertificateType; +import gnu.javax.net.ssl.provider.ServerNameList.NameType; +import gnu.javax.net.ssl.provider.ServerNameList.ServerName; + +import java.nio.ByteBuffer; +import java.security.AccessController; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.SignatureException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; +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.NoSuchPaddingException; +import javax.crypto.interfaces.DHPrivateKey; +import javax.crypto.interfaces.DHPublicKey; +import javax.crypto.spec.DHParameterSpec; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.X509ExtendedKeyManager; +import javax.net.ssl.SSLEngineResult.HandshakeStatus; +import javax.security.auth.x500.X500Principal; + +/** + * @author Casey Marshall (csm@gnu.org) + */ +public class ClientHandshake extends AbstractHandshake +{ + static enum State + { + WRITE_CLIENT_HELLO (false, true), + READ_SERVER_HELLO (true, false), + READ_CERTIFICATE (true, false), + READ_SERVER_KEY_EXCHANGE (true, false), + READ_CERTIFICATE_REQUEST (true, false), + READ_SERVER_HELLO_DONE (true, false), + WRITE_CERTIFICATE (false, true), + WRITE_CLIENT_KEY_EXCHANGE (false, true), + WRITE_CERTIFICATE_VERIFY (false, true), + WRITE_FINISHED (false, true), + READ_FINISHED (true, false), + DONE (false, false); + + private final boolean isWriteState; + private final boolean isReadState; + + private State(boolean isReadState, boolean isWriteState) + { + this.isReadState = isReadState; + this.isWriteState = isWriteState; + } + + boolean isReadState() + { + return isReadState; + } + + boolean isWriteState() + { + return isWriteState; + } + } + + private State state; + private ByteBuffer outBuffer; + private boolean continuedSession; + private SessionImpl continued; + private KeyPair dhPair; + private String keyAlias; + private PrivateKey privateKey; + private MaxFragmentLength maxFragmentLengthSent; + private boolean truncatedHMacSent; + private ProtocolVersion sentVersion; + + // Delegated tasks. + private CertVerifier certVerifier; + private ParamsVerifier paramsVerifier; + private DelegatedTask keyExchange; + private CertLoader certLoader; + private GenCertVerify genCertVerify; + + public ClientHandshake(SSLEngineImpl engine) throws NoSuchAlgorithmException + { + super(engine); + state = WRITE_CLIENT_HELLO; + continuedSession = false; + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.AbstractHandshake#implHandleInput() + */ + @Override protected HandshakeStatus implHandleInput() throws SSLException + { + if (state == DONE) + return HandshakeStatus.FINISHED; + + if (state.isWriteState() + || (outBuffer != null && outBuffer.hasRemaining())) + return HandshakeStatus.NEED_WRAP; + + // Copy the current buffer, and prepare it for reading. + ByteBuffer buffer = handshakeBuffer.duplicate (); + buffer.flip(); + buffer.position(handshakeOffset); + + Handshake handshake = new Handshake(buffer.slice(), + engine.session().suite, + engine.session().version); + + if (Debug.DEBUG) + logger.logv(Component.SSL_HANDSHAKE, "processing in state {0}:\n{1}", + state, handshake); + + switch (state) + { + // Server Hello. + case READ_SERVER_HELLO: + { + if (handshake.type() != Handshake.Type.SERVER_HELLO) + throw new AlertException(new Alert(Alert.Level.FATAL, + Alert.Description.UNEXPECTED_MESSAGE)); + ServerHello hello = (ServerHello) handshake.body(); + serverRandom = hello.random().copy(); + engine.session().suite = hello.cipherSuite(); + engine.session().version = hello.version(); + compression = hello.compressionMethod(); + Session.ID serverId = new Session.ID(hello.sessionId()); + if (continued != null + && continued.id().equals(serverId)) + { + continuedSession = true; + engine.setSession(continued); + } + else if (engine.getEnableSessionCreation()) + { + ((AbstractSessionContext) engine.contextImpl + .engineGetClientSessionContext()).put(engine.session()); + } + ExtensionList extensions = hello.extensions(); + if (extensions != null) + { + for (Extension extension : extensions) + { + Extension.Type type = extension.type(); + if (type == null) + continue; + switch (type) + { + case MAX_FRAGMENT_LENGTH: + MaxFragmentLength mfl + = (MaxFragmentLength) extension.value(); + if (maxFragmentLengthSent == mfl) + engine.session().setApplicationBufferSize(mfl.maxLength()); + break; + + case TRUNCATED_HMAC: + if (truncatedHMacSent) + engine.session().setTruncatedMac(true); + break; + } + } + } + + KeyExchangeAlgorithm kex = engine.session().suite.keyExchangeAlgorithm(); + if (continuedSession) + { + byte[][] keys = generateKeys(clientRandom, serverRandom, + engine.session()); + setupSecurityParameters(keys, true, engine, compression); + state = READ_FINISHED; + } + else if (kex == RSA || kex == DH_DSS || kex == DH_RSA + || kex == DHE_DSS || kex == DHE_RSA || kex == RSA_PSK) + state = READ_CERTIFICATE; + else if (kex == DH_anon || kex == PSK || kex == DHE_PSK) + state = READ_SERVER_KEY_EXCHANGE; + else + state = READ_CERTIFICATE_REQUEST; + } + break; + + // Server Certificate. + case READ_CERTIFICATE: + { + if (handshake.type() != Handshake.Type.CERTIFICATE) + { + // We need a certificate for non-anonymous suites. + if (engine.session().suite.signatureAlgorithm() != SignatureAlgorithm.ANONYMOUS) + throw new AlertException(new Alert(Level.FATAL, + Description.UNEXPECTED_MESSAGE)); + state = READ_SERVER_KEY_EXCHANGE; + } + Certificate cert = (Certificate) handshake.body(); + X509Certificate[] chain = null; + try + { + chain = cert.certificates().toArray(new X509Certificate[0]); + } + catch (CertificateException ce) + { + throw new AlertException(new Alert(Level.FATAL, + Description.BAD_CERTIFICATE), + ce); + } + catch (NoSuchAlgorithmException nsae) + { + throw new AlertException(new Alert(Level.FATAL, + Description.UNSUPPORTED_CERTIFICATE), + nsae); + } + engine.session().setPeerCertificates(chain); + certVerifier = new CertVerifier(true, chain); + tasks.add(certVerifier); + + // If we are doing an RSA key exchange, generate our parameters. + KeyExchangeAlgorithm kea = engine.session().suite.keyExchangeAlgorithm(); + if (kea == RSA || kea == RSA_PSK) + { + keyExchange = new RSAGen(kea == RSA); + tasks.add(keyExchange); + if (kea == RSA) + state = READ_CERTIFICATE_REQUEST; + else + state = READ_SERVER_KEY_EXCHANGE; + } + else + state = READ_SERVER_KEY_EXCHANGE; + } + break; + + // Server Key Exchange. + case READ_SERVER_KEY_EXCHANGE: + { + CipherSuite s = engine.session().suite; + KeyExchangeAlgorithm kexalg = s.keyExchangeAlgorithm(); + // XXX also SRP. + if (kexalg != DHE_DSS && kexalg != DHE_RSA && kexalg != DH_anon + && kexalg != DHE_PSK && kexalg != PSK && kexalg != RSA_PSK) + throw new AlertException(new Alert(Level.FATAL, + Description.UNEXPECTED_MESSAGE)); + + if (handshake.type() != Handshake.Type.SERVER_KEY_EXCHANGE) + { + if (kexalg != RSA_PSK && kexalg != PSK) + throw new AlertException(new Alert(Level.FATAL, + Description.UNEXPECTED_MESSAGE)); + state = READ_CERTIFICATE_REQUEST; + return HandshakeStatus.NEED_UNWRAP; + } + + ServerKeyExchange skex = (ServerKeyExchange) handshake.body(); + ByteBuffer paramsBuffer = null; + if (kexalg == DHE_DSS || kexalg == DHE_RSA || kexalg == DH_anon) + { + ServerDHParams dhParams = (ServerDHParams) skex.params(); + ByteBuffer b = dhParams.buffer(); + paramsBuffer = ByteBuffer.allocate(b.remaining()); + paramsBuffer.put(b); + } + + if (s.signatureAlgorithm() != SignatureAlgorithm.ANONYMOUS) + { + byte[] signature = skex.signature().signature(); + paramsVerifier = new ParamsVerifier(paramsBuffer, signature); + tasks.add(paramsVerifier); + } + + if (kexalg == DHE_DSS || kexalg == DHE_RSA || kexalg == DH_anon) + { + ServerDHParams dhParams = (ServerDHParams) skex.params(); + DHPublicKey serverKey = new GnuDHPublicKey(null, + dhParams.p(), + dhParams.g(), + dhParams.y()); + DHParameterSpec params = new DHParameterSpec(dhParams.p(), + dhParams.g()); + keyExchange = new ClientDHGen(serverKey, params, true); + tasks.add(keyExchange); + } + if (kexalg == DHE_PSK) + { + ServerDHE_PSKParameters pskParams = (ServerDHE_PSKParameters) + skex.params(); + ServerDHParams dhParams = pskParams.params(); + DHPublicKey serverKey = new GnuDHPublicKey(null, + dhParams.p(), + dhParams.g(), + dhParams.y()); + DHParameterSpec params = new DHParameterSpec(dhParams.p(), + dhParams.g()); + keyExchange = new ClientDHGen(serverKey, params, false); + tasks.add(keyExchange); + } + state = READ_CERTIFICATE_REQUEST; + } + break; + + // Certificate Request. + case READ_CERTIFICATE_REQUEST: + { + if (handshake.type() != Handshake.Type.CERTIFICATE_REQUEST) + { + state = READ_SERVER_HELLO_DONE; + return HandshakeStatus.NEED_UNWRAP; + } + + CertificateRequest req = (CertificateRequest) handshake.body(); + ClientCertificateTypeList types = req.types(); + LinkedList typeList = new LinkedList(); + for (ClientCertificateType t : types) + typeList.add(t.name()); + + X500PrincipalList issuers = req.authorities(); + LinkedList issuerList = new LinkedList(); + for (X500Principal p : issuers) + issuerList.add(p); + + certLoader = new CertLoader(typeList, issuerList); + tasks.add(certLoader); + } + break; + + // Server Hello Done. + case READ_SERVER_HELLO_DONE: + { + if (handshake.type() != Handshake.Type.SERVER_HELLO_DONE) + throw new AlertException(new Alert(Level.FATAL, + Description.UNEXPECTED_MESSAGE)); + state = WRITE_CERTIFICATE; + } + break; + + // Finished. + case READ_FINISHED: + { + if (handshake.type() != Handshake.Type.FINISHED) + throw new AlertException(new Alert(Level.FATAL, + Description.UNEXPECTED_MESSAGE)); + + Finished serverFinished = (Finished) handshake.body(); + MessageDigest md5copy = null; + MessageDigest shacopy = null; + try + { + md5copy = (MessageDigest) md5.clone(); + shacopy = (MessageDigest) sha.clone(); + } + catch (CloneNotSupportedException cnse) + { + // We're improperly configured to use a non-cloneable + // md5/sha-1, OR there's a runtime bug. + throw new SSLException(cnse); + } + Finished clientFinished = + new Finished(generateFinished(md5copy, shacopy, + false, engine.session()), + engine.session().version); + + if (Debug.DEBUG) + logger.logv(Component.SSL_HANDSHAKE, "clientFinished: {0}", + clientFinished); + + if (engine.session().version == ProtocolVersion.SSL_3) + { + if (!Arrays.equals(clientFinished.md5Hash(), + serverFinished.md5Hash()) + || !Arrays.equals(clientFinished.shaHash(), + serverFinished.shaHash())) + { + engine.session().invalidate(); + throw new SSLException("session verify failed"); + } + } + else + { + if (!Arrays.equals(clientFinished.verifyData(), + serverFinished.verifyData())) + { + engine.session().invalidate(); + throw new SSLException("session verify failed"); + } + } + + if (continuedSession) + { + engine.changeCipherSpec(); + state = WRITE_FINISHED; + } + else + state = DONE; + } + break; + + default: + throw new IllegalStateException("invalid state: " + state); + } + + handshakeOffset += handshake.length() + 4; + + if (!tasks.isEmpty()) + return HandshakeStatus.NEED_TASK; + if (state.isWriteState() + || (outBuffer != null && outBuffer.hasRemaining())) + return HandshakeStatus.NEED_WRAP; + if (state.isReadState()) + return HandshakeStatus.NEED_UNWRAP; + + return HandshakeStatus.FINISHED; + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.AbstractHandshake#implHandleOutput(java.nio.ByteBuffer) + */ + @Override protected HandshakeStatus implHandleOutput(ByteBuffer fragment) + throws SSLException + { + if (Debug.DEBUG) + logger.logv(Component.SSL_HANDSHAKE, "output to {0}; state:{1}; outBuffer:{2}", + fragment, state, outBuffer); + + // Drain the output buffer, if it needs it. + if (outBuffer != null && outBuffer.hasRemaining()) + { + int l = Math.min(fragment.remaining(), outBuffer.remaining()); + fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l)); + outBuffer.position(outBuffer.position() + l); + } + + if (!fragment.hasRemaining()) + { + if (state.isWriteState() || outBuffer.hasRemaining()) + return HandshakeStatus.NEED_WRAP; + else + return HandshakeStatus.NEED_UNWRAP; + } + +outer_loop: + while (fragment.remaining() >= 4 && state.isWriteState()) + { + if (Debug.DEBUG) + logger.logv(Component.SSL_HANDSHAKE, "loop state={0}", state); + + switch (state) + { + case WRITE_CLIENT_HELLO: + { + ClientHelloBuilder hello = new ClientHelloBuilder(); + AbstractSessionContext ctx = (AbstractSessionContext) + engine.contextImpl.engineGetClientSessionContext(); + continued = (SessionImpl) ctx.getSession(engine.getPeerHost(), + engine.getPeerPort()); + engine.session().setId(new Session.ID(new byte[0])); + Session.ID sid = engine.session().id(); + // If we have a session that we may want to continue, send + // that ID. + if (continued != null) + sid = continued.id(); + + hello.setSessionId(sid.id()); + sentVersion = chooseVersion(); + hello.setVersion(sentVersion); + hello.setCipherSuites(getSuites()); + hello.setCompressionMethods(getCompressionMethods()); + Random r = hello.random(); + r.setGmtUnixTime(Util.unixTime()); + byte[] nonce = new byte[28]; + engine.session().random().nextBytes(nonce); + r.setRandomBytes(nonce); + clientRandom = r.copy(); + if (enableExtensions()) + { + List extensions = new LinkedList(); + MaxFragmentLength fraglen = maxFragmentLength(); + if (fraglen != null) + { + extensions.add(new Extension(Extension.Type.MAX_FRAGMENT_LENGTH, + fraglen)); + maxFragmentLengthSent = fraglen; + } + + String host = engine.getPeerHost(); + if (host != null) + { + ServerName name + = new ServerName(NameType.HOST_NAME, host); + ServerNameList names + = new ServerNameList(Collections.singletonList(name)); + extensions.add(new Extension(Extension.Type.SERVER_NAME, + names)); + } + + if (truncatedHMac()) + { + extensions.add(new Extension(Extension.Type.TRUNCATED_HMAC, + new TruncatedHMAC())); + truncatedHMacSent = true; + } + + ExtensionList elist = new ExtensionList(extensions); + hello.setExtensions(elist.buffer()); + } + else + hello.setDisableExtensions(true); + + if (Debug.DEBUG) + logger.logv(Component.SSL_HANDSHAKE, "{0}", hello); + + fragment.putInt((Handshake.Type.CLIENT_HELLO.getValue() << 24) + | (hello.length() & 0xFFFFFF)); + outBuffer = hello.buffer(); + int l = Math.min(fragment.remaining(), outBuffer.remaining()); + fragment.put((ByteBuffer) outBuffer.duplicate() + .limit(outBuffer.position() + l)); + outBuffer.position(outBuffer.position() + l); + + state = READ_SERVER_HELLO; + } + break; + + case WRITE_CERTIFICATE: + { + java.security.cert.Certificate[] chain + = engine.session().getLocalCertificates(); + if (chain != null) + { + CertificateBuilder cert + = new CertificateBuilder(CertificateType.X509); + try + { + cert.setCertificates(Arrays.asList(chain)); + } + catch (CertificateException ce) + { + throw new AlertException(new Alert(Level.FATAL, + Description.INTERNAL_ERROR), + ce); + } + + outBuffer = cert.buffer(); + + fragment.putInt((Handshake.Type.CERTIFICATE.getValue() << 24) + | (cert.length() & 0xFFFFFF)); + + int l = Math.min(fragment.remaining(), outBuffer.remaining()); + fragment.put((ByteBuffer) outBuffer.duplicate() + .limit(outBuffer.position() + l)); + outBuffer.position(outBuffer.position() + l); + } + state = WRITE_CLIENT_KEY_EXCHANGE; + } + break; + + case WRITE_CLIENT_KEY_EXCHANGE: + { + KeyExchangeAlgorithm kea = engine.session().suite.keyExchangeAlgorithm(); + ClientKeyExchangeBuilder ckex + = new ClientKeyExchangeBuilder(engine.session().suite, + engine.session().version); + if (kea == DHE_DSS || kea == DHE_RSA || kea == DH_anon + || kea == DH_DSS || kea == DH_RSA) + { + assert(dhPair != null); + DHPublicKey pubkey = (DHPublicKey) dhPair.getPublic(); + ClientDiffieHellmanPublic pub + = new ClientDiffieHellmanPublic(pubkey.getY()); + ckex.setExchangeKeys(pub.buffer()); + } + if (kea == RSA || kea == RSA_PSK) + { + assert(keyExchange instanceof RSAGen); + assert(keyExchange.hasRun()); + if (keyExchange.thrown() != null) + throw new AlertException(new Alert(Level.FATAL, + Description.HANDSHAKE_FAILURE), + keyExchange.thrown()); + EncryptedPreMasterSecret epms + = new EncryptedPreMasterSecret(((RSAGen) keyExchange).encryptedSecret(), + engine.session().version); + if (kea == RSA) + ckex.setExchangeKeys(epms.buffer()); + else + { + String identity = getPSKIdentity(); + if (identity == null) + throw new SSLException("no pre-shared-key identity;" + + " set the security property" + + " \"jessie.client.psk.identity\""); + ClientRSA_PSKParameters params = + new ClientRSA_PSKParameters(identity, epms.buffer()); + ckex.setExchangeKeys(params.buffer()); + generatePSKSecret(identity, preMasterSecret, true); + } + } + if (kea == DHE_PSK) + { + assert(keyExchange instanceof ClientDHGen); + assert(dhPair != null); + String identity = getPSKIdentity(); + if (identity == null) + throw new SSLException("no pre-shared key identity; set" + + " the security property" + + " \"jessie.client.psk.identity\""); + DHPublicKey pubkey = (DHPublicKey) dhPair.getPublic(); + ClientDHE_PSKParameters params = + new ClientDHE_PSKParameters(identity, + new ClientDiffieHellmanPublic(pubkey.getY())); + ckex.setExchangeKeys(params.buffer()); + generatePSKSecret(identity, preMasterSecret, true); + } + if (kea == PSK) + { + String identity = getPSKIdentity(); + if (identity == null) + throw new SSLException("no pre-shared key identity; set" + + " the security property" + + " \"jessie.client.psk.identity\""); + generatePSKSecret(identity, null, true); + ClientPSKParameters params = new ClientPSKParameters(identity); + ckex.setExchangeKeys(params.buffer()); + } + if (kea == NONE) + { + Inflater inflater = null; + Deflater deflater = null; + if (compression == CompressionMethod.ZLIB) + { + inflater = new Inflater(); + deflater = new Deflater(); + } + inParams = new InputSecurityParameters(null, null, inflater, + engine.session(), + engine.session().suite); + outParams = new OutputSecurityParameters(null, null, deflater, + engine.session(), + engine.session().suite); + engine.session().privateData.masterSecret = new byte[0]; + } + + if (Debug.DEBUG) + logger.logv(Component.SSL_HANDSHAKE, "{0}", ckex); + + outBuffer = ckex.buffer(); + if (Debug.DEBUG) + logger.logv(Component.SSL_HANDSHAKE, "client kex buffer {0}", outBuffer); + fragment.putInt((Handshake.Type.CLIENT_KEY_EXCHANGE.getValue() << 24) + | (ckex.length() & 0xFFFFFF)); + int l = Math.min(fragment.remaining(), outBuffer.remaining()); + fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l)); + outBuffer.position(outBuffer.position() + l); + + if (privateKey != null) + { + genCertVerify = new GenCertVerify(md5, sha); + tasks.add(genCertVerify); + state = WRITE_CERTIFICATE_VERIFY; + } + else + { + engine.changeCipherSpec(); + state = WRITE_FINISHED; + } + } + // Both states terminate in a NEED_TASK, or a need to change cipher + // specs; so we can't write any more messages here. + break outer_loop; + + case WRITE_CERTIFICATE_VERIFY: + { + assert(genCertVerify != null); + assert(genCertVerify.hasRun()); + CertificateVerify verify = new CertificateVerify(genCertVerify.signed(), + engine.session().suite.signatureAlgorithm()); + + outBuffer = verify.buffer(); + fragment.putInt((Handshake.Type.CERTIFICATE_VERIFY.getValue() << 24) + | (verify.length() & 0xFFFFFF)); + int l = Math.min(fragment.remaining(), outBuffer.remaining()); + fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l)); + outBuffer.position(outBuffer.position() + l); + + // XXX This is a potential problem: we may not have drained + // outBuffer, but set the changeCipherSpec toggle. + engine.changeCipherSpec(); + state = WRITE_FINISHED; + } + break outer_loop; + + case WRITE_FINISHED: + { + MessageDigest md5copy = null; + MessageDigest shacopy = null; + try + { + md5copy = (MessageDigest) md5.clone(); + shacopy = (MessageDigest) sha.clone(); + } + catch (CloneNotSupportedException cnse) + { + // We're improperly configured to use a non-cloneable + // md5/sha-1, OR there's a runtime bug. + throw new SSLException(cnse); + } + outBuffer + = generateFinished(md5copy, shacopy, true, + engine.session()); + + fragment.putInt((Handshake.Type.FINISHED.getValue() << 24) + | outBuffer.remaining() & 0xFFFFFF); + + int l = Math.min(outBuffer.remaining(), fragment.remaining()); + fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l)); + outBuffer.position(outBuffer.position() + l); + + if (continuedSession) + state = DONE; + else + state = READ_FINISHED; + } + break; + + default: + throw new IllegalStateException("invalid state: " + state); + } + } + + if (!tasks.isEmpty()) + return HandshakeStatus.NEED_TASK; + if (state.isWriteState() || + (outBuffer != null && outBuffer.hasRemaining())) + return HandshakeStatus.NEED_WRAP; + if (state.isReadState()) + return HandshakeStatus.NEED_UNWRAP; + + return HandshakeStatus.FINISHED; + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.AbstractHandshake#status() + */ + @Override HandshakeStatus status() + { + if (state.isReadState()) + return HandshakeStatus.NEED_UNWRAP; + if (state.isWriteState()) + return HandshakeStatus.NEED_WRAP; + return HandshakeStatus.FINISHED; + } + + @Override void checkKeyExchange() throws SSLException + { + // XXX implement. + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.AbstractHandshake#handleV2Hello(java.nio.ByteBuffer) + */ + @Override void handleV2Hello(ByteBuffer hello) throws SSLException + { + throw new SSLException("this should be impossible"); + } + + private ProtocolVersion chooseVersion() throws SSLException + { + // Select the highest enabled version, for our initial key exchange. + ProtocolVersion version = null; + for (String ver : engine.getEnabledProtocols()) + { + try + { + ProtocolVersion v = ProtocolVersion.forName(ver); + if (version == null || version.compareTo(v) < 0) + version = v; + } + catch (Exception x) + { + continue; + } + } + + if (version == null) + throw new SSLException("no suitable enabled versions"); + + return version; + } + + private List getSuites() throws SSLException + { + List suites = new LinkedList(); + for (String s : engine.getEnabledCipherSuites()) + { + CipherSuite suite = CipherSuite.forName(s); + if (suite != null) + suites.add(suite); + } + if (suites.isEmpty()) + throw new SSLException("no cipher suites enabled"); + return suites; + } + + private List getCompressionMethods() + { + List methods = new LinkedList(); + GetSecurityPropertyAction gspa = new GetSecurityPropertyAction("jessie.enable.compression"); + if (Boolean.valueOf(AccessController.doPrivileged(gspa))) + methods.add(CompressionMethod.ZLIB); + methods.add(CompressionMethod.NULL); + return methods; + } + + private boolean enableExtensions() + { + GetSecurityPropertyAction action + = new GetSecurityPropertyAction("jessie.client.enable.extensions"); + return Boolean.valueOf(AccessController.doPrivileged(action)); + } + + private MaxFragmentLength maxFragmentLength() + { + GetSecurityPropertyAction action + = new GetSecurityPropertyAction("jessie.client.maxFragmentLength"); + String s = AccessController.doPrivileged(action); + if (s != null) + { + try + { + int len = Integer.parseInt(s); + switch (len) + { + case 9: + case (1 << 9): return MaxFragmentLength.LEN_2_9; + case 10: + case (1 << 10): return MaxFragmentLength.LEN_2_10; + case 11: + case (1 << 11): return MaxFragmentLength.LEN_2_11; + case 12: + case (1 << 12): return MaxFragmentLength.LEN_2_12; + } + } + catch (NumberFormatException nfe) + { + } + } + return null; + } + + private boolean truncatedHMac() + { + GetSecurityPropertyAction action + = new GetSecurityPropertyAction("jessie.client.truncatedHMac"); + return Boolean.valueOf(AccessController.doPrivileged(action)); + } + + private String getPSKIdentity() + { + GetSecurityPropertyAction action + = new GetSecurityPropertyAction("jessie.client.psk.identity"); + return AccessController.doPrivileged(action); + } + + // Delegated tasks. + + class ParamsVerifier extends DelegatedTask + { + private final ByteBuffer paramsBuffer; + private final byte[] signature; + private boolean verified; + + ParamsVerifier(ByteBuffer paramsBuffer, byte[] signature) + { + this.paramsBuffer = paramsBuffer; + this.signature = signature; + } + + public void implRun() + throws InvalidKeyException, NoSuchAlgorithmException, + SSLPeerUnverifiedException, SignatureException + { + java.security.Signature s + = java.security.Signature.getInstance(engine.session().suite + .signatureAlgorithm().algorithm()); + s.initVerify(engine.session().getPeerCertificates()[0]); + s.update(paramsBuffer); + verified = s.verify(signature); + synchronized (this) + { + notifyAll(); + } + } + + boolean verified() + { + return verified; + } + } + + class ClientDHGen extends DelegatedTask + { + private final DHPublicKey serverKey; + private final DHParameterSpec params; + private final boolean full; + + ClientDHGen(DHPublicKey serverKey, DHParameterSpec params, boolean full) + { + this.serverKey = serverKey; + this.params = params; + this.full = full; + } + + public void implRun() + throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, + SSLException + { + if (Debug.DEBUG) + logger.log(Component.SSL_DELEGATED_TASK, "running client DH phase"); + if (paramsVerifier != null) + { + synchronized (paramsVerifier) + { + try + { + while (!paramsVerifier.hasRun()) + paramsVerifier.wait(500); + } + catch (InterruptedException ie) + { + // Ignore. + } + } + } + KeyPairGenerator gen = KeyPairGenerator.getInstance("DH"); + gen.initialize(params, engine.session().random()); + dhPair = gen.generateKeyPair(); + if (Debug.DEBUG_KEY_EXCHANGE) + logger.logv(Component.SSL_KEY_EXCHANGE, + "client keys public:{0} private:{1}", dhPair.getPublic(), + dhPair.getPrivate()); + + initDiffieHellman((DHPrivateKey) dhPair.getPrivate(), engine.session().random()); + + // We have enough info to do the full key exchange; so let's do it. + DHPhase phase = new DHPhase(serverKey, full); + phase.run(); + if (phase.thrown() != null) + throw new SSLException(phase.thrown()); + } + + DHPublicKey serverKey() + { + return serverKey; + } + } + + class CertLoader extends DelegatedTask + { + private final List keyTypes; + private final List issuers; + + CertLoader(List keyTypes, List issuers) + { + this.keyTypes = keyTypes; + this.issuers = issuers; + } + + public void implRun() + { + X509ExtendedKeyManager km = engine.contextImpl.keyManager; + if (km == null) + return; + keyAlias = km.chooseEngineClientAlias(keyTypes.toArray(new String[keyTypes.size()]), + issuers.toArray(new X500Principal[issuers.size()]), + engine); + engine.session().setLocalCertificates(km.getCertificateChain(keyAlias)); + privateKey = km.getPrivateKey(keyAlias); + } + } + + class RSAGen extends DelegatedTask + { + private byte[] encryptedPreMasterSecret; + private final boolean full; + + RSAGen() + { + this(true); + } + + RSAGen(boolean full) + { + this.full = full; + } + + public void implRun() + throws BadPaddingException, IllegalBlockSizeException, InvalidKeyException, + NoSuchAlgorithmException, NoSuchPaddingException, + SSLException + { + if (certVerifier != null) + { + synchronized (certVerifier) + { + try + { + while (!certVerifier.hasRun()) + certVerifier.wait(500); + } + catch (InterruptedException ie) + { + // Ignore. + } + } + } + preMasterSecret = new byte[48]; + engine.session().random().nextBytes(preMasterSecret); + preMasterSecret[0] = (byte) sentVersion.major(); + preMasterSecret[1] = (byte) sentVersion.minor(); + Cipher rsa = Cipher.getInstance("RSA"); + java.security.cert.Certificate cert + = engine.session().getPeerCertificates()[0]; + if (cert instanceof X509Certificate) + { + boolean[] keyUsage = ((X509Certificate) cert).getKeyUsage(); + if (keyUsage != null && !keyUsage[2]) + throw new InvalidKeyException("certificate's keyUsage does not permit keyEncipherment"); + } + rsa.init(Cipher.ENCRYPT_MODE, cert.getPublicKey()); + encryptedPreMasterSecret = rsa.doFinal(preMasterSecret); + + // Generate our session keys, because we can. + if (full) + { + generateMasterSecret(clientRandom, serverRandom, engine.session()); + byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session()); + setupSecurityParameters(keys, true, engine, compression); + } + } + + byte[] encryptedSecret() + { + return encryptedPreMasterSecret; + } + } + + class GenCertVerify extends DelegatedTask + { + private final MessageDigest md5, sha; + private byte[] signed; + + GenCertVerify(MessageDigest md5, MessageDigest sha) + { + try + { + this.md5 = (MessageDigest) md5.clone(); + this.sha = (MessageDigest) sha.clone(); + } + catch (CloneNotSupportedException cnse) + { + // Our message digests *should* be cloneable. + throw new Error(cnse); + } + } + + public void implRun() + throws InvalidKeyException, NoSuchAlgorithmException, SignatureException + { + byte[] toSign; + if (engine.session().version == ProtocolVersion.SSL_3) + { + toSign = genV3CertificateVerify(md5, sha, engine.session()); + } + else + { + if (engine.session().suite.signatureAlgorithm() == SignatureAlgorithm.RSA) + toSign = Util.concat(md5.digest(), sha.digest()); + else + toSign = sha.digest(); + } + + java.security.Signature sig = + java.security.Signature.getInstance(engine.session().suite.signatureAlgorithm().name()); + sig.initSign(privateKey); + sig.update(toSign); + signed = sig.sign(); + } + + byte[] signed() + { + return signed; + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientHello.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHello.java new file mode 100644 index 000000000..a58dc5d7a --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHello.java @@ -0,0 +1,240 @@ +/* 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.PrintWriter; +import java.io.StringWriter; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * A ClientHello handshake message. + * + *
    +struct
    +{
    +  ProtocolVersion   client_version;                // 2
    +  Random            random;                        // 32
    +  SessionID         session_id;                    // 1 + 0..32
    +  CipherSuite       cipher_suites<2..2^16-1>
    +  CompressionMethod compression_methods<1..2^8-1>
    +  Extension         client_hello_extension_list<0..2^16-1>
    +} ClientHello;
    +
    + */ +public class ClientHello implements Handshake.Body +{ + + // Fields. + // ------------------------------------------------------------------------- + + // To help track offsets into the message: + // The location of the 'random' field. + protected static final int RANDOM_OFFSET = 2; + // The location of the sesion_id length. + protected static final int SESSID_OFFSET = 32 + RANDOM_OFFSET; + // The location of the session_id bytes (if any). + protected static final int SESSID_OFFSET2 = SESSID_OFFSET + 1; + + protected ByteBuffer buffer; + protected boolean disableExtensions; + + // Constructor. + // ------------------------------------------------------------------------- + + public ClientHello (final ByteBuffer buffer) + { + this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); + disableExtensions = false; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public int length() + { + int len = SESSID_OFFSET2 + buffer.get(SESSID_OFFSET); + len += (buffer.getShort(len) & 0xFFFF) + 2; + len += (buffer.get(len) & 0xFF) + 1; + if (!disableExtensions && len + 1 < buffer.capacity()) + len += (buffer.getShort(len) & 0xFFFF) + 2; + return len; + } + + /** + * Gets the protocol version field. + * + * @return The protocol version field. + */ + public ProtocolVersion version() + { + return ProtocolVersion.getInstance (buffer.getShort (0)); + } + + /** + * Gets the SSL nonce. + * + * @return The nonce. + */ + public Random random() + { + ByteBuffer randomBuf = + ((ByteBuffer) buffer.duplicate ().position (RANDOM_OFFSET) + .limit (SESSID_OFFSET)).slice (); + return new Random (randomBuf); + } + + public byte[] sessionId() + { + int idlen = buffer.get (SESSID_OFFSET) & 0xFF; + byte[] sessionId = new byte[idlen]; + buffer.position (SESSID_OFFSET2); + buffer.get (sessionId); + return sessionId; + } + + public CipherSuiteList cipherSuites() + { + int offset = getCipherSuitesOffset (); + + // We give the CipherSuiteList all the remaining bytes to play with, + // since this might be an in-construction packet that will fill in + // the length field itself. + ByteBuffer listBuf = ((ByteBuffer) buffer.duplicate ().position (offset) + .limit (buffer.capacity ())).slice (); + return new CipherSuiteList (listBuf, version ()); + } + + public CompressionMethodList compressionMethods() + { + int offset = getCompressionMethodsOffset (); + ByteBuffer listBuf = ((ByteBuffer) buffer.duplicate ().position (offset) + .limit (buffer.capacity ())).slice (); + return new CompressionMethodList (listBuf); + } + + public boolean hasExtensions() + { + int offset = getExtensionsOffset(); + return (offset + 1 < buffer.limit()); + } + + public ExtensionList extensions() + { + int offset = getExtensionsOffset (); + if (offset + 1 >= buffer.limit()) + return null; + int len = buffer.getShort(offset) & 0xFFFF; + if (len == 0) + len = buffer.limit() - offset - 2; + ByteBuffer ebuf = ((ByteBuffer) buffer.duplicate().position(offset) + .limit(offset + len + 2)).slice (); + return new ExtensionList(ebuf); + } + + public int extensionsLength() + { + if (hasExtensions()) + return 0; + return buffer.getShort(getExtensionsOffset()) & 0xFFFF; + } + + protected int getCipherSuitesOffset () + { + return (SESSID_OFFSET2 + (buffer.get (SESSID_OFFSET) & 0xFF)); + } + + protected int getCompressionMethodsOffset () + { + int csOffset = getCipherSuitesOffset (); + int csLen = buffer.getShort (csOffset) & 0xFFFF; + return csOffset + csLen + 2; + } + + protected int getExtensionsOffset () + { + int cmOffset = getCompressionMethodsOffset (); + return (buffer.get (cmOffset) & 0xFF) + cmOffset + 1; + } + + public String toString () + { + return toString (null); + } + + public String toString (final String prefix) + { + StringWriter str = new StringWriter (); + PrintWriter out = new PrintWriter (str); + String subprefix = " "; + if (prefix != null) + subprefix += prefix; + if (prefix != null) + out.print (prefix); + out.println ("struct {"); + if (prefix != null) + out.print (prefix); + out.print (" version: "); + out.print (version ()); + out.println (";"); + out.print (subprefix); + out.println ("random:"); + out.print (random ().toString (subprefix)); + if (prefix != null) + out.print (prefix); + out.print (" sessionId: "); + out.print (Util.toHexString (sessionId (), ':')); + out.println (";"); + out.print (subprefix); + out.println ("cipher_suites:"); + out.println (cipherSuites ().toString (subprefix)); + out.print (subprefix); + out.println ("compression_methods:"); + out.println (compressionMethods ().toString (subprefix)); + out.print (subprefix); + out.print ("extensions: "); + ExtensionList el = extensions(); + out.println (el != null ? el.toString(subprefix+" ") : "(nil)"); + if (prefix != null) + out.print (prefix); + out.print ("} ClientHello;"); + return str.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientHelloBuilder.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHelloBuilder.java new file mode 100644 index 000000000..90405c45b --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHelloBuilder.java @@ -0,0 +1,137 @@ +/* ClientHelloBuilder.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.net.ssl.provider; + +import java.nio.ByteBuffer; +import java.util.List; + +/** + * Builder for {@link ClientHello} objects. + * + * @author Casey Marshall (csm@gnu.org) + */ +public class ClientHelloBuilder extends ClientHello implements Builder +{ + public ClientHelloBuilder() + { + super(ByteBuffer.allocate(256)); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Builder#buffer() + */ + public ByteBuffer buffer() + { + return (ByteBuffer) buffer.duplicate().position(0).limit(length()); + } + + public void setVersion(final ProtocolVersion version) + { + ensureCapacity(2); + buffer.putShort(0, (short) version.rawValue ()); + } + + public void setSessionId (final byte[] buffer) + { + setSessionId(buffer, 0, buffer.length); + } + + public void setSessionId (final byte[] buffer, final int offset, final int length) + { + ensureCapacity(SESSID_OFFSET2 + length); + int len = Math.min (32, length); + this.buffer.put (SESSID_OFFSET, (byte) len); + this.buffer.position (SESSID_OFFSET2); + this.buffer.put (buffer, offset, len); + } + + public void setCipherSuites(List suites) + { + int off = getCipherSuitesOffset(); + ensureCapacity(off + (2 * suites.size()) + 2); + buffer.putShort(off, (short) (suites.size() * 2)); + int i = 2; + for (CipherSuite suite : suites) + { + ((ByteBuffer) buffer.duplicate().position(off+i)).put(suite.id()); + i += 2; + } + } + + public void setCompressionMethods(List methods) + { + int off = getCompressionMethodsOffset(); + ensureCapacity(off + methods.size() + 1); + buffer.put(off, (byte) methods.size()); + for (CompressionMethod method : methods) + buffer.put(++off, (byte) method.getValue()); + } + + public void setExtensionsLength (final int length) + { + if (length < 0 || length > 16384) + throw new IllegalArgumentException("length must be nonnegative and not exceed 16384"); + int needed = getExtensionsOffset() + 2 + length; + if (buffer.capacity() < needed) + ensureCapacity(needed); + buffer.putShort(getExtensionsOffset(), (short) length); + } + + public void setExtensions(ByteBuffer extensions) + { + int elen = extensions.getShort(0) & 0xFFFF; + setExtensionsLength(elen); + ((ByteBuffer) buffer.duplicate().position(getExtensionsOffset())).put(extensions); + } + + public void setDisableExtensions(boolean disableExtensions) + { + this.disableExtensions = disableExtensions; + } + + public void ensureCapacity(final int length) + { + if (buffer.capacity() >= length) + return; + ByteBuffer newBuf = ByteBuffer.allocate(length); + newBuf.put((ByteBuffer) buffer.position(0)); + newBuf.position(0); + this.buffer = newBuf; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientHelloV2.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHelloV2.java new file mode 100644 index 000000000..6009d52a3 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientHelloV2.java @@ -0,0 +1,158 @@ +/* ClientHelloV2.java -- a hello message from SSLv2. + 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.PrintWriter; +import java.io.StringWriter; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.ArrayList; +import java.util.List; + +/** + * A client hello message from SSLv2. In SSLv3 and later, clients can + * send an SSLv2 client hello message, but set the protocol version + * for a later version. + * + *

    The format of a version 2 client hello is: + * + *

    +    char MSG-CLIENT-HELLO          // equals 1
    +    char CLIENT-VERSION-MSB
    +    char CLIENT-VERSION-LSB
    +    char CIPHER-SPECS-LENGTH-MSB
    +    char CIPHER-SPECS-LENGTH-LSB
    +    char SESSION-ID-LENGTH-MSB
    +    char SESSION-ID-LENGTH-LSB
    +    char CHALLENGE-LENGTH-MSB
    +    char CHALLENGE-LENGTH-LSB
    +    char CIPHER-SPECS-DATA[(MSB<<8)|LSB]
    +    char SESSION-ID-DATA[(MSB<<8)|LSB]
    +    char CHALLENGE-DATA[(MSB<<8)|LSB]
    + */ +class ClientHelloV2 implements Constructed +{ + private final ByteBuffer buffer; + + ClientHelloV2 (final ByteBuffer buffer) + { + this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); + } + + public int length () + { + return 9 + cipherSpecsLength () + sessionIdLength () + challengeLength (); + } + + ProtocolVersion version () + { + return ProtocolVersion.getInstance (buffer.getShort (1)); + } + + int cipherSpecsLength () + { + return buffer.getShort (3) & 0xFFFF; + } + + int sessionIdLength () + { + return buffer.getShort (5) & 0xFFFF; + } + + int challengeLength () + { + return buffer.getShort (7) & 0xFFFF; + } + + public List cipherSpecs () + { + int n = cipherSpecsLength (); + List l = new ArrayList(n / 3); + ByteBuffer b = (ByteBuffer) buffer.duplicate ().position (9); + for (int i = 0; i < n; i += 3) + { + if (b.get () == 0) + l.add (CipherSuite.forValue(b.getShort()).resolve()); + else + b.getShort (); + } + return l; + } + + byte[] sessionId () + { + byte[] id = new byte[sessionIdLength ()]; + ((ByteBuffer) buffer.duplicate ().position (9 + cipherSpecsLength ())).get (id); + return id; + } + + byte[] challenge () + { + byte[] challenge = new byte[challengeLength ()]; + ((ByteBuffer) buffer.duplicate ().position (9 + cipherSpecsLength () + sessionIdLength ())).get (challenge); + return challenge; + } + + public String toString () + { + return toString (null); + } + + public String toString (String prefix) + { + StringWriter str = new StringWriter (); + PrintWriter out = new PrintWriter (str); + + if (prefix != null) out.print (prefix); + out.println ("CLIENT-HELLO-MSG"); + if (prefix != null) out.print (prefix); + out.print (" version: "); + out.println (version ()); + if (prefix != null) out.print (prefix); + out.println (" suites: "); + out.println (cipherSpecs ()); + if (prefix != null) out.print (prefix); + out.print (" sessionId: "); + out.println (Util.toHexString (sessionId (), ':')); + if (prefix != null) out.print (prefix); + out.print (" challenge: "); + out.println (Util.toHexString (challenge (), ':')); + return str.toString (); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchange.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchange.java new file mode 100644 index 000000000..2006e7385 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchange.java @@ -0,0 +1,132 @@ +/* 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.PrintWriter; +import java.io.StringWriter; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * The client key exchange message. + * + *
    +struct {
    +  select (KeyExchangeAlgorithm) {
    +    case rsa: EncryptedPreMasterSecret;
    +    case diffie_hellman: ClientDiffieHellmanPublic;
    +  } exchange_keys;
    +} ClientKeyExchange;
    + */ +public class ClientKeyExchange implements Handshake.Body +{ + + // Fields. + // ------------------------------------------------------------------------- + + protected ByteBuffer buffer; + protected final CipherSuite suite; + protected final ProtocolVersion version; + + // Constructors. + // ------------------------------------------------------------------------- + + public ClientKeyExchange (final ByteBuffer buffer, final CipherSuite suite, + final ProtocolVersion version) + { + suite.getClass(); + version.getClass (); + this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); + this.suite = suite; + this.version = version; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public ExchangeKeys exchangeKeys () + { + KeyExchangeAlgorithm alg = suite.keyExchangeAlgorithm(); + if (alg == KeyExchangeAlgorithm.RSA) + return new EncryptedPreMasterSecret(buffer, version); + else if (alg == KeyExchangeAlgorithm.DH_anon + || alg == KeyExchangeAlgorithm.DHE_DSS + || alg == KeyExchangeAlgorithm.DHE_RSA) + return new ClientDiffieHellmanPublic(buffer.duplicate()); + else if (alg == KeyExchangeAlgorithm.DHE_PSK) + return new ClientDHE_PSKParameters(buffer.duplicate()); + else if (alg == KeyExchangeAlgorithm.PSK) + return new ClientPSKParameters(buffer.duplicate()); + else if (alg == KeyExchangeAlgorithm.RSA_PSK) + return new ClientRSA_PSKParameters(buffer.duplicate()); + else if (alg == KeyExchangeAlgorithm.NONE) + return new EmptyExchangeKeys(); + throw new IllegalArgumentException("unsupported key exchange: " + alg); + } + + public int length() + { + if (suite.keyExchangeAlgorithm() == KeyExchangeAlgorithm.NONE) + return 0; + return exchangeKeys().length(); + } + + public String toString () + { + return toString (null); + } + + public String toString (final String prefix) + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + if (prefix != null) + out.print (prefix); + out.println("struct {"); + String subprefix = " "; + if (prefix != null) + subprefix = prefix + subprefix; + out.println (exchangeKeys ().toString (subprefix)); + if (prefix != null) + out.print (prefix); + out.println("} ClientKeyExchange;"); + return str.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchangeBuilder.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchangeBuilder.java new file mode 100644 index 000000000..a43873510 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchangeBuilder.java @@ -0,0 +1,75 @@ +/* ClientKeyExchangeBuilder.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.net.ssl.provider; + +import java.nio.ByteBuffer; + +/** + * Builder for {@link ClientKeyExchange} objects. + * + * @author Casey Marshall (csm@gnu.org) + */ +public class ClientKeyExchangeBuilder extends ClientKeyExchange + implements Builder +{ + public ClientKeyExchangeBuilder(CipherSuite suite, ProtocolVersion version) + { + super(ByteBuffer.allocate(512), suite, version); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Builder#buffer() + */ + public ByteBuffer buffer() + { + return ((ByteBuffer) buffer.duplicate().position(0).limit(length())).slice(); + } + + public void setExchangeKeys(ByteBuffer exchangeKeys) + { + // For SSLv3 and RSA key exchange, the message is sent without length. + // So we use the precise capacity of the buffer to signal the size of + // the message. + if (buffer.capacity() < exchangeKeys.remaining() + || (suite.keyExchangeAlgorithm() == KeyExchangeAlgorithm.RSA + && version == ProtocolVersion.SSL_3)) + buffer = ByteBuffer.allocate(exchangeKeys.remaining()); + ((ByteBuffer) buffer.duplicate().position(0)).put(exchangeKeys); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientPSKParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientPSKParameters.java new file mode 100644 index 000000000..22c6333e9 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientPSKParameters.java @@ -0,0 +1,121 @@ +/* ClientPSKParameters.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.net.ssl.provider; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; + +/** + *
    +      struct {
    +          select (KeyExchangeAlgorithm) {
    +              /* other cases for rsa, diffie_hellman, etc. */
    +              case psk:   /* NEW */
    +                  opaque psk_identity<0..2^16-1>;
    +          } exchange_keys;
    +      } ClientKeyExchange;
    + * + * @author Casey Marshall (csm@gnu.org) + */ +public class ClientPSKParameters extends ExchangeKeys implements Builder, Constructed +{ + public ClientPSKParameters(ByteBuffer buffer) + { + super(buffer); + } + + public ClientPSKParameters(String identity) + { + super(null); + Charset utf8 = Charset.forName("UTF-8"); + ByteBuffer idBuf = utf8.encode(CharBuffer.wrap(identity)); + buffer = ByteBuffer.allocate(idBuf.remaining() + 2); + buffer.putShort((short) idBuf.remaining()); + buffer.put(idBuf); + buffer.rewind(); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Builder#buffer() + */ + public ByteBuffer buffer() + { + return (ByteBuffer) buffer.duplicate().rewind().limit(length()); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Constructed#length() + */ + public int length() + { + return (buffer.getShort(0) & 0xFFFF) + 2; + } + + public String identity() + { + Charset utf8 = Charset.forName("UTF-8"); + return utf8.decode((ByteBuffer) buffer.duplicate().position(2).limit(length())).toString(); + } + + public @Override String toString() + { + return toString(null); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Constructed#toString(java.lang.String) + */ + public String toString(String prefix) + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + if (prefix != null) out.print(prefix); + out.println("struct {"); + if (prefix != null) out.print(prefix); + out.print(" identity = "); + out.print(identity()); + out.println(";"); + if (prefix != null) out.print(prefix); + out.print("} ClientPSKParameters;"); + return str.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java new file mode 100644 index 000000000..842e911d0 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java @@ -0,0 +1,122 @@ +/* ClientRSA_PSKParameters.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.net.ssl.provider; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; + +/** + * @author Casey Marshall (csm@gnu.org) + */ +public class ClientRSA_PSKParameters extends ExchangeKeys implements Builder, Constructed +{ + public ClientRSA_PSKParameters(ByteBuffer buffer) + { + super(buffer); + } + + public ClientRSA_PSKParameters(String identity, ByteBuffer epms) + { + super(null); + Charset utf8 = Charset.forName("UTF-8"); + ByteBuffer idBuf = utf8.encode(identity); + buffer = ByteBuffer.allocate(2 + idBuf.remaining() + epms.remaining()); + buffer.putShort((short) idBuf.remaining()); + buffer.put(idBuf); + buffer.put(epms); + buffer.rewind(); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Builder#buffer() + */ + public ByteBuffer buffer() + { + return (ByteBuffer) buffer.duplicate().rewind().limit(length()); + } + + public String identity() + { + Charset utf8 = Charset.forName("UTF-8"); + return utf8.decode((ByteBuffer) buffer.duplicate().position(2).limit + (identityLength())).toString(); + } + + private int identityLength() + { + return (buffer.getShort(0) & 0xFFFF) + 2; + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Constructed#length() + */ + public int length() + { + return identityLength() + secret().length(); + } + + public EncryptedPreMasterSecret secret() + { + return new EncryptedPreMasterSecret + (((ByteBuffer) buffer.duplicate().position(identityLength()) + .limit(buffer.capacity())).slice(), ProtocolVersion.TLS_1); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Constructed#toString(java.lang.String) + */ + public String toString(String prefix) + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + if (prefix != null) out.print(prefix); + out.println("struct {"); + if (prefix != null) out.print(prefix); + out.print(" identity = "); + out.print(identity()); + if (prefix != null) out.print(prefix); + out.println(" encrypted_pre_master_secret ="); + out.println(secret().toString(prefix != null ? prefix + " " : " ")); + if (prefix != null) out.print(prefix); + out.print("} ClientRSA_PSKParameters;"); + return str.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethod.java b/libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethod.java new file mode 100644 index 000000000..3005dd9fc --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethod.java @@ -0,0 +1,69 @@ +/* CompressionMethod.java -- The CompressionMethod 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; + +public enum CompressionMethod +{ + NULL (0), ZLIB(1); + + private final int value; + + private CompressionMethod(int value) + { + this.value = value; + } + + public static CompressionMethod getInstance (final int value) + { + switch (value & 0xFF) + { + case 0: return NULL; + case 1: return ZLIB; + + // Note: we can't throw an exception here, because we get these values + // over the wire, and need to just ignore ones we don't recognize. + default: return null; + } + } + + public int getValue() + { + return value; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethodList.java b/libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethodList.java new file mode 100644 index 000000000..b57e0c6a6 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethodList.java @@ -0,0 +1,281 @@ +/* CompressionMethodList.java -- A list of compression 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.io.PrintWriter; +import java.io.StringWriter; + +import java.nio.ByteBuffer; + +import java.util.ConcurrentModificationException; +import java.util.ListIterator; +import java.util.NoSuchElementException; + +/** + * A basic list interface to a list of compression methods in an SSL + * packet. + */ +public final class CompressionMethodList implements Iterable +{ + private final ByteBuffer buffer; + private int modCount; + + public CompressionMethodList (final ByteBuffer buffer) + { + this.buffer = buffer; + modCount = 0; + } + + /** + * Return the number of elements in this list. + * + * @return The size of this list. + */ + public int size () + { + return (buffer.get (0) & 0xFF); + } + + /** + * Get the cipher suite at the specified index. + * + * @param index The index of the suite to get. + * @return The cipher suite at that index. + * @throws IndexOutOfBoundsException If the index is negative or is + * not less than {@link #size()}. + */ + public CompressionMethod get (final int index) + { + int size = size (); + if (index < 0 || index >= size) + throw new IndexOutOfBoundsException ("limit: " + size + + "; requested: " + index); + return CompressionMethod.getInstance (buffer.get (1 + index)); + } + + /** + * Set the CompressionMethod at the specified index. The list must + * have sufficient size to hold the element (that is, index + * <= size ()). + * + * @param index The index to put the suite. + * @param method The CompressionMethod object. + * @throws IndexOutOfBoundsException If index is not + * less than @{link #size()}, or if it is negative. + * @throws NullPointerException If suite is + * null. + * @throws java.nio.ReadOnlyBufferException If the underlying buffer + * is not writable. + */ + public void put (final int index, final CompressionMethod method) + { + int size = size (); + if (index < 0 || index >= size) + throw new IndexOutOfBoundsException ("limit: " + size + + "; requested: " + index); + buffer.position (1 + index); + buffer.put ((byte) method.getValue ()); + modCount++; + } + + /** + * Sets the size of this list. You must call this if you are adding + * elements to the list; calling {@link + * #put(int,gnu.jessie.provider.CipherSuite)} does not expand the + * list size (the same goes for removing elements, as there is no + * remove method). + * + * @param newSize The new size of this list. + * @throws IllegalArgumentException If the new size is negative or + * greater than 32767, or if there is insufficient space for that + * many elements in the underlying buffer. + * @throws java.nio.ReadOnlyBufferException If the underlying buffer + * is not writable. + */ + public void setSize (final int newSize) + { + if (newSize < 0 || newSize > 255) + throw new IllegalArgumentException ("size must be between 0 and 255"); + if (newSize + 1 > buffer.capacity ()) + throw new IllegalArgumentException ("limit: " + buffer.capacity () + + "; requested: " + newSize); + buffer.put (0, (byte) newSize); + modCount++; + } + + public String toString () + { + return toString (null); + } + + public String toString (final String prefix) + { + StringWriter str = new StringWriter (); + PrintWriter out = new PrintWriter (str); + if (prefix != null) + out.print (prefix); + out.print ("["); + out.print (size ()); + out.println ("] {"); + for (Iterator it = new Iterator (); it.hasNext (); ) + { + CompressionMethod method = (CompressionMethod) it.next (); + if (prefix != null) + out.print (prefix); + out.print (" "); + out.print (method); + if (it.hasNext ()) + out.print (","); + out.println (); + } + if (prefix != null) + out.print (prefix); + out.print ("};"); + return str.toString (); + } + + public boolean equals (Object o) + { + if (!(o instanceof CompressionMethodList)) + return false; + CompressionMethodList that = (CompressionMethodList) o; + + if (size () != that.size ()) + return false; + + for (Iterator it1 = new Iterator (), it2 = that.new Iterator (); + it1.hasNext () && it2.hasNext (); ) + { + if (!it1.next ().equals (it2.next ())) + return false; + } + return true; + } + + public java.util.Iterator iterator () + { + return new Iterator (); + } + + /** + * An iterator for the elements in this list. The iterator supports + * only the set method out of the optional methods, + * because elements in a CipherSuiteList may not be removed or + * added; only the size of the list can be changed, and elements at + * a specific index changed. + */ + public class Iterator implements ListIterator + { + private int index; + private final int modCount; + + Iterator () + { + index = 0; + modCount = CompressionMethodList.this.modCount; + } + + public void add (CompressionMethod cm) + { + throw new UnsupportedOperationException (); + } + + public boolean hasNext () + { + return (index < size ()); + } + + public boolean hasPrevious () + { + return (index > 0); + } + + public CompressionMethod next () throws NoSuchElementException + { + if (modCount != CompressionMethodList.this.modCount) + throw new ConcurrentModificationException (); + try + { + return get (index++); + } + catch (IndexOutOfBoundsException ioobe) + { + throw new NoSuchElementException (); + } + } + + public int nextIndex () + { + if (hasNext ()) + return (index + 1); + return -1; + } + + public CompressionMethod previous () throws NoSuchElementException + { + if (index == 0) + throw new NoSuchElementException (); + if (modCount != CompressionMethodList.this.modCount) + throw new ConcurrentModificationException (); + try + { + return get (--index); + } + catch (IndexOutOfBoundsException ioobe) // on empty list + { + throw new NoSuchElementException (); + } + } + + public int previousIndex () + { + return (index - 1); + } + + public void remove () + { + throw new UnsupportedOperationException (); + } + + public void set (final CompressionMethod cm) + { + put (index, cm); + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Constructed.java b/libjava/classpath/gnu/javax/net/ssl/provider/Constructed.java new file mode 100644 index 000000000..23ff68812 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Constructed.java @@ -0,0 +1,86 @@ +/* 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; + +/** + * The base interface to SSL constructed types. + * + *

    Contract for ByteBuffer-based constructed types: + * + *

    Most implementations of this interface supported by this library + * take a "view" of an underlying ByteBuffer. The general contract of + * such classes is that they will not modify the position or + * limit of the buffer when doing read operations. That is, the position + * of the underlying buffer should remain at 0 throughout the + * lifetime of the object, and the limit should be either set to the + * capacity of the buffer, or to the size of the object (in most cases, + * the length of the protocol object is determined by the contents of + * the object, so the limit isn't useful in such cases. Of course, if the + * limit is set to something other than the object's length, it must be + * larger than the object length). + * + *

    Setter methods (usually in a class that implements the {@link Builder} + * interface) may modify the limit, but the general contract remains that + * the position remain at zero, and that the limit be at least as large as + * the object length. + * + *

    Thus, very often the code will use absolute getters and setters + * for primitive types, or it will use the {@link java.nio.ByteBuffer#duplicate()} + * method, and sometimes the {@link java.nio.ByteBuffer#slice()} method, and + * will change the position or limit of the duplicate buffer. + */ +public interface Constructed +{ + /** + * Returns the total length, in bytes, of this structure. + * + * @return The length of this structure. + */ + int length(); + + /** + * Returns a printable representation of this structure, with the + * given prefix prepended to each line. + * + * @param prefix The prefix to prepend to each line of the + * output. This value may be null. + * @return A printable representation of this structure. + */ + String toString(String prefix); +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ContentType.java b/libjava/classpath/gnu/javax/net/ssl/provider/ContentType.java new file mode 100644 index 000000000..eaebebf4b --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ContentType.java @@ -0,0 +1,89 @@ +/* ContentType.java -- SSL 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; + +/** + * 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;
    + * + *

    There is also a "pseudo" content type, client_hello_v2 + * (1), which is used for backwards compatibility with SSLv2. + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +public enum ContentType +{ + + CLIENT_HELLO_V2 ( 1), + CHANGE_CIPHER_SPEC (20), + ALERT (21), + HANDSHAKE (22), + APPLICATION_DATA (23); + + private int value; + + // Constructors. + // ------------------------------------------------------------------------ + + private ContentType(int value) + { + this.value = value; + } + + static final ContentType forInteger (final int value) + { + 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 null; + } + } + + public int getValue() + { + return value; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Debug.java b/libjava/classpath/gnu/javax/net/ssl/provider/Debug.java new file mode 100644 index 000000000..308ef67a0 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Debug.java @@ -0,0 +1,66 @@ +/* Debug.java -- Jessie debug constants. + 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; + +/** + * Debug constants for Jessie. + * + * @author Casey Marshall (csm@gnu.org) + */ +public final class Debug +{ + /** + * Set to true to dump out traces of SSL connections to the system + * logger. + */ + public static final boolean DEBUG = true; + + /** + * Set to true to dump out info about the SSL key exchange. Since this + * MAY contain sensitive data, it is a separate value. + */ + public static final boolean DEBUG_KEY_EXCHANGE = true; + + /** + * Set to true to turn on dumping of decrypted packets. Since this will + * log potentially-sensitive information (i.e., decrypted messages), only + * enable this in debug scenarios. + */ + public static final boolean DEBUG_DECRYPTION = false; +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/DelegatedTask.java b/libjava/classpath/gnu/javax/net/ssl/provider/DelegatedTask.java new file mode 100644 index 000000000..34fd39d19 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/DelegatedTask.java @@ -0,0 +1,93 @@ +/* DelegatedTask.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.net.ssl.provider; + +import gnu.classpath.debug.Component; +import gnu.classpath.debug.SystemLogger; + +/** + * @author Casey Marshall (csm@gnu.org) + */ +public abstract class DelegatedTask implements Runnable +{ + private static final SystemLogger logger = SystemLogger.SYSTEM; + private boolean hasRun; + protected Throwable thrown; + + protected DelegatedTask() + { + hasRun = false; + } + + public final void run() + { + if (hasRun) + throw new IllegalStateException("task already ran"); + try + { + if (Debug.DEBUG) + logger.logv(Component.SSL_DELEGATED_TASK, + "running delegated task {0} in {1}", this, + Thread.currentThread()); + implRun(); + } + catch (Throwable t) + { + if (Debug.DEBUG) + logger.log(Component.SSL_DELEGATED_TASK, "task threw exception", t); + thrown = t; + } + finally + { + hasRun = true; + } + } + + public final boolean hasRun() + { + return hasRun; + } + + public final Throwable thrown() + { + return thrown; + } + + protected abstract void implRun() throws Throwable; +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/DiffieHellman.java b/libjava/classpath/gnu/javax/net/ssl/provider/DiffieHellman.java new file mode 100644 index 000000000..5a5275712 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/DiffieHellman.java @@ -0,0 +1,289 @@ +/* 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 java.security.AccessController; + +import gnu.java.security.action.GetSecurityPropertyAction; +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 = AccessController.doPrivileged + (new GetSecurityPropertyAction("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/libjava/classpath/gnu/javax/net/ssl/provider/EmptyExchangeKeys.java b/libjava/classpath/gnu/javax/net/ssl/provider/EmptyExchangeKeys.java new file mode 100644 index 000000000..55b59998d --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/EmptyExchangeKeys.java @@ -0,0 +1,77 @@ +/* EmptyExchangeKeys.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.net.ssl.provider; + +import java.nio.ByteBuffer; + +/** + * @author Casey Marshall (csm@gnu.org) + */ +public class EmptyExchangeKeys + extends ExchangeKeys +{ + + public EmptyExchangeKeys() + { + super(ByteBuffer.allocate(0)); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Constructed#length() + */ + public int length() + { + return 0; + } + + public String toString() + { + return toString(null); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Constructed#toString(java.lang.String) + */ + public String toString(String prefix) + { + String ret = "struct { };"; + if (prefix != null) ret = prefix + ret; + return ret; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java b/libjava/classpath/gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java new file mode 100644 index 000000000..a40223dd0 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java @@ -0,0 +1,148 @@ +/* EncryptedPreMasterSecret.java -- RSA encrypted secret. + 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.PrintWriter; +import java.io.StringWriter; + +import java.nio.ByteBuffer; + +/** + * The client's RSA-encrypted pre-master secret. + * + *

      +struct {
      +  public-key-encrypted PreMasterSecret pre_master_secret;
      +} EncryptedPreMasterSecret;
      + */ +public final class EncryptedPreMasterSecret extends ExchangeKeys implements Builder +{ + private final ProtocolVersion version; + + public EncryptedPreMasterSecret(ByteBuffer buffer, ProtocolVersion version) + { + super(buffer); + version.getClass(); + this.version = version; + } + + public EncryptedPreMasterSecret(byte[] encryptedSecret, ProtocolVersion version) + { + this(ByteBuffer.allocate(version == ProtocolVersion.SSL_3 + ? encryptedSecret.length + : encryptedSecret.length + 2), version); + ByteBuffer b = buffer.duplicate(); + if (version != ProtocolVersion.SSL_3) + b.putShort((short) encryptedSecret.length); + b.put(encryptedSecret); + } + + public ByteBuffer buffer() + { + return (ByteBuffer) buffer.duplicate().rewind(); + } + + public byte[] encryptedSecret() + { + byte[] secret; + if (version == ProtocolVersion.SSL_3) + { + buffer.position (0); + secret = new byte[buffer.limit ()]; + buffer.get(secret); + } + else + { + int len = buffer.getShort(0) & 0xFFFF; + secret = new byte[len]; + buffer.position(2); + buffer.get(secret); + } + return secret; + } + + public void setEncryptedSecret(final byte[] secret, final int offset, final int length) + { + if (version == ProtocolVersion.SSL_3) + { + buffer.position(0); + buffer.put(secret, offset, length); + buffer.rewind(); + } + else + { + buffer.putShort(0, (short) length); + buffer.position(2); + buffer.put(secret, offset, length); + buffer.rewind(); + } + } + + public int length () + { + if (version == ProtocolVersion.SSL_3) + { + return buffer.capacity(); + } + else + { + return (buffer.getShort(0) & 0xFFFF) + 2; + } + } + + public String toString () + { + return toString (null); + } + + public String toString (final String prefix) + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + if (prefix != null) out.print(prefix); + out.println("struct {"); + if (prefix != null) out.print(prefix); + out.println(" pre_master_secret = "); + out.print(Util.hexDump(encryptedSecret(), prefix != null ? prefix + " " + : " ")); + if (prefix != null) out.print(prefix); + out.print("} EncryptedPreMasterSecret;"); + return str.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ExchangeKeys.java b/libjava/classpath/gnu/javax/net/ssl/provider/ExchangeKeys.java new file mode 100644 index 000000000..a6664b856 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ExchangeKeys.java @@ -0,0 +1,54 @@ +/* ExchangeKeys.java -- key exchange values. + 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.nio.ByteBuffer; +import java.nio.ByteOrder; + +public abstract class ExchangeKeys implements Constructed +{ + + protected ByteBuffer buffer; + + public ExchangeKeys (final ByteBuffer buffer) + { + if (buffer != null) + this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Extension.java b/libjava/classpath/gnu/javax/net/ssl/provider/Extension.java new file mode 100644 index 000000000..5cbcd5790 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Extension.java @@ -0,0 +1,246 @@ +/* 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.PrintWriter; +import java.io.StringWriter; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * An SSL hello extension. + * + *
      + * struct {
      + *   ExtensionType extension_type;
      + *   opaque extension_data<0..2^16-1>;
      + * } Extension;
      + * + * @author csm@gnu.org + */ +public final class Extension implements Builder, Constructed +{ + + // Fields. + // ------------------------------------------------------------------------- + + private ByteBuffer buffer; + + // Constructor. + // ------------------------------------------------------------------------- + + public Extension(final ByteBuffer buffer) + { + this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); + } + + public Extension(final Type type, final Value value) + { + ByteBuffer valueBuffer = value.buffer(); + int length = 2 + 2 + valueBuffer.remaining(); + buffer = ByteBuffer.allocate(length); + buffer.putShort((short) type.getValue()); + buffer.putShort((short) valueBuffer.remaining()); + buffer.put(valueBuffer); + buffer.rewind(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public int length () + { + return (buffer.getShort (2) & 0xFFFF) + 4; + } + + public ByteBuffer buffer() + { + return (ByteBuffer) buffer.duplicate().limit(length()); + } + + public Type type() + { + return Type.forValue (buffer.getShort (0) & 0xFFFF); + } + + public byte[] valueBytes() + { + int len = buffer.getShort (2) & 0xFFFF; + byte[] value = new byte[len]; + ((ByteBuffer) buffer.duplicate ().position (4)).get (value); + return value; + } + + public ByteBuffer valueBuffer() + { + int len = buffer.getShort(2) & 0xFFFF; + return ((ByteBuffer) buffer.duplicate().position(4).limit(len+4)).slice(); + } + + public Value value() + { + switch (type ()) + { + case SERVER_NAME: + return new ServerNameList(valueBuffer()); + + case MAX_FRAGMENT_LENGTH: + switch (valueBuffer().get() & 0xFF) + { + case 1: return MaxFragmentLength.LEN_2_9; + case 2: return MaxFragmentLength.LEN_2_10; + case 3: return MaxFragmentLength.LEN_2_11; + case 4: return MaxFragmentLength.LEN_2_12; + default: + throw new IllegalArgumentException("invalid max_fragment_len"); + } + + case TRUNCATED_HMAC: + return new TruncatedHMAC(); + + case CLIENT_CERTIFICATE_URL: + return new CertificateURL(valueBuffer()); + + case TRUSTED_CA_KEYS: + return new TrustedAuthorities(valueBuffer()); + + case STATUS_REQUEST: + return new CertificateStatusRequest(valueBuffer()); + + case SRP: + case CERT_TYPE: + } + return new UnresolvedExtensionValue(valueBuffer()); + } + + public void setLength (final int newLength) + { + if (newLength < 0 || newLength > 65535) + throw new IllegalArgumentException ("length is out of bounds"); + buffer.putShort (2, (short) newLength); + } + + public void setType (final Type type) + { + buffer.putShort(0, (short) type.getValue()); + } + + public void setValue (byte[] value) + { + setValue (value, 0, value.length); + } + + public void setValue (final byte[] value, final int offset, final int length) + { + if (length != length ()) + throw new IllegalArgumentException ("length is different than claimed length"); + ((ByteBuffer) buffer.duplicate().position(4)).put(value, offset, length); + } + + public String toString() + { + return toString(null); + } + + public String toString(String prefix) + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + if (prefix != null) out.print (prefix); + out.println("struct {"); + if (prefix != null) out.print (prefix); + out.println(" type = " + type () + ";"); + if (prefix != null) out.print (prefix); + String subprefix = " "; + if (prefix != null) subprefix = prefix + subprefix; + out.println(" value ="); + out.println(value().toString(subprefix)); + if (prefix != null) out.print (prefix); + out.print("} Extension;"); + return str.toString(); + } + + // Inner classes. + // ------------------------------------------------------------------------- + + public static enum Type + { + SERVER_NAME (0), + MAX_FRAGMENT_LENGTH (1), + CLIENT_CERTIFICATE_URL (2), + TRUSTED_CA_KEYS (3), + TRUNCATED_HMAC (4), + STATUS_REQUEST (5), + SRP (6), + CERT_TYPE (7); + + private final int value; + + private Type(int value) + { + this.value = value; + } + + public static Type forValue (final int value) + { + switch (value & 0xFFFF) + { + 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 null; + } + } + + public int getValue() + { + return value; + } + } + + public static abstract class Value implements Builder, Constructed + { + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ExtensionList.java b/libjava/classpath/gnu/javax/net/ssl/provider/ExtensionList.java new file mode 100644 index 000000000..fb7b12d9e --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ExtensionList.java @@ -0,0 +1,290 @@ +package gnu.javax.net.ssl.provider; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.NoSuchElementException; + +/** + * A list of extensions, that may appear in either the {@link ClientHello} or + * {@link ServerHello}. The form of the extensions list is: + * + * Extension extensions_list<1..2^16-1> + * + * @author csm + */ +public class ExtensionList implements Builder, Iterable +{ + private final ByteBuffer buffer; + private int modCount; + + public ExtensionList (ByteBuffer buffer) + { + this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); + modCount = 0; + } + + public ExtensionList(List extensions) + { + int length = 2; + for (Extension extension : extensions) + length += extension.length(); + buffer = ByteBuffer.allocate(length); + buffer.putShort((short) (length - 2)); + for (Extension extension : extensions) + buffer.put(extension.buffer()); + buffer.rewind(); + } + + public ByteBuffer buffer() + { + return (ByteBuffer) buffer.duplicate().limit(length()); + } + + public Extension get (final int index) + { + int length = length (); + int i; + int n = 0; + for (i = 2; i < length && n < index; ) + { + int l = buffer.getShort (i+2) & 0xFFFF; + i += l + 4; + n++; + } + if (n < index) + throw new IndexOutOfBoundsException ("no elemenet at " + index); + int el = buffer.getShort (i+2) & 0xFFFF; + ByteBuffer b = (ByteBuffer) buffer.duplicate().position(i).limit(i+el+4); + return new Extension(b.slice()); + } + + /** + * Returns the number of extensions this list contains. + * + * @return The number of extensions. + */ + public int size () + { + int length = length (); + if (length == 0) + return 0; + int n = 0; + for (int i = 2; i < length; ) + { + int len = buffer.getShort (i+2) & 0xFFFF; + i += len + 4; + n++; + } + return n; + } + + /** + * Returns the length of this extension list, in bytes. + * + * @return The length of this extension list, in bytes. + */ + public int length () + { + return (buffer.getShort (0) & 0xFFFF) + 2; + } + + /** + * Sets the extension at index i to e. Note that setting an + * element at an index may invalidate any other elements that come + * after element at index i. In other words, no attempt is made to + * move existing elements in this list, and since extensions are variable + * length, you can not guarantee that extensions later in the list + * will still be valid. + * + *

      Thus, elements of this list must be set in order of increasing + * index. + * + * @param index The index to set the extension at. + * @param e The extension. + * @throws java.nio.BufferOverflowException If setting the extension overflows + * the buffer. + * @throws IllegalArgumentException If it isn't possible to find the given index + * in the current list (say, if no element index - 1 is set), or if setting + * the extension will overflow the current list length (given by {@link + * #length()}). + */ + public void set (final int index, Extension e) + { + int length = length(); + int n = 0; + int i; + for (i = 2; i < length && n < index; ) + { + int len = buffer.getShort(i+2) & 0xFFFF; + i += len + 4; + n++; + } + if (n < index) + throw new IllegalArgumentException("nothing set at index " + (index-1) + + " or insufficient space"); + if (i + e.length() + 2 > length) + throw new IllegalArgumentException("adding this element will exceed the " + + "list length"); + buffer.putShort(i, (short) e.type().getValue()); + buffer.putShort(i+2, (short) e.length()); + ((ByteBuffer) buffer.duplicate().position(i+4)).put (e.valueBuffer()); + modCount++; + } + + /** + * Reserve space for an extension at index i in the list. In other + * words, this does the job of {@link #set(int, Extension)}, but does not + * copy the extension value to the underlying buffer. + * + * @param index The index of the extension to reserve space for. + * @param t The type of the extension. + * @param eLength The number of bytes to reserve for this extension. The total + * number of bytes used by this method is this length, plus four. + */ + public void set (final int index, Extension.Type t, final int eLength) + { + int length = length (); + int n = 0; + int i; + for (i = 2; i < length && n < index; ) + { + int len = buffer.getShort (i+2) & 0xFFFF; + i += len + 4; + n++; + } + if (n < index) + throw new IllegalArgumentException ("nothing set at index " + (index-1) + + " or insufficient space"); + if (i + eLength + 2 > length) + throw new IllegalArgumentException ("adding this element will exceed the " + + "list length"); + buffer.putShort(i, (short) t.getValue()); + buffer.putShort(i+2, (short) eLength); + modCount++; + } + + /** + * Set the total length of this list, in bytes. + * + * @param newLength The new list length. + */ + public void setLength (final int newLength) + { + if (newLength < 0 || newLength > 65535) + throw new IllegalArgumentException ("invalid length"); + buffer.putShort (0, (short) newLength); + modCount++; + } + + public Iterator iterator() + { + return new ExtensionsIterator(); + } + + public String toString() + { + return toString (null); + } + + public String toString(final String prefix) + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + if (prefix != null) out.print(prefix); + out.println("ExtensionList {"); + if (prefix != null) out.print(prefix); + out.print(" length = "); + out.print(length()); + out.println(";"); + String subprefix = " "; + if (prefix != null) + subprefix = prefix + subprefix; + for (Extension e : this) + out.println(e.toString(subprefix)); + if (prefix != null) out.print(prefix); + out.print("};"); + return str.toString(); + } + + /** + * List iterator interface to an extensions list. + * + * @author csm@gnu.org + */ + public final class ExtensionsIterator implements ListIterator + { + private final int modCount; + private int index; + private final int size; + + public ExtensionsIterator () + { + this.modCount = ExtensionList.this.modCount; + index = 0; + size = size (); + } + + public boolean hasNext() + { + return index < size; + } + + public boolean hasPrevious() + { + return index > 0; + } + + public Extension next() throws NoSuchElementException + { + if (modCount != ExtensionList.this.modCount) + throw new ConcurrentModificationException (); + if (!hasNext ()) + throw new NoSuchElementException (); + return get (index++); + } + + public Extension previous() throws NoSuchElementException + { + if (modCount != ExtensionList.this.modCount) + throw new ConcurrentModificationException (); + if (!hasPrevious ()) + throw new NoSuchElementException (); + return get (--index); + } + + public int nextIndex() + { + if (hasNext ()) + return index + 1; + return index; + } + + public int previousIndex() + { + if (hasPrevious ()) + return index - 1; + return -1; + } + + public void add(Extension e) + { + throw new UnsupportedOperationException ("cannot add items to this iterator"); + } + + public void remove() + { + throw new UnsupportedOperationException ("cannot remove items from this iterator"); + } + + public void set(Extension e) + { + ExtensionList.this.set (index, e); + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Finished.java b/libjava/classpath/gnu/javax/net/ssl/provider/Finished.java new file mode 100644 index 000000000..9a2a4707a --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Finished.java @@ -0,0 +1,173 @@ +/* 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.PrintWriter; +import java.io.StringWriter; + +import java.nio.ByteBuffer; + +final class Finished implements Handshake.Body +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final ByteBuffer buffer; + private final ProtocolVersion version; + + // Constructor. + // ------------------------------------------------------------------------- + + Finished (final ByteBuffer buffer, final ProtocolVersion version) + { + buffer.getClass (); + version.getClass (); + this.buffer = buffer; + this.version = version; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public int length () + { + if (version.compareTo(ProtocolVersion.TLS_1) >= 0) + return 12; + if (version == ProtocolVersion.SSL_3) + return 36; + throw new IllegalArgumentException ("length for this version unknown"); + } + + byte[] verifyData() + { + if (version.compareTo(ProtocolVersion.TLS_1) >= 0) + { + byte[] verify = new byte[12]; + buffer.position (0); + buffer.get (verify); + return verify; + } + throw new IllegalArgumentException ("not TLSv1.0 or later"); + } + + byte[] md5Hash() + { + if (version == ProtocolVersion.SSL_3) + { + byte[] md5 = new byte[16]; + buffer.position (0); + buffer.get (md5); + return md5; + } + throw new IllegalArgumentException ("not SSLv3"); + } + + byte[] shaHash() + { + if (version == ProtocolVersion.SSL_3) + { + byte[] sha = new byte[20]; + buffer.position (16); + buffer.get (sha); + return sha; + } + throw new IllegalArgumentException ("not SSLv3"); + } + + void setVerifyData (final byte[] verifyData, final int offset) + { + if (version == ProtocolVersion.SSL_3) + throw new IllegalArgumentException ("not TLSv1"); + buffer.position (0); + buffer.put (verifyData, offset, 12); + } + + void setMD5Hash (final byte[] md5, final int offset) + { + if (version != ProtocolVersion.SSL_3) + throw new IllegalArgumentException ("not SSLv3"); + buffer.position (0); + buffer.put (md5, offset, 16); + } + + void setShaHash (final byte[] sha, final int offset) + { + if (version != ProtocolVersion.SSL_3) + throw new IllegalArgumentException ("not SSLv3"); + buffer.position (16); + buffer.put (sha, offset, 20); + } + + public String toString () + { + return toString (null); + } + + public String toString (final String prefix) + { + StringWriter str = new StringWriter (); + PrintWriter out = new PrintWriter (str); + if (prefix != null) + out.print (prefix); + out.println ("struct {"); + if (prefix != null) + out.print (prefix); + if (version.compareTo(ProtocolVersion.TLS_1) >= 0) + { + out.print (" verifyData = "); + out.print (Util.toHexString (verifyData (), ':')); + } + else if (version == ProtocolVersion.SSL_3) + { + out.print (" md5 = "); + out.print (Util.toHexString (md5Hash (), ':')); + out.println (';'); + if (prefix != null) + out.print (prefix); + out.print (" sha = "); + out.print (Util.toHexString (shaHash (), ':')); + } + out.println (';'); + if (prefix != null) + out.print (prefix); + out.print ("} Finished;"); + return str.toString (); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Handshake.java b/libjava/classpath/gnu/javax/net/ssl/provider/Handshake.java new file mode 100644 index 000000000..31f142d3e --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Handshake.java @@ -0,0 +1,299 @@ +/* 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.PrintWriter; +import java.io.StringWriter; + +import java.nio.ByteBuffer; + +/** + * An SSL handshake message. SSL handshake messages have the following + * form: + * + *

      +struct
      +{
      +  HandshakeType msg_type;
      +  uint24        length;
      +  select (msg_type)
      +  {
      +    case hello_request:       HelloRequest;
      +    case client_hello:        ClientHello;
      +    case server_hello:        ServerHello;
      +    case certificate:         Certificate;
      +    case server_key_exchange: ServerKeyExchange;
      +    case certificate_request: CertificateRequest;
      +    case server_hello_done:   ServerHelloDone;
      +    case certificate_verify:  CertificateVerify;
      +    case client_key_exchange: ClientKeyExchange;
      +    case finished:            Finished;
      +  } body;
      +};
      + */ +public final class Handshake implements Constructed +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final ByteBuffer buffer; + private final CipherSuite suite; + private final ProtocolVersion version; + + // Constructors. + // ------------------------------------------------------------------------- + + public Handshake (final ByteBuffer buffer) + { + this (buffer, null, ProtocolVersion.TLS_1_1); + } + + public Handshake (final ByteBuffer buffer, final CipherSuite suite, + final ProtocolVersion version) + { + this.buffer = buffer; + this.suite = suite; + this.version = version; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + /** + * Returns the handshake type. + * + * @return The handshake type. + */ + public Type type() + { + return Type.forInteger (buffer.get (0) & 0xFF); + } + + /** + * Returns the message length. + * + * @return The message length. + */ + public int length () + { + // Length is a uint24. + return buffer.getInt (0) & 0xFFFFFF; + } + + /** + * Returns the handshake message body. Depending on the handshake + * type, some implementation of the Body interface is returned. + * + * @return The handshake body. + */ + public Body body() + { + Type type = type (); + ByteBuffer bodyBuffer = bodyBuffer (); + switch (type) + { + case HELLO_REQUEST: + return new HelloRequest (); + + case CLIENT_HELLO: + return new ClientHello (bodyBuffer); + + case SERVER_HELLO: + return new ServerHello (bodyBuffer); + + case CERTIFICATE: + return new Certificate (bodyBuffer, CertificateType.X509); + + case SERVER_KEY_EXCHANGE: + return new ServerKeyExchange (bodyBuffer, suite); + + case CERTIFICATE_REQUEST: + return new CertificateRequest (bodyBuffer); + + case SERVER_HELLO_DONE: + return new ServerHelloDone (); + + case CERTIFICATE_VERIFY: + return new CertificateVerify (bodyBuffer, suite.signatureAlgorithm ()); + + case CLIENT_KEY_EXCHANGE: + return new ClientKeyExchange (bodyBuffer, suite, version); + + case FINISHED: + return new Finished (bodyBuffer, version); + + case CERTIFICATE_URL: + case CERTIFICATE_STATUS: + throw new UnsupportedOperationException ("FIXME"); + } + throw new IllegalArgumentException ("unknown handshake type " + type); + } + + /** + * Returns a subsequence of the underlying buffer, containing only + * the bytes that compose the handshake body. + * + * @return The body's byte buffer. + */ + public ByteBuffer bodyBuffer () + { + int length = length (); + return ((ByteBuffer) buffer.position (4).limit (4 + length)).slice (); + } + + /** + * Sets the handshake body type. + * + * @param type The handshake type. + */ + public void setType (final Type type) + { + buffer.put (0, (byte) type.getValue ()); + } + + /** + * Sets the length of the handshake body. + * + * @param length The handshake body length. + * @throws java.nio.ReadOnlyBufferException If the underlying buffer + * is not writable. + * @throws IllegalArgumentException of length is not + * between 0 and 16777215, inclusive. + */ + public void setLength (final int length) + { + if (length < 0 || length > 0xFFFFFF) + throw new IllegalArgumentException ("length " + length + " out of range;" + + " must be between 0 and 16777215"); + buffer.put (1, (byte) (length >>> 16)); + buffer.put (2, (byte) (length >>> 8)); + buffer.put (3, (byte) length); + } + + public String toString() + { + return toString (null); + } + + public String toString (final String prefix) + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + if (prefix != null) out.print (prefix); + out.println("struct {"); + if (prefix != null) out.print (prefix); + out.print (" type: "); + out.print (type ()); + out.println (";"); + Body body = body (); + out.println (body.toString (prefix != null ? (prefix + " ") : " ")); + if (prefix != null) out.print (prefix); + out.print ("} Handshake;"); + return str.toString(); + } + + // Inner class. + // ------------------------------------------------------------------------- + + public static interface Body extends Constructed + { + int length (); + + String toString (String prefix); + } + + public static enum Type + { + HELLO_REQUEST ( 0), + CLIENT_HELLO ( 1), + SERVER_HELLO ( 2), + CERTIFICATE (11), + SERVER_KEY_EXCHANGE (12), + CERTIFICATE_REQUEST (13), + SERVER_HELLO_DONE (14), + CERTIFICATE_VERIFY (15), + CLIENT_KEY_EXCHANGE (16), + FINISHED (20), + CERTIFICATE_URL (21), + CERTIFICATE_STATUS (22); + + private final int value; + + private Type(int value) + { + this.value = value; + } + + // Class methods. + // ----------------------------------------------------------------------- + + /** + * Convert a raw handshake type value to a type enum value. + * + * @return The corresponding enum value for the raw integer value. + * @throws IllegalArgumentException If the value is not a known handshake + * type. + */ + public static Type forInteger (final int value) + { + switch (value & 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: throw new IllegalArgumentException ("unsupported value type " + value); + } + } + + public int getValue() + { + return value; + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/HelloRequest.java b/libjava/classpath/gnu/javax/net/ssl/provider/HelloRequest.java new file mode 100644 index 000000000..81dfce591 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/HelloRequest.java @@ -0,0 +1,72 @@ +/* HelloRequest.java -- SSL HelloRequest 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 gnu.java.lang.CPStringBuilder; + +/** + * The handshake body for a HelloRequest handshake message. + * + *
      struct { } HelloRequest;
      + */ +public final class HelloRequest implements Handshake.Body +{ + public HelloRequest () + { + } + + public String toString (final String prefix) + { + CPStringBuilder str = new CPStringBuilder (); + if (prefix != null) + str.append (prefix); + str.append ("HelloRequest { };"); + return str.toString (); + } + + public int length () + { + return 0; + } + + public String toString () + { + return toString (null); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/InputSecurityParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/InputSecurityParameters.java new file mode 100644 index 000000000..1d3da833a --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/InputSecurityParameters.java @@ -0,0 +1,334 @@ +/* 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 gnu.classpath.debug.Component; +import gnu.classpath.debug.SystemLogger; +import gnu.java.security.util.ByteArray; +import gnu.java.security.util.ByteBufferOutputStream; + +import java.nio.BufferOverflowException; +import java.nio.ByteBuffer; + +import java.util.Arrays; +import java.util.zip.DataFormatException; +import java.util.zip.Inflater; + +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.Mac; +import javax.crypto.ShortBufferException; + +import javax.net.ssl.SSLException; + +public class InputSecurityParameters +{ + private static final SystemLogger logger = SystemLogger.SYSTEM; + private final Cipher cipher; + private final Mac mac; + private final Inflater inflater; + private SessionImpl session; + private final CipherSuite suite; + private long sequence; + + public InputSecurityParameters (final Cipher cipher, final Mac mac, + final Inflater inflater, + final SessionImpl session, + final CipherSuite suite) + { + this.cipher = cipher; + this.mac = mac; + this.inflater = inflater; + this.session = session; + this.suite = suite; + sequence = 0; + } + + /** + * Decrypt a record, storing the decrypted fragment into the given array + * of byte buffers. + * + * @param record The input record. + * @param output The output buffers. + * @param offset The offset of the first buffer to use. + * @param length The number of buffers to use. + * @return The number of bytes put in the output buffers. + * @throws DataFormatException If decompression fails. + * @throws IllegalBlockSizeException If the current cipher is a block cipher, + * and the input fragment is not a multiple of the block size. + * @throws MacException If verifying the MAC fails. + * @throws SSLException ??? + * @throws ShortBufferException + */ + public int decrypt(Record record, ByteBuffer[] output, int offset, int length) + throws DataFormatException, IllegalBlockSizeException, + MacException, SSLException, ShortBufferException + { + return decrypt(record, output, offset, length, null); + } + + /** + * Decrypt a record, storing the decrypted fragment into the given growable + * buffer. + * + * @param record The input record. + * @param outputStream The output buffer. + * @return The number of bytes put into the output buffer. + * @throws DataFormatException + * @throws IllegalBlockSizeException + * @throws MacException + * @throws SSLException + * @throws ShortBufferException + */ + public int decrypt(Record record, ByteBufferOutputStream outputStream) + throws DataFormatException, IllegalBlockSizeException, + MacException, SSLException, ShortBufferException + { + return decrypt(record, null, 0, 0, outputStream); + } + + private int decrypt(Record record, ByteBuffer[] output, int offset, int length, + ByteBufferOutputStream outputStream) + throws DataFormatException, IllegalBlockSizeException, + MacException, SSLException, ShortBufferException + { + boolean badPadding = false; + ByteBuffer fragment; + if (cipher != null) + { + ByteBuffer input = record.fragment(); + fragment = ByteBuffer.allocate(input.remaining()); + cipher.update(input, fragment); + } + else + fragment = record.fragment(); + + if (Debug.DEBUG_DECRYPTION) + logger.logv(Component.SSL_RECORD_LAYER, "decrypted fragment:\n{0}", + Util.hexDump((ByteBuffer) fragment.duplicate().position(0), " >> ")); + + int fragmentLength = record.length(); + int maclen = 0; + if (mac != null) + maclen = mac.getMacLength(); + fragmentLength -= maclen; + + int padlen = 0; + int padRemoveLen = 0; + if (!suite.isStreamCipher ()) + { + padlen = fragment.get(record.length() - 1) & 0xFF; + padRemoveLen = padlen + 1; + if (Debug.DEBUG) + logger.logv(Component.SSL_RECORD_LAYER, "padlen:{0}", padlen); + + if (record.version() == ProtocolVersion.SSL_3) + { + // In SSLv3, the padding length must not be larger than + // the cipher's block size. + if (padlen > cipher.getBlockSize ()) + badPadding = true; + } + else if (record.version().compareTo(ProtocolVersion.TLS_1) >= 0) + { + // In TLSv1 and later, the padding must be `padlen' copies of the + // value `padlen'. + byte[] pad = new byte[padlen]; + ((ByteBuffer) fragment.duplicate().position(record.length() - padlen - 1)).get(pad); + for (int i = 0; i < pad.length; i++) + if ((pad[i] & 0xFF) != padlen) + badPadding = true; + if (Debug.DEBUG) + logger.logv(Component.SSL_RECORD_LAYER, "TLSv1.x padding\n{0}", + new ByteArray(pad)); + } + + if (Debug.DEBUG) + logger.logv(Component.SSL_RECORD_LAYER, "padding bad? {0}", + badPadding); + if (!badPadding) + fragmentLength = fragmentLength - padRemoveLen; + } + + int ivlen = 0; + if (session.version.compareTo(ProtocolVersion.TLS_1_1) >= 0 + && !suite.isStreamCipher()) + ivlen = cipher.getBlockSize(); + + // Compute and check the MAC. + if (mac != null) + { + mac.update((byte) (sequence >>> 56)); + mac.update((byte) (sequence >>> 48)); + mac.update((byte) (sequence >>> 40)); + mac.update((byte) (sequence >>> 32)); + mac.update((byte) (sequence >>> 24)); + mac.update((byte) (sequence >>> 16)); + mac.update((byte) (sequence >>> 8)); + mac.update((byte) sequence); + mac.update((byte) record.getContentType().getValue()); + ProtocolVersion version = record.version(); + if (version != ProtocolVersion.SSL_3) + { + mac.update((byte) version.major()); + mac.update((byte) version.minor()); + } + mac.update((byte) ((fragmentLength - ivlen) >>> 8)); + mac.update((byte) (fragmentLength - ivlen)); + ByteBuffer content = + (ByteBuffer) fragment.duplicate().position(ivlen).limit(fragmentLength); + mac.update(content); + byte[] mac1 = mac.doFinal (); + byte[] mac2 = new byte[maclen]; + mac.reset(); + ((ByteBuffer) fragment.duplicate().position(fragmentLength)).get(mac2); + if (Debug.DEBUG) + logger.logv(Component.SSL_RECORD_LAYER, "mac1:{0} mac2:{1}", + Util.toHexString(mac1, ':'), Util.toHexString(mac2, ':')); + if (!Arrays.equals (mac1, mac2)) + badPadding = true; + } + + // We always say "bad MAC" and not "bad padding," because saying + // the latter will leak information to an attacker. + if (badPadding) + throw new MacException (); + + // Inflate the compressed bytes. + int produced = 0; + if (inflater != null) + { + ByteBufferOutputStream out = new ByteBufferOutputStream(fragmentLength); + byte[] inbuffer = new byte[1024]; + byte[] outbuffer = new byte[1024]; + boolean done = false; + if (record.version().compareTo(ProtocolVersion.TLS_1_1) >= 0 + && !suite.isStreamCipher()) + fragment.position (cipher.getBlockSize()); + else + fragment.position(0); + fragment.limit(fragmentLength); + + while (!done) + { + int l; + if (inflater.needsInput()) + { + l = Math.min(inbuffer.length, fragment.remaining()); + fragment.get(inbuffer, 0, l); + inflater.setInput(inbuffer); + } + + l = inflater.inflate(outbuffer); + out.write(outbuffer, 0, l); + done = !fragment.hasRemaining() && inflater.finished(); + } + + ByteBuffer outbuf = out.buffer(); + if (outputStream != null) + { + byte[] buf = new byte[1024]; + while (outbuf.hasRemaining()) + { + int l = Math.min(outbuf.remaining(), buf.length); + outbuf.get(buf, 0, l); + outputStream.write(buf, 0, l); + produced += l; + } + } + else + { + int i = offset; + while (outbuf.hasRemaining() && i < offset + length) + { + int l = Math.min(output[i].remaining(), outbuf.remaining()); + ByteBuffer b = (ByteBuffer) + outbuf.duplicate().limit(outbuf.position() + l); + output[i++].put(b); + outbuf.position(outbuf.position() + l); + produced += l; + } + if (outbuf.hasRemaining()) + throw new BufferOverflowException(); + } + } + else + { + ByteBuffer outbuf = (ByteBuffer) + fragment.duplicate().position(0).limit(record.length() - maclen - padRemoveLen); + if (record.version().compareTo(ProtocolVersion.TLS_1_1) >= 0 + && !suite.isStreamCipher()) + outbuf.position(cipher.getBlockSize()); + if (outputStream != null) + { + byte[] buf = new byte[1024]; + while (outbuf.hasRemaining()) + { + int l = Math.min(outbuf.remaining(), buf.length); + outbuf.get(buf, 0, l); + outputStream.write(buf, 0, l); + produced += l; + } + } + else + { + int i = offset; + while (outbuf.hasRemaining() && i < offset + length) + { + int l = Math.min(output[i].remaining(), outbuf.remaining()); + ByteBuffer b = (ByteBuffer) outbuf.duplicate().limit(outbuf.position() + l); + output[i++].put(b); + outbuf.position(outbuf.position() + l); + produced += l; + } + if (outbuf.hasRemaining()) + throw new BufferOverflowException(); + } + } + + sequence++; + + return produced; + } + + CipherSuite cipherSuite () + { + return suite; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Jessie.java b/libjava/classpath/gnu/javax/net/ssl/provider/Jessie.java new file mode 100644 index 000000000..d3fb3a658 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Jessie.java @@ -0,0 +1,102 @@ +/* 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 +{ + private static final long serialVersionUID = -1; + + public static final String VERSION = "2.0.0"; + public static final double VERSION_DOUBLE = 2.0; + + public Jessie() + { + super("Jessie", VERSION_DOUBLE, + "Implementing TLSv1.1, with SSLv3, TLSv1.0 compatibility modes; " + + "X.509 Key Manager Factory; " + + "X.509 Trust Manager Factory; " + + "SSLv3 MD5 and SHA Mac."); + + AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + put("SSLContext.TLSv1.1", SSLContextImpl.class.getName()); + put("Alg.Alias.SSLContext.SSLv3", "TLSv1.1"); + put("Alg.Alias.SSLContext.TLSv1", "TLSv1.1"); + put("Alg.Alias.SSLContext.TLSv1.0", "TLSv1.1"); + put("Alg.Alias.SSLContext.TLS", "TLSv1.1"); + put("Alg.Alias.SSLContext.SSL", "TLSv1.1"); + + put("KeyManagerFactory.JessieX509", X509KeyManagerFactory.class.getName()); + put("TrustManagerFactory.JessieX509", X509TrustManagerFactory.class.getName()); + put("KeyManagerFactory.JessiePSK", PreSharedKeyManagerFactoryImpl.class.getName()); + //put("TrustManagerFactory.SRP", SRPTrustManagerFactory.class.getName()); + + put("Mac.SSLv3HMac-MD5", SSLv3HMacMD5Impl.class.getName()); + put("Mac.SSLv3HMac-SHA", SSLv3HMacSHAImpl.class.getName()); + + put("Signature.TLSv1.1-RSA", SSLRSASignatureImpl.class.getName()); + put("Alg.Alias.Signature.TLSv1-RSA", "TLSv1.1-RSA"); + put("Alg.Alias.Signature.SSLv3-RSA", "TLSv1.1-RSA"); + + return null; + } + }); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/KeyExchangeAlgorithm.java b/libjava/classpath/gnu/javax/net/ssl/provider/KeyExchangeAlgorithm.java new file mode 100644 index 000000000..04416c5a5 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/KeyExchangeAlgorithm.java @@ -0,0 +1,57 @@ +/* KeyExchangeAlgorithm.java -- Key exchange algorithm enumeration. + 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; + +/** + * The enumeration of supported key exchange algorithms. + */ +public enum KeyExchangeAlgorithm +{ + NONE, + RSA, + DH_DSS, + DH_RSA, + DH_anon, + DHE_DSS, + DHE_RSA, +// SRP, + PSK, + DHE_PSK, + RSA_PSK; +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/MacAlgorithm.java b/libjava/classpath/gnu/javax/net/ssl/provider/MacAlgorithm.java new file mode 100644 index 000000000..cae0efbfa --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/MacAlgorithm.java @@ -0,0 +1,47 @@ +/* MacAlgorithm.java -- MAC algorithm enumeration. + 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 enumeration of MAC algorithms we support. + */ +public enum MacAlgorithm +{ + NULL, MD5, SHA; +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/MacException.java b/libjava/classpath/gnu/javax/net/ssl/provider/MacException.java new file mode 100644 index 000000000..b8c479fdb --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/MaxFragmentLength.java b/libjava/classpath/gnu/javax/net/ssl/provider/MaxFragmentLength.java new file mode 100644 index 000000000..acbfedff1 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/MaxFragmentLength.java @@ -0,0 +1,59 @@ +package gnu.javax.net.ssl.provider; + +import gnu.javax.net.ssl.provider.Extension.Value; + +import java.nio.ByteBuffer; + +/** + * Extension value + * @author csm + */ +public class MaxFragmentLength extends Value +{ + public static final MaxFragmentLength LEN_2_9 = new MaxFragmentLength(1, 1 << 9); + public static final MaxFragmentLength LEN_2_10 = new MaxFragmentLength(2, 1 << 10); + public static final MaxFragmentLength LEN_2_11 = new MaxFragmentLength(3, 1 << 11); + public static final MaxFragmentLength LEN_2_12 = new MaxFragmentLength(4, 1 << 12); + + private final int value; + private final int length; + + private MaxFragmentLength(int value, int length) + { + this.value = value; + this.length = length; + } + + public ByteBuffer buffer() + { + return ByteBuffer.allocate(1).put(0, (byte) value); + } + + public int length() + { + return 1; + } + + public int getValue() + { + return value; + } + + public int maxLength() + { + return length; + } + + public String toString() + { + return toString(null); + } + + public String toString(String prefix) + { + String s = "max_fragment_length = "; + if (prefix != null) + s = prefix + s; + return s + maxLength() + ";"; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/OutputSecurityParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/OutputSecurityParameters.java new file mode 100644 index 000000000..c6ed7d587 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/OutputSecurityParameters.java @@ -0,0 +1,294 @@ +/* OutputSecurityParameters.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.net.ssl.provider; + +import gnu.classpath.debug.Component; +import gnu.classpath.debug.SystemLogger; +import gnu.java.security.util.ByteBufferOutputStream; + +import java.nio.ByteBuffer; + +import java.util.zip.DataFormatException; +import java.util.zip.Deflater; + +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.Mac; +import javax.crypto.ShortBufferException; + +public class OutputSecurityParameters +{ + private static final SystemLogger logger = SystemLogger.SYSTEM; + private final Cipher cipher; + private final Mac mac; + private final Deflater deflater; + private final SessionImpl session; + private final CipherSuite suite; + private long sequence; + + public OutputSecurityParameters (final Cipher cipher, final Mac mac, + final Deflater deflater, SessionImpl session, + CipherSuite suite) + { + this.cipher = cipher; + this.mac = mac; + this.deflater = deflater; + this.session = session; + this.suite = suite; + sequence = 0; + } + + /** + * Encrypt a record, storing the result in the given output buffer. + * + * @return The number of bytes taken from the input, and the number stored + * into `output;' that is, the size of the encrypted fragment, plus the + * encoding for the record. + */ + public int[] encrypt (final ByteBuffer[] input, int offset, int length, + final ContentType contentType, final ByteBuffer output) + throws DataFormatException, IllegalBlockSizeException, ShortBufferException + { + if (offset < 0 || offset >= input.length + || length <= 0 || offset + length > input.length) + throw new IndexOutOfBoundsException(); + + if (Debug.DEBUG) + for (int i = offset; i < offset+length; i++) + logger.logv(Component.SSL_RECORD_LAYER, "encrypting record [{0}]: {1}", + i-offset, input[i]); + + int maclen = 0; + if (mac != null) + maclen = session.isTruncatedMac() ? 10 : mac.getMacLength (); + + int ivlen = 0; + byte[] iv = null; + if (session.version.compareTo(ProtocolVersion.TLS_1_1) >= 0 + && !suite.isStreamCipher()) + { + ivlen = cipher.getBlockSize(); + iv = new byte[ivlen]; + session.random().nextBytes(iv); + } + + int padaddlen = 0; + if (!suite.isStreamCipher() + && session.version.compareTo(ProtocolVersion.TLS_1) >= 0) + { + padaddlen = (session.random().nextInt(255 / cipher.getBlockSize()) + * cipher.getBlockSize()); + } + + int fragmentLength = 0; + ByteBuffer[] fragments = null; + // Compress the content, if needed. + if (deflater != null) + { + ByteBufferOutputStream deflated = new ByteBufferOutputStream(); + + byte[] inbuf = new byte[1024]; + byte[] outbuf = new byte[1024]; + int written = 0; + + // Here we use the guarantee that the deflater won't increase the + // output size by more than 1K -- we resign ourselves to only deflate + // as much data as we have space for *uncompressed*, + int limit = output.remaining() - (maclen + ivlen + padaddlen) - 1024; + + for (int i = offset; i < length && written < limit; i++) + { + ByteBuffer in = input[i]; + while (in.hasRemaining() && written < limit) + { + int l = Math.min(in.remaining(), inbuf.length); + l = Math.min(limit - written, l); + in.get(inbuf, 0, l); + deflater.setInput(inbuf, 0, l); + l = deflater.deflate(outbuf); + deflated.write(outbuf, 0, l); + written += l; + } + } + deflater.finish(); + while (!deflater.finished()) + { + int l = deflater.deflate(outbuf); + deflated.write(outbuf, 0, l); + written += l; + } + fragments = new ByteBuffer[] { deflated.buffer() }; + fragmentLength = ((int) deflater.getBytesWritten()) + maclen + ivlen; + deflater.reset(); + offset = 0; + length = 1; + } + else + { + int limit = output.remaining() - (maclen + ivlen + padaddlen); + fragments = input; + for (int i = offset; i < length && fragmentLength < limit; i++) + { + int l = Math.min(limit - fragmentLength, fragments[i].remaining()); + fragmentLength += l; + } + fragmentLength += maclen + ivlen; + } + + // Compute padding... + int padlen = 0; + byte[] pad = null; + if (!suite.isStreamCipher()) + { + int bs = cipher.getBlockSize(); + padlen = bs - (fragmentLength % bs); + if (Debug.DEBUG) + logger.logv(Component.SSL_RECORD_LAYER, + "framentLen:{0} padlen:{1} blocksize:{2}", + fragmentLength, padlen, bs); + if (session.version.compareTo(ProtocolVersion.TLS_1) >= 0) + { + // TLS 1.0 and later uses a random amount of padding, up to + // 255 bytes. Each byte of the pad is equal to the padding + // length, minus one. + padlen += padaddlen; + while (padlen > 255) + padlen -= bs; + pad = new byte[padlen]; + for (int i = 0; i < padlen; i++) + pad[i] = (byte) (padlen - 1); + } + else + { + // SSL 3 uses a pad only as large as the block size, but the + // pad may contain any values. + pad = new byte[padlen]; + session.random().nextBytes(pad); + pad[padlen - 1] = (byte) (padlen - 1); + } + fragmentLength += pad.length; + } + + // If there is a MAC, compute it. + byte[] macValue = null; + if (mac != null) + { + mac.update((byte) (sequence >>> 56)); + mac.update((byte) (sequence >>> 48)); + mac.update((byte) (sequence >>> 40)); + mac.update((byte) (sequence >>> 32)); + mac.update((byte) (sequence >>> 24)); + mac.update((byte) (sequence >>> 16)); + mac.update((byte) (sequence >>> 8)); + mac.update((byte) sequence); + mac.update((byte) contentType.getValue()); + if (session.version != ProtocolVersion.SSL_3) + { + mac.update((byte) session.version.major ()); + mac.update((byte) session.version.minor ()); + } + int toWrite = fragmentLength - maclen - ivlen - padlen; + mac.update((byte) (toWrite >>> 8)); + mac.update((byte) toWrite); + int written = 0; + for (int i = offset; i < length && written < toWrite; i++) + { + ByteBuffer fragment = fragments[i].duplicate(); + int l = Math.min(fragment.remaining(), toWrite - written); + fragment.limit(fragment.position() + l); + mac.update(fragment); + } + macValue = mac.doFinal(); + } + + Record outrecord = new Record(output); + outrecord.setContentType(contentType); + outrecord.setVersion(session.version); + outrecord.setLength(fragmentLength); + + int consumed = 0; + ByteBuffer outfragment = outrecord.fragment(); + + if (cipher != null) + { + if (iv != null) + cipher.update(ByteBuffer.wrap(iv), outfragment); + int toWrite = fragmentLength - maclen - ivlen - padlen; + for (int i = offset; i < offset + length && consumed < toWrite; i++) + { + ByteBuffer fragment = fragments[i].slice(); + int l = Math.min(fragment.remaining(), toWrite - consumed); + fragment.limit(fragment.position() + l); + cipher.update(fragment, outfragment); + fragments[i].position(fragments[i].position() + l); + consumed += l; + } + if (macValue != null) + cipher.update(ByteBuffer.wrap(macValue), outfragment); + if (pad != null) + cipher.update(ByteBuffer.wrap(pad), outfragment); + } + else + { + // iv and pad are only used if we have a block cipher. + int toWrite = fragmentLength - maclen; + for (int i = offset; i < offset + length && consumed < toWrite; i++) + { + ByteBuffer fragment = fragments[i]; + int l = Math.min(fragment.remaining(), toWrite - consumed); + fragment.limit(fragment.position() + l); + outfragment.put(fragment); + consumed += l; + } + if (macValue != null) + outfragment.put(macValue); + } + + // Advance the output buffer's position. + output.position(output.position() + outrecord.length() + 5); + sequence++; + + return new int[] { consumed, fragmentLength + 5 }; + } + + CipherSuite suite() + { + return suite; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/PreSharedKeyManagerFactoryImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/PreSharedKeyManagerFactoryImpl.java new file mode 100644 index 000000000..16263fb37 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/PreSharedKeyManagerFactoryImpl.java @@ -0,0 +1,118 @@ +/* PreSharedKeyManagerFactory.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.net.ssl.provider; + +import gnu.javax.net.ssl.PreSharedKeyManager; +import gnu.javax.net.ssl.PreSharedKeyManagerParameters; + +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.util.Iterator; + +import javax.crypto.SecretKey; +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactorySpi; +import javax.net.ssl.ManagerFactoryParameters; + +/** + * @author Casey Marshall (csm@gnu.org) + */ +public class PreSharedKeyManagerFactoryImpl + extends KeyManagerFactorySpi +{ + PreSharedKeyManagerParameters params; + + /* (non-Javadoc) + * @see javax.net.ssl.KeyManagerFactorySpi#engineGetKeyManagers() + */ + @Override protected KeyManager[] engineGetKeyManagers() + { + if (params == null) + throw new IllegalStateException("not initialized"); + return new KeyManager[] { new Manager() }; + } + + /* (non-Javadoc) + * @see javax.net.ssl.KeyManagerFactorySpi#engineInit(javax.net.ssl.ManagerFactoryParameters) + */ + @Override protected void engineInit(ManagerFactoryParameters params) + throws InvalidAlgorithmParameterException + { + if (!(params instanceof PreSharedKeyManagerParameters)) + throw new InvalidAlgorithmParameterException("only supports gnu.javax.net.ssl.PreSharedKeyManagerParameters"); + params = (PreSharedKeyManagerParameters) params; + } + + /* (non-Javadoc) + * @see javax.net.ssl.KeyManagerFactorySpi#engineInit(java.security.KeyStore, char[]) + */ + @Override protected void engineInit(KeyStore store, char[] passwd) + throws KeyStoreException, NoSuchAlgorithmException, + UnrecoverableKeyException + { + // XXX Could implement this. + } + + class Manager implements PreSharedKeyManager + { + Manager() + { + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.PreSharedKeyManager#getKey(java.lang.String) + */ + public SecretKey getKey(String name) throws KeyManagementException + { + return params.getKey(name); + } + + public String chooseIdentityHint() + { + Iterator it = params.identities(); + if (it.hasNext()) + return it.next(); + return null; + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ProtocolVersion.java b/libjava/classpath/gnu/javax/net/ssl/provider/ProtocolVersion.java new file mode 100644 index 000000000..3c3f29a21 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ProtocolVersion.java @@ -0,0 +1,200 @@ +/* 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; + +public final class ProtocolVersion + implements Comparable, Constructed +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + public static final ProtocolVersion SSL_3 = new ProtocolVersion(3, 0); + public static final ProtocolVersion TLS_1 = new ProtocolVersion(3, 1); + public 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. + // ------------------------------------------------------------------------- + + public static ProtocolVersion read(InputStream in) throws IOException + { + int major = in.read() & 0xFF; + int minor = in.read() & 0xFF; + return getInstance(major, minor); + } + + public static ProtocolVersion forName (final String name) + { + if (name.equalsIgnoreCase ("SSLv3")) + return SSL_3; + if (name.equalsIgnoreCase ("TLSv1")) + return TLS_1; + if (name.equalsIgnoreCase("TLSv1.1")) + return TLS_1_1; + throw new IllegalArgumentException ("unknown protocol name: " + name); + } + + public static ProtocolVersion getInstance(final int major, final 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); + } + + public static ProtocolVersion getInstance (final short raw_value) + { + int major = raw_value >>> 8 & 0xFF; + int minor = raw_value & 0xFF; + return getInstance (major, minor); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public int length () + { + return 2; + } + + public byte[] getEncoded() + { + return new byte[] { + (byte) major, (byte) minor + }; + } + + public int major() + { + return major; + } + + public int minor() + { + return minor; + } + + public int rawValue () + { + return (major << 8) | minor; + } + + public boolean equals(Object o) + { + if (!(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(ProtocolVersion that) + { + if (major > that.major) + { + return 1; + } + else if (major < that.major) + { + return -1; + } + + if (minor > that.minor) + { + return 1; + } + else if (minor < that.minor) + { + return -1; + } + return 0; + } + + public String toString (String prefix) + { + return toString (); + } + + 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/libjava/classpath/gnu/javax/net/ssl/provider/Random.java b/libjava/classpath/gnu/javax/net/ssl/provider/Random.java new file mode 100644 index 000000000..bd5c037f5 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Random.java @@ -0,0 +1,150 @@ +/* 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.PrintWriter; +import java.io.StringWriter; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * An SSL nonce. + * + *
      +struct
      +{
      +  uint32 gmt_unix_time;
      +  opaque random_bytes[28];
      +} Random;
      + */
      +public class Random implements Builder, Constructed
      +{
      +
      +  // Fields.
      +  // -------------------------------------------------------------------------
      +
      +  static final int RANDOM_LENGTH = 28;
      +
      +  private final ByteBuffer buffer;
      +
      +  // Constructors.
      +  // -------------------------------------------------------------------------
      +
      +  public Random (final ByteBuffer buffer)
      +  {
      +    this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
      +  }
      +
      +  public Random copy()
      +  {
      +    ByteBuffer buffer = ByteBuffer.allocate(32);
      +    buffer.put((ByteBuffer) this.buffer.duplicate().position(0));
      +    return new Random(buffer);
      +  }
      +
      +  public int length()
      +  {
      +    return RANDOM_LENGTH + 4;
      +  }
      +
      +  public ByteBuffer buffer()
      +  {
      +    return ((ByteBuffer) buffer.duplicate().position(0).limit(length())).slice();
      +  }
      +
      +  public int gmtUnixTime ()
      +  {
      +    return buffer.getInt(0);
      +  }
      +
      +  public byte[] randomBytes()
      +  {
      +    byte[] buf = new byte[28];
      +    buffer.position (4);
      +    buffer.get (buf);
      +    return buf;
      +  }
      +
      +  public void setGmtUnixTime (final int gmtUnixTime)
      +  {
      +    buffer.putInt (0, gmtUnixTime);
      +  }
      +
      +  public void setRandomBytes (final byte[] randomBytes)
      +  {
      +    setRandomBytes (randomBytes, 0);
      +  }
      +
      +  public void setRandomBytes (final byte[] randomBytes, final int offset)
      +  {
      +    if (randomBytes.length - offset < RANDOM_LENGTH)
      +      throw new IllegalArgumentException ("random value too short");
      +    buffer.position (4);
      +    buffer.put (randomBytes, offset, RANDOM_LENGTH);
      +  }
      +
      +  public String toString (final String prefix)
      +  {
      +    StringWriter str = new StringWriter();
      +    PrintWriter out = new PrintWriter(str);
      +    if (prefix != null)
      +      out.print (prefix);
      +    out.println("struct {");
      +    if (prefix != null)
      +      out.print (prefix);
      +    out.print ("  gmt_unix_time: ");
      +    out.print (gmtUnixTime ());
      +    out.println (";");
      +    if (prefix != null)
      +      out.print (prefix);
      +    out.print ("  random_bytes:  ");
      +    out.print (Util.toHexString (randomBytes (), ':'));
      +    out.println (";");
      +    if (prefix != null)
      +      out.print (prefix);
      +    out.print ("} Random;");
      +    return str.toString();
      +  }
      +
      +  public String toString ()
      +  {
      +    return toString (null);
      +  }
      +}
      diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Record.java b/libjava/classpath/gnu/javax/net/ssl/provider/Record.java
      new file mode 100644
      index 000000000..6f5a23ef4
      --- /dev/null
      +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Record.java
      @@ -0,0 +1,198 @@
      +/* Record.java -- A single SSL Record.
      +   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.PrintWriter;
      +import java.io.StringWriter;
      +import java.nio.ByteBuffer;
      +import java.nio.ByteOrder;
      +
      +/**
      + * A SSL/TLS record structure. An SSL record is defined to be:
      + *
      + * 
      +struct
      +{
      +  {@link ContentType}     type;
      +  {@link ProtocolVersion} version;
      +  uint16          length;
      +  opaque          fragment[TLSPlaintext.length];
      +} TLSPlaintext;
      +
      + */ +public class Record +{ + private final ByteBuffer buffer; + + public Record (final ByteBuffer buffer) + { + this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); + } + + // XXX remove + public ContentType getContentType () + { + return contentType (); + } + + /** + * Gets the content type field. + * + * @return The content type field. + */ + public ContentType contentType () + { + return ContentType.forInteger (buffer.get (0) & 0xFF); + } + + /** + * Get the fragment content, storing it into sink. + * + * @param sink The sink for the fragment bytes. + * @return The number of bytes put into sink + */ + public int fragment (final ByteBuffer sink) + { + int length = length (); + sink.put (((ByteBuffer) buffer.limit (5 + length).position (5)).slice ()); + return length; + } + + /** + * Returns the fragment field as a ByteBuffer. The returned buffer + * is shared with this object's underlying buffer, so it will share + * its attributes. For example, if the underlying buffer is + * read-only, the returned buffer will be read-only. + * + * @return The fragment buffer. + */ + public ByteBuffer fragment () + { + int length = length (); + return ((ByteBuffer) buffer.limit (5 + length).position (5)).slice (); + } + + /** + * Gets the fragment length. + * + * @return The fragment length. + */ + public int length () + { + // XXX this is different behavior than we usually want: we return the + // length field, not the total length. We should consider changing this. + return buffer.getShort (3) & 0xFFFF; + } + + /** + * Gets the protocol version field. + * + * @return The protocol version field. + */ + public ProtocolVersion version () + { + int major = buffer.get (1) & 0xFF; + int minor = buffer.get (2) & 0xFF; + return ProtocolVersion.getInstance (major, minor); + } + + /** + * Sets the content type field. + * + * @param type The content type. + * @throws java.nio.ReadOnlyBufferException If the underlying buffer + * is not writeable. + * @throws NullPointerException If type is null. + */ + public void setContentType (final ContentType type) + { + buffer.put (0, (byte) type.getValue ()); + } + + /** + * Sets the fragment length. + * + * @param length The fragment length. + * @throws java.nio.ReadOnlyBufferException If the underlying buffer + * is not writeable. + * @throws IllegalArgumentException If the length is not between 0 + * and 16384, inclusive. + */ + public void setLength (final int length) + { + if (length < 0 || length > 16384) + throw new IllegalArgumentException ("length " + length + " out of range; " + + "must be between 0 and 16384"); + buffer.putShort (3, (short) length); + } + + /** + * Sets the protocol version field. + * + * @param version The protocol version. + * @throws java.nio.ReadOnlyBufferException If the underlying buffer + * is not writeable. + * @throws NullPointerException If version is null. + */ + public void setVersion (final ProtocolVersion version) + { + buffer.put (1, (byte) version.major ()).put (2, (byte) version.minor ()); + } + + public String toString () + { + StringWriter str = new StringWriter (); + PrintWriter out = new PrintWriter (str); + out.println ("struct {"); + out.print (" type: "); + out.print (contentType ()); + out.println (";"); + out.print (" version: "); + out.print (version ()); + out.println (";"); + out.print(" length: "); + out.print(length()); + out.println(";"); + out.println (" fragment {"); + out.print (Util.hexDump (fragment (), " ")); + out.println (" };"); + out.print ("} Record;"); + return str.toString (); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SRPTrustManagerFactory.java b/libjava/classpath/gnu/javax/net/ssl/provider/SRPTrustManagerFactory.java new file mode 100644 index 000000000..c5422871d --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SRPTrustManagerFactory.java @@ -0,0 +1,223 @@ +/* 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.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/libjava/classpath/gnu/javax/net/ssl/provider/SSLContextImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLContextImpl.java new file mode 100644 index 000000000..50bbdb61b --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLContextImpl.java @@ -0,0 +1,315 @@ +/* SSLContextImpl.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.net.ssl.provider; + +import gnu.java.security.action.GetSecurityPropertyAction; +import gnu.javax.net.ssl.AbstractSessionContext; +import gnu.javax.net.ssl.NullManagerParameters; +import gnu.javax.net.ssl.PreSharedKeyManager; +import gnu.javax.net.ssl.SRPTrustManager; + +import java.security.AccessController; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.SecureRandom; +import java.security.UnrecoverableKeyException; + +import javax.net.ssl.KeyManager; +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContextSpi; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSessionContext; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.TrustManagerFactory; +import javax.net.ssl.X509ExtendedKeyManager; +import javax.net.ssl.X509TrustManager; + +/** + * Our implementation of {@link SSLContextSpi}. + * + * @author Casey Marshall (csm@gnu.org) + */ +public final class SSLContextImpl extends SSLContextSpi +{ + AbstractSessionContext serverContext; + AbstractSessionContext clientContext; + + PreSharedKeyManager pskManager; + X509ExtendedKeyManager keyManager; + X509TrustManager trustManager; + SRPTrustManager srpTrustManager; + SecureRandom random; + + public SSLContextImpl() + { + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLContextSpi#engineCreateSSLEngine() + */ + protected @Override SSLEngine engineCreateSSLEngine() + { + return engineCreateSSLEngine(null, -1); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLContextSpi#engineCreateSSLEngine(java.lang.String, int) + */ + protected @Override SSLEngine engineCreateSSLEngine(String host, int port) + { + return new SSLEngineImpl(this, host, port); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLContextSpi#engineGetClientSessionContext() + */ + protected @Override synchronized SSLSessionContext engineGetClientSessionContext() + { + if (clientContext == null) + { + try + { + clientContext = AbstractSessionContext.newInstance(); + } + catch (SSLException ssle) + { + // XXX Ignore? + } + } + return clientContext; + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLContextSpi#engineGetServerSessionContext() + */ + protected @Override synchronized SSLSessionContext engineGetServerSessionContext() + { + if (serverContext == null) + { + try + { + serverContext = AbstractSessionContext.newInstance(); + } + catch (SSLException ssle) + { + // XXX Ignore? + } + } + return serverContext; + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLContextSpi#engineGetServerSocketFactory() + */ + protected @Override SSLServerSocketFactory engineGetServerSocketFactory() + { + return new SSLServerSocketFactoryImpl(this); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLContextSpi#engineGetSocketFactory() + */ + protected @Override SSLSocketFactory engineGetSocketFactory() + { + return new SSLSocketFactoryImpl(this); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLContextSpi#engineInit(javax.net.ssl.KeyManager[], javax.net.ssl.TrustManager[], java.security.SecureRandom) + */ + protected @Override 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 X509ExtendedKeyManager) + && keyManager == null) + keyManager = (X509ExtendedKeyManager) keyManagers[i]; + if (keyManagers[i] instanceof PreSharedKeyManager + && pskManager == null) + pskManager = (PreSharedKeyManager) keyManagers[i]; + } + } + 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(); + } + } + + /** + * Create and return a default key manager. The default is the JessieX509 + * algorithm, loaded from either the jssecerts file, or the cacerts file. + * + * @return The default key manager instance. + * @throws KeyManagementException If the instance cannot be created. + */ + private X509ExtendedKeyManager defaultKeyManager() throws KeyManagementException + { + KeyManagerFactory fact = null; + try + { + fact = KeyManagerFactory.getInstance("JessieX509", "Jessie"); + } + catch (NoSuchAlgorithmException nsae) + { + throw new KeyManagementException(nsae); + } + catch (NoSuchProviderException nspe) + { + throw new KeyManagementException(nspe); + } + try + { + fact.init(null, null); + return (X509ExtendedKeyManager) fact.getKeyManagers()[0]; + } + catch (NoSuchAlgorithmException nsae) { } + catch (KeyStoreException kse) { } + catch (UnrecoverableKeyException uke) { } + catch (IllegalStateException ise) { } + + try + { + fact.init(new NullManagerParameters()); + return (X509ExtendedKeyManager) fact.getKeyManagers()[0]; + } + catch (Exception shouldNotHappen) + { + throw new Error(shouldNotHappen.toString()); + } + } + + /** + * Create and return a default trust manager. The default is the JessieX509 + * algorithm, loaded from either the jssecerts file, or the cacerts file. + * + * @return The default trust manager instance. + * @throws KeyManagementException If the instance cannot be created. + */ + private X509TrustManager defaultTrustManager() throws KeyManagementException + { + try + { + TrustManagerFactory fact = + TrustManagerFactory.getInstance("JessieX509", "Jessie"); + fact.init((KeyStore) null); + return (X509TrustManager) fact.getTrustManagers()[0]; + } + catch (NoSuchAlgorithmException nsae) + { + throw new KeyManagementException(nsae); + } + catch (NoSuchProviderException nspe) + { + throw new KeyManagementException(nspe); + } + catch (KeyStoreException kse) + { + throw new KeyManagementException(kse); + } + } + + /** + * Create a default secure PRNG. This is defined as either the algorithm + * given in the gnu.javax.net.ssl.secureRandom security + * property, or Fortuna if that property is not set. If none of these + * algorithms can be found, and instance created with the SecureRandom + * constructor is returned. + * + * @return The default secure PRNG instance. + */ + private SecureRandom defaultRandom() + { + GetSecurityPropertyAction gspa + = new GetSecurityPropertyAction("gnu.javax.net.ssl.secureRandom"); + String alg = AccessController.doPrivileged(gspa); + if (alg == null) + alg = "Fortuna"; + SecureRandom rand = null; + try + { + rand = SecureRandom.getInstance(alg); + } + catch (NoSuchAlgorithmException nsae) + { + rand = new SecureRandom(); + } + + return rand; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLEngineImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLEngineImpl.java new file mode 100644 index 000000000..b63fb2f20 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLEngineImpl.java @@ -0,0 +1,842 @@ +/* SSLEngineImpl.java -- implementation of SSLEngine. + 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.debug.Component; +import gnu.classpath.debug.SystemLogger; + +import gnu.java.security.util.ByteBufferOutputStream; +import gnu.javax.net.ssl.Session; +import gnu.javax.net.ssl.SSLRecordHandler; + +import java.nio.BufferOverflowException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.List; +import java.util.zip.DataFormatException; + +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.ShortBufferException; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLEngineResult; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLEngineResult.HandshakeStatus; +import javax.net.ssl.SSLEngineResult.Status; + +public final class SSLEngineImpl extends SSLEngine +{ + final SSLContextImpl contextImpl; + private SSLRecordHandler[] handlers; + private static final SystemLogger logger = SystemLogger.SYSTEM; + private SessionImpl session; + private InputSecurityParameters insec; + private OutputSecurityParameters outsec; + private boolean inClosed; + private boolean outClosed; + private boolean createSessions; + private boolean needClientAuth; + private boolean wantClientAuth; + private boolean initialHandshakeDone; + private AbstractHandshake handshake; + private Alert lastAlert; + private SSLEngineResult.HandshakeStatus handshakeStatus; + private boolean changeCipherSpec; + + private String[] enabledSuites; + private String[] enabledProtocols; + + /** + * We can receive any message chunked across multiple records, + * including alerts, even though all alert messages are only two + * bytes long. Handshake messages are de-chunked in the handshake + * handler, change-cipher-spec messages are always empty, and we + * don't care about chunking of application messages. + * + * This buffer will hold the incomplete alert that we receive, if + * any. + */ + private final ByteBuffer alertBuffer; + + private Mode mode; + + private enum Mode { SERVER, CLIENT } + + SSLEngineImpl (SSLContextImpl contextImpl, String host, int port) + { + super(host, port); + this.contextImpl = contextImpl; + handlers = new SSLRecordHandler[256]; + session = new SessionImpl(); + session.suite = CipherSuite.TLS_NULL_WITH_NULL_NULL; + session.version = ProtocolVersion.TLS_1_1; + byte[] sid = new byte[32]; + contextImpl.random.nextBytes(sid); + session.setId(new Session.ID(sid)); + session.setRandom(contextImpl.random); + + if (Debug.DEBUG) + logger.logv(Component.SSL_RECORD_LAYER, "generated session ID {0} with random {1}", + session.id(), contextImpl.random); + + // Begin with no encryption. + insec = new InputSecurityParameters (null, null, null, session, + CipherSuite.TLS_NULL_WITH_NULL_NULL); + outsec = new OutputSecurityParameters (null, null, null, session, + CipherSuite.TLS_NULL_WITH_NULL_NULL); + inClosed = false; + outClosed = false; + needClientAuth = false; + wantClientAuth = false; + createSessions = true; + initialHandshakeDone = false; + alertBuffer = ByteBuffer.wrap (new byte[2]); + mode = null; + lastAlert = null; + handshakeStatus = SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING; + changeCipherSpec = false; + + // Set up default protocols and suites. + enabledProtocols = new String[] { + ProtocolVersion.TLS_1_1.toString(), + ProtocolVersion.TLS_1.toString(), + ProtocolVersion.SSL_3.toString() + }; + enabledSuites = defaultSuites(); + } + + static String[] defaultSuites() + { + return new String[] { + CipherSuite.TLS_DHE_DSS_WITH_AES_256_CBC_SHA.toString(), + CipherSuite.TLS_DHE_RSA_WITH_AES_256_CBC_SHA.toString(), + CipherSuite.TLS_DH_DSS_WITH_AES_256_CBC_SHA.toString(), + CipherSuite.TLS_DH_RSA_WITH_AES_256_CBC_SHA.toString(), + CipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA.toString(), + CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA.toString(), + CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA.toString(), + CipherSuite.TLS_DH_DSS_WITH_AES_128_CBC_SHA.toString(), + CipherSuite.TLS_DH_RSA_WITH_AES_128_CBC_SHA.toString(), + CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA.toString(), + CipherSuite.TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA.toString(), + CipherSuite.TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA.toString(), + CipherSuite.TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA.toString(), + CipherSuite.TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA.toString(), + CipherSuite.TLS_RSA_WITH_3DES_EDE_CBC_SHA.toString(), + CipherSuite.TLS_RSA_WITH_RC4_128_MD5.toString(), + CipherSuite.TLS_RSA_WITH_RC4_128_SHA.toString(), + CipherSuite.TLS_DHE_DSS_WITH_DES_CBC_SHA.toString(), + CipherSuite.TLS_DHE_RSA_WITH_DES_CBC_SHA.toString(), + CipherSuite.TLS_DH_DSS_WITH_DES_CBC_SHA.toString(), + CipherSuite.TLS_DH_RSA_WITH_DES_CBC_SHA.toString(), + CipherSuite.TLS_RSA_WITH_DES_CBC_SHA.toString(), + CipherSuite.TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA.toString(), + CipherSuite.TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA.toString(), + CipherSuite.TLS_RSA_EXPORT_WITH_DES40_CBC_SHA.toString(), + CipherSuite.TLS_RSA_EXPORT_WITH_RC4_40_MD5.toString(), + CipherSuite.TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA.toString(), + CipherSuite.TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA.toString(), + CipherSuite.TLS_RSA_WITH_NULL_MD5.toString(), + CipherSuite.TLS_RSA_WITH_NULL_SHA.toString() + }; + } + + // XXX implement? + /*public void registerHandler (final int contentType, + SSLRecordHandler handler) + throws SSLException + { + if (type.equals (ContentType.CHANGE_CIPHER_SPEC) + || type.equals (ContentType.ALERT) + || type.equals (ContentType.HANDSHAKE) + || type.equals (ContentType.APPLICATION_DATA)) + throw new SSLException ("can't override handler for content type " + type); + int i = type.getValue (); + if (i < 0 || i > 255) + throw new SSLException ("illegal content type: " + type); + handlers[i] = handler; + }*/ + + @Override + public void beginHandshake () throws SSLException + { + if (Debug.DEBUG) + logger.log(Component.SSL_HANDSHAKE, "{0} handshake begins", mode); + + if (mode == null) + throw new IllegalStateException("setUseClientMode was never used"); + + switch (mode) + { + case SERVER: + if (getHandshakeStatus() != SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING) + throw new SSLException("handshake already in progress"); + try + { + handshake = new ServerHandshake(initialHandshakeDone, this); + } + catch (NoSuchAlgorithmException nsae) + { + throw new SSLException(nsae); + } + break; + + case CLIENT: + try + { + handshake = new ClientHandshake(this); + } + catch (NoSuchAlgorithmException nsae) + { + throw new SSLException(nsae); + } + break; + } + } + + @Override + public void closeInbound() + { + inClosed = true; + } + + @Override + public void closeOutbound() + { + lastAlert = new Alert(Alert.Level.WARNING, Alert.Description.CLOSE_NOTIFY); + } + + @Override + public Runnable getDelegatedTask() + { + if (handshake == null) + return null; + return handshake.getTask(); + } + + @Override + public String[] getEnabledCipherSuites() + { + return (String[]) enabledSuites.clone(); + } + + @Override + public String[] getEnabledProtocols() + { + return (String[]) enabledProtocols.clone(); + } + + @Override + public boolean getEnableSessionCreation() + { + return createSessions; + } + + @Override + public HandshakeStatus getHandshakeStatus() + { + if (handshake == null) + return HandshakeStatus.NOT_HANDSHAKING; + return handshake.status(); + } + + @Override + public boolean getNeedClientAuth() + { + return needClientAuth; + } + + @Override + public SSLSession getSession() + { + return session; + } + + @Override + public boolean getUseClientMode () + { + return (mode == Mode.CLIENT); + } + + @Override + public boolean getWantClientAuth() + { + return wantClientAuth; + } + + @Override + public boolean isInboundDone() + { + return inClosed; + } + + @Override + public boolean isOutboundDone() + { + return outClosed; + } + + @Override + public void setEnableSessionCreation(final boolean createSessions) + { + this.createSessions = createSessions; + } + + @Override + public void setEnabledCipherSuites(final String[] suites) + { + if (suites.length == 0) + throw new IllegalArgumentException("need at least one suite"); + enabledSuites = (String[]) suites.clone(); + } + + @Override + public void setEnabledProtocols(final String[] protocols) + { + if (protocols.length == 0) + throw new IllegalArgumentException("need at least one protocol"); + enabledProtocols = (String[]) protocols.clone(); + } + + @Override + public String[] getSupportedCipherSuites() + { + // XXX if we ever want to support "pluggable" cipher suites, we'll need + // to figure this out. + + return CipherSuite.availableSuiteNames().toArray(new String[0]); + } + + @Override + public String[] getSupportedProtocols() + { + return new String[] { ProtocolVersion.SSL_3.toString(), + ProtocolVersion.TLS_1.toString(), + ProtocolVersion.TLS_1_1.toString() }; + } + + @Override + public void setNeedClientAuth(final boolean needClientAuth) + { + this.needClientAuth = needClientAuth; + } + + @Override + public void setUseClientMode (final boolean clientMode) + { + if (clientMode) + mode = Mode.CLIENT; + else + mode = Mode.SERVER; + } + + public @Override void setWantClientAuth(final boolean wantClientAuth) + { + this.wantClientAuth = wantClientAuth; + } + + public @Override SSLEngineResult unwrap (final ByteBuffer source, + final ByteBuffer[] sinks, + final int offset, final int length) + throws SSLException + { + if (mode == null) + throw new IllegalStateException ("setUseClientMode was never called"); + + if (inClosed) + return new SSLEngineResult(SSLEngineResult.Status.CLOSED, + handshakeStatus, 0, 0); + + if (source.remaining() < 5) + { + return new SSLEngineResult(SSLEngineResult.Status.BUFFER_UNDERFLOW, + handshakeStatus, 0, 0); + } + + Record record = null; + boolean helloV2 = false; + + // XXX: messages may be chunked across multiple records; does this + // include the SSLv2 message? I don't think it does, but we should + // make sure. + if (!getUseClientMode() && (source.get(source.position()) & 0x80) == 0x80) + { + if (handshake == null) + beginHandshake(); + int hellolen = source.getShort(source.position()) & 0x7FFF; + this.handshake.handleV2Hello(source.slice()); + if (!insec.cipherSuite().equals (CipherSuite.TLS_NULL_WITH_NULL_NULL)) + throw new SSLException ("received SSLv2 client hello in encrypted " + + "session; this is invalid."); + if (Debug.DEBUG) + logger.log (Component.SSL_RECORD_LAYER, + "converting SSLv2 client hello to version 3 hello"); + + source.getShort(); // skip length + ClientHelloV2 v2 = new ClientHelloV2(source.slice()); + + if (Debug.DEBUG) + logger.log(Component.SSL_RECORD_LAYER, "v2 hello: {0}", v2); + + List suites = v2.cipherSpecs(); + + ClientHelloBuilder hello = new ClientHelloBuilder(); + hello.setVersion(v2.version ()); + + Random random = hello.random(); + byte[] challenge = v2.challenge(); + if (challenge.length < 32) + { + byte[] b = new byte[32]; + System.arraycopy(challenge, 0, b, b.length - challenge.length, + challenge.length); + challenge = b; + } + random.setGmtUnixTime((challenge[0] & 0xFF) << 24 + | (challenge[1] & 0xFF) << 16 + | (challenge[2] & 0xFF) << 8 + | (challenge[3] & 0xFF)); + random.setRandomBytes(challenge, 4); + + byte[] sessionId = v2.sessionId(); + hello.setSessionId(sessionId, 0, sessionId.length); + hello.setCipherSuites(suites); + ArrayList comps = new ArrayList(1); + comps.add(CompressionMethod.NULL); + hello.setCompressionMethods(comps); + + record = new Record(ByteBuffer.allocate(hello.length() + 9)); + record.setContentType(ContentType.HANDSHAKE); + record.setVersion(v2.version()); + record.setLength(hello.length() + 4); + + Handshake handshake = new Handshake(record.fragment()); + handshake.setLength(hello.length()); + handshake.setType(Handshake.Type.CLIENT_HELLO); + + handshake.bodyBuffer().put(hello.buffer()); + source.position(source.position() + hellolen); + helloV2 = true; + } + else + record = new Record(source); + + ContentType type = record.contentType (); + + if (Debug.DEBUG) + logger.log(Component.SSL_RECORD_LAYER, "input record:\n{0}", record); + + if (record.length() > session.getPacketBufferSize() - 5) + { + lastAlert = new Alert(Alert.Level.FATAL, + Alert.Description.RECORD_OVERFLOW); + throw new AlertException(lastAlert); + } + + ByteBufferOutputStream sysMsg = null; + ByteBuffer msg = null; + + int produced = 0; + try + { + // Application data will get decrypted directly into the user's + // output buffers. + if (record.contentType() == ContentType.APPLICATION_DATA) + produced = insec.decrypt(record, sinks, offset, length); + else + { + if (insec.cipherSuite() == CipherSuite.TLS_NULL_WITH_NULL_NULL) + msg = record.fragment(); + else + { + sysMsg = new ByteBufferOutputStream(); + insec.decrypt(record, sysMsg); + } + } + + // Advance the input buffer past the record we just read. + if (!helloV2) + source.position(source.position() + record.length() + 5); + } + catch (BufferOverflowException boe) + { + // We throw this if the output buffers are not large enough; signal + // the caller about this. + logger.log(Component.SSL_RECORD_LAYER, "buffer overflow when decrypting", boe); + return new SSLEngineResult(SSLEngineResult.Status.BUFFER_OVERFLOW, + handshakeStatus, 0, 0); + } + catch (IllegalBlockSizeException ibse) + { + lastAlert = new Alert(Alert.Level.FATAL, + Alert.Description.BAD_RECORD_MAC); + throw new AlertException(lastAlert, ibse); + } + catch (DataFormatException dfe) + { + lastAlert = new Alert(Alert.Level.FATAL, + Alert.Description.DECOMPRESSION_FAILURE); + throw new AlertException(lastAlert, dfe); + } + catch (MacException me) + { + lastAlert = new Alert(Alert.Level.FATAL, + Alert.Description.BAD_RECORD_MAC); + throw new AlertException(lastAlert, me); + } + catch (ShortBufferException sbe) + { + // We've messed up if this happens. + lastAlert = new Alert(Alert.Level.FATAL, + Alert.Description.INTERNAL_ERROR); + throw new AlertException(lastAlert, sbe); + } + + SSLEngineResult result = null; + + // If we need to handle the output here, do it. Otherwise, the output + // has been stored in the supplied output buffers. + if (sysMsg != null) + { + if (Debug.DEBUG) + logger.logv(Component.SSL_RECORD_LAYER, "sysmessage {0}", sysMsg); + msg = sysMsg.buffer(); + } + + if (type == ContentType.CHANGE_CIPHER_SPEC) + { + // We *may* get a partial message, even though the message is only + // one byte long. + if (msg.remaining() == 0) + { + result = new SSLEngineResult (SSLEngineResult.Status.OK, + handshakeStatus, + record.length() + 5, 0); + } + else + { + byte b = msg.get(); + if (b != 1) + throw new SSLException ("unknown ChangeCipherSpec value: " + (b & 0xFF)); + InputSecurityParameters params = handshake.getInputParams(); + logger.log (Component.SSL_RECORD_LAYER, + "switching to input security parameters {0}", + params.cipherSuite()); + insec = params; + result = new SSLEngineResult (SSLEngineResult.Status.OK, + handshakeStatus, + record.length() + 5, 0); + } + } + else if (type == ContentType.ALERT) + { + int len = 0; + if (alertBuffer.position() > 0) + { + alertBuffer.put(msg.get()); + len = 1; + } + if (Debug.DEBUG) + logger.logv(Component.SSL_RECORD_LAYER, "processing alerts {0}", + Util.wrapBuffer(msg)); + len += msg.remaining() / 2; + Alert[] alerts = new Alert[len]; + int i = 0; + if (alertBuffer.position() > 0) + { + alertBuffer.flip(); + alerts[0] = new Alert(alertBuffer); + i++; + } + while (i < alerts.length) + { + alerts[i++] = new Alert(msg.duplicate()); + msg.position(msg.position() + 2); + } + if (Debug.DEBUG) + logger.logv(Component.SSL_RECORD_LAYER, "alerts: {0}", alerts.length); + + for (i = 0; i < alerts.length; i++) + { + if (alerts[i].level() == Alert.Level.FATAL) + throw new AlertException(alerts[i], false); + if (alerts[i].description() != Alert.Description.CLOSE_NOTIFY) + logger.log(java.util.logging.Level.WARNING, + "received alert: {0}", alerts[i]); + if (alerts[i].description() == Alert.Description.CLOSE_NOTIFY) + inClosed = true; + } + + if (msg.hasRemaining()) + alertBuffer.position(0).limit(2); + + result = new SSLEngineResult (SSLEngineResult.Status.OK, + handshakeStatus, + record.length() + 5, 0); + } + else if (type == ContentType.HANDSHAKE) + { + if (handshake == null) + beginHandshake(); + try + { + handshakeStatus = handshake.handleInput(msg); + } + catch (AlertException ae) + { + lastAlert = ae.alert(); + return new SSLEngineResult(SSLEngineResult.Status.OK, + SSLEngineResult.HandshakeStatus.NEED_WRAP, + 0, 0); + } + if (Debug.DEBUG) + logger.logv(Component.SSL_HANDSHAKE, "handshake status {0}", handshakeStatus); + result = new SSLEngineResult(SSLEngineResult.Status.OK, + handshakeStatus, + record.length() + 5, + 0); + if (handshakeStatus == HandshakeStatus.FINISHED) + { + handshake = null; + handshakeStatus = HandshakeStatus.NOT_HANDSHAKING; + } + } + else if (type == ContentType.APPLICATION_DATA) + { + // Do nothing more; the application data has been put into + // the output buffers. + result = new SSLEngineResult(SSLEngineResult.Status.OK, + handshakeStatus, + record.length() + 5, + produced); + } + else + { + SSLRecordHandler handler = handlers[type.getValue()]; + if (handler != null) + { + result = new SSLEngineResult(SSLEngineResult.Status.OK, + handshakeStatus, + record.length() + 5, + 0); + } + else + throw new SSLException ("unknown content type: " + type); + } + + if (Debug.DEBUG) + logger.logv(Component.SSL_RECORD_LAYER, "return result: {0}", result); + + return result; + } + + public @Override SSLEngineResult wrap (ByteBuffer[] sources, int offset, int length, + ByteBuffer sink) + throws SSLException + { + if (mode == null) + throw new IllegalStateException ("setUseClientMode was never called"); + + if (outClosed) + return new SSLEngineResult(SSLEngineResult.Status.CLOSED, + handshakeStatus, 0, 0); + + ContentType type = null; + ByteBuffer sysMessage = null; + if (Debug.DEBUG) + logger.logv(Component.SSL_RECORD_LAYER, "wrap {0} {1} {2} {3} / {4}", + sources, offset, length, sink, getHandshakeStatus()); + if (lastAlert != null) + { + type = ContentType.ALERT; + sysMessage = ByteBuffer.allocate(2); + Alert alert = new Alert(sysMessage); + alert.setDescription(lastAlert.description()); + alert.setLevel(lastAlert.level()); + if (lastAlert.description() == Alert.Description.CLOSE_NOTIFY) + outClosed = true; + } + else if (changeCipherSpec) + { + type = ContentType.CHANGE_CIPHER_SPEC; + sysMessage = ByteBuffer.allocate(1); + sysMessage.put(0, (byte) 1); + } + else if (getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_WRAP) + { + // If we are not encrypting, optimize the handshake to fill + // the buffer directly. + if (outsec.suite() == CipherSuite.TLS_NULL_WITH_NULL_NULL) + { + int orig = sink.position(); + sink.order(ByteOrder.BIG_ENDIAN); + sink.put((byte) ContentType.HANDSHAKE.getValue()); + sink.putShort((short) session.version.rawValue()); + sink.putShort((short) 0); + handshakeStatus = handshake.handleOutput(sink); + int produced = sink.position() - orig; + sink.putShort(orig + 3, (short) (produced - 5)); + if (Debug.DEBUG) + logger.logv(Component.SSL_RECORD_LAYER, "emitting record:\n{0}", + new Record((ByteBuffer) sink.duplicate().position(orig))); + SSLEngineResult result = new SSLEngineResult(SSLEngineResult.Status.OK, + handshakeStatus, 0, produced); + + // Note, this will only happen if we transition from + // TLS_NULL_WITH_NULL_NULL *to* TLS_NULL_WITH_NULL_NULL, which + // doesn't make a lot of sense, but we support it anyway. + if (handshakeStatus == HandshakeStatus.FINISHED) + { + handshake = null; // finished with it. + handshakeStatus = HandshakeStatus.NOT_HANDSHAKING; + } + return result; + } + + // Rough guideline; XXX. + sysMessage = ByteBuffer.allocate(sink.remaining() - 2048); + type = ContentType.HANDSHAKE; + try + { + handshakeStatus = handshake.handleOutput(sysMessage); + } + catch (AlertException ae) + { + lastAlert = ae.alert(); + return new SSLEngineResult(Status.OK, + HandshakeStatus.NEED_WRAP, 0, 0); + } + sysMessage.flip(); + if (Debug.DEBUG) + logger.logv(Component.SSL_HANDSHAKE, "handshake status {0}", + handshakeStatus); + } + + int produced = 0; + int consumed = 0; + + try + { + int orig = sink.position(); + int[] inout = null; + if (sysMessage != null) + { + if (Debug.DEBUG) + logger.logv(Component.SSL_RECORD_LAYER, "encrypt system message {0} to {1}", sysMessage, sink); + inout = outsec.encrypt(new ByteBuffer[] { sysMessage }, 0, 1, + type, sink); + produced = inout[1]; + } + else + { + inout = outsec.encrypt(sources, offset, length, + ContentType.APPLICATION_DATA, sink); + consumed = inout[0]; + produced = inout[1]; + } + + if (Debug.DEBUG) + logger.logv(Component.SSL_RECORD_LAYER, "emitting record:\n{0}", + new Record((ByteBuffer) sink.duplicate().position(orig).limit(produced))); + } + catch (ShortBufferException sbe) + { + // We don't expect this to happen, except for bugs; signal an + // internal error. + lastAlert = new Alert(Alert.Level.FATAL, Alert.Description.INTERNAL_ERROR); + return new SSLEngineResult(SSLEngineResult.Status.OK, handshakeStatus, 0, 0); + } + catch (IllegalBlockSizeException ibse) + { + // We don't expect this to happen, except for bugs; signal an + // internal error. + lastAlert = new Alert(Alert.Level.FATAL, Alert.Description.INTERNAL_ERROR); + return new SSLEngineResult(SSLEngineResult.Status.OK, handshakeStatus, 0, 0); + } + catch (DataFormatException dfe) + { + // We don't expect this to happen; signal an internal error. + lastAlert = new Alert(Alert.Level.FATAL, Alert.Description.INTERNAL_ERROR); + return new SSLEngineResult(SSLEngineResult.Status.OK, handshakeStatus, 0, 0); + } + + if (lastAlert != null && lastAlert.level() == Alert.Level.FATAL) + { + AlertException ae = new AlertException(lastAlert); + lastAlert = null; + throw ae; + } + + if (changeCipherSpec) + { + outsec = handshake.getOutputParams(); + changeCipherSpec = false; + } + SSLEngineResult result + = new SSLEngineResult(outClosed ? SSLEngineResult.Status.CLOSED + : SSLEngineResult.Status.OK, + handshakeStatus, consumed, produced); + if (handshakeStatus == HandshakeStatus.FINISHED) + { + handshake = null; // done with it. + handshakeStatus = HandshakeStatus.NOT_HANDSHAKING; + } + return result; + } + + // Package-private methods. + + SessionImpl session () + { + return session; + } + + void setSession(SessionImpl session) + { + this.session = session; + } + + void changeCipherSpec() + { + changeCipherSpec = true; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLHMac.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLHMac.java new file mode 100644 index 000000000..002b3077f --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/SSLRSASignatureImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLRSASignatureImpl.java new file mode 100644 index 000000000..105b4d5d7 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLRSASignatureImpl.java @@ -0,0 +1,234 @@ +/* SSLRSASignatureImpl.java -- SSL/TLS RSA 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 gnu.classpath.debug.Component; +import gnu.classpath.debug.SystemLogger; +import gnu.java.security.sig.rsa.RSA; + +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.InvalidParameterException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SignatureException; +import java.security.SignatureSpi; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.util.Arrays; + +/** + * An implementation of of the RSA signature algorithm; this is an RSA + * encrypted MD5 hash followed by a SHA-1 hash. + * + * @author Casey Marshall (csm@gnu.org) + */ +public class SSLRSASignatureImpl extends SignatureSpi +{ + private static final SystemLogger logger = SystemLogger.SYSTEM; + private RSAPublicKey pubkey; + private RSAPrivateKey privkey; + private final MessageDigest md5, sha; + private boolean initSign = false; + private boolean initVerify = false; + + public SSLRSASignatureImpl() throws NoSuchAlgorithmException + { + md5 = MessageDigest.getInstance("MD5"); + sha = MessageDigest.getInstance("SHA-1"); + } + + /* (non-Javadoc) + * @see java.security.SignatureSpi#engineInitVerify(java.security.PublicKey) + */ + @Override protected void engineInitVerify(PublicKey publicKey) + throws InvalidKeyException + { + try + { + pubkey = (RSAPublicKey) publicKey; + initVerify = true; + initSign = false; + privkey = null; + } + catch (ClassCastException cce) + { + throw new InvalidKeyException(cce); + } + } + + /* (non-Javadoc) + * @see java.security.SignatureSpi#engineInitSign(java.security.PrivateKey) + */ + @Override protected void engineInitSign(PrivateKey privateKey) + throws InvalidKeyException + { + try + { + privkey = (RSAPrivateKey) privateKey; + initSign = true; + initVerify = false; + pubkey = null; + } + catch (ClassCastException cce) + { + throw new InvalidKeyException(cce); + } + } + + /* (non-Javadoc) + * @see java.security.SignatureSpi#engineUpdate(byte) + */ + @Override protected void engineUpdate(byte b) throws SignatureException + { + if (!initSign && !initVerify) + throw new IllegalStateException("not initialized"); + if (Debug.DEBUG) + logger.log(Component.SSL_HANDSHAKE, "SSL/RSA update 0x{0}", + Util.formatInt(b & 0xFF, 16, 2)); + md5.update(b); + sha.update(b); + } + + /* (non-Javadoc) + * @see java.security.SignatureSpi#engineUpdate(byte[], int, int) + */ + @Override protected void engineUpdate(byte[] b, int off, int len) + throws SignatureException + { + if (!initSign && !initVerify) + throw new IllegalStateException("not initialized"); + if (Debug.DEBUG) + logger.log(Component.SSL_HANDSHAKE, "SSL/RSA update\n{0}", + Util.hexDump(b, off, len, ">> ")); + md5.update(b, off, len); + sha.update(b, off, len); + } + + /* (non-Javadoc) + * @see java.security.SignatureSpi#engineSign() + */ + @Override protected byte[] engineSign() throws SignatureException + { + // FIXME we need to add RSA blinding to this, somehow. + + if (!initSign) + throw new SignatureException("not initialized for signing"); + // 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 SignatureException("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); + } + + /* (non-Javadoc) + * @see java.security.SignatureSpi#engineVerify(byte[]) + */ + @Override protected boolean engineVerify(byte[] sigBytes) + throws SignatureException + { + if (!initVerify) + throw new SignatureException("not initialized for verifying"); + + // Public-key decrypt the signature representative. + BigInteger EM = new BigInteger(1, (byte[]) sigBytes); + 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 SignatureException("bad padding"); + } + } + i++; + } + else + { + throw new SignatureException("decryption failed"); + } + byte[] d1 = Util.trim(eb, i, eb.length - i); + byte[] d2 = Util.concat(md5.digest(), sha.digest()); + if (Debug.DEBUG) + logger.logv(Component.SSL_HANDSHAKE, "SSL/RSA d1:{0} d2:{1}", + Util.toHexString(d1, ':'), Util.toHexString(d2, ':')); + return Arrays.equals(d1, d2); + } + + /* (non-Javadoc) + * @see java.security.SignatureSpi#engineSetParameter(java.lang.String, java.lang.Object) + */ + @Override protected void engineSetParameter(String param, Object value) + throws InvalidParameterException + { + throw new InvalidParameterException("parameters not supported"); + } + + /* (non-Javadoc) + * @see java.security.SignatureSpi#engineGetParameter(java.lang.String) + */ + @Override protected Object engineGetParameter(String param) + throws InvalidParameterException + { + throw new InvalidParameterException("parameters not supported"); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLRandom.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLRandom.java new file mode 100644 index 000000000..0b28f1044 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketFactoryImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketFactoryImpl.java new file mode 100644 index 000000000..67620d173 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketFactoryImpl.java @@ -0,0 +1,108 @@ +/* SSLServerSocketFactoryImpl.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.net.ssl.provider; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; + +import javax.net.ssl.SSLServerSocketFactory; + +/** + * @author Casey Marshall (csm@gnu.org) + */ +public class SSLServerSocketFactoryImpl extends SSLServerSocketFactory +{ + private final SSLContextImpl contextImpl; + + public SSLServerSocketFactoryImpl(SSLContextImpl contextImpl) + { + this.contextImpl = contextImpl; + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLServerSocketFactory#getDefaultCipherSuites() + */ + @Override public String[] getDefaultCipherSuites() + { + return SSLEngineImpl.defaultSuites(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLServerSocketFactory#getSupportedCipherSuites() + */ + @Override public String[] getSupportedCipherSuites() + { + return CipherSuite.availableSuiteNames().toArray(new String[0]); + } + + /* (non-Javadoc) + * @see javax.net.ServerSocketFactory#createServerSocket(int) + */ + @Override public SSLServerSocketImpl createServerSocket(int port) + throws IOException + { + SSLServerSocketImpl socket = new SSLServerSocketImpl(contextImpl); + socket.bind(new InetSocketAddress(port)); + return socket; + } + + /* (non-Javadoc) + * @see javax.net.ServerSocketFactory#createServerSocket(int, int) + */ + @Override public SSLServerSocketImpl createServerSocket(int port, int backlog) + throws IOException + { + SSLServerSocketImpl socket = new SSLServerSocketImpl(contextImpl); + socket.bind(new InetSocketAddress(port), backlog); + return socket; + } + + /* (non-Javadoc) + * @see javax.net.ServerSocketFactory#createServerSocket(int, int, java.net.InetAddress) + */ + @Override public SSLServerSocketImpl createServerSocket(int port, int backlog, + InetAddress bindAddress) + throws IOException + { + SSLServerSocketImpl socket = new SSLServerSocketImpl(contextImpl); + socket.bind(new InetSocketAddress(bindAddress, port), backlog); + return socket; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketImpl.java new file mode 100644 index 000000000..5b07017f0 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketImpl.java @@ -0,0 +1,199 @@ +/* SSLServerSocketImpl.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.net.ssl.provider; + +import java.io.IOException; + +import javax.net.ssl.SSLServerSocket; + +/** + * @author Casey Marshall (csm@gnu.org) + */ +public class SSLServerSocketImpl extends SSLServerSocket +{ + private final SSLContextImpl contextImpl; + + private boolean enableSessionCreation; + private String[] enabledCipherSuites; + private String[] enabledProtocols; + private boolean needClientAuth; + private boolean wantClientAuth; + private boolean clientMode; + + public SSLServerSocketImpl(SSLContextImpl contextImpl) throws IOException + { + super(); + this.contextImpl = contextImpl; + enableSessionCreation = true; + enabledCipherSuites = SSLEngineImpl.defaultSuites(); + enabledProtocols = new String[] { ProtocolVersion.SSL_3.toString(), + ProtocolVersion.TLS_1.toString(), + ProtocolVersion.TLS_1_1.toString() }; + needClientAuth = false; + wantClientAuth = false; + clientMode = false; + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLServerSocket#getEnableSessionCreation() + */ + @Override public boolean getEnableSessionCreation() + { + return enableSessionCreation; + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLServerSocket#getEnabledCipherSuites() + */ + @Override public String[] getEnabledCipherSuites() + { + return (String[]) enabledCipherSuites.clone(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLServerSocket#getEnabledProtocols() + */ + @Override public String[] getEnabledProtocols() + { + return (String[]) enabledProtocols.clone(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLServerSocket#getNeedClientAuth() + */ + @Override public boolean getNeedClientAuth() + { + return needClientAuth; + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLServerSocket#getSupportedCipherSuites() + */ + @Override public String[] getSupportedCipherSuites() + { + return CipherSuite.availableSuiteNames().toArray(new String[0]); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLServerSocket#getSupportedProtocols() + */ + @Override public String[] getSupportedProtocols() + { + return new String[] { ProtocolVersion.SSL_3.toString(), + ProtocolVersion.TLS_1.toString(), + ProtocolVersion.TLS_1_1.toString() }; + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLServerSocket#getUseClientMode() + */ + @Override public boolean getUseClientMode() + { + return clientMode; + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLServerSocket#getWantClientAuth() + */ + @Override public boolean getWantClientAuth() + { + return wantClientAuth; + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLServerSocket#setEnableSessionCreation(boolean) + */ + @Override public void setEnableSessionCreation(final boolean enabled) + { + enableSessionCreation = enabled; + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLServerSocket#setEnabledCipherSuites(java.lang.String[]) + */ + @Override public void setEnabledCipherSuites(final String[] suites) + { + enabledCipherSuites = (String[]) suites.clone(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLServerSocket#setEnabledProtocols(java.lang.String[]) + */ + @Override public void setEnabledProtocols(final String[] protocols) + { + enabledProtocols = (String[]) protocols.clone(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLServerSocket#setNeedClientAuth(boolean) + */ + @Override public void setNeedClientAuth(final boolean needAuth) + { + needClientAuth = needAuth; + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLServerSocket#setUseClientMode(boolean) + */ + @Override public void setUseClientMode(final boolean clientMode) + { + this.clientMode = clientMode; + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLServerSocket#setWantClientAuth(boolean) + */ + @Override public void setWantClientAuth(final boolean wantAuth) + { + wantClientAuth = wantAuth; + } + + @Override public SSLSocketImpl accept() throws IOException + { + SSLSocketImpl socketImpl = new SSLSocketImpl(contextImpl, null, -1); + implAccept(socketImpl); + socketImpl.setEnableSessionCreation(enableSessionCreation); + socketImpl.setEnabledCipherSuites(enabledCipherSuites); + socketImpl.setEnabledProtocols(enabledProtocols); + socketImpl.setNeedClientAuth(needClientAuth); + socketImpl.setUseClientMode(clientMode); + socketImpl.setWantClientAuth(wantClientAuth); + return socketImpl; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketFactoryImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketFactoryImpl.java new file mode 100644 index 000000000..d5dd54bce --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketFactoryImpl.java @@ -0,0 +1,143 @@ +/* SSLSocketFactoryImpl.java -- + Copyright (C) 2006, 2007 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you 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.InetSocketAddress; +import java.net.Socket; +import java.net.UnknownHostException; + +import javax.net.ssl.SSLSocketFactory; + +/** + * @author Casey Marshall (csm@gnu.org) + */ +public class SSLSocketFactoryImpl extends SSLSocketFactory +{ + /** + * The SSLContextImpl that created us. + */ + private final SSLContextImpl contextImpl; + + public SSLSocketFactoryImpl(SSLContextImpl contextImpl) + { + this.contextImpl = contextImpl; + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocketFactory#createSocket(java.net.Socket, java.lang.String, int, boolean) + */ + @Override public Socket createSocket(Socket socket, String host, int port, + boolean autoClose) + throws IOException + { + return new SSLSocketImpl(contextImpl, host, port, socket, autoClose); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocketFactory#getDefaultCipherSuites() + */ + @Override public String[] getDefaultCipherSuites() + { + return SSLEngineImpl.defaultSuites(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocketFactory#getSupportedCipherSuites() + */ + @Override public String[] getSupportedCipherSuites() + { + return CipherSuite.availableSuiteNames().toArray(new String[0]); + } + + /* (non-Javadoc) + * @see javax.net.SocketFactory#createSocket(java.lang.String, int) + */ + @Override public SSLSocketImpl createSocket(String host, int port) + throws IOException, UnknownHostException + { + return createSocket(host, port, null, 0); + } + + /* (non-Javadoc) + * @see javax.net.SocketFactory#createSocket(java.lang.String, int, java.net.InetAddress, int) + */ + @Override public SSLSocketImpl createSocket(String host, int port, + InetAddress localHost, int localPort) + throws IOException, UnknownHostException + { + SSLSocketImpl socket = new SSLSocketImpl(contextImpl, host, port); + InetSocketAddress endpoint = new InetSocketAddress(host, port); + socket.bind(new InetSocketAddress(localHost, localPort)); + socket.connect(endpoint); + return socket; + } + + /* (non-Javadoc) + * @see javax.net.SocketFactory#createSocket(java.net.InetAddress, int) + */ + @Override public SSLSocketImpl createSocket(InetAddress host, int port) + throws IOException + { + return createSocket(host, port, null, 0); + } + + /* (non-Javadoc) + * @see javax.net.SocketFactory#createSocket(java.net.InetAddress, int, java.net.InetAddress, int) + */ + @Override public SSLSocketImpl createSocket(InetAddress host, int port, + InetAddress localHost, int localPort) + throws IOException + { + SSLSocketImpl socket = new SSLSocketImpl(contextImpl, + host.getCanonicalHostName(), port); + socket.bind(new InetSocketAddress(localHost, localPort)); + socket.connect(new InetSocketAddress(host, port)); + return socket; + } + + /* (non-Javadoc) + * @see javax.net.SocketFactory#createSocket() + */ + @Override public Socket createSocket() throws IOException + { + return new SSLSocketImpl(contextImpl, null, -1, new Socket(), true); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketImpl.java new file mode 100644 index 000000000..9072c2886 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketImpl.java @@ -0,0 +1,740 @@ +/* SSLSocketImpl.java -- implementation of an SSL client 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 gnu.classpath.debug.Component; +import gnu.classpath.debug.SystemLogger; + +import java.io.DataInputStream; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketException; +import java.nio.ByteBuffer; +import java.nio.channels.SocketChannel; +import java.util.HashSet; +import java.util.Set; + +import javax.net.ssl.HandshakeCompletedEvent; +import javax.net.ssl.HandshakeCompletedListener; +import javax.net.ssl.SSLEngineResult; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLEngineResult.HandshakeStatus; +import javax.net.ssl.SSLEngineResult.Status; + +/** + * @author Casey Marshall (csm@gnu.org) + */ +public class SSLSocketImpl extends SSLSocket +{ + private class SocketOutputStream extends OutputStream + { + private final ByteBuffer buffer; + private final OutputStream out; + + SocketOutputStream() throws IOException + { + buffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]); + if (underlyingSocket != null) + out = underlyingSocket.getOutputStream(); + else + out = SSLSocketImpl.super.getOutputStream(); + } + + @Override public void write(byte[] buf, int off, int len) throws IOException + { + if (!initialHandshakeDone + || engine.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING) + { + doHandshake(); + if (handshakeException != null) + throw handshakeException; + } + + int k = 0; + while (k < len) + { + synchronized (engine) + { + int l = Math.min(len-k, getSession().getApplicationBufferSize()); + ByteBuffer in = ByteBuffer.wrap(buf, off+k, l); + SSLEngineResult result = engine.wrap(in, buffer); + if (result.getStatus() == Status.CLOSED) + return; + if (result.getStatus() != Status.OK) + throw new SSLException("unexpected SSL state " + result.getStatus()); + buffer.flip(); + out.write(buffer.array(), 0, buffer.limit()); + k += result.bytesConsumed(); + buffer.clear(); + } + } + } + + @Override public void write(int b) throws IOException + { + write(new byte[] { (byte) b }); + } + + @Override public void close() throws IOException + { + SSLSocketImpl.this.close(); + } + } + + private class SocketInputStream extends InputStream + { + private final ByteBuffer inBuffer; + private final ByteBuffer appBuffer; + private final DataInputStream in; + + SocketInputStream() throws IOException + { + inBuffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]); + inBuffer.limit(0); + appBuffer = ByteBuffer.allocate(getSession().getApplicationBufferSize()); + appBuffer.flip(); + if (underlyingSocket != null) + in = new DataInputStream(underlyingSocket.getInputStream()); + else + in = new DataInputStream(SSLSocketImpl.super.getInputStream()); + } + + @Override public int read(byte[] buf, int off, int len) throws IOException + { + if (!initialHandshakeDone || + engine.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING) + { + doHandshake(); + if (handshakeException != null) + throw handshakeException; + } + + if (!appBuffer.hasRemaining()) + { + int x = in.read(); + if (x == -1) + return -1; + inBuffer.clear(); + inBuffer.put((byte) x); + inBuffer.putInt(in.readInt()); + int reclen = inBuffer.getShort(3) & 0xFFFF; + in.readFully(inBuffer.array(), 5, reclen); + inBuffer.position(0).limit(reclen + 5); + synchronized (engine) + { + appBuffer.clear(); + SSLEngineResult result = engine.unwrap(inBuffer, appBuffer); + Status status = result.getStatus(); + if (status == Status.CLOSED && result.bytesProduced() == 0) + return -1; + } + inBuffer.compact(); + appBuffer.flip(); + } + int l = Math.min(len, appBuffer.remaining()); + appBuffer.get(buf, off, l); + return l; + } + + @Override public int read() throws IOException + { + byte[] b = new byte[1]; + if (read(b) == -1) + return -1; + return b[0] & 0xFF; + } + } + + private static final SystemLogger logger = SystemLogger.getSystemLogger(); + + private SSLEngineImpl engine; + private Set listeners; + private Socket underlyingSocket; + private boolean isHandshaking; + private IOException handshakeException; + private boolean initialHandshakeDone = false; + private final boolean autoClose; + + public SSLSocketImpl(SSLContextImpl contextImpl, String host, int port) + { + this(contextImpl, host, port, new Socket(), true); + } + + public SSLSocketImpl(SSLContextImpl contextImpl, String host, int port, + Socket underlyingSocket, boolean autoClose) + { + engine = new SSLEngineImpl(contextImpl, host, port); + engine.setUseClientMode(true); // default to client mode + listeners = new HashSet(); + this.underlyingSocket = underlyingSocket; + this.autoClose = autoClose; + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#addHandshakeCompletedListener(javax.net.ssl.HandshakeCompletedListener) + */ + @Override + public void addHandshakeCompletedListener(HandshakeCompletedListener listener) + { + listeners.add(listener); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#getEnableSessionCreation() + */ + @Override public boolean getEnableSessionCreation() + { + return engine.getEnableSessionCreation(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#getEnabledCipherSuites() + */ + @Override public String[] getEnabledCipherSuites() + { + return engine.getEnabledCipherSuites(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#getEnabledProtocols() + */ + @Override public String[] getEnabledProtocols() + { + return engine.getEnabledProtocols(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#getNeedClientAuth() + */ + @Override public boolean getNeedClientAuth() + { + return engine.getNeedClientAuth(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#getSession() + */ + @Override public SSLSession getSession() + { + return engine.getSession(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#getSupportedCipherSuites() + */ + @Override public String[] getSupportedCipherSuites() + { + return engine.getSupportedCipherSuites(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#getSupportedProtocols() + */ + @Override public String[] getSupportedProtocols() + { + return engine.getSupportedProtocols(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#getUseClientMode() + */ + @Override public boolean getUseClientMode() + { + return engine.getUseClientMode(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#getWantClientAuth() + */ + @Override public boolean getWantClientAuth() + { + return engine.getWantClientAuth(); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#removeHandshakeCompletedListener(javax.net.ssl.HandshakeCompletedListener) + */ + @Override + public void removeHandshakeCompletedListener(HandshakeCompletedListener listener) + { + listeners.remove(listener); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#setEnableSessionCreation(boolean) + */ + @Override public void setEnableSessionCreation(boolean enable) + { + engine.setEnableSessionCreation(enable); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#setEnabledCipherSuites(java.lang.String[]) + */ + @Override public void setEnabledCipherSuites(String[] suites) + { + engine.setEnabledCipherSuites(suites); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#setEnabledProtocols(java.lang.String[]) + */ + @Override public void setEnabledProtocols(String[] protocols) + { + engine.setEnabledProtocols(protocols); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#setNeedClientAuth(boolean) + */ + @Override public void setNeedClientAuth(boolean needAuth) + { + engine.setNeedClientAuth(needAuth); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#setUseClientMode(boolean) + */ + @Override public void setUseClientMode(boolean clientMode) + { + engine.setUseClientMode(clientMode); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#setWantClientAuth(boolean) + */ + @Override public void setWantClientAuth(boolean wantAuth) + { + engine.setWantClientAuth(wantAuth); + } + + /* (non-Javadoc) + * @see javax.net.ssl.SSLSocket#startHandshake() + */ + @Override public void startHandshake() throws IOException + { + if (isHandshaking) + return; + + if (handshakeException != null) + throw handshakeException; + + Thread t = new Thread(new Runnable() + { + public void run() + { + try + { + doHandshake(); + } + catch (IOException ioe) + { + handshakeException = ioe; + } + } + }, "HandshakeThread@" + System.identityHashCode(this)); + t.start(); + } + + void doHandshake() throws IOException + { + synchronized (engine) + { + if (isHandshaking) + { + try + { + engine.wait(); + } + catch (InterruptedException ie) + { + } + return; + } + isHandshaking = true; + } + + if (initialHandshakeDone) + throw new SSLException("rehandshaking not yet implemented"); + + long now = -System.currentTimeMillis(); + engine.beginHandshake(); + + HandshakeStatus status = engine.getHandshakeStatus(); + assert(status != HandshakeStatus.NOT_HANDSHAKING); + + ByteBuffer inBuffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]); + inBuffer.position(inBuffer.limit()); + ByteBuffer outBuffer = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]); + ByteBuffer emptyBuffer = ByteBuffer.allocate(0); + SSLEngineResult result = null; + + DataInputStream sockIn = new DataInputStream(underlyingSocket.getInputStream()); + OutputStream sockOut = underlyingSocket.getOutputStream(); + + try + { + while (status != HandshakeStatus.NOT_HANDSHAKING + && status != HandshakeStatus.FINISHED) + { + logger.logv(Component.SSL_HANDSHAKE, "socket processing state {0}", + status); + + if (inBuffer.capacity() != getSession().getPacketBufferSize()) + { + ByteBuffer b + = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]); + if (inBuffer.hasRemaining()) + b.put(inBuffer).flip(); + inBuffer = b; + } + if (outBuffer.capacity() != getSession().getPacketBufferSize()) + outBuffer + = ByteBuffer.wrap(new byte[getSession().getPacketBufferSize()]); + + switch (status) + { + case NEED_UNWRAP: + // Read in a single SSL record. + inBuffer.clear(); + int i = sockIn.read(); + if (i == -1) + throw new EOFException(); + if ((i & 0x80) == 0x80) // SSLv2 client hello. + { + inBuffer.put((byte) i); + int v2len = (i & 0x7f) << 8; + i = sockIn.read(); + v2len = v2len | (i & 0xff); + inBuffer.put((byte) i); + sockIn.readFully(inBuffer.array(), 2, v2len); + inBuffer.position(0).limit(v2len + 2); + } + else + { + inBuffer.put((byte) i); + inBuffer.putInt(sockIn.readInt()); + int reclen = inBuffer.getShort(3) & 0xFFFF; + sockIn.readFully(inBuffer.array(), 5, reclen); + inBuffer.position(0).limit(reclen + 5); + } + result = engine.unwrap(inBuffer, emptyBuffer); + status = result.getHandshakeStatus(); + if (result.getStatus() != Status.OK) + throw new SSLException("unexpected SSL status " + + result.getStatus()); + break; + + case NEED_WRAP: + { + outBuffer.clear(); + result = engine.wrap(emptyBuffer, outBuffer); + status = result.getHandshakeStatus(); + if (result.getStatus() != Status.OK) + throw new SSLException("unexpected SSL status " + + result.getStatus()); + outBuffer.flip(); + sockOut.write(outBuffer.array(), outBuffer.position(), + outBuffer.limit()); + } + break; + + case NEED_TASK: + { + Runnable task; + while ((task = engine.getDelegatedTask()) != null) + task.run(); + status = engine.getHandshakeStatus(); + } + break; + + case FINISHED: + break; + } + } + + initialHandshakeDone = true; + + HandshakeCompletedEvent hce = new HandshakeCompletedEvent(this, getSession()); + for (HandshakeCompletedListener l : listeners) + { + try + { + l.handshakeCompleted(hce); + } + catch (ThreadDeath td) + { + throw td; + } + catch (Throwable x) + { + logger.log(Component.WARNING, + "HandshakeCompletedListener threw exception", x); + } + } + + now += System.currentTimeMillis(); + if (Debug.DEBUG) + logger.logv(Component.SSL_HANDSHAKE, + "handshake completed in {0}ms in thread {1}", now, + Thread.currentThread().getName()); + } + catch (SSLException ssle) + { + handshakeException = ssle; + throw ssle; + } + finally + { + synchronized (engine) + { + isHandshaking = false; + engine.notifyAll(); + } + } + } + + // Methods overriding Socket. + + @Override public void bind(SocketAddress bindpoint) throws IOException + { + underlyingSocket.bind(bindpoint); + } + + @Override public void connect(SocketAddress endpoint) throws IOException + { + underlyingSocket.connect(endpoint); + } + + @Override public void connect(SocketAddress endpoint, int timeout) + throws IOException + { + underlyingSocket.connect(endpoint, timeout); + } + + @Override public InetAddress getInetAddress() + { + return underlyingSocket.getInetAddress(); + } + + @Override public InetAddress getLocalAddress() + { + return underlyingSocket.getLocalAddress(); + } + + @Override public int getPort() + { + return underlyingSocket.getPort(); + } + + @Override public int getLocalPort() + { + return underlyingSocket.getLocalPort(); + } + + @Override public SocketAddress getRemoteSocketAddress() + { + return underlyingSocket.getRemoteSocketAddress(); + } + + public SocketAddress getLocalSocketAddress() + { + return underlyingSocket.getLocalSocketAddress(); + } + + @Override public SocketChannel getChannel() + { + throw new UnsupportedOperationException("use javax.net.ssl.SSLEngine for NIO"); + } + + @Override public InputStream getInputStream() throws IOException + { + return new SocketInputStream(); + } + + @Override public OutputStream getOutputStream() throws IOException + { + return new SocketOutputStream(); + } + + @Override public void setTcpNoDelay(boolean on) throws SocketException + { + underlyingSocket.setTcpNoDelay(on); + } + + @Override public boolean getTcpNoDelay() throws SocketException + { + return underlyingSocket.getTcpNoDelay(); + } + + @Override public void setSoLinger(boolean on, int linger) throws SocketException + { + underlyingSocket.setSoLinger(on, linger); + } + + public int getSoLinger() throws SocketException + { + return underlyingSocket.getSoLinger(); + } + + @Override public void sendUrgentData(int x) throws IOException + { + throw new UnsupportedOperationException("not supported"); + } + + @Override public void setOOBInline(boolean on) throws SocketException + { + underlyingSocket.setOOBInline(on); + } + + @Override public boolean getOOBInline() throws SocketException + { + return underlyingSocket.getOOBInline(); + } + + @Override public void setSoTimeout(int timeout) throws SocketException + { + underlyingSocket.setSoTimeout(timeout); + } + + @Override public int getSoTimeout() throws SocketException + { + return underlyingSocket.getSoTimeout(); + } + + @Override public void setSendBufferSize(int size) throws SocketException + { + underlyingSocket.setSendBufferSize(size); + } + + @Override public int getSendBufferSize() throws SocketException + { + return underlyingSocket.getSendBufferSize(); + } + + @Override public void setReceiveBufferSize(int size) throws SocketException + { + underlyingSocket.setReceiveBufferSize(size); + } + + @Override public int getReceiveBufferSize() throws SocketException + { + return underlyingSocket.getReceiveBufferSize(); + } + + @Override public void setKeepAlive(boolean on) throws SocketException + { + underlyingSocket.setKeepAlive(on); + } + + @Override public boolean getKeepAlive() throws SocketException + { + return underlyingSocket.getKeepAlive(); + } + + @Override public void setTrafficClass(int tc) throws SocketException + { + underlyingSocket.setTrafficClass(tc); + } + + @Override public int getTrafficClass() throws SocketException + { + return underlyingSocket.getTrafficClass(); + } + + @Override public void setReuseAddress(boolean reuseAddress) + throws SocketException + { + underlyingSocket.setReuseAddress(reuseAddress); + } + + @Override public boolean getReuseAddress() throws SocketException + { + return underlyingSocket.getReuseAddress(); + } + + @Override public void close() throws IOException + { + // XXX closure alerts. + if (autoClose) + underlyingSocket.close(); + } + + @Override public void shutdownInput() throws IOException + { + underlyingSocket.shutdownInput(); + } + + @Override public void shutdownOutput() throws IOException + { + underlyingSocket.shutdownOutput(); + } + + @Override public boolean isConnected() + { + return underlyingSocket.isConnected(); + } + + @Override public boolean isBound() + { + return underlyingSocket.isBound(); + } + + @Override public boolean isClosed() + { + return underlyingSocket.isClosed(); + } + + @Override public boolean isInputShutdown() + { + return underlyingSocket.isInputShutdown(); + } + + @Override public boolean isOutputShutdown() + { + return underlyingSocket.isOutputShutdown(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLv3HMacMD5Impl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLv3HMacMD5Impl.java new file mode 100644 index 000000000..5ef84ca1c --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLv3HMacMD5Impl.java @@ -0,0 +1,116 @@ +/* SSLv3HMacMD5.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.net.ssl.provider; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.spec.AlgorithmParameterSpec; +import java.util.Collections; +import java.util.Map; + +import javax.crypto.MacSpi; +import javax.crypto.SecretKey; + +/** + * @author csm + */ +public class SSLv3HMacMD5Impl extends MacSpi +{ + private final SSLHMac adaptee; + + public SSLv3HMacMD5Impl() + { + adaptee = new SSLHMac("MD5"); + } + + /* (non-Javadoc) + * @see javax.crypto.MacSpi#engineDoFinal() + */ + @Override protected byte[] engineDoFinal() + { + return adaptee.digest(); + } + + /* (non-Javadoc) + * @see javax.crypto.MacSpi#engineGetMacLength() + */ + @Override protected int engineGetMacLength() + { + return adaptee.macSize(); + } + + /* (non-Javadoc) + * @see javax.crypto.MacSpi#engineInit(java.security.Key, java.security.spec.AlgorithmParameterSpec) + */ + @Override protected void engineInit(Key key, AlgorithmParameterSpec params) + throws InvalidAlgorithmParameterException, InvalidKeyException + { + if (!(key instanceof SecretKey) + || !key.getAlgorithm().equalsIgnoreCase("SSLv3HMac-MD5")) + throw new InvalidKeyException("expecting secret key with algorithm \"SSLv3HMac-MD5\""); + Map attr = + Collections.singletonMap(SSLHMac.MAC_KEY_MATERIAL, key.getEncoded()); + adaptee.init(attr); + } + + /* (non-Javadoc) + * @see javax.crypto.MacSpi#engineReset() + */ + @Override protected void engineReset() + { + adaptee.reset(); + } + + /* (non-Javadoc) + * @see javax.crypto.MacSpi#engineUpdate(byte) + */ + @Override protected void engineUpdate(byte input) + { + adaptee.update(input); + } + + /* (non-Javadoc) + * @see javax.crypto.MacSpi#engineUpdate(byte[], int, int) + */ + @Override protected void engineUpdate(byte[] input, int offset, int length) + { + adaptee.update(input, offset, length); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SSLv3HMacSHAImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SSLv3HMacSHAImpl.java new file mode 100644 index 000000000..6b9c9e9cc --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SSLv3HMacSHAImpl.java @@ -0,0 +1,116 @@ +/* SSLv3HMacSHA.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.net.ssl.provider; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.spec.AlgorithmParameterSpec; +import java.util.Collections; +import java.util.Map; + +import javax.crypto.MacSpi; +import javax.crypto.SecretKey; + +/** + * @author csm + */ +public class SSLv3HMacSHAImpl extends MacSpi +{ + private final SSLHMac adaptee; + + public SSLv3HMacSHAImpl() + { + adaptee = new SSLHMac("SHA-160"); + } + + /* (non-Javadoc) + * @see javax.crypto.MacSpi#engineDoFinal() + */ + @Override protected byte[] engineDoFinal() + { + return adaptee.digest(); + } + + /* (non-Javadoc) + * @see javax.crypto.MacSpi#engineGetMacLength() + */ + @Override protected int engineGetMacLength() + { + return adaptee.macSize(); + } + + /* (non-Javadoc) + * @see javax.crypto.MacSpi#engineInit(java.security.Key, java.security.spec.AlgorithmParameterSpec) + */ + @Override protected void engineInit(Key key, AlgorithmParameterSpec params) + throws InvalidAlgorithmParameterException, InvalidKeyException + { + if (!(key instanceof SecretKey) + || !key.getAlgorithm().equalsIgnoreCase("SSLv3HMac-SHA")) + throw new InvalidKeyException("expecting secret key with algorithm \"SSLv3HMac-SHA\""); + Map attr = + Collections.singletonMap(SSLHMac.MAC_KEY_MATERIAL, key.getEncoded()); + adaptee.init(attr); + } + + /* (non-Javadoc) + * @see javax.crypto.MacSpi#engineReset() + */ + @Override protected void engineReset() + { + adaptee.reset(); + } + + /* (non-Javadoc) + * @see javax.crypto.MacSpi#engineUpdate(byte) + */ + @Override protected void engineUpdate(byte input) + { + adaptee.update(input); + } + + /* (non-Javadoc) + * @see javax.crypto.MacSpi#engineUpdate(byte[], int, int) + */ + @Override protected void engineUpdate(byte[] input, int offset, int length) + { + adaptee.update(input, offset, length); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java new file mode 100644 index 000000000..1de3f8124 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java @@ -0,0 +1,148 @@ +/* ServerDHE_PSKParameters.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.net.ssl.provider; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.charset.Charset; + +/** + *

      +      struct {
      +          select (KeyExchangeAlgorithm) {
      +              /* other cases for rsa, diffie_hellman, etc. */
      +              case diffie_hellman_psk:  /* NEW */
      +                  opaque psk_identity_hint<0..2^16-1>;
      +                  ServerDHParams params;
      +          };
      +      } ServerKeyExchange;
      + * + * @author Casey Marshall (csm@gnu.org) + */ +public class ServerDHE_PSKParameters implements Constructed, Builder, ServerKeyExchangeParams +{ + private ByteBuffer buffer; + + public ServerDHE_PSKParameters(ByteBuffer buffer) + { + this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); + } + + public ServerDHE_PSKParameters(String identityHint, ServerDHParams dhParams) + { + this(identityHint, dhParams.buffer()); + } + + public ServerDHE_PSKParameters(String identityHint, ByteBuffer dhParams) + { + Charset utf8 = Charset.forName("UTF-8"); + ByteBuffer hintBuf = utf8.encode(identityHint); + buffer = ByteBuffer.allocate(2 + hintBuf.remaining() + dhParams.remaining()); + buffer.putShort((short) hintBuf.remaining()); + buffer.put(hintBuf); + buffer.put(dhParams); + } + + public KeyExchangeAlgorithm algorithm() + { + return KeyExchangeAlgorithm.DHE_PSK; + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Constructed#length() + */ + public int length() + { + return (buffer.getShort(0) & 0xFFFF) + 2 + params().length(); + } + + private int hintLength() + { + return (buffer.getShort(0) & 0xFFFF) + 2; + } + + public String identityHint() + { + Charset utf8 = Charset.forName("UTF-8"); + return utf8.decode((ByteBuffer) buffer.duplicate().position(2).limit + (hintLength())).toString(); + } + + public ServerDHParams params() + { + return new ServerDHParams(((ByteBuffer) buffer.duplicate().position + (hintLength()).limit(buffer.capacity())).slice()); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Builder#buffer() + */ + public ByteBuffer buffer() + { + return (ByteBuffer) buffer.duplicate().rewind().limit(length()); + } + + public @Override String toString() + { + return toString(null); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Constructed#toString(java.lang.String) + */ + public String toString(String prefix) + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + if (prefix != null) out.print(prefix); + out.println("struct {"); + if (prefix != null) out.print(prefix); + out.print(" identity_hint = "); + out.print(identityHint()); + out.println(";"); + if (prefix != null) out.print(prefix); + out.println(" params ="); + out.println(params().toString(prefix != null ? prefix + " " : " ")); + if (prefix != null) out.print(prefix); + out.print("} ServerDHE_PSKParameters;"); + return str.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerDHParams.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerDHParams.java new file mode 100644 index 000000000..0e2c34881 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerDHParams.java @@ -0,0 +1,248 @@ +/* ServerDHParams.java -- The server's Diffie-Hellman 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.PrintWriter; +import java.io.StringWriter; +import java.math.BigInteger; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * The server's Diffie-Hellman parameters message. + * + *
      +struct
      +{
      +  opaque dh_p<1..2^16-1>;
      +  opaque dh_g<1..2^16-1>;
      +  opaque dh_Ys<1..2^16-1>;
      +} ServerDHParams;
      +
      + */ +public class ServerDHParams implements Builder, ServerKeyExchangeParams +{ + private final ByteBuffer buffer; + + public ServerDHParams (final ByteBuffer buffer) + { + this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); + } + + public ServerDHParams (final BigInteger p, final BigInteger g, + final BigInteger y) + { + byte[] p_bytes = p.toByteArray(); + byte[] g_bytes = g.toByteArray(); + byte[] y_bytes = y.toByteArray(); + int len = p_bytes.length + g_bytes.length + y_bytes.length + 6; + + int p_off = 0; + if (p_bytes[0] == 0x00) + { + p_off = 1; + len--; + } + int g_off = 0; + if (g_bytes[0] == 0x00) + { + g_off = 1; + len--; + } + int y_off = 0; + if (y_bytes[0] == 0x00) + { + y_off = 1; + len--; + } + int p_len = p_bytes.length - p_off; + int g_len = g_bytes.length - g_off; + int y_len = y_bytes.length - y_off; + + buffer = ByteBuffer.allocate(len); + buffer.putShort((short) p_len); + buffer.put(p_bytes, p_off, p_len); + buffer.putShort((short) g_len); + buffer.put(g_bytes, g_off, g_len); + buffer.putShort((short) y_len); + buffer.put(y_bytes, y_off, y_len); + } + + @Deprecated public KeyExchangeAlgorithm algorithm () + { + return null; // XXX can't support this. + } + + public int length () + { + int offset1 = buffer.getShort (0) & 0xFFFF; + int offset2 = buffer.getShort (offset1 + 2) & 0xFFFF; + return ((buffer.getShort (offset1 + offset2 + 4) & 0xFFFF) + + offset1 + offset2 + 6); + } + + public ByteBuffer buffer() + { + return (ByteBuffer) buffer.duplicate().position(0).limit(length()); + } + + /** + * Returns the server's prime modulus. + * + * @return p. + */ + public BigInteger p () + { + int len = buffer.getShort (0) & 0xFFFF; + byte[] buf = new byte[len]; + buffer.position (2); + buffer.get (buf); + return new BigInteger (1, buf); + } + + /** + * Returns the server's generator value. + * + * @return g. + */ + public BigInteger g () + { + int off = (buffer.getShort (0) & 0xFFFF) + 2; + int len = buffer.getShort (off) & 0xFFFF; + byte[] buf = new byte[len]; + buffer.position (off + 2); + buffer.get (buf); + return new BigInteger (1, buf); + } + + /** + * Returns the server's public value. + * + * @return Y. + */ + public BigInteger y () + { + int offset1 = (buffer.getShort (0) & 0xFFFF) + 2; + int offset2 = (buffer.getShort (offset1) & 0xFFFF) + offset1 + 2; + int len = buffer.getShort (offset2) & 0xFFFF; + byte[] buf = new byte[len]; + buffer.position (offset2 + 2); + buffer.get (buf); + return new BigInteger (1, buf); + } + + /** + * Sets the server's prime modulus, p. + * + * @param p The p parameter. + * @throws java.nio.ReadOnlyBufferException If the underlying buffer + * is not writeable. + */ + public void setP (final BigInteger p) + { + byte[] buf = p.toByteArray (); + int length = (buf[0] == 0x00 ? buf.length - 1 : buf.length); + int offset = (buf[0] == 0x00 ? 1 : 0); + buffer.putShort (0, (short) length); + buffer.position (2); + buffer.put (buf, offset, length); + } + + /** + * Sets the server's generator value, g. + * + * @param g The g parameter. + * @throws java.nio.ReadOnlyBufferException If the underlying buffer + * is not writeable. + */ + public void setG (final BigInteger g) + { + byte[] buf = g.toByteArray (); + int length = (buf[0] == 0x00 ? buf.length -1 : buf.length); + int offset = (buf[0] == 0x00 ? 1 : 0); + int where = (buffer.getShort (0) & 0xFFFF) + 2; + buffer.putShort (where, (short) length); + buffer.position (where + 2); + buffer.put (buf, offset, length); + } + + /** + * Sets the server's public value, Y. + * + * @param y The Y parameter. + * @throws java.nio.ReadOnlyBufferException If the underlying buffer + * is not writeable. + */ + public void setY (final BigInteger y) + { + int offset1 = (buffer.getShort (0) & 0xFFFF) + 2; + int offset2 = (buffer.getShort (offset1) & 0xFFFF) + offset1 + 2; + byte[] buf = y.toByteArray (); + int length = (buf[0] == 0x00 ? buf.length -1 : buf.length); + int offset = (buf[0] == 0x00 ? 1 : 0); + buffer.putShort (offset2, (short) length); + buffer.position (offset2 + 2); + buffer.put (buf, offset, length); + } + + public String toString () + { + return toString (null); + } + + public String toString (final String prefix) + { + StringWriter str = new StringWriter (); + PrintWriter out = new PrintWriter (str); + if (prefix != null) out.print (prefix); + out.println ("struct {"); + if (prefix != null) out.print (prefix); + out.print (" dh_p: "); + out.println (p ().toString (16)); + if (prefix != null) out.print (prefix); + out.print (" dh_g: "); + out.println (g ().toString (16)); + if (prefix != null) out.print (prefix); + out.print (" dh_Ys: "); + out.println (y ().toString (16)); + if (prefix != null) out.print (prefix); + out.print ("} ServerDHParams;"); + return str.toString (); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerHandshake.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerHandshake.java new file mode 100644 index 000000000..d69fa120d --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerHandshake.java @@ -0,0 +1,1377 @@ +/* ServerHandshake.java -- the server-side handshake. + 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 static gnu.javax.net.ssl.provider.Handshake.Type.*; +import static gnu.javax.net.ssl.provider.KeyExchangeAlgorithm.*; +import static gnu.javax.net.ssl.provider.ServerHandshake.State.*; + +import gnu.classpath.debug.Component; +import gnu.java.security.action.GetSecurityPropertyAction; +import gnu.javax.crypto.key.dh.GnuDHPublicKey; +import gnu.javax.net.ssl.AbstractSessionContext; +import gnu.javax.net.ssl.Session; +import gnu.javax.net.ssl.provider.Alert.Description; +import gnu.javax.net.ssl.provider.CertificateRequest.ClientCertificateType; + +import java.nio.ByteBuffer; + +import java.security.AccessController; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.KeyManagementException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.Principal; +import java.security.PrivateKey; +import java.security.SignatureException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.logging.Level; +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.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.interfaces.DHPrivateKey; +import javax.crypto.interfaces.DHPublicKey; +import javax.crypto.spec.DHParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.SSLSession; +import javax.net.ssl.X509ExtendedKeyManager; +import javax.net.ssl.SSLEngineResult.HandshakeStatus; +import javax.security.auth.x500.X500Principal; + +class ServerHandshake extends AbstractHandshake +{ + /** + * Handshake state enumeration. + */ + static enum State + { + WRITE_HELLO_REQUEST (true, false), + WRITE_SERVER_HELLO (true, false), + WRITE_CERTIFICATE (true, false), + WRITE_SERVER_KEY_EXCHANGE (true, false), + WRITE_CERTIFICATE_REQUEST (true, false), + WRITE_SERVER_HELLO_DONE (true, false), + WRITE_FINISHED (true, false), + READ_CLIENT_HELLO (false, true), + READ_CERTIFICATE (false, true), + READ_CLIENT_KEY_EXCHANGE (false, true), + READ_CERTIFICATE_VERIFY (false, true), + READ_FINISHED (false, true), + DONE (false, false); + + private final boolean isWriteState; + private final boolean isReadState; + + private State(final boolean isWriteState, final boolean isReadState) + { + this.isWriteState = isWriteState; + this.isReadState = isReadState; + } + + boolean isReadState() + { + return isReadState; + } + + boolean isWriteState() + { + return isWriteState; + } + } + + private State state; + + /* Handshake result fields. */ + private ByteBuffer outBuffer; + private boolean clientHadExtensions = false; + private boolean continuedSession = false; + private ServerNameList requestedNames = null; + private String keyAlias = null; + private X509Certificate clientCert = null; + private X509Certificate localCert = null; + private boolean helloV2 = false; + private KeyPair dhPair; + private PrivateKey serverKey; + + // Delegated tasks we use. + private GenDH genDH; + private CertVerifier certVerifier; + private CertLoader certLoader; + private DelegatedTask keyExchangeTask; + + ServerHandshake (boolean writeHelloRequest, final SSLEngineImpl engine) + throws NoSuchAlgorithmException + { + super(engine); + if (writeHelloRequest) + state = WRITE_HELLO_REQUEST; + else + state = READ_CLIENT_HELLO; + handshakeOffset = 0; + } + + /** + * Choose the protocol version. Here we choose the largest protocol + * version we support that is not greater than the client's + * requested version. + */ + private static ProtocolVersion chooseProtocol (final ProtocolVersion clientVersion, + final String[] enabledVersions) + throws SSLException + { + ProtocolVersion version = null; + for (int i = 0; i < enabledVersions.length; i++) + { + ProtocolVersion v = ProtocolVersion.forName (enabledVersions[i]); + if (v.compareTo (clientVersion) <= 0) + { + if (version == null + || v.compareTo (version) > 0) + version = v; + } + } + + // The client requested a protocol version too old, or no protocol + // versions are enabled. + if (version == null) + throw new SSLException ("no acceptable protocol version available"); + return version; + } + + /** + * Choose the first cipher suite in the client's requested list that + * we have enabled. + */ + private CipherSuite chooseSuite (final CipherSuiteList clientSuites, + final String[] enabledSuites, + final ProtocolVersion version) + throws SSLException + { + // Figure out which SignatureAlgorithms we can support. + HashSet kexes = new HashSet(8); + + kexes.add(NONE); + X509ExtendedKeyManager km = engine.contextImpl.keyManager; + if (km != null) + { + if (km.getServerAliases(DH_DSS.name(), null).length > 0) + kexes.add(DH_DSS); + if (km.getServerAliases(DH_RSA.name(), null).length > 0) + kexes.add(DH_RSA); + if (km.getServerAliases(DHE_DSS.name(), null).length > 0) + kexes.add(DHE_DSS); + if (km.getServerAliases(DHE_RSA.name(), null).length > 0) + kexes.add(DHE_RSA); + if (km.getServerAliases(RSA.name(), null).length > 0) + kexes.add(RSA); + if (km.getServerAliases(RSA_PSK.name(), null).length > 0 + && engine.contextImpl.pskManager != null) + kexes.add(RSA_PSK); + } + if (engine.contextImpl.pskManager != null) + { + kexes.add(DHE_PSK); + kexes.add(PSK); + } + + if (Debug.DEBUG) + logger.logv(Component.SSL_HANDSHAKE, + "we have certs for key exchange algorithms {0}", kexes); + + HashSet suites = new HashSet(); + for (String s : enabledSuites) + { + CipherSuite suite = CipherSuite.forName(s); + if (suite == null) + continue; + if (!kexes.contains(suite.keyExchangeAlgorithm())) + continue; + suites.add(suite); + } + for (CipherSuite suite : clientSuites) + { + CipherSuite resolved = suite.resolve(); + if (!resolved.isResolved()) + continue; + if (suites.contains(resolved)) + return resolved; + } + + // We didn't find a match? + throw new AlertException(new Alert(Alert.Level.FATAL, + Alert.Description.INSUFFICIENT_SECURITY)); + } + + /** + * Choose a compression method that we support, among the client's + * requested compression methods. We prefer ZLIB over NONE in this + * implementation. + * + * XXX Maybe consider implementing lzo (GNUTLS supports that). + */ + private static CompressionMethod chooseCompression (final CompressionMethodList comps) + throws SSLException + { + GetSecurityPropertyAction gspa + = new GetSecurityPropertyAction("jessie.enable.compression"); + String enable = AccessController.doPrivileged(gspa); + // Scan for ZLIB first. + if (Boolean.valueOf(enable)) + { + for (CompressionMethod cm : comps) + { + if (cm.equals (CompressionMethod.ZLIB)) + return CompressionMethod.ZLIB; + } + } + for (CompressionMethod cm : comps) + { + if (cm.equals (CompressionMethod.NULL)) + return CompressionMethod.NULL; + } + + throw new SSLException ("no supported compression method"); + } + + protected @Override boolean doHash() + { + boolean b = helloV2; + helloV2 = false; + return (state != WRITE_HELLO_REQUEST) && !b; + } + + public @Override HandshakeStatus implHandleInput() + throws SSLException + { + if (state == DONE) + return HandshakeStatus.FINISHED; + + if (state.isWriteState() + || (outBuffer != null && outBuffer.hasRemaining())) + return HandshakeStatus.NEED_WRAP; + + // Copy the current buffer, and prepare it for reading. + ByteBuffer buffer = handshakeBuffer.duplicate (); + buffer.flip(); + buffer.position(handshakeOffset); + Handshake handshake = new Handshake(buffer.slice(), + engine.session().suite, + engine.session().version); + + if (Debug.DEBUG) + logger.logv(Component.SSL_HANDSHAKE, "processing in state {0}:\n{1}", + state, handshake); + + switch (state) + { + // Client Hello. + // + // This message is sent by the client to initiate a new handshake. + // On a new connection, it is the first handshake message sent. + // + // The state of the handshake, after this message is processed, + // will have a protocol version, cipher suite, compression method, + // session ID, and various extensions (that the server also + // supports). + case READ_CLIENT_HELLO: + if (handshake.type () != CLIENT_HELLO) + throw new AlertException(new Alert(Alert.Level.FATAL, + Alert.Description.UNEXPECTED_MESSAGE)); + + { + ClientHello hello = (ClientHello) handshake.body (); + engine.session().version + = chooseProtocol (hello.version (), + engine.getEnabledProtocols ()); + engine.session().suite = + chooseSuite (hello.cipherSuites (), + engine.getEnabledCipherSuites (), + engine.session().version); + compression = chooseCompression (hello.compressionMethods ()); + if (Debug.DEBUG) + logger.logv(Component.SSL_HANDSHAKE, + "chose version:{0} suite:{1} compression:{2}", + engine.session().version, engine.session().suite, + compression); + clientRandom = hello.random().copy(); + byte[] sessionId = hello.sessionId(); + if (hello.hasExtensions()) + { + ExtensionList exts = hello.extensions(); + clientHadExtensions = exts.size() > 0; + for (Extension e : hello.extensions()) + { + Extension.Type type = e.type(); + if (type == null) + continue; + switch (type) + { + case TRUNCATED_HMAC: + engine.session().setTruncatedMac(true); + break; + + case MAX_FRAGMENT_LENGTH: + MaxFragmentLength len = (MaxFragmentLength) e.value(); + engine.session().maxLength = len; + engine.session().setApplicationBufferSize(len.maxLength()); + break; + + case SERVER_NAME: + requestedNames = (ServerNameList) e.value(); + List names + = new ArrayList(requestedNames.size()); + for (ServerNameList.ServerName name : requestedNames) + names.add(name.name()); + engine.session().putValue("gnu.javax.net.ssl.RequestedServerNames", names); + break; + + default: + logger.log(Level.INFO, "skipping unsupported extension {0}", e); + } + } + } + AbstractSessionContext sessions = (AbstractSessionContext) + engine.contextImpl.engineGetServerSessionContext(); + SSLSession s = sessions.getSession(sessionId); + if (Debug.DEBUG) + logger.logv(Component.SSL_HANDSHAKE, "looked up saved session {0}", s); + if (s != null && s.isValid() && (s instanceof SessionImpl)) + { + engine.setSession((SessionImpl) s); + continuedSession = true; + } + else + { + // We *may* wind up with a badly seeded PRNG, and emit the + // same session ID over and over (this did happen to me, + // so we add this sanity check just in case). + if (engine.session().id().equals(new Session.ID(sessionId))) + { + byte[] newId = new byte[32]; + engine.session().random().nextBytes(newId); + engine.session().setId(new Session.ID(newId)); + } + sessions.put(engine.session()); + } + state = WRITE_SERVER_HELLO; + } + break; + + // Certificate. + // + // This message is sent by the client if the server had previously + // requested that the client authenticate itself with a certificate, + // and if the client has an appropriate certificate available. + // + // Processing this message will save the client's certificate, + // rejecting it if the certificate is not trusted, in preparation + // for the certificate verify message that will follow. + case READ_CERTIFICATE: + { + if (handshake.type() != CERTIFICATE) + { + if (engine.getNeedClientAuth()) // XXX throw better exception. + throw new SSLException("client auth required"); + state = READ_CLIENT_KEY_EXCHANGE; + return HandshakeStatus.NEED_UNWRAP; + } + + Certificate cert = (Certificate) handshake.body(); + try + { + engine.session().setPeerVerified(false); + X509Certificate[] chain + = cert.certificates().toArray(new X509Certificate[0]); + if (chain.length == 0) + throw new CertificateException("no certificates in chain"); + certVerifier = new CertVerifier(false, chain); + tasks.add(certVerifier); + engine.session().setPeerCertificates(chain); + clientCert = chain[0]; + // Delay setting 'peerVerified' until CertificateVerify. + } + catch (CertificateException ce) + { + if (engine.getNeedClientAuth()) + { + SSLPeerUnverifiedException x + = new SSLPeerUnverifiedException("client certificates could not be verified"); + x.initCause(ce); + throw x; + } + } + catch (NoSuchAlgorithmException nsae) + { + throw new SSLException(nsae); + } + state = READ_CLIENT_KEY_EXCHANGE; + } + break; + + // Client Key Exchange. + // + // The client's key exchange. This message is sent either following + // the certificate message, or if no certificate is available or + // requested, following the server's hello done message. + // + // After receipt of this message, the session keys for this + // session will have been created. + case READ_CLIENT_KEY_EXCHANGE: + { + if (handshake.type() != CLIENT_KEY_EXCHANGE) + throw new SSLException("expecting client key exchange"); + ClientKeyExchange kex = (ClientKeyExchange) handshake.body(); + + KeyExchangeAlgorithm alg = engine.session().suite.keyExchangeAlgorithm(); + switch (alg) + { + case DHE_DSS: + case DHE_RSA: + case DH_anon: + { + ClientDiffieHellmanPublic pub = (ClientDiffieHellmanPublic) + kex.exchangeKeys(); + DHPublicKey myKey = (DHPublicKey) dhPair.getPublic(); + DHPublicKey clientKey = + new GnuDHPublicKey(null, myKey.getParams().getP(), + myKey.getParams().getG(), + pub.publicValue()); + keyExchangeTask = new DHPhase(clientKey); + tasks.add(keyExchangeTask); + } + break; + + case RSA: + { + EncryptedPreMasterSecret secret = (EncryptedPreMasterSecret) + kex.exchangeKeys(); + keyExchangeTask = new RSAKeyExchange(secret.encryptedSecret()); + tasks.add(keyExchangeTask); + } + break; + + case PSK: + { + ClientPSKParameters params = (ClientPSKParameters) + kex.exchangeKeys(); + generatePSKSecret(params.identity(), null, false); + } + break; + + case DHE_PSK: + { + ClientDHE_PSKParameters params = (ClientDHE_PSKParameters) + kex.exchangeKeys(); + DHPublicKey serverKey = (DHPublicKey) dhPair.getPublic(); + DHPublicKey clientKey = + new GnuDHPublicKey(null, serverKey.getParams().getP(), + serverKey.getParams().getG(), + params.params().publicValue()); + SecretKey psk = null; + try + { + psk = engine.contextImpl.pskManager.getKey(params.identity()); + } + catch (KeyManagementException kme) + { + } + keyExchangeTask = new DHE_PSKGen(clientKey, psk, false); + tasks.add(keyExchangeTask); + } + break; + + case RSA_PSK: + { + ClientRSA_PSKParameters params = (ClientRSA_PSKParameters) + kex.exchangeKeys(); + SecretKey psk = null; + try + { + psk = engine.contextImpl.pskManager.getKey(params.identity()); + } + catch (KeyManagementException kme) + { + } + if (psk == null) + { + byte[] fakeKey = new byte[16]; + engine.session().random().nextBytes(fakeKey); + psk = new SecretKeySpec(fakeKey, "DHE_PSK"); + } + keyExchangeTask = + new RSA_PSKExchange(params.secret().encryptedSecret(), psk); + tasks.add(keyExchangeTask); + } + break; + + case NONE: + { + Inflater inflater = null; + Deflater deflater = null; + if (compression == CompressionMethod.ZLIB) + { + inflater = new Inflater(); + deflater = new Deflater(); + } + inParams = new InputSecurityParameters(null, null, inflater, + engine.session(), + engine.session().suite); + outParams = new OutputSecurityParameters(null, null, deflater, + engine.session(), + engine.session().suite); + engine.session().privateData.masterSecret = new byte[0]; + } + break; + } + // XXX SRP + + if (clientCert != null) + state = READ_CERTIFICATE_VERIFY; + else + state = READ_FINISHED; + } + break; + + // Certificate Verify. + // + // This message is sent following the client key exchange message, + // but only when the client included its certificate in a previous + // message. + // + // After receipt of this message, the client's certificate (and, + // to a degree, the client's identity) will have been verified. + case READ_CERTIFICATE_VERIFY: + { + if (handshake.type() != CERTIFICATE_VERIFY) + throw new SSLException("expecting certificate verify message"); + + CertificateVerify verify = (CertificateVerify) handshake.body(); + try + { + verifyClient(verify.signature()); + if (certVerifier != null && certVerifier.verified()) + engine.session().setPeerVerified(true); + } + catch (SignatureException se) + { + if (engine.getNeedClientAuth()) + throw new SSLException("client auth failed", se); + } + if (continuedSession) + { + engine.changeCipherSpec(); + state = WRITE_FINISHED; + } + else + state = READ_FINISHED; + } + break; + + // Finished. + // + // This message is sent immediately following the change cipher + // spec message (which is sent outside of the handshake layer). + // After receipt of this message, the session keys for the client + // side will have been verified (this is the first message the + // client sends encrypted and authenticated with the newly + // negotiated keys). + // + // In the case of a continued session, the client sends its + // finished message first. Otherwise, the server will send its + // finished message first. + case READ_FINISHED: + { + if (handshake.type() != FINISHED) + throw new AlertException(new Alert(Alert.Level.FATAL, + Description.UNEXPECTED_MESSAGE)); + + Finished clientFinished = (Finished) handshake.body(); + + MessageDigest md5copy = null; + MessageDigest shacopy = null; + try + { + md5copy = (MessageDigest) md5.clone(); + shacopy = (MessageDigest) sha.clone(); + } + catch (CloneNotSupportedException cnse) + { + // We're improperly configured to use a non-cloneable + // md5/sha-1, OR there's a runtime bug. + throw new SSLException(cnse); + } + Finished serverFinished = + new Finished(generateFinished(md5copy, shacopy, + true, engine.session()), + engine.session().version); + + if (Debug.DEBUG) + logger.log(Component.SSL_HANDSHAKE, "server finished: {0}", + serverFinished); + + if (engine.session().version == ProtocolVersion.SSL_3) + { + if (!Arrays.equals(clientFinished.md5Hash(), + serverFinished.md5Hash()) + || !Arrays.equals(clientFinished.shaHash(), + serverFinished.shaHash())) + { + engine.session().invalidate(); + throw new SSLException("session verify failed"); + } + } + else + { + if (!Arrays.equals(clientFinished.verifyData(), + serverFinished.verifyData())) + { + engine.session().invalidate(); + throw new SSLException("session verify failed"); + } + } + + if (continuedSession) + state = DONE; + else + { + engine.changeCipherSpec(); + state = WRITE_FINISHED; + } + } + break; + } + + handshakeOffset += handshake.length() + 4; + + if (!tasks.isEmpty()) + return HandshakeStatus.NEED_TASK; + if (state.isReadState()) + return HandshakeStatus.NEED_UNWRAP; + if (state.isWriteState()) + return HandshakeStatus.NEED_WRAP; + + return HandshakeStatus.FINISHED; + } + + public @Override HandshakeStatus implHandleOutput (ByteBuffer fragment) + throws SSLException + { + if (Debug.DEBUG) + logger.logv(Component.SSL_HANDSHAKE, + "handle output state: {0}; output fragment: {1}", + state, fragment); + + // Drain the output buffer, if it needs it. + if (outBuffer != null && outBuffer.hasRemaining()) + { + int l = Math.min(fragment.remaining(), outBuffer.remaining()); + fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l)); + outBuffer.position(outBuffer.position() + l); + } + + if (!fragment.hasRemaining()) + { + if (state.isWriteState() || outBuffer.hasRemaining()) + return HandshakeStatus.NEED_WRAP; + else + return HandshakeStatus.NEED_UNWRAP; + } + + // XXX what we need to do here is generate a "stream" of handshake + // messages, and insert them into fragment amounts that we have available. + // A handshake message can span multiple records, and we can put + // multiple records into a single record. + // + // So, we can have one of two states: + // + // 1) We have enough space in the record we are creating to push out + // everything we need to on this round. This is easy; we just + // repeatedly fill in these messages in the buffer, so we get something + // that looks like this: + // ________________________________ + // records: |________________________________| + // handshakes: |______|__|__________| + // + // 2) We can put part of one handshake message in the current record, + // but we must put the rest of it in the following record, or possibly + // more than one following record. So here, we'd see this: + // + // ________________________ + // records: |_______|_______|________| + // handshakes: |____|_______|_________| + // + // We *could* make this a lot easier by just only ever emitting one + // record per call, but then we would waste potentially a lot of space + // and waste a lot of TCP packets by doing it the simple way. What + // we desire here is that we *maximize* our usage of the resources + // given to us, and to use as much space in the present fragment as + // we can. + // + // Note that we pretty much have to support this, anyway, because SSL + // provides no guarantees that the record size is large enough to + // admit *even one* handshake message. Also, callers could call on us + // with a short buffer, even though they aren't supposed to. + // + // This is somewhat complicated by the fact that we don't know, a priori, + // how large a handshake message will be until we've built it, and our + // design builds the message around the byte buffer. + // + // Some ways to handle this: + // + // 1. Write our outgoing handshake messages to a private buffer, + // big enough per message (and, if we run out of space, resize that + // buffer) and push (possibly part of) this buffer out to the + // outgoing buffer. This isn't that great because we'd need to + // store and copy things unnecessarily. + // + // 2. Build outgoing handshake objects 'virtually', that is, store them + // as collections of objects, then compute the length, and then write + // them to a buffer, instead of making the objects views on + // ByteBuffers for both input and output. This would complicate the + // protocol objects a bit (although, it would amount to doing + // separation between client objects and server objects, which is + // pretty OK), and we still need to figure out how exactly to chunk + // those objects across record boundaries. + // + // 3. Try to build these objects on the buffer we're given, but detect + // when we run out of space in the output buffer, and split the + // overflow message. This sounds like the best, but also probably + // the hardest to code. +output_loop: + while (fragment.remaining() >= 4 && state.isWriteState()) + { + switch (state) + { + // Hello Request. + // + // This message is sent by the server to initiate a new + // handshake, to establish new session keys. + case WRITE_HELLO_REQUEST: + { + Handshake handshake = new Handshake(fragment); + handshake.setType(Handshake.Type.HELLO_REQUEST); + handshake.setLength(0); + fragment.position(fragment.position() + 4); + if (Debug.DEBUG) + logger.log(Component.SSL_HANDSHAKE, "{0}", handshake); + state = READ_CLIENT_HELLO; + } + break output_loop; // XXX temporary + + // Server Hello. + // + // This message is sent immediately following the client hello. + // It informs the client of the cipher suite, compression method, + // session ID (which may have been a continued session), and any + // supported extensions. + case WRITE_SERVER_HELLO: + { + ServerHelloBuilder hello = new ServerHelloBuilder(); + hello.setVersion(engine.session().version); + Random r = hello.random(); + r.setGmtUnixTime(Util.unixTime()); + byte[] nonce = new byte[28]; + engine.session().random().nextBytes(nonce); + r.setRandomBytes(nonce); + serverRandom = r.copy(); + hello.setSessionId(engine.session().getId()); + hello.setCipherSuite(engine.session().suite); + hello.setCompressionMethod(compression); + if (clientHadExtensions) + { + // XXX figure this out. + } + else // Don't send any extensions. + hello.setDisableExtensions(true); + + if (Debug.DEBUG) + logger.log(Component.SSL_HANDSHAKE, "{0}", hello); + + int typeLen = ((Handshake.Type.SERVER_HELLO.getValue() << 24) + | (hello.length() & 0xFFFFFF)); + fragment.putInt(typeLen); + + outBuffer = hello.buffer(); + int l = Math.min(fragment.remaining(), outBuffer.remaining()); + fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l)); + outBuffer.position(outBuffer.position() + l); + + CipherSuite cs = engine.session().suite; + KeyExchangeAlgorithm kex = cs.keyExchangeAlgorithm(); + if (continuedSession) + { + byte[][] keys = generateKeys(clientRandom, serverRandom, + engine.session()); + setupSecurityParameters(keys, false, engine, compression); + engine.changeCipherSpec(); + state = WRITE_FINISHED; + } + else if (kex == DHE_DSS || kex == DHE_RSA || kex == RSA + || kex == RSA_PSK) + { + certLoader = new CertLoader(); + tasks.add(certLoader); + state = WRITE_CERTIFICATE; + if (kex == DHE_DSS || kex == DHE_RSA) + { + genDH = new GenDH(); + tasks.add(genDH); + } + break output_loop; + } + else if (kex == PSK) + { + state = WRITE_SERVER_KEY_EXCHANGE; + } + else if (kex == DHE_PSK || kex == DH_anon) + { + genDH = new GenDH(); + tasks.add(genDH); + state = WRITE_SERVER_KEY_EXCHANGE; + break output_loop; + } + else if (engine.getWantClientAuth() || engine.getNeedClientAuth()) + { + state = WRITE_CERTIFICATE_REQUEST; + } + else + state = WRITE_SERVER_HELLO_DONE; + } + break; + + // Certificate. + // + // This message is sent immediately following the server hello, + // IF the cipher suite chosen requires that the server identify + // itself (usually, servers must authenticate). + case WRITE_CERTIFICATE: + { + // We must have scheduled a certificate loader to run. + assert(certLoader != null); + assert(certLoader.hasRun()); + if (certLoader.thrown() != null) + throw new AlertException(new Alert(Alert.Level.FATAL, + Alert.Description.HANDSHAKE_FAILURE), + certLoader.thrown()); + java.security.cert.Certificate[] chain + = engine.session().getLocalCertificates(); + CertificateBuilder cert = new CertificateBuilder(CertificateType.X509); + try + { + cert.setCertificates(Arrays.asList(chain)); + } + catch (CertificateException ce) + { + throw new SSLException(ce); + } + + if (Debug.DEBUG) + { + logger.logv(Component.SSL_HANDSHAKE, "my cert:\n{0}", localCert); + logger.logv(Component.SSL_HANDSHAKE, "{0}", cert); + } + + int typeLen = ((CERTIFICATE.getValue() << 24) + | (cert.length() & 0xFFFFFF)); + fragment.putInt(typeLen); + + outBuffer = cert.buffer(); + final int l = Math.min(fragment.remaining(), outBuffer.remaining()); + fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l)); + outBuffer.position(outBuffer.position() + l); + + CipherSuite s = engine.session().suite; + KeyExchangeAlgorithm kexalg = s.keyExchangeAlgorithm(); + if (kexalg == DHE_DSS || kexalg == DHE_RSA) + { + genDH = new GenDH(); + tasks.add(genDH); + state = WRITE_SERVER_KEY_EXCHANGE; + break output_loop; + } + else if (kexalg == RSA_PSK) + state = WRITE_SERVER_KEY_EXCHANGE; + else if (engine.getWantClientAuth() || engine.getNeedClientAuth()) + { + state = WRITE_CERTIFICATE_REQUEST; + } + else + state = WRITE_SERVER_HELLO_DONE; + } + break output_loop; // XXX temporary + + // Server key exchange. + // + // This message is sent, following the certificate if sent, + // otherwise following the server hello, IF the chosen cipher + // suite requires that the server send explicit key exchange + // parameters (that is, if the key exchange parameters are not + // implicit in the server's certificate). + case WRITE_SERVER_KEY_EXCHANGE: + { + KeyExchangeAlgorithm kex = engine.session().suite.keyExchangeAlgorithm(); + + ByteBuffer paramBuffer = null; + ByteBuffer sigBuffer = null; + if (kex == DHE_DSS || kex == DHE_RSA || kex == DH_anon + || kex == DHE_PSK) + { + assert(genDH != null); + assert(genDH.hasRun()); + if (genDH.thrown() != null) + throw new AlertException(new Alert(Alert.Level.FATAL, + Alert.Description.HANDSHAKE_FAILURE), + genDH.thrown()); + assert(dhPair != null); + initDiffieHellman((DHPrivateKey) dhPair.getPrivate(), + engine.session().random()); + paramBuffer = genDH.paramsBuffer; + sigBuffer = genDH.sigBuffer; + + if (kex == DHE_PSK) + { + String identityHint + = engine.contextImpl.pskManager.chooseIdentityHint(); + ServerDHE_PSKParameters psk = + new ServerDHE_PSKParameters(identityHint, paramBuffer); + paramBuffer = psk.buffer(); + } + } + if (kex == RSA_PSK) + { + String idHint = engine.contextImpl.pskManager.chooseIdentityHint(); + if (idHint != null) + { + ServerRSA_PSKParameters params + = new ServerRSA_PSKParameters(idHint); + paramBuffer = params.buffer(); + } + } + if (kex == PSK) + { + String idHint = engine.contextImpl.pskManager.chooseIdentityHint(); + if (idHint != null) + { + ServerPSKParameters params + = new ServerPSKParameters(idHint); + paramBuffer = params.buffer(); + } + } + // XXX handle SRP + + if (paramBuffer != null) + { + ServerKeyExchangeBuilder ske + = new ServerKeyExchangeBuilder(engine.session().suite); + ske.setParams(paramBuffer); + if (sigBuffer != null) + ske.setSignature(sigBuffer); + + if (Debug.DEBUG) + logger.log(Component.SSL_HANDSHAKE, "{0}", ske); + + outBuffer = ske.buffer(); + int l = Math.min(fragment.remaining(), outBuffer.remaining()); + fragment.putInt((SERVER_KEY_EXCHANGE.getValue() << 24) + | (ske.length() & 0xFFFFFF)); + fragment.put((ByteBuffer) outBuffer.duplicate().limit + (outBuffer.position() + l)); + outBuffer.position(outBuffer.position() + l); + } + + if (engine.getWantClientAuth() || engine.getNeedClientAuth()) + state = WRITE_CERTIFICATE_REQUEST; + else + state = WRITE_SERVER_HELLO_DONE; + } + break; + + // Certificate Request. + // + // This message is sent when the server desires or requires + // client authentication with a certificate; if it is sent, it + // will be sent just after the Certificate or Server Key + // Exchange messages, whichever is sent. If neither of the + // above are sent, it will be the message that follows the + // server hello. + case WRITE_CERTIFICATE_REQUEST: + { + CertificateRequestBuilder req = new CertificateRequestBuilder(); + + List types + = new ArrayList(4); + types.add(ClientCertificateType.RSA_SIGN); + types.add(ClientCertificateType.RSA_FIXED_DH); + types.add(ClientCertificateType.DSS_SIGN); + types.add(ClientCertificateType.DSS_FIXED_DH); + req.setTypes(types); + + X509Certificate[] anchors + = engine.contextImpl.trustManager.getAcceptedIssuers(); + List issuers + = new ArrayList(anchors.length); + for (X509Certificate cert : anchors) + issuers.add(cert.getIssuerX500Principal()); + req.setAuthorities(issuers); + + if (Debug.DEBUG) + logger.log(Component.SSL_HANDSHAKE, "{0}", req); + + fragment.putInt((CERTIFICATE_REQUEST.getValue() << 24) + | (req.length() & 0xFFFFFF)); + + outBuffer = req.buffer(); + int l = Math.min(outBuffer.remaining(), fragment.remaining()); + fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l)); + outBuffer.position(outBuffer.position() + l); + + state = WRITE_SERVER_HELLO_DONE; + } + break; + + // Server Hello Done. + // + // This message is always sent by the server, to terminate its + // side of the handshake. Since the server's handshake message + // may comprise multiple, optional messages, this sentinel + // message lets the client know when the server's message stream + // is complete. + case WRITE_SERVER_HELLO_DONE: + { + // ServerHelloDone is zero-length; just put in the type + // field. + fragment.putInt(SERVER_HELLO_DONE.getValue() << 24); + if (Debug.DEBUG) + logger.logv(Component.SSL_HANDSHAKE, "writing ServerHelloDone"); + state = READ_CERTIFICATE; + } + break output_loop; // XXX temporary + + // Finished. + // + // This is always sent by the server to verify the keys that the + // server will use to encrypt and authenticate. In a full + // handshake, this message will be sent after the client's + // finished message; in an abbreviated handshake (with a continued + // session) the server sends its finished message first. + // + // This message follows the change cipher spec message, which is + // sent out-of-band in a different SSL content-type. + // + // This is the first message that the server will send encrypted + // and authenticated with the newly negotiated session keys. + case WRITE_FINISHED: + { + MessageDigest md5copy = null; + MessageDigest shacopy = null; + try + { + md5copy = (MessageDigest) md5.clone(); + shacopy = (MessageDigest) sha.clone(); + } + catch (CloneNotSupportedException cnse) + { + // We're improperly configured to use a non-cloneable + // md5/sha-1, OR there's a runtime bug. + throw new SSLException(cnse); + } + outBuffer + = generateFinished(md5copy, shacopy, false, + engine.session()); + + fragment.putInt((FINISHED.getValue() << 24) + | outBuffer.remaining() & 0xFFFFFF); + + int l = Math.min(outBuffer.remaining(), fragment.remaining()); + fragment.put((ByteBuffer) outBuffer.duplicate().limit(outBuffer.position() + l)); + outBuffer.position(outBuffer.position() + l); + + if (continuedSession) + state = READ_FINISHED; + else + state = DONE; + } + break; + } + } + if (!tasks.isEmpty()) + return HandshakeStatus.NEED_TASK; + if (state.isWriteState() || outBuffer.hasRemaining()) + return HandshakeStatus.NEED_WRAP; + if (state.isReadState()) + return HandshakeStatus.NEED_UNWRAP; + + return HandshakeStatus.FINISHED; + } + + @Override HandshakeStatus status() + { + if (!tasks.isEmpty()) + return HandshakeStatus.NEED_TASK; + if (state.isReadState()) + return HandshakeStatus.NEED_UNWRAP; + if (state.isWriteState()) + return HandshakeStatus.NEED_WRAP; + + return HandshakeStatus.FINISHED; + } + + @Override void checkKeyExchange() throws SSLException + { + if (continuedSession) // No key exchange needed. + return; + KeyExchangeAlgorithm kex = engine.session().suite.keyExchangeAlgorithm(); + if (kex == NONE || kex == PSK || kex == RSA_PSK) // Don't need one. + return; + if (keyExchangeTask == null) // An error if we never created one. + throw new AlertException(new Alert(Alert.Level.FATAL, + Alert.Description.INTERNAL_ERROR)); + if (!keyExchangeTask.hasRun()) // An error if the caller never ran it. + throw new AlertException(new Alert(Alert.Level.FATAL, + Alert.Description.INTERNAL_ERROR)); + if (keyExchangeTask.thrown() != null) // An error was thrown. + throw new AlertException(new Alert(Alert.Level.FATAL, + Alert.Description.HANDSHAKE_FAILURE), + keyExchangeTask.thrown()); + } + + @Override void handleV2Hello(ByteBuffer hello) + { + int len = hello.getShort(0) & 0x7FFF; + md5.update((ByteBuffer) hello.duplicate().position(2).limit(len+2)); + sha.update((ByteBuffer) hello.duplicate().position(2).limit(len+2)); + helloV2 = true; + } + + private ByteBuffer signParams(ByteBuffer serverParams) + throws NoSuchAlgorithmException, InvalidKeyException, SignatureException + { + SignatureAlgorithm alg = engine.session().suite.signatureAlgorithm(); + java.security.Signature sig + = java.security.Signature.getInstance(alg.algorithm()); + PrivateKey key = engine.contextImpl.keyManager.getPrivateKey(keyAlias); + if (Debug.DEBUG_KEY_EXCHANGE) + logger.logv(Component.SSL_HANDSHAKE, "server key: {0}", key); + sig.initSign(key); + sig.update(clientRandom.buffer()); + sig.update(serverRandom.buffer()); + sig.update(serverParams); + byte[] sigVal = sig.sign(); + Signature signature = new Signature(sigVal, engine.session().suite.signatureAlgorithm()); + return signature.buffer(); + } + + private void verifyClient(byte[] sigValue) throws SSLException, SignatureException + { + MessageDigest md5copy = null; + MessageDigest shacopy = null; + try + { + md5copy = (MessageDigest) md5.clone(); + shacopy = (MessageDigest) sha.clone(); + } + catch (CloneNotSupportedException cnse) + { + // Mis-configured with non-cloneable digests. + throw new SSLException(cnse); + } + byte[] toSign = null; + if (engine.session().version == ProtocolVersion.SSL_3) + toSign = genV3CertificateVerify(md5copy, shacopy, engine.session()); + else + { + if (engine.session().suite.signatureAlgorithm() == SignatureAlgorithm.RSA) + toSign = Util.concat(md5copy.digest(), shacopy.digest()); + else + toSign = shacopy.digest(); + } + + try + { + java.security.Signature sig = java.security.Signature.getInstance(engine.session().suite.signatureAlgorithm().toString()); + sig.initVerify(clientCert); + sig.update(toSign); + sig.verify(sigValue); + } + catch (InvalidKeyException ike) + { + throw new SSLException(ike); + } + catch (NoSuchAlgorithmException nsae) + { + throw new SSLException(nsae); + } + } + + // Delegated tasks. + + class CertLoader extends DelegatedTask + { + CertLoader() + { + } + + public void implRun() throws SSLException + { + KeyExchangeAlgorithm kexalg = engine.session().suite.keyExchangeAlgorithm(); + X509ExtendedKeyManager km = engine.contextImpl.keyManager; + Principal[] issuers = null; // XXX use TrustedAuthorities extension. + keyAlias = km.chooseEngineServerAlias(kexalg.name(), issuers, engine); + if (keyAlias == null) + throw new SSLException("no certificates available"); + X509Certificate[] chain = km.getCertificateChain(keyAlias); + engine.session().setLocalCertificates(chain); + localCert = chain[0]; + serverKey = km.getPrivateKey(keyAlias); + if (kexalg == DH_DSS || kexalg == DH_RSA) + dhPair = new KeyPair(localCert.getPublicKey(), + km.getPrivateKey(keyAlias)); + } + } + + /** + * Delegated task for generating Diffie-Hellman parameters. + */ + private class GenDH extends DelegatedTask + { + ByteBuffer paramsBuffer; + ByteBuffer sigBuffer; + + protected void implRun() + throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, + InvalidKeyException, SignatureException + { + KeyPairGenerator dhGen = KeyPairGenerator.getInstance("DH"); + DHParameterSpec dhparams = DiffieHellman.getParams().getParams(); + dhGen.initialize(dhparams, engine.session().random()); + dhPair = dhGen.generateKeyPair(); + DHPublicKey pub = (DHPublicKey) dhPair.getPublic(); + + // Generate the parameters message. + ServerDHParams params = new ServerDHParams(pub.getParams().getP(), + pub.getParams().getG(), + pub.getY()); + paramsBuffer = params.buffer(); + + // Sign the parameters, if needed. + if (engine.session().suite.signatureAlgorithm() != SignatureAlgorithm.ANONYMOUS) + { + sigBuffer = signParams(paramsBuffer); + paramsBuffer.rewind(); + } + if (Debug.DEBUG_KEY_EXCHANGE) + logger.logv(Component.SSL_KEY_EXCHANGE, + "Diffie-Hellman public:{0} private:{1}", + dhPair.getPublic(), dhPair.getPrivate()); + } + } + + class RSAKeyExchange extends DelegatedTask + { + private final byte[] encryptedPreMasterSecret; + + RSAKeyExchange(byte[] encryptedPreMasterSecret) + { + this.encryptedPreMasterSecret = encryptedPreMasterSecret; + } + + public void implRun() + throws BadPaddingException, IllegalBlockSizeException, InvalidKeyException, + NoSuchAlgorithmException, NoSuchPaddingException, SSLException + { + Cipher rsa = Cipher.getInstance("RSA"); + rsa.init(Cipher.DECRYPT_MODE, serverKey); + rsa.init(Cipher.DECRYPT_MODE, localCert); + preMasterSecret = rsa.doFinal(encryptedPreMasterSecret); + generateMasterSecret(clientRandom, serverRandom, engine.session()); + byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session()); + setupSecurityParameters(keys, false, engine, compression); + } + } + + class RSA_PSKExchange extends DelegatedTask + { + private final byte[] encryptedPreMasterSecret; + private final SecretKey psKey; + + RSA_PSKExchange(byte[] encryptedPreMasterSecret, SecretKey psKey) + { + this.encryptedPreMasterSecret = encryptedPreMasterSecret; + this.psKey = psKey; + } + + public @Override void implRun() + throws BadPaddingException, IllegalBlockSizeException, InvalidKeyException, + NoSuchAlgorithmException, NoSuchPaddingException, SSLException + { + Cipher rsa = Cipher.getInstance("RSA"); + rsa.init(Cipher.DECRYPT_MODE, serverKey); + rsa.init(Cipher.DECRYPT_MODE, localCert); + byte[] rsaSecret = rsa.doFinal(encryptedPreMasterSecret); + byte[] psSecret = psKey.getEncoded(); + preMasterSecret = new byte[rsaSecret.length + psSecret.length + 4]; + preMasterSecret[0] = (byte) (rsaSecret.length >>> 8); + preMasterSecret[1] = (byte) rsaSecret.length; + System.arraycopy(rsaSecret, 0, preMasterSecret, 2, rsaSecret.length); + preMasterSecret[rsaSecret.length + 2] = (byte) (psSecret.length >>> 8); + preMasterSecret[rsaSecret.length + 3] = (byte) psSecret.length; + System.arraycopy(psSecret, 0, preMasterSecret, rsaSecret.length+4, + psSecret.length); + + generateMasterSecret(clientRandom, serverRandom, engine.session()); + byte[][] keys = generateKeys(clientRandom, serverRandom, engine.session()); + setupSecurityParameters(keys, false, engine, compression); + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerHello.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerHello.java new file mode 100644 index 000000000..944194b3e --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerHello.java @@ -0,0 +1,231 @@ +/* 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.PrintWriter; +import java.io.StringWriter; + +import java.nio.ByteBuffer; + +/** + * The server hello message. + * + *
      +struct
      +{
      +  ProtocolVersion server_version;
      +  Random random;
      +  SessionID session_id;
      +  CipherSuite cipher_suite;
      +  CompressionMethod compression_method;
      +  Extensions server_hello_extension_list<0..2^16-1>
      +} ServerHello;
      +
      + * + *

      Server hello messages may contain extra data after the + * compression_method field, which are interpreted as + * extensions to the basic handshake. + */ +public class ServerHello implements Handshake.Body +{ + + // Fields. + // ------------------------------------------------------------------------- + + protected static final int RANDOM_OFFSET = 2; + protected static final int SESSID_OFFSET = 32 + RANDOM_OFFSET; + protected static final int SESSID_OFFSET2 = SESSID_OFFSET + 1; + + protected ByteBuffer buffer; + protected boolean disableExtensions; + + // Constructor. + // ------------------------------------------------------------------------- + + public ServerHello (final ByteBuffer buffer) + { + this.buffer = buffer; + disableExtensions = false; + } + + public int length () + { + int sessionLen = buffer.get(SESSID_OFFSET) & 0xFF; + int len = SESSID_OFFSET2 + sessionLen + 3; + int elen = 0; + if (!disableExtensions && len + 1 < buffer.limit() + && (elen = buffer.getShort(len)) != 0) + len += 2 + elen; + return len; + } + + /** + * Returns the server's protocol version. This will read two bytes + * from the beginning of the underlying buffer, and return an + * instance of the appropriate {@link ProtocolVersion}; if the + * version read is a supported version, this method returns a static + * constant instance. + * + * @return The server's protocol version. + */ + public ProtocolVersion version() + { + return ProtocolVersion.getInstance (buffer.getShort (0)); + } + + /** + * Returns the server's random value. This method returns a + * lightwieght wrapper around the existing bytes; modifications to + * the underlying buffer will modify the returned object, and + * vice-versa. + * + * @return The server's random value. + */ + public Random random() + { + ByteBuffer randomBuf = + ((ByteBuffer) buffer.duplicate ().position (RANDOM_OFFSET) + .limit (SESSID_OFFSET)).slice (); + return new Random (randomBuf); + } + + /** + * Returns the session ID. This method returns a new byte array with + * the session ID bytes. + * + * @return The session ID. + */ + public byte[] sessionId() + { + int idlen = buffer.get (SESSID_OFFSET) & 0xFF; + byte[] sessionId = new byte[idlen]; + buffer.position (SESSID_OFFSET2); + buffer.get (sessionId); + return sessionId; + } + + /** + * Returns the server's chosen cipher suite. The returned cipher + * suite will be "resolved" to this structure's version. + * + * @return The server's chosen cipher suite. + */ + public CipherSuite cipherSuite() + { + int offset = SESSID_OFFSET2 + (buffer.get(SESSID_OFFSET) & 0xFF); + return CipherSuite.forValue(buffer.getShort(offset)).resolve(); + } + + /** + * Returns the server's chosen compression method. + * + * @return The chosen compression method. + */ + public CompressionMethod compressionMethod() + { + int offset = SESSID_OFFSET2 + (buffer.get(SESSID_OFFSET) & 0xFF) + 2; + return CompressionMethod.getInstance(buffer.get(offset) & 0xFF); + } + + public int extensionsLength() + { + int offset = SESSID_OFFSET2 + (buffer.get (SESSID_OFFSET) & 0xFF) + 3; + if (offset + 1 >= buffer.limit()) + return 0; + return buffer.getShort(offset) & 0xFFFF; + } + + public ExtensionList extensions () + { + int offset = SESSID_OFFSET2 + (buffer.get (SESSID_OFFSET) & 0xFF) + 3; + if (offset + 1 >= buffer.limit()) + return null; + int len = buffer.getShort(offset) & 0xFFFF; + if (len == 0) + len = buffer.limit() - offset - 2; + ByteBuffer ebuf = ((ByteBuffer) buffer.duplicate().position(offset) + .limit(offset + len + 2)).slice(); + return new ExtensionList(ebuf); + } + + public String toString() + { + return toString(null); + } + + public String toString (final String prefix) + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + if (prefix != null) + out.print (prefix); + out.println ("struct {"); + String subprefix = " "; + if (prefix != null) + subprefix += prefix; + out.print (subprefix); + out.print ("version: "); + out.print (version ()); + out.println (";"); + out.print (subprefix); + out.println ("random:"); + out.println (random ().toString (subprefix)); + out.print (subprefix); + out.print ("sessionId: "); + out.print (Util.toHexString(sessionId (), ':')); + out.println (";"); + out.print (subprefix); + out.print ("cipherSuite: "); + out.print (cipherSuite ()); + out.println (";"); + out.print (subprefix); + out.print ("compressionMethod: "); + out.print (compressionMethod ()); + out.println (";"); + ExtensionList exts = extensions (); + out.print (subprefix); + out.println ("extensions:"); + out.println (exts != null ? exts.toString (subprefix+" ") + : subprefix + " (nil)"); + if (prefix != null) + out.print (prefix); + out.print ("} ServerHello;"); + return str.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerHelloBuilder.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerHelloBuilder.java new file mode 100644 index 000000000..47bce29ee --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerHelloBuilder.java @@ -0,0 +1,131 @@ +/* ServerHelloBuilder.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.net.ssl.provider; + +import java.nio.ByteBuffer; + +/** + * @author csm + * + */ +public class ServerHelloBuilder extends ServerHello implements Builder +{ + public ServerHelloBuilder() + { + // Allocate a large enough buffer to hold a hello with the maximum + // size session ID, and no extensions. + super(ByteBuffer.allocate(SESSID_OFFSET2 + 35)); + } + + public ByteBuffer buffer() + { + return ((ByteBuffer) buffer.duplicate().position(0).limit(length())).slice(); + } + + // We don't reallocate the buffer in any of the following methods, + // because we always allocate a large enough buffer for the base + // object in the constructor. + + public void setVersion (final ProtocolVersion version) + { + buffer.putShort (0, (short) version.rawValue ()); + } + + public void setSessionId (final byte[] sessionId) + { + setSessionId (sessionId, 0, sessionId.length); + } + + public void setSessionId (final byte[] sessionId, final int offset, + final int length) + { + if (length < 0 || length > 32) + throw new IllegalArgumentException("length must be between 0 and 32"); + buffer.put(SESSID_OFFSET, (byte) length); + ((ByteBuffer) buffer.duplicate().position(SESSID_OFFSET2)) + .put(sessionId, offset, length); + } + + public void setCipherSuite (final CipherSuite suite) + { + int offset = SESSID_OFFSET + (buffer.get(SESSID_OFFSET) & 0xFF) + 1; + ((ByteBuffer) buffer.duplicate().position(offset)).put(suite.id()); + } + + public void setCompressionMethod (final CompressionMethod comp) + { + int offset = SESSID_OFFSET + (buffer.get(SESSID_OFFSET) & 0xFF) + 3; + buffer.put (offset, (byte) comp.getValue ()); + } + + // For extensions, we do reallocate the buffer. + + public void setDisableExtensions(boolean disable) + { + disableExtensions = disable; + } + + public void setExtensionsLength (final int length) + { + if (length < 0 || length > 16384) + throw new IllegalArgumentException("length must be nonnegative and not exceed 16384"); + int needed = SESSID_OFFSET2 + (buffer.get(SESSID_OFFSET) & 0xFF) + 5 + length; + if (buffer.capacity() < needed) + ensureCapacity(needed); + buffer.putShort (SESSID_OFFSET2 + (buffer.get (SESSID_OFFSET) & 0xFF) + 3, + (short) length); + } + + public void setExtensions(ByteBuffer extensions) + { + extensions = (ByteBuffer) + extensions.duplicate().limit(extensions.position() + extensionsLength()); + ((ByteBuffer) buffer.duplicate().position(SESSID_OFFSET2 + + (buffer.get(SESSID_OFFSET) & 0xFF) + )).put(extensions); + } + + public void ensureCapacity(int newCapacity) + { + ByteBuffer newBuffer = ByteBuffer.allocate(newCapacity); + newBuffer.put(buffer); + newBuffer.position(0); + buffer = newBuffer; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerHelloDone.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerHelloDone.java new file mode 100644 index 000000000..987b51c56 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerHelloDone.java @@ -0,0 +1,66 @@ +/* ServerHelloDone.java -- SSL ServerHelloDone 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; + +/** + * An empty message that signals that the server is finished sending + * its handshake data. + * + *

      struct { } ServerHelloDone;
      + */ +public class ServerHelloDone implements Handshake.Body +{ + public ServerHelloDone () { } + + public int length () + { + return 0; + } + + public String toString () + { + return toString (null); + } + + public String toString (final String prefix) + { + return ((prefix != null ? prefix : "") + + "struct { } ServerHelloDone;"); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchange.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchange.java new file mode 100644 index 000000000..1206ae6b2 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchange.java @@ -0,0 +1,173 @@ +/* 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.PrintWriter; +import java.io.StringWriter; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; + +/** + * The server key exchange message. + * + *
      +struct
      +{
      +  select (KeyExchangeAlgorithm)
      +  {
      +    case diffie_hellman:
      +      ServerDHParams params;
      +      Signature signed_params;
      +    case rsa:
      +      ServerRSAParams params;
      +      Signature signed_params;
      +    case srp:
      +      ServerSRPParams params;
      +      Signature signed_params;
      +  };
      +} ServerKeyExchange;
      +
      + */ +public class ServerKeyExchange implements Handshake.Body +{ + + protected ByteBuffer buffer; + protected final CipherSuite suite; + + public ServerKeyExchange(final ByteBuffer buffer, final CipherSuite suite) + { + suite.getClass(); + this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); + this.suite = suite; + } + + public int length () + { + if (suite.keyExchangeAlgorithm ().equals (KeyExchangeAlgorithm.NONE)) + return 0; + int len = 0; + ServerKeyExchangeParams params = params(); + Signature sig = signature(); + if (params != null) + len += params.length(); + if (sig != null) + len += sig.length(); + return len; + } + + /** + * Returns the server's key exchange parameters. The value returned will + * depend on the key exchange algorithm this object was created with. + * + * @return The server's key exchange parameters. + */ + public ServerKeyExchangeParams params () + { + KeyExchangeAlgorithm kex = suite.keyExchangeAlgorithm (); + if (kex == KeyExchangeAlgorithm.RSA) + return new ServerRSAParams(buffer.duplicate ()); + else if (kex == KeyExchangeAlgorithm.DHE_DSS + || kex == KeyExchangeAlgorithm.DHE_RSA + || kex == KeyExchangeAlgorithm.DH_anon) + return new ServerDHParams(buffer.duplicate()); +// else if (kex.equals (KeyExchangeAlgorithm.SRP)) +// return new ServerSRPParams (buffer.duplicate ()); + else if (kex == KeyExchangeAlgorithm.NONE) + return null; + else if (kex == KeyExchangeAlgorithm.DHE_PSK) + return new ServerDHE_PSKParameters(buffer.duplicate()); + else if (kex == KeyExchangeAlgorithm.PSK) + return new ServerPSKParameters(buffer.duplicate()); + else if (kex == KeyExchangeAlgorithm.RSA_PSK) + return new ServerPSKParameters(buffer.duplicate()); + throw new IllegalArgumentException ("unsupported key exchange: " + kex); + } + + /** + * Returns the digital signature made over the key exchange parameters. + * + * @return The signature. + */ + public Signature signature () + { + KeyExchangeAlgorithm kex = suite.keyExchangeAlgorithm(); + if (kex == KeyExchangeAlgorithm.NONE + || kex == KeyExchangeAlgorithm.DH_anon + || kex == KeyExchangeAlgorithm.DHE_PSK + || kex == KeyExchangeAlgorithm.PSK + || kex == KeyExchangeAlgorithm.RSA_PSK) + return null; + ServerKeyExchangeParams params = params(); + ByteBuffer sigbuf = ((ByteBuffer) buffer.position(params.length ())).slice (); + return new Signature (sigbuf, suite.signatureAlgorithm ()); + } + + public String toString() + { + return toString (null); + } + + public String toString (final String prefix) + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + if (prefix != null) out.print (prefix); + out.println("struct {"); + if (prefix != null) out.print (prefix); + out.print (" algorithm: "); + out.print (suite.keyExchangeAlgorithm ()); + out.println (";"); + if (!suite.keyExchangeAlgorithm ().equals (KeyExchangeAlgorithm.NONE)) + { + if (prefix != null) out.print (prefix); + out.println (" parameters:"); + out.println (params ().toString (prefix != null ? prefix+" " : " ")); + } + if (!suite.signatureAlgorithm ().equals (SignatureAlgorithm.ANONYMOUS)) + { + if (prefix != null) out.print (prefix); + out.println (" signature:"); + out.println (signature ().toString (prefix != null ? prefix+" " : " ")); + } + if (prefix != null) out.print (prefix); + out.print ("} ServerKeyExchange;"); + return str.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchangeBuilder.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchangeBuilder.java new file mode 100644 index 000000000..658ae228a --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchangeBuilder.java @@ -0,0 +1,89 @@ +/* ServerKeyExchangeBuilder.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.net.ssl.provider; + +import java.nio.ByteBuffer; + +/** + * Builder for {@link ServerKeyExchange} objects. + * + * @author Casey Marshall (csm@gnu.org) + */ +public class ServerKeyExchangeBuilder extends ServerKeyExchange + implements Builder +{ + public ServerKeyExchangeBuilder(final CipherSuite suite) + { + super(ByteBuffer.allocate(1024), suite); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Builder#buffer() + */ + public ByteBuffer buffer() + { + return ((ByteBuffer) buffer.duplicate().position(0).limit(length())).slice(); + } + + public void setParams(ByteBuffer params) + { + if (suite.keyExchangeAlgorithm() == KeyExchangeAlgorithm.NONE) + throw new IllegalArgumentException("key exchange algorithm is none"); + ensureCapacity(params.remaining()); + buffer.duplicate().put(params); + } + + public void setSignature(ByteBuffer signature) + { + if (suite.keyExchangeAlgorithm() == KeyExchangeAlgorithm.NONE) + throw new IllegalArgumentException("key exchange algorithm is none"); + int paramsLen = params().length(); + ensureCapacity(paramsLen + signature.remaining()); + ((ByteBuffer) buffer.duplicate().position(paramsLen)).put(signature); + } + + public void ensureCapacity(int capacity) + { + if (buffer.capacity() >= capacity) + return; + ByteBuffer newBuffer = ByteBuffer.allocate(capacity); + newBuffer.duplicate().put(buffer); + buffer = newBuffer; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchangeParams.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchangeParams.java new file mode 100644 index 000000000..cb523650f --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchangeParams.java @@ -0,0 +1,50 @@ +/* ServerKeyExchangeParams.java -- Server key exchange parameters 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; + +/** + * A parameter structure sent by the server in an SSL key exchange. + * + * @see ServerRSAParams + * @see ServerDHParams + */ +interface ServerKeyExchangeParams extends Constructed +{ + KeyExchangeAlgorithm algorithm (); +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerNameList.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerNameList.java new file mode 100644 index 000000000..38f092476 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerNameList.java @@ -0,0 +1,311 @@ +/* ServerNameList.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.net.ssl.provider; + +import gnu.javax.net.ssl.provider.Extension.Value; + +import java.io.PrintWriter; +import java.io.StringWriter; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.CharBuffer; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; +import java.util.List; +import java.util.NoSuchElementException; + +/** + * The ServerName extension. + * + *
      + struct {
      +   NameType name_type;
      +   select (name_type) {
      +     case host_name: HostName;
      +   } name;
      +} ServerName;
      +
      +enum {
      +  host_name(0), (255)
      +} NameType;
      +
      +opaque HostName<1..2^16-1>;
      +
      +struct {
      +  ServerName server_name_list<1..2^16-1>
      +} ServerNameList;
      + * + *

      Implementation note: this class does not currently contain a + * set method. If you are modifying this list, then use the + * {@link #get(int)} method, and modify the returned {@link ServerName}. + * + * @author csm + */ +public class ServerNameList extends Value implements Iterable +{ + private ByteBuffer buffer; + + public ServerNameList (final ByteBuffer buffer) + { + this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); + } + + public ServerNameList(List names) + { + int length = 2; + for (ServerName name : names) + length += name.length(); + buffer = ByteBuffer.allocate(length); + buffer.putShort((short) (length - 2)); + for (ServerName name : names) + buffer.put(name.buffer()); + buffer.rewind(); + } + + public int length() + { + return (buffer.getShort(0) & 0xFFFF) + 2; + } + + public ByteBuffer buffer() + { + return (ByteBuffer) buffer.duplicate().limit(length()); + } + + public int size() + { + int n = 0; + final int len = length(); + for (int i = 2; i < len; ) + { + int l = buffer.getShort(i+1); + i += l + 3; + n++; + } + return n; + } + + public ServerName get (int index) + { + final int len = length(); + if (len == 0) + throw new IndexOutOfBoundsException("0; " + index); + int n = 0; + int i; + int l = buffer.getShort(3); + for (i = 2; i < len && n < index; ) + { + l = buffer.getShort(i+1); + i += l + 3; + n++; + } + if (n < index) + throw new IndexOutOfBoundsException(n + "; " + index); + ByteBuffer buf = ((ByteBuffer) buffer.duplicate().position(i).limit(i+l+3)).slice(); + return new ServerName (buf); + } + + public void setLength(final int newLength) + { + if (newLength < 0 || newLength > 65535) + throw new IllegalArgumentException("length must be between 0 and 65535"); + buffer.putShort(0, (short) newLength); + } + + public String toString() + { + return toString(null); + } + + public String toString(String prefix) + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + if (prefix != null) out.print(prefix); + out.println ("ServerNameList {"); + String subprefix = " "; + if (prefix != null) + subprefix = prefix + subprefix; + for (ServerName name : this) + { + out.println (name.toString(subprefix)); + } + if (prefix != null) out.print(prefix); + out.print ("};"); + return str.toString(); + } + + public java.util.Iterator iterator() + { + return new Iterator(); + } + + public class Iterator implements java.util.Iterator + { + private int index; + + public Iterator() + { + index = 0; + } + + public boolean hasNext() + { + return index < size(); + } + + public ServerName next() throws NoSuchElementException + { + try + { + return get (index++); + } + catch (IndexOutOfBoundsException ioobe) + { + throw new NoSuchElementException(); + } + } + + public void remove() + { + throw new UnsupportedOperationException(); + } + } + + public static class ServerName implements Constructed + { + private ByteBuffer buffer; + + public ServerName(final ByteBuffer buffer) + { + this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); + } + + public ServerName(NameType type, String name) + { + CharsetEncoder utf8 = Charset.forName("UTF-8").newEncoder(); + ByteBuffer nameBuf = null; + try + { + nameBuf = utf8.encode(CharBuffer.wrap(name)); + } + catch (CharacterCodingException cce) + { + // We don't expect this to happen; it's UTF-8. + throw new IllegalArgumentException(cce); + } + int length = 3 + nameBuf.remaining(); + buffer = ByteBuffer.allocate(length); + buffer.put((byte) type.getValue()); + buffer.putShort((short) (length - 3)); + buffer.put(nameBuf); + buffer.rewind(); + } + + public int length() + { + return (buffer.getShort(1) & 0xFFFF) + 3; + } + + public ByteBuffer buffer() + { + return (ByteBuffer) buffer.duplicate().limit(length()); + } + + public NameType type() + { + int v = (buffer.get(0) & 0xFF); + if (v == 0) + { + return NameType.HOST_NAME; + } + throw new IllegalArgumentException ("illegal name type: " + v); + } + + public String name() + { + int len = length(); + Charset cs = Charset.forName ("UTF-8"); + return cs.decode(((ByteBuffer) buffer.duplicate().position(3).limit(len))).toString(); + } + + public String toString() + { + return toString (null); + } + + public String toString(String prefix) + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + if (prefix != null) out.print (prefix); + out.println ("struct {"); + if (prefix != null) out.print (prefix); + out.print (" name_type = "); + out.print (type()); + out.println (";"); + if (prefix != null) out.print (prefix); + out.print (" server_name = "); + out.print (name()); + out.println (";"); + if (prefix != null) out.print (prefix); + out.print ("} ServerName;"); + return str.toString(); + } + } + + public static enum NameType + { + HOST_NAME (0); + + private final int value; + + private NameType (int value) + { + this.value = value; + } + + public int getValue() + { + return value; + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerPSKParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerPSKParameters.java new file mode 100644 index 000000000..9ecedb513 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerPSKParameters.java @@ -0,0 +1,127 @@ +/* ServerPSKParameters.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.net.ssl.provider; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.charset.Charset; + +/** + *

      +      struct {
      +          select (KeyExchangeAlgorithm) {
      +              /* other cases for rsa, diffie_hellman, etc. */
      +              case psk:  /* NEW */
      +                  opaque psk_identity_hint<0..2^16-1>;
      +          };
      +      } ServerKeyExchange;
      + * + * @author Casey Marshall (csm@gnu.org) + */ +public class ServerPSKParameters implements Builder, Constructed, ServerKeyExchangeParams +{ + private ByteBuffer buffer; + + public ServerPSKParameters(ByteBuffer buffer) + { + this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); + } + + public ServerPSKParameters(String identityHint) + { + Charset utf8 = Charset.forName("UTF-8"); + ByteBuffer identityHintBuffer = utf8.encode(identityHint); + buffer = ByteBuffer.allocate(2 + identityHintBuffer.remaining()); + buffer.putShort((short) identityHintBuffer.remaining()); + buffer.put(identityHintBuffer); + buffer.rewind(); + } + + public KeyExchangeAlgorithm algorithm() + { + return KeyExchangeAlgorithm.PSK; + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Builder#buffer() + */ + public ByteBuffer buffer() + { + return (ByteBuffer) buffer.duplicate().rewind().limit(length()); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Constructed#length() + */ + public int length() + { + return (buffer.getShort(0) & 0xFFFF) + 2; + } + + public String identityHint() + { + Charset utf8 = Charset.forName("UTF-8"); + return utf8.decode((ByteBuffer) buffer.duplicate().position(2).limit(length())).toString(); + } + + public @Override String toString() + { + return toString(null); + } + + /* (non-Javadoc) + * @see gnu.javax.net.ssl.provider.Constructed#toString(java.lang.String) + */ + public String toString(String prefix) + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + if (prefix != null) out.print(prefix); + out.println("struct {"); + if (prefix != null) out.print(prefix); + out.print(" identity_hint = "); + out.print(identityHint()); + out.println(";"); + if (prefix != null) out.print(prefix); + out.print("} ServerPSKParamaters;"); + return str.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerRSAParams.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerRSAParams.java new file mode 100644 index 000000000..ff265ce8a --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerRSAParams.java @@ -0,0 +1,163 @@ +/* ServerRSAParams.java -- The server's RSA 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.PrintWriter; +import java.io.StringWriter; +import java.math.BigInteger; +import java.nio.ByteBuffer; + +/** + * The ServerRSAParams structure. + * + *
      +struct
      +{
      +  opaque rsa_modulus<1..2^16-1>;
      +  opaque rsa_exponent<1..2^16-1>;
      +} ServerRSAParams;
      +
      + */ +public class ServerRSAParams implements ServerKeyExchangeParams +{ + + private final ByteBuffer buffer; + + public ServerRSAParams (final ByteBuffer buffer) + { + this.buffer = buffer; + } + + public KeyExchangeAlgorithm algorithm () + { + return KeyExchangeAlgorithm.RSA; + } + + public int length () + { + int offset = buffer.getShort (0) & 0xFFFF; + return (buffer.getShort (offset + 2) & 0xFFFF) + offset + 4; + } + + /** + * Gets the modulus field. + * + * @return The modulus. + */ + public BigInteger modulus () + { + int len = buffer.getShort (0) & 0xFFFF; + byte[] buf = new byte[len]; + buffer.position (2); + buffer.get (buf); + return new BigInteger (1, buf); + } + + /** + * Returns the exponent field. + * + * @return The exponent. + */ + public BigInteger exponent () + { + int off = (buffer.getShort (0) & 0xFFFF) + 2; + int len = buffer.getShort (off) & 0xFFFF; + byte[] buf = new byte[len]; + buffer.position (off + 2); + buffer.get (buf); + return new BigInteger (1, buf); + } + + /** + * Sets the modulus. + * + * @param modulus The modulus. + * @throws java.nio.ReadOnlyBufferException If the underlying buffer + * is not writable. + */ + public void setModulus (final BigInteger modulus) + { + byte[] buf = modulus.toByteArray (); + int length = (buf[0] == 0x00 ? buf.length - 1 : buf.length); + int offset = (buf[0] == 0x00 ? 1 : 0); + buffer.putShort (0, (short) length); + buffer.position (2); + buffer.put (buf, offset, length); + } + + /** + * Sets the exponent. + * + * @param exponent The exponent. + * @throws java.nio.ReadOnlyBufferException If the underlying buffer + * is not writeable. + */ + public void setExponent (final BigInteger exponent) + { + byte[] buf = exponent.toByteArray (); + int length = (buf[0] == 0x00 ? buf.length -1 : buf.length); + int offset = (buf[0] == 0x00 ? 1 : 0); + int where = (buffer.getShort (0) & 0xFFFF) + 2; + buffer.putShort (where, (short) length); + buffer.position (where + 2); + buffer.put (buf, offset, length); + } + + public String toString () + { + return toString (null); + } + + public String toString (final String prefix) + { + StringWriter str = new StringWriter (); + PrintWriter out = new PrintWriter (str); + if (prefix != null) out.print (prefix); + out.println ("struct {"); + if (prefix != null) out.print (prefix); + out.print (" rsa_modulus: "); + out.println (modulus ().toString (16)); + if (prefix != null) out.print (prefix); + out.print (" rsa_exponent: "); + out.println (exponent ()); + if (prefix != null) out.print (prefix); + out.print ("} ServerRSAParams;"); + return str.toString (); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/ServerRSA_PSKParameters.java b/libjava/classpath/gnu/javax/net/ssl/provider/ServerRSA_PSKParameters.java new file mode 100644 index 000000000..0895afe96 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/ServerRSA_PSKParameters.java @@ -0,0 +1,62 @@ +/* ServerRSA_PSKParameters.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.net.ssl.provider; + +import java.nio.ByteBuffer; + +/** + * @author Casey Marshall (csm@gnu.org) + */ +public class ServerRSA_PSKParameters extends ServerPSKParameters +{ + public ServerRSA_PSKParameters(ByteBuffer buffer) + { + super(buffer); + } + + public ServerRSA_PSKParameters(String identityHint) + { + super(identityHint); + } + + public @Override KeyExchangeAlgorithm algorithm() + { + return KeyExchangeAlgorithm.RSA_PSK; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SessionImpl.java b/libjava/classpath/gnu/javax/net/ssl/provider/SessionImpl.java new file mode 100644 index 000000000..6eb070efc --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SessionImpl.java @@ -0,0 +1,192 @@ +/* SessionImpl.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.net.ssl.provider; + +import gnu.javax.crypto.key.GnuPBEKey; +import gnu.javax.net.ssl.Session; +import java.io.IOException; +import java.io.Serializable; + +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SealedObject; +import javax.net.ssl.SSLException; + +public class SessionImpl extends Session +{ + static final long serialVersionUID = 8932976607588442485L; + CipherSuite suite; + ProtocolVersion version; + byte[] privateDataSalt; + SealedObject sealedPrivateData; + MaxFragmentLength maxLength; + + transient PrivateData privateData; + + public SessionImpl() + { + super(); + privateData = new PrivateData(); + } + + SecureRandom random () + { + return random; + } + + public String getProtocol() + { + return version.toString(); + } + + public void prepare(char[] passwd) throws SSLException + { + try + { + privateDataSalt = new byte[32]; + random.nextBytes(privateDataSalt); + GnuPBEKey key = new GnuPBEKey(passwd, privateDataSalt, 1000); + Cipher cipher = Cipher.getInstance("PBEWithHMacSHA256AndAES/OFB/PKCS7Padding"); + cipher.init(Cipher.ENCRYPT_MODE, key); + sealedPrivateData = new SealedObject(privateData, cipher); + } + catch (IllegalBlockSizeException ibse) + { + throw new SSLException(ibse); + } + catch (InvalidKeyException ike) + { + throw new SSLException(ike); + } + catch (IOException ioe) + { + throw new SSLException(ioe); + } + catch (NoSuchAlgorithmException nsae) + { + throw new SSLException(nsae); + } + catch (NoSuchPaddingException nspe) + { + throw new SSLException(nspe); + } + } + + public void repair(char[] passwd) throws SSLException + { + try + { + GnuPBEKey key = new GnuPBEKey(passwd, privateDataSalt, 1000); + privateData = (PrivateData) sealedPrivateData.getObject(key); + } + catch (ClassNotFoundException cnfe) + { + throw new SSLException(cnfe); + } + catch (InvalidKeyException ike) + { + throw new SSLException(ike); + } + catch (IOException ioe) + { + throw new SSLException(ioe); + } + catch (NoSuchAlgorithmException nsae) + { + throw new SSLException(nsae); + } + } + + public SealedObject privateData() throws SSLException + { + if (privateData == null) + throw new SSLException("this session has not been prepared"); + return sealedPrivateData; + } + + public void setPrivateData(SealedObject so) throws SSLException + { + this.sealedPrivateData = so; + } + + void setApplicationBufferSize(int size) + { + applicationBufferSize = size; + } + + void setRandom(SecureRandom random) + { + this.random = random; + } + + void setTruncatedMac(boolean truncatedMac) + { + this.truncatedMac = truncatedMac; + } + + void setId(Session.ID id) + { + this.sessionId = id; + } + + void setLocalCertificates(java.security.cert.Certificate[] chain) + { + this.localCerts = chain; + } + + void setPeerCertificates(java.security.cert.Certificate[] chain) + { + this.peerCerts = chain; + } + + void setPeerVerified(boolean peerVerified) + { + this.peerVerified = peerVerified; + } + + static class PrivateData implements Serializable + { + static final long serialVersionUID = -8040597659545984581L; + byte[] masterSecret; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Signature.java b/libjava/classpath/gnu/javax/net/ssl/provider/Signature.java new file mode 100644 index 000000000..160dd805f --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Signature.java @@ -0,0 +1,157 @@ +/* Signature.java -- SSL Signature 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.PrintWriter; +import java.io.StringWriter; + +import java.nio.ByteBuffer; + +/** + * The signature structure. + * + *
      +select (SignatureAlgorithm)
      +{
      +case anonymous:
      +  struct { };
      +case rsa:
      +  digitally-signed struct
      +  {
      +    opaque md5_hash[16];
      +    opaque sha_hash[20];
      +  };
      +case dsa:
      +  digitally-signed struct
      +  {
      +    opaque sha_hash[20];
      +  };
      +} Signature;
      + */ +public class Signature implements Builder, Constructed +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final ByteBuffer buffer; + private final SignatureAlgorithm alg; + + // Constructor. + // ------------------------------------------------------------------------- + + public Signature (final ByteBuffer buffer, final SignatureAlgorithm alg) + { + this.buffer = buffer; + this.alg = alg; + } + + public Signature (final byte[] sigValue, final SignatureAlgorithm alg) + { + buffer = ByteBuffer.allocate(sigValue.length + 2); + buffer.putShort((short) sigValue.length); + buffer.put(sigValue); + buffer.position(0); + this.alg = alg; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public int length () + { + if (alg.equals (SignatureAlgorithm.ANONYMOUS)) + return 0; + return (buffer.getShort (0) & 0xFFFF) + 2; + } + + public ByteBuffer buffer() + { + return (ByteBuffer) buffer.duplicate().limit(length()); + } + + public byte[] signature () + { + if (alg.equals (SignatureAlgorithm.ANONYMOUS)) + return new byte[0]; + int length = buffer.getShort (0) & 0xFFFF; + byte[] buf = new byte[length]; + ((ByteBuffer) buffer.duplicate().position(2)).get(buf); + return buf; + } + + public void setSignature (final byte[] signature) + { + setSignature (signature, 0, signature.length); + } + + public void setSignature (final byte[] signature, final int offset, final int length) + { + if (alg.equals (SignatureAlgorithm.ANONYMOUS)) + return; + buffer.putShort (0, (short) length); + buffer.position (2); + buffer.put (signature, offset, length); + } + + public String toString () + { + return toString (null); + } + + public String toString (final String prefix) + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + if (prefix != null) + out.print (prefix); + out.println("struct {"); + if (!alg.equals (SignatureAlgorithm.ANONYMOUS)) + { + String subprefix = " "; + if (prefix != null) + subprefix = prefix + subprefix; + out.print (Util.hexDump (signature (), subprefix)); + } + if (prefix != null) + out.print (prefix); + out.print ("} Signature;"); + return str.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SignatureAlgorithm.java b/libjava/classpath/gnu/javax/net/ssl/provider/SignatureAlgorithm.java new file mode 100644 index 000000000..79cff5626 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SignatureAlgorithm.java @@ -0,0 +1,62 @@ +/* SignatureAlgorithm.java -- Signature algorithm enumeration. + 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; + +public enum SignatureAlgorithm +{ + ANONYMOUS, RSA, DSA; + + /** + * Returns the algorithm name for this signature algorithm, which can + * be used with the JCA API to get a {@link java.security.Signature} for + * that algorithm. + * + * @return The algorithm name. + */ + public String algorithm() + { + switch (this) + { + case ANONYMOUS: return null; + case RSA: return "TLSv1.1-RSA"; + case DSA: return "DSS"; + } + return null; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/SimpleSessionContext.java b/libjava/classpath/gnu/javax/net/ssl/provider/SimpleSessionContext.java new file mode 100644 index 000000000..8d5745061 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/SimpleSessionContext.java @@ -0,0 +1,144 @@ +/* SimpleSessionContext.java -- memory-only session store. + 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.javax.net.ssl.AbstractSessionContext; +import gnu.javax.net.ssl.Session; +import gnu.javax.net.ssl.SessionStoreException; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * A simple, non-persistent SessionContext. + * + * @author csm + */ +public final class SimpleSessionContext + extends AbstractSessionContext +{ + /** + * By default, sessions last for 5 minutes. + */ + public static final int DEFAULT_TIMEOUT = 300; + + private final HashMap store; + private int storeLimit; + + public SimpleSessionContext() + { + super(DEFAULT_TIMEOUT); + storeLimit = 0; + store = new HashMap(); + } + + @Override + protected Session implGet(byte[] sessionId) + { + return store.get(new Session.ID(sessionId)); + } + + @Override + public void load(char[] password) throws SessionStoreException + { + // Not supported. Memory-only. + } + + @Override + public void put(Session session) + { + if (storeLimit > 0 && store.size() >= storeLimit) + { + Session oldest = null; + for (Map.Entry e : store.entrySet()) + { + Session s = e.getValue(); + long stamp = s.getLastAccessedTime(); + if (oldest == null || oldest.getLastAccessedTime() > stamp) + oldest = s; + } + store.remove(oldest.id()); + } + store.put(session.id(), session); + } + + @Override + public void remove(byte[] sessionId) + { + store.remove(new Session.ID(sessionId)); + } + + @Override + public void store(char[] password) throws SessionStoreException + { + // Not supported. Memory-only. + } + + public Enumeration getIds() + { + return new Enumeration() + { + Iterator it = store.keySet().iterator(); + + public boolean hasMoreElements() + { + return it.hasNext(); + } + + public Object nextElement() + { + return it.next().id(); + } + }; + } + + public int getSessionCacheSize() + { + return storeLimit; + } + + public void setSessionCacheSize(int size) + { + if (size < 0) + throw new IllegalArgumentException("cache size must be nonnegative"); + this.storeLimit = size; + } + +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/TLSHMac.java b/libjava/classpath/gnu/javax/net/ssl/provider/TLSHMac.java new file mode 100644 index 000000000..8bdda930b --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/TLSHMac.java @@ -0,0 +1,137 @@ +/* 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.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/libjava/classpath/gnu/javax/net/ssl/provider/TLSRandom.java b/libjava/classpath/gnu/javax/net/ssl/provider/TLSRandom.java new file mode 100644 index 000000000..ded632928 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/net/ssl/provider/TruncatedHMAC.java b/libjava/classpath/gnu/javax/net/ssl/provider/TruncatedHMAC.java new file mode 100644 index 000000000..97fff98dc --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/TruncatedHMAC.java @@ -0,0 +1,76 @@ +/* TruncatedHMAC.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.net.ssl.provider; + +import gnu.javax.net.ssl.provider.Extension.Value; + +import java.nio.ByteBuffer; + +/** + * The value type for the {@link Extension.Type#TRUNCATED_HMAC} extension. + * This extension has an empty value; this class is thusly empty. + * + * @author csm + */ +public class TruncatedHMAC extends Value +{ + + public int length() + { + return 0; + } + + public ByteBuffer buffer() + { + return ByteBuffer.wrap(new byte[0]); + } + + public String toString() + { + return toString(null); + } + + public String toString(String prefix) + { + String s = "TruncatedHMAC;"; + if (prefix != null) + s = prefix + s; + return s; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/TrustedAuthorities.java b/libjava/classpath/gnu/javax/net/ssl/provider/TrustedAuthorities.java new file mode 100644 index 000000000..72d072739 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/TrustedAuthorities.java @@ -0,0 +1,297 @@ +/* TrustedAuthorities.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.net.ssl.provider; + +import gnu.javax.net.ssl.provider.Extension.Value; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.Iterator; +import java.util.NoSuchElementException; + +import javax.security.auth.x500.X500Principal; + +/** + * The trusted authorities hello extension. + * + *
      +struct {
      +  TrustedAuthority trusted_authorities_list<0..2^16-1>;
      +} TrustedAuthorities;
      +
      +struct {
      +  IdentifierType identifier_type;
      +  select (identifier_type) {
      +    case pre_agreed: struct {};
      +    case key_sha1_hash: SHA1Hash;
      +    case x509_name: DistinguishedName;
      +    case cert_sha1_hash: SHA1Hash;
      +  } identifier;
      +} TrustedAuthority;
      +
      +enum {
      +  pre_agreed(0), key_sha1_hash(1), x509_name(2),
      +  cert_sha1_hash(3), (255)
      +} IdentifierType;
      +
      +opaque DistinguishedName<1..2^16-1>;
      + * + * @author csm + */ +public class TrustedAuthorities extends Value + implements Iterable +{ + private final ByteBuffer buffer; + + public TrustedAuthorities(final ByteBuffer buffer) + { + this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN); + } + + // XXX really implement Builder. + + public int length() + { + return 2 + (buffer.getShort(0) & 0xFFFF); + } + + public ByteBuffer buffer() + { + return (ByteBuffer) buffer.duplicate().limit(length()); + } + + public int size() + { + int len = buffer.getShort(0) & 0xFFFF; + int n = 0; + for (int i = 2; i < len; i++) + { + TrustedAuthority auth = + new TrustedAuthority((ByteBuffer) buffer.duplicate().position(i)); + i += auth.length(); + n++; + } + return n; + } + + public TrustedAuthority get(final int index) + { + int len = buffer.getShort(0) & 0xFFFF; + int n = 0; + int i = 2; + while (i < len && n <= index) + { + TrustedAuthority auth = + new TrustedAuthority((ByteBuffer) buffer.duplicate().position(i)); + if (n == index) + return auth; + i += auth.length(); + n++; + } + throw new IndexOutOfBoundsException(); + } + + public String toString() + { + return toString(null); + } + + public String toString(String prefix) + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + if (prefix != null) out.print(prefix); + out.println("struct {"); + String subprefix = " "; + if (prefix != null) + subprefix = prefix + subprefix; + for(TrustedAuthority ta : this) + out.println(ta); + if (prefix != null) out.print(prefix); + out.print("} TrustedAuthorities;"); + return str.toString(); + } + + public Iterator iterator() + { + return new AuthoritiesIterator(); + } + + public class AuthoritiesIterator implements Iterator + { + private int index; + + public AuthoritiesIterator() + { + index = 0; + } + + public TrustedAuthority next() throws NoSuchElementException + { + try + { + return get(index++); + } + catch (IndexOutOfBoundsException ioobe) + { + throw new NoSuchElementException(); + } + } + + public boolean hasNext() + { + return index < size(); + } + + public void remove() + { + throw new UnsupportedOperationException(); + } + } + + public static class TrustedAuthority implements Constructed + { + private final ByteBuffer buffer; + + public TrustedAuthority(final ByteBuffer buffer) + { + this.buffer = buffer; + } + + public int length() + { + switch (type().getValue()) + { + case 0: return 1; + case 1: + case 3: return 21; + case 2: return 3 + (buffer.getShort(1) & 0xFFFF); + } + throw new IllegalArgumentException("unknown authority type"); + } + + public byte[] sha1Hash() + { + IdentifierType t = type(); + if (t != IdentifierType.CERT_SHA1_HASH + && t != IdentifierType.KEY_SHA1_HASH) + throw new IllegalArgumentException(t + " does not have a hash value"); + byte[] b = new byte[20]; + ((ByteBuffer) buffer.duplicate().position(1)).get(b); + return b; + } + + public X500Principal name() + { + int len = buffer.getShort(1) & 0xFFFF; + byte[] b = new byte[len]; + ((ByteBuffer) buffer.duplicate().position(3)).get(b); + return new X500Principal(b); + } + + public IdentifierType type() + { + switch (buffer.get(0)) + { + case 0: return IdentifierType.PRE_AGREED; + case 1: return IdentifierType.KEY_SHA1_HASH; + case 2: return IdentifierType.X509_NAME; + case 3: return IdentifierType.CERT_SHA1_HASH; + } + + throw new IllegalArgumentException("invalid IdentifierType"); + } + + public String toString() + { + return toString(null); + } + + public String toString(String prefix) + { + StringWriter str = new StringWriter(); + PrintWriter out = new PrintWriter(str); + if (prefix != null) out.print(prefix); + out.println("struct {"); + if (prefix != null) out.print(prefix); + out.print(" identifier_type = "); + out.print(type()); + out.println(";"); + switch (type().getValue()) + { + case 0: break; + case 1: + case 3: + if (prefix != null) out.print(prefix); + out.print(" sha1_hash = "); + out.print(Util.toHexString(sha1Hash(), ':')); + out.println(";"); + break; + + case 2: + if (prefix != null) out.print(prefix); + out.print(" name = "); + out.print(name()); + out.println(";"); + } + if (prefix != null) out.print(prefix); + out.print("} TrustedAuthority;"); + return str.toString(); + } + } + + public static enum IdentifierType + { + PRE_AGREED (0), KEY_SHA1_HASH (1), X509_NAME (2), CERT_SHA1_HASH (3); + + private final int value; + + private IdentifierType(final int value) + { + this.value = value; + } + + public int getValue() + { + return value; + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java b/libjava/classpath/gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java new file mode 100644 index 000000000..94cd091c5 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java @@ -0,0 +1,81 @@ +/* UnresolvedExtensionValue.jav -- + 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.javax.net.ssl.provider.Extension.Value; + +import java.nio.ByteBuffer; + +public class UnresolvedExtensionValue extends Value +{ + private final ByteBuffer buffer; + + public UnresolvedExtensionValue (final ByteBuffer buffer) + { + this.buffer = buffer; + } + + public int length() + { + return buffer.limit(); + } + + public ByteBuffer buffer() + { + return value(); + } + + public ByteBuffer value() + { + return buffer.slice(); + } + + public String toString() + { + return toString(null); + } + + public String toString(final String prefix) + { + String s = Util.hexDump(buffer); + if (prefix != null) + s = prefix + s; + return s; + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/Util.java b/libjava/classpath/gnu/javax/net/ssl/provider/Util.java new file mode 100644 index 000000000..a2004b7aa --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/Util.java @@ -0,0 +1,495 @@ +/* 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 gnu.java.lang.CPStringBuilder; + +import java.io.PrintWriter; +import java.io.StringWriter; + +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.math.BigInteger; + +import java.nio.ByteBuffer; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.Security; + +/** + * A collection of useful class methods. + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +public final class Util +{ + + // Constants. + // ------------------------------------------------------------------------- + + static final String HEX = "0123456789abcdef"; + + // Static methods only. + private Util() { } + + // Class methods. + // ------------------------------------------------------------------------- + + public static Object wrapBuffer(ByteBuffer buffer) + { + return wrapBuffer(buffer, ""); + } + + public static Object wrapBuffer(ByteBuffer buffer, String prefix) + { + return new WrappedBuffer(buffer, prefix); + } + + private static class WrappedBuffer + { + private final ByteBuffer buffer; + private final String prefix; + + WrappedBuffer(ByteBuffer buffer, String prefix) + { + this.buffer = buffer; + this.prefix = prefix; + } + + public String toString() + { + return hexDump(buffer, prefix); + } + } + + /** + * Convert a hexadecimal string into its byte representation. + * + * @param hex The hexadecimal string. + * @return The converted bytes. + */ + public 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. + */ + public static String toHexString(byte[] buf, int off, int len) + { + CPStringBuilder str = new CPStringBuilder(); + 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)}. + */ + public 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. + */ + public static String toHexString(byte[] buf, int off, int len, char sep) + { + CPStringBuilder str = new CPStringBuilder(); + 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)}. + */ + public 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. + */ + public static String hexDump(byte[] buf, int off, int len, String prefix) + { + String nl = getProperty("line.separator"); + CPStringBuilder str = new CPStringBuilder(); + 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 = s.length(); j < 49; 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(); + } + + public static String hexDump (ByteBuffer buf) + { + return hexDump (buf, null); + } + + public static String hexDump (ByteBuffer buf, String prefix) + { + buf = buf.duplicate(); + StringWriter str = new StringWriter (); + PrintWriter out = new PrintWriter (str); + int i = 0; + int len = buf.remaining(); + byte[] line = new byte[16]; + while (i < len) + { + if (prefix != null) + out.print(prefix); + out.print(Util.formatInt (i, 16, 8)); + out.print(" "); + int l = Math.min(16, len - i); + buf.get(line, 0, l); + String s = Util.toHexString(line, 0, l, ' '); + out.print(s); + for (int j = s.length(); j < 49; j++) + out.print(' '); + for (int j = 0; j < l; j++) + { + int c = line[j] & 0xFF; + if (c < 0x20 || c > 0x7E) + out.print('.'); + else + out.print((char) c); + } + out.println(); + i += 16; + } + return str.toString(); + } + + /** + * See {@link #hexDump(byte[],int,int,String)}. + */ + public static String hexDump(byte[] buf, int off, int len) + { + return hexDump(buf, off, len, ""); + } + + /** + * See {@link #hexDump(byte[],int,int,String)}. + */ + public static String hexDump(byte[] buf, String prefix) + { + return hexDump(buf, 0, buf.length, prefix); + } + + /** + * See {@link #hexDump(byte[],int,int,String)}. + */ + public 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. + */ + public static String formatInt(int i, int radix, int len) + { + String s = Integer.toString(i, radix); + CPStringBuilder buf = new CPStringBuilder(); + 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. + */ + public 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)}. + */ + public 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. + */ + public 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. + */ + public 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. + */ + public 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. + */ + @Deprecated 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. + */ + @Deprecated static String getSecurityProperty(final String name) + { + return (String) AccessController.doPrivileged( + new PrivilegedAction() + { + public Object run() + { + return Security.getProperty(name); + } + } + ); + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/X500PrincipalList.java b/libjava/classpath/gnu/javax/net/ssl/provider/X500PrincipalList.java new file mode 100644 index 000000000..ffdcbbad2 --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/X500PrincipalList.java @@ -0,0 +1,272 @@ +/* X500PrincipalList.java -- A list of X.500 names. + 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.PrintWriter; +import java.io.StringWriter; + +import java.nio.ByteBuffer; + +import java.util.ConcurrentModificationException; +import java.util.ListIterator; +import java.util.NoSuchElementException; + +import javax.security.auth.x500.X500Principal; + +public final class X500PrincipalList implements Iterable +{ + private final ByteBuffer buffer; + private int modCount; + + public X500PrincipalList (final ByteBuffer buffer) + { + this.buffer = buffer; + modCount = 0; + } + + public int size () + { + return (buffer.getShort (0) & 0xFFFF); + } + + public int count () + { + int size = size (); + int i = 0; + for (int offset = 2; offset < size; i++) + { + int _size = (buffer.getShort (offset) & 0xFFFF); + // We don't want this going into an infinite loop if + // you mistakenly put a zero-length name. + if (_size == 0) + break; + offset += _size + 2; + } + return i; + } + + public X500Principal get (final int index) + { + if (index < 0) + throw new IndexOutOfBoundsException ("negative index"); + int size = size (); + int i = 0; + for (int offset = 2; offset < size; i++) + { + int _size = (buffer.getShort (offset) & 0xFFFF); + if (_size == 0) + throw new IndexOutOfBoundsException ("zero-length name encountered"); + if (i == index) + { + byte[] buf = new byte[_size]; + buffer.position (offset + 2); + buffer.get (buf); + return new X500Principal (buf); + } + offset += 2 + _size; + } + throw new IndexOutOfBoundsException ("limit: " + i + "; requested: " + index); + } + + public void put (final int index, final X500Principal principal) + { + put (index, principal.getEncoded ()); + } + + public void put (final int index, final byte[] encoded) + { + if (index < 0) + throw new IndexOutOfBoundsException ("negative index"); + int size = size (); + int i = 0; + for (int offset = 2; offset < size; i++) + { + int off = (buffer.getShort (offset) & 0xFFFF); + if (i == index) + { + buffer.putShort (offset, (short) encoded.length); + buffer.position (offset + 2); + buffer.put (encoded); + modCount++; + return; + } + offset += 2 + off; + } + throw new IndexOutOfBoundsException ("limit: " + (i-1) + "; requested: " + index); + } + + public void setSize (final int numNames, final int namesSize) + { + if (numNames < 1) + throw new IllegalArgumentException ("must have at least one name"); + int size = (numNames * 2) + namesSize; + if (size < 3 || size > buffer.capacity () || size > 0xFFFF) + throw new IllegalArgumentException ("size out of range; maximum: " + + Math.min (buffer.capacity (), 0xFFFF)); + buffer.putShort (0, (short) size); + } + + public String toString () + { + return toString (null); + } + + public String toString (final String prefix) + { + StringWriter str = new StringWriter (); + PrintWriter out = new PrintWriter (str); + if (prefix != null) out.print (prefix); + out.print ("["); + out.print (count ()); + out.println ("] {"); + for (Iterator it = new Iterator (); it.hasNext (); ) + { + if (prefix != null) out.print (prefix); + out.print (" "); + out.println (it.next ()); + } + if (prefix != null) out.print (prefix); + out.print ("};"); + return str.toString (); + } + + public boolean equals (Object o) + { + if (!(o instanceof X500PrincipalList)) + return false; + X500PrincipalList that = (X500PrincipalList) o; + + if (size () != that.size ()) + return false; + + for (Iterator it1 = new Iterator (), it2 = that.new Iterator (); + it1.hasNext () && it2.hasNext (); ) + { + if (!it1.next ().equals (it2.next ())) + return false; + } + return true; + } + + public java.util.Iterator iterator () + { + return new Iterator(); + } + + public class Iterator implements ListIterator + { + private final int modCount; + private int index; + private final int count; + + public Iterator () + { + this.modCount = X500PrincipalList.this.modCount; + index = 0; + count = count (); + } + + public void add (X500Principal o) + { + throw new UnsupportedOperationException (); + } + + public boolean hasNext () + { + return (index < count); + } + + public boolean hasPrevious () + { + return (index > 0); + } + + public X500Principal next () throws NoSuchElementException + { + if (modCount != X500PrincipalList.this.modCount) + throw new ConcurrentModificationException (); + try + { + return get (index++); + } + catch (IndexOutOfBoundsException ioobe) + { + throw new NoSuchElementException (); + } + } + + public int nextIndex () + { + if (hasNext ()) + return (index + 1); + return -1; + } + + public X500Principal previous () throws NoSuchElementException + { + if (index == 0) + throw new NoSuchElementException (); + if (modCount != X500PrincipalList.this.modCount) + throw new ConcurrentModificationException (); + try + { + return get (--index); + } + catch (IndexOutOfBoundsException ioobe) + { + throw new NoSuchElementException (); + } + } + + public int previousIndex () + { + return (index - 1); + } + + public void remove () + { + throw new UnsupportedOperationException (); + } + + public void set (final X500Principal o) + { + throw new UnsupportedOperationException (); + } + } +} diff --git a/libjava/classpath/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java b/libjava/classpath/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java new file mode 100644 index 000000000..a63cb2cbe --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java @@ -0,0 +1,396 @@ +/* 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.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.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.SSLEngine; +import javax.net.ssl.X509ExtendedKeyManager; +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 extends X509ExtendedKeyManager + { + // 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 @Override String chooseEngineClientAlias(String[] keyTypes, + Principal[] issuers, + SSLEngine engine) + { + for (String type : keyTypes) + { + String[] s = getClientAliases(type, 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 @Override String chooseEngineServerAlias(String keyType, + Principal[] issuers, + SSLEngine engine) + { + 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.equalsIgnoreCase("RSA") + || keyType.equalsIgnoreCase("DHE_RSA") + || keyType.equalsIgnoreCase("SRP_RSA") + || keyType.equalsIgnoreCase("rsa_sign") + || keyType.equalsIgnoreCase("RSA_PSK")) + { + if (!(privKey instanceof RSAPrivateKey) || + !(pubKey instanceof RSAPublicKey)) + continue; + } + else if (keyType.equalsIgnoreCase("DHE_DSS") + || keyType.equalsIgnoreCase("dss_sign") + || keyType.equalsIgnoreCase("SRP_DSS") + || keyType.equalsIgnoreCase("DSA")) + { + if (!(privKey instanceof DSAPrivateKey) || + !(pubKey instanceof DSAPublicKey)) + continue; + } + else if (keyType.equalsIgnoreCase("DH_RSA") + || keyType.equalsIgnoreCase("rsa_fixed_dh")) + { + if (!(privKey instanceof DHPrivateKey) || + !(pubKey instanceof DHPublicKey)) + continue; + if (!chain[0].getSigAlgName().equalsIgnoreCase("RSA")) + continue; + } + else if (keyType.equalsIgnoreCase("DH_DSS") + || keyType.equalsIgnoreCase("dss_fixed_dh")) + { + if (!(privKey instanceof DHPrivateKey) || + !(pubKey instanceof DHPublicKey)) + continue; + if (!chain[0].getSigAlgName().equalsIgnoreCase("DSA")) + continue; + } + else // Unknown key type; ignore it. + continue; + if (issuers == null || issuers.length == 0) + { + l.add(alias); + continue; + } + for (Principal issuer : issuers) + { + if (chain[0].getIssuerDN().equals(issuer)) + { + l.add(alias); + break; + } + } + } + return 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/libjava/classpath/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java b/libjava/classpath/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java new file mode 100644 index 000000000..ddd2f9c8b --- /dev/null +++ b/libjava/classpath/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java @@ -0,0 +1,295 @@ +/* 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.util.Set; + +import java.security.AccessController; +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertPath; +import java.security.cert.CertPathValidator; +import java.security.cert.CertPathValidatorException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.PKIXParameters; +import java.security.cert.TrustAnchor; +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.java.security.action.GetPropertyAction; +import gnu.java.security.x509.X509CertPath; +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. + // ------------------------------------------------------------------------- + + private static final String sep + = AccessController.doPrivileged(new GetPropertyAction("file.separator")); + + /** + * The location of the JSSE key store. + */ + private static final String JSSE_CERTS + = AccessController.doPrivileged(new GetPropertyAction("java.home")) + + sep + "lib" + sep + "security" + sep + "jssecerts"; + + /** + * The location of the system key store, containing the CA certs. + */ + private static final String CA_CERTS + = AccessController.doPrivileged(new GetPropertyAction("java.home")) + + sep + "lib" + sep + "security" + sep + "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) + { + GetPropertyAction gpa = new GetPropertyAction("javax.net.ssl.trustStoreType"); + String s = AccessController.doPrivileged(gpa); + if (s == null) + s = KeyStore.getDefaultType(); + store = KeyStore.getInstance(s); + try + { + s = AccessController.doPrivileged(gpa.setParameters("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 = AccessController.doPrivileged(gpa.setParameters("javax.net.ssl.trustStorePassword")); + store.load(in, p != null ? p.toCharArray() : null); + } + catch (IOException ioe) + { + throw new KeyStoreException(ioe); + } + catch (CertificateException ce) + { + throw new KeyStoreException(ce); + } + catch (NoSuchAlgorithmException nsae) + { + throw new KeyStoreException(nsae); + } + } + + 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((X509Certificate) c); + } + current = this.new Manager(l.toArray(new X509Certificate[l.size()])); + } + + // Inner class. + // ------------------------------------------------------------------------- + + /** + * The actual manager implementation returned. + */ + private class Manager implements X509TrustManager + { + + // Fields. + // ----------------------------------------------------------------------- + + private final Set anchors; + + // Constructor. + // ----------------------------------------------------------------------- + + Manager(X509Certificate[] trusted) + { + anchors = new HashSet(); + if (trusted != null) + { + for (X509Certificate cert : trusted) + { + anchors.add(new TrustAnchor(cert, null)); + } + } + } + + // 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() + { + return anchors.toArray(new X509Certificate[anchors.size()]); + } + + // Own methods. + // ----------------------------------------------------------------------- + + private void checkTrusted(X509Certificate[] chain, String authType) + throws CertificateException + { + CertPathValidator validator = null; + + try + { + validator = CertPathValidator.getInstance("PKIX"); + } + catch (NoSuchAlgorithmException nsae) + { + throw new CertificateException(nsae); + } + + CertPath path = new X509CertPath(Arrays.asList(chain)); + + PKIXParameters params = null; + try + { + params = new PKIXParameters(anchors); + // XXX we probably do want to enable revocation, but it's a pain + // in the ass. + params.setRevocationEnabled(false); + } + catch (InvalidAlgorithmParameterException iape) + { + throw new CertificateException(iape); + } + + try + { + validator.validate(path, params); + } + catch (CertPathValidatorException cpve) + { + throw new CertificateException(cpve); + } + catch (InvalidAlgorithmParameterException iape) + { + throw new CertificateException(iape); + } + } + } +} diff --git a/libjava/classpath/gnu/javax/print/CupsIppOperation.java b/libjava/classpath/gnu/javax/print/CupsIppOperation.java new file mode 100644 index 000000000..96744c1f3 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/CupsIppOperation.java @@ -0,0 +1,99 @@ +/* CupsIppOperation.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.javax.print; + + +/** + * Operations as provided by CUPS up to version 1.1 + *

      + * See: CUPS Implementation of IPP, chapter 3.2
      + * http://www.cups.org/doc-1.1/ipp.html + *

      + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class CupsIppOperation +{ + + /** Get the default destination - since CUPS 1.0 */ + public static final int CUPS_GET_DEFAULT = 0x4001; + + /** Get all of the available printers - since CUPS 1.0 */ + public static final int CUPS_GET_PRINTERS = 0x4002; + + /** Add or modify a printer - since CUPS 1.0 */ + public static final int CUPS_ADD_MODIFY_PRINTER = 0x4003; + + /** Delete a printer - since CUPS 1.0 */ + public static final int CUPS_DELETE_PRINTER = 0x4004; + + /** Get all of the available printer classes - since CUPS 1.0 */ + public static final int CUPS_GET_CLASSES = 0x4005; + + /** Add or modify a printer class - since CUPS 1.0 */ + public static final int CUPS_ADD_MODIFY_CLASS = 0x4006; + + /** Delete a printer class - since CUPS 1.0 */ + public static final int CUPS_DELETE_CLASS = 0x4007; + + /** Accept jobs on a printer or printer class - since CUPS 1.0 */ + public static final int CUPS_ACCEPT_JOBS = 0x4008; + + /** Reject jobs on a printer or printer class - since CUPS 1.0 */ + public static final int CUPS_REJECT_JOBS = 0x4009; + + /** Set the default destination - since CUPS 1.0 */ + public static final int CUPS_SET_DEFAULT = 0x400A; + + /** Get all of the available PPDs - since CUPS 1.1 */ + public static final int CUPS_GET_DEVICES = 0x400B; + + /** Get all of the available PPDs - since CUPS 1.1 */ + public static final int CUPS_GET_PPDS = 0x400C; + + /** Move a job to a different printer - since CUPS 1.1 */ + public static final int CUPS_MOVE_JOB = 0x400D; + + + private CupsIppOperation() + { + // not to be instantiated + } + +} diff --git a/libjava/classpath/gnu/javax/print/CupsMediaMapping.java b/libjava/classpath/gnu/javax/print/CupsMediaMapping.java new file mode 100644 index 000000000..49bd94d6f --- /dev/null +++ b/libjava/classpath/gnu/javax/print/CupsMediaMapping.java @@ -0,0 +1,176 @@ +/* CupsMediaMapping.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.javax.print; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import javax.print.attribute.standard.MediaSizeName; + +/** + * Provides the currently known mappings of the media attribute + * values of the CUPS printing system to the IPP standard values. + *

      + * The mapping is used to build up print service specific mappings + * for use of media attribute translation between Java JPS API and + * CUPS. + *

      + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public class CupsMediaMapping +{ + // the mapping map + private static final HashMap ippByCups = new HashMap(); + + /** + * Initialize currently known mappings. + */ + static + { + ippByCups.put("Postcard", MediaSizeName.JAPANESE_POSTCARD); + ippByCups.put("Statement", MediaSizeName.INVOICE); + + ippByCups.put("Letter", MediaSizeName.NA_LETTER); + ippByCups.put("Executive", MediaSizeName.EXECUTIVE); + ippByCups.put("Legal", MediaSizeName.NA_LEGAL); + + ippByCups.put("A0", MediaSizeName.ISO_A0); + ippByCups.put("A1", MediaSizeName.ISO_A1); + ippByCups.put("A2", MediaSizeName.ISO_A2); + ippByCups.put("A3", MediaSizeName.ISO_A3); + ippByCups.put("A4", MediaSizeName.ISO_A4); + ippByCups.put("A5", MediaSizeName.ISO_A5); + ippByCups.put("A6", MediaSizeName.ISO_A6); + ippByCups.put("A7", MediaSizeName.ISO_A7); + ippByCups.put("A8", MediaSizeName.ISO_A8); + ippByCups.put("A9", MediaSizeName.ISO_A9); + ippByCups.put("A10", MediaSizeName.ISO_A10); + + ippByCups.put("B0", MediaSizeName.JIS_B0); + ippByCups.put("B1", MediaSizeName.JIS_B1); + ippByCups.put("B2", MediaSizeName.JIS_B2); + ippByCups.put("B3", MediaSizeName.JIS_B3); + ippByCups.put("B4", MediaSizeName.JIS_B4); + ippByCups.put("B5", MediaSizeName.JIS_B5); + ippByCups.put("B6", MediaSizeName.JIS_B6); + ippByCups.put("B7", MediaSizeName.JIS_B7); + ippByCups.put("B8", MediaSizeName.JIS_B8); + ippByCups.put("B9", MediaSizeName.JIS_B9); + ippByCups.put("B10", MediaSizeName.JIS_B10); + + ippByCups.put("ISOB0", MediaSizeName.ISO_B0); + ippByCups.put("ISOB1", MediaSizeName.ISO_B1); + ippByCups.put("ISOB2", MediaSizeName.ISO_B2); + ippByCups.put("ISOB3", MediaSizeName.ISO_B3); + ippByCups.put("ISOB4", MediaSizeName.ISO_B4); + ippByCups.put("ISOB5", MediaSizeName.ISO_B5); + ippByCups.put("ISOB6", MediaSizeName.ISO_B6); + ippByCups.put("ISOB7", MediaSizeName.ISO_B7); + ippByCups.put("ISOB8", MediaSizeName.ISO_B8); + ippByCups.put("ISOB9", MediaSizeName.ISO_B9); + ippByCups.put("ISOB10", MediaSizeName.ISO_B10); + ippByCups.put("EnvISOB0", MediaSizeName.ISO_B0); + ippByCups.put("EnvISOB1", MediaSizeName.ISO_B1); + ippByCups.put("EnvISOB2", MediaSizeName.ISO_B2); + ippByCups.put("EnvISOB3", MediaSizeName.ISO_B3); + ippByCups.put("EnvISOB4", MediaSizeName.ISO_B4); + ippByCups.put("EnvISOB5", MediaSizeName.ISO_B5); + ippByCups.put("EnvISOB6", MediaSizeName.ISO_B6); + ippByCups.put("EnvISOB7", MediaSizeName.ISO_B7); + ippByCups.put("EnvISOB8", MediaSizeName.ISO_B8); + ippByCups.put("EnvISOB9", MediaSizeName.ISO_B9); + ippByCups.put("EnvISOB10", MediaSizeName.ISO_B10); + + ippByCups.put("C0", MediaSizeName.ISO_C0); + ippByCups.put("C1", MediaSizeName.ISO_C1); + ippByCups.put("C2", MediaSizeName.ISO_C2); + ippByCups.put("C3", MediaSizeName.ISO_C3); + ippByCups.put("C4", MediaSizeName.ISO_C4); + ippByCups.put("C5", MediaSizeName.ISO_C5); + ippByCups.put("C6", MediaSizeName.ISO_C6); + + ippByCups.put("EnvPersonal", MediaSizeName.PERSONAL_ENVELOPE); + ippByCups.put("EnvMonarch", MediaSizeName.MONARCH_ENVELOPE); + ippByCups.put("Monarch", MediaSizeName.MONARCH_ENVELOPE); + ippByCups.put("Env9", MediaSizeName.NA_NUMBER_9_ENVELOPE); + ippByCups.put("Env10", MediaSizeName.NA_NUMBER_10_ENVELOPE); + ippByCups.put("Env11", MediaSizeName.NA_NUMBER_11_ENVELOPE); + ippByCups.put("Env12", MediaSizeName.NA_NUMBER_12_ENVELOPE); + ippByCups.put("Env14", MediaSizeName.NA_NUMBER_14_ENVELOPE); + ippByCups.put("c8x10", MediaSizeName.NA_8X10); + + ippByCups.put("EnvDL", MediaSizeName.ISO_DESIGNATED_LONG); + ippByCups.put("DL", MediaSizeName.ISO_DESIGNATED_LONG); + ippByCups.put("EnvC0", MediaSizeName.ISO_C0); + ippByCups.put("EnvC1", MediaSizeName.ISO_C1); + ippByCups.put("EnvC2", MediaSizeName.ISO_C2); + ippByCups.put("EnvC3", MediaSizeName.ISO_C3); + ippByCups.put("EnvC4", MediaSizeName.ISO_C4); + ippByCups.put("EnvC5", MediaSizeName.ISO_C5); + ippByCups.put("EnvC6", MediaSizeName.ISO_C6); + } + + /** + * Returns the IPP media name of the given cups name. + * + * @param cupsName the name in cups + * @return The IPP name if a mapping is known, null otherwise. + */ + public static final String getIppName(String cupsName) + { + return (String) ippByCups.get(cupsName); + } + + /** + * Returns the mapping map for iteration. + * + * @return The mapping map as unmodifiable map. + */ + public static final Map getMappingMap() + { + return Collections.unmodifiableMap(ippByCups); + } + + private CupsMediaMapping() + { + // not to be instantiated + } +} diff --git a/libjava/classpath/gnu/javax/print/CupsPrintService.java b/libjava/classpath/gnu/javax/print/CupsPrintService.java new file mode 100644 index 000000000..f3bec996c --- /dev/null +++ b/libjava/classpath/gnu/javax/print/CupsPrintService.java @@ -0,0 +1,104 @@ +/* CupsPrintService.java -- Cups specific implementation subclass + 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.print; + +import gnu.javax.print.ipp.IppException; +import gnu.javax.print.ipp.IppMultiDocPrintService; +import gnu.javax.print.ipp.IppResponse; + +import java.net.URI; + +import javax.print.DocFlavor; +import javax.print.attribute.AttributeSet; + +/** + * Implementation of the PrintService/MultiDocPrintService + * interface for Cups printers (supports Cups 1.1 and up) + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class CupsPrintService extends IppMultiDocPrintService +{ + + /** + * Creates a CupsPrintService object. + * + * @param uri the URI of the IPP printer. + * @param username the user of this print service. + * @param password the password of the user. + * + * @throws IppException if an error during connection occurs. + */ + public CupsPrintService(URI uri, String username, String password) + throws IppException + { + super(uri, username, password); + } + + /** + * Overridden for CUPS specific handling of the media attribute. + */ + protected Object handleSupportedAttributeValuesResponse(IppResponse response, + Class category) + { + // TODO Implement different behaviour of cups here - actually the Media + // printing attribute stuff. For now just use IPP reference implementation. + return super.handleSupportedAttributeValuesResponse(response, category); + } + + /** + * Overridden for CUPS specific handling of the media attribute. + */ + public Object getDefaultAttributeValue(Class category) + { + // TODO Implement media attribute behaviour for cups here + //if (category.equals(Media.class) + + return super.getDefaultAttributeValue(category); + } + + /** + * Overridden as CUPS does not implement Validate-Job correctly. + */ + public AttributeSet getUnsupportedAttributes(DocFlavor flavor, AttributeSet attributes) + { + // TODO Implement a heuristic unsupported attribute identification. + return super.getUnsupportedAttributes(flavor, attributes); + } +} diff --git a/libjava/classpath/gnu/javax/print/CupsPrintServiceLookup.java b/libjava/classpath/gnu/javax/print/CupsPrintServiceLookup.java new file mode 100644 index 000000000..d537c398f --- /dev/null +++ b/libjava/classpath/gnu/javax/print/CupsPrintServiceLookup.java @@ -0,0 +1,260 @@ +/* CupsPrintServiceLookup.java -- Implementation based on CUPS + 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.print; + +import gnu.javax.print.ipp.IppException; + +import java.util.ArrayList; + +import javax.print.DocFlavor; +import javax.print.MultiDocPrintService; +import javax.print.PrintService; +import javax.print.PrintServiceLookup; +import javax.print.attribute.Attribute; +import javax.print.attribute.AttributeSet; + +/** + * The platform default implementation based on CUPS. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public class CupsPrintServiceLookup extends PrintServiceLookup +{ + private CupsServer server; + + /** + * Default constructor checking security access. + */ + public CupsPrintServiceLookup() + { + // security + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPrintJobAccess(); + + // use the localhost cups server + server = new CupsServer(null, null); + } + + /** + * This is the printer marked as default in CUPS. + * + * @return The default lookup service or + * null if there is no default. + */ + public PrintService getDefaultPrintService() + { + try + { + return server.getDefaultPrinter(); + } + catch (IppException e) + { + // if discovery fails treat as if there is none + return null; + } + } + + /** + * All printers and printer classes of the CUPS server are checked. + * If flavors or attributes are null the constraint is not used. + * + * @param flavors the document flavors which have to be supported. + * @param attributes the attributes which have to be supported. + * + * @return The multidoc print services of the implementing lookup service + * for the given parameters, or an array of length 0 if none is available. + */ + public MultiDocPrintService[] getMultiDocPrintServices(DocFlavor[] flavors, + AttributeSet attributes) + { + ArrayList result = new ArrayList(); + PrintService[] services = getPrintServices(); + + for (int i=0; i < services.length; i++) + { + if (checkMultiDocPrintService(flavors, attributes, services[i])) + result.add(services[i]); + } + + return (MultiDocPrintService[]) result.toArray( + new MultiDocPrintService[result.size()]); + } + + /** + * These are all printers and printer classes of the CUPS server. + * + * @return All known print services regardless of supported features, + * or an array of length 0 if none is available. + */ + public PrintService[] getPrintServices() + { + ArrayList result = new ArrayList(); + + try + { + result.addAll(server.getAllPrinters()); + result.addAll(server.getAllClasses()); + } + catch (IppException e) + { + // ignore as this method cannot throw exceptions + // if print service discovery fails - bad luck + } + return (PrintService[]) result.toArray(new PrintService[result.size()]); + } + + + /** + * All printers and printer classes of the CUPS server are checked. + * If flavor or attributes are null the constraint is not used. + * + * @param flavor the document flavor which has to be supported. + * @param attributes the attributes which have to be supported. + * + * @return The print services of the implementing lookup service + * for the given parameters, or an array of length 0 if none is available. + */ + public PrintService[] getPrintServices(DocFlavor flavor, + AttributeSet attributes) + { + ArrayList result = new ArrayList(); + PrintService[] services = getPrintServices(); + + for (int i=0; i < services.length; i++) + { + if (checkPrintService(flavor, attributes, services[i])) + result.add(services[i]); + } + + return (PrintService[]) result.toArray(new PrintService[result.size()]); + } + + /** + * Checks the given print service - own method so it can be used also + * to check application registered print services from PrintServiceLookup. + * + * @param flavor the document flavor which has to be supported. + * @param attributes the attributes which have to be supported. + * @param service the service to check + * + * @return true if all constraints match, false + * otherwise. + */ + public boolean checkPrintService(DocFlavor flavor, AttributeSet attributes, + PrintService service) + { + boolean allAttributesSupported = true; + if (flavor == null || service.isDocFlavorSupported(flavor)) + { + if (attributes == null || attributes.size() == 0) + return allAttributesSupported; + + Attribute[] atts = attributes.toArray(); + for (int i = 0; i < atts.length; i++) + { + if (! service.isAttributeCategorySupported(atts[i].getCategory())) + { + allAttributesSupported = false; + break; + } + } + return allAttributesSupported; + } + + return false; + } + + /** + * Checks the given print service - own method so it can be used also + * to check application registered print services from PrintServiceLookup. + * + * @param flavors the document flavors which have to be supported. + * @param attributes the attributes which have to be supported. + * @param service the service to check + * + * @return true if all constraints match, false + * otherwise. + */ + public boolean checkMultiDocPrintService(DocFlavor[] flavors, + AttributeSet attributes, PrintService service) + { + if (service instanceof MultiDocPrintService) + { + boolean allFlavorsSupported = true; + boolean allAttributesSupported = true; + + if (flavors == null || flavors.length != 0) + allFlavorsSupported = true; + else + { + for (int k = 0; k < flavors.length; k++) + { + if (! service.isDocFlavorSupported(flavors[k])) + { + allFlavorsSupported = false; + break; + } + } + } + + if (attributes == null || attributes.size() == 0) + allAttributesSupported = true; + else + { + Attribute[] atts = attributes.toArray(); + for (int j = 0; j < atts.length; j++) + { + if (! service.isAttributeCategorySupported( + atts[j].getCategory())) + { + allAttributesSupported = false; + break; + } + } + } + + if (allAttributesSupported && allFlavorsSupported) + return true; + } + + return false; + } + +} diff --git a/libjava/classpath/gnu/javax/print/CupsServer.java b/libjava/classpath/gnu/javax/print/CupsServer.java new file mode 100644 index 000000000..6dbcfc732 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/CupsServer.java @@ -0,0 +1,288 @@ +/* CupsServer.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.javax.print; + +import gnu.javax.print.ipp.IppException; +import gnu.javax.print.ipp.IppPrintService; +import gnu.javax.print.ipp.IppRequest; +import gnu.javax.print.ipp.IppResponse; +import gnu.javax.print.ipp.attribute.RequestedAttributes; +import gnu.javax.print.ipp.attribute.supported.PrinterUriSupported; + +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * CupsServer represents a host running a cups + * compatible server. It mainly consists of its URI and optional + * user and password combination if access is restricted. + *

      + * It provides methods for retrival of valid CUPS printer uris + * that are used to construct IppPrintService objects. + *

      + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public class CupsServer +{ + /** + * The URI of the CUPS server. + * This is something like: http://localhost:631 + */ + private transient URI uri; + + /** + * The optional username. + */ + private transient String username; + + /** + * The optional password for the user. + */ + private transient String password; + + /** + * Creates a CupsServer object which + * tries to connect to a cups server. + * + * If gnu.javax.print.server is explicitly set, then + * that hostname will be used. Otherwise it will default to localhost. + * + * @param username the username + * @param password the password for the username. + */ + public CupsServer(String username, String password) + { + this.username = username; + this.password = password; + + this.uri = null; + try + { + String serv = System.getProperty("gnu.javax.print.server"); + if( serv != null ) + this.uri = new URI("http://"+serv+":631"); + } + catch(URISyntaxException use) + { + throw new RuntimeException("gnu.javax.print.CupsServer value is not a valid hostname."); + } + catch(SecurityException se) + { + } + + try + { + if( this.uri == null ) + this.uri = new URI("http://localhost:631"); + } + catch (URISyntaxException e) + { + // does not happen + } + } + + /** + * Creates a CupsServer object which + * tries to connect to a running cups server on the + * given URI. + * + * @param uri the URI of the server. + * @param username the username + * @param password the password for the username. + */ + public CupsServer(URI uri, String username, String password) + { + this.uri = uri; + this.username = username; + this.password = password; + } + + /** + * Requests the default printer from this CUPS server. + * This is always returned as IppPrintService. + * + * @return The default printer. + * @throws IppException if problems during request/response processing occur. + */ + public IppPrintService getDefaultPrinter() throws IppException + { + IppResponse response = null; + + try + { + IppRequest request = new IppRequest(uri, username, password); + request.setOperationID((short)CupsIppOperation.CUPS_GET_DEFAULT); + request.setOperationAttributeDefaults(); + + RequestedAttributes requestedAttrs + = new RequestedAttributes("printer-uri-supported"); + request.addOperationAttribute(requestedAttrs); + + response = request.send(); + } + catch (IOException e) + { + throw new IppException("IOException in IPP request/response.", e); + } + + Map printerAttributes = (Map) response.getPrinterAttributes().get(0); + Set uris = (Set) printerAttributes.get(PrinterUriSupported.class); + PrinterUriSupported uri = (PrinterUriSupported) uris.toArray()[0]; + + IppPrintService service + = new CupsPrintService(uri.getURI(), username, password); + + return service; + } + + /** + * Requests all printers from this CUPS server. + * + * @return The list of available printers. + * @throws IppException if problems during request/response processing occur. + */ + public List getAllPrinters() throws IppException + { + IppResponse response = null; + + try + { + IppRequest request = new IppRequest(uri, username, password); + request.setOperationID((short)CupsIppOperation.CUPS_GET_PRINTERS); + request.setOperationAttributeDefaults(); + + RequestedAttributes requestedAttrs + = new RequestedAttributes("printer-uri-supported"); + request.addOperationAttribute(requestedAttrs); + + response = request.send(); + } + catch (IOException e) + { + throw new IppException("IOException in IPP request/response.", e); + } + + List prAttr = response.getPrinterAttributes(); + List services = new ArrayList(); + + for (int i=0; i < prAttr.size(); i++) + { + Map printerAttributes = (Map) prAttr.get(i); + Set uris = (Set) printerAttributes.get(PrinterUriSupported.class); + PrinterUriSupported uri = (PrinterUriSupported) uris.toArray()[0]; + + try + { + CupsPrintService cups = new CupsPrintService(uri.getURI(), + username, password); + services.add(cups); + } + catch (IppException e) + { + // do nothing, we only catch the IppException which could be + // thrown during instantiation as single printers may be discovered + // correctly but not usable due to other security restrictions + } + } + + return services; + } + + /** + * Requests all classes from this CUPS server. Classes in cups are + * collections of printers. This means jobs directed to a class + * are forwarded to the first available printer of the collection. + * + * @return The list of available classes. + * @throws IppException if problems during request/response processing occur. + */ + public List getAllClasses() throws IppException + { + IppResponse response = null; + + try + { + IppRequest request = new IppRequest(uri, username, password); + request.setOperationID((short)CupsIppOperation.CUPS_GET_CLASSES); + request.setOperationAttributeDefaults(); + + RequestedAttributes requestedAttrs + = new RequestedAttributes("printer-uri-supported"); + request.addOperationAttribute(requestedAttrs); + + response = request.send(); + } + catch (IOException e) + { + throw new IppException("IOException in IPP request/response.", e); + } + + List prAttr = response.getPrinterAttributes(); + List services = new ArrayList(); + + for (int i=0; i < prAttr.size(); i++) + { + Map printerAttributes = (Map) prAttr.get(i); + Set uris = (Set) printerAttributes.get(PrinterUriSupported.class); + PrinterUriSupported uri = (PrinterUriSupported) uris.toArray()[0]; + + try + { + CupsPrintService cups = new CupsPrintService(uri.getURI(), + username, password); + services.add(cups); + } + catch (IppException e) + { + // do nothing, we only catch the IppException which could be + // thrown during instantiation as single printers may be discovered + // correctly but not usable due to other security restrictions + } + } + + return services; + } + +} diff --git a/libjava/classpath/gnu/javax/print/PrintAttributeException.java b/libjava/classpath/gnu/javax/print/PrintAttributeException.java new file mode 100644 index 000000000..5bcc59fc9 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/PrintAttributeException.java @@ -0,0 +1,148 @@ +/* PrintAttributeException.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.javax.print; + +import javax.print.AttributeException; +import javax.print.PrintException; +import javax.print.attribute.Attribute; + +/** + * A PrintException further refining the exception + * cause by providing an implementation of the print exception + * interface AttributeException. + * + * @see javax.print.PrintException + * @see javax.print.AttributeException + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class PrintAttributeException extends PrintException + implements AttributeException +{ + private Class[] categories; + private Attribute[] values; + + /** + * Constructs a PrintAttributeException + * with the given unsupported attributes and/or values. + * + * @param unsupportedAttributes the unsupported categories, + * may be null. + * @param unsupportedValues the unsupported attribute values, + * may be null. + */ + public PrintAttributeException(Class[] unsupportedAttributes, + Attribute[] unsupportedValues) + { + super(); + categories = unsupportedAttributes; + values = unsupportedValues; + } + + /** + * Constructs a PrintAttributeException + * with the given unsupported attributes and/or values. + * + * @param e chained exception + * @param unsupportedAttributes the unsupported categories, + * may be null. + * @param unsupportedValues the unsupported attribute values, + * may be null. + */ + public PrintAttributeException(Exception e, + Class[] unsupportedAttributes, Attribute[] unsupportedValues) + { + super(e); + categories = unsupportedAttributes; + values = unsupportedValues; + } + + /** + * Constructs a PrintAttributeException + * with the given unsupported attributes and/or values. + * + * @param s detailed message + * @param unsupportedAttributes the unsupported categories, + * may be null. + * @param unsupportedValues the unsupported attribute values, + * may be null. + */ + public PrintAttributeException(String s, + Class[] unsupportedAttributes, Attribute[] unsupportedValues) + { + super(s); + categories = unsupportedAttributes; + values = unsupportedValues; + } + + /** + * Constructs a PrintAttributeException + * with the given unsupported attributes and/or values. + * + * @param s detailed message + * @param e chained exception + * @param unsupportedAttributes the unsupported categories, + * may be null. + * @param unsupportedValues the unsupported attribute values, + * may be null. + */ + public PrintAttributeException(String s, Exception e, + Class[] unsupportedAttributes, Attribute[] unsupportedValues) + { + super(s, e); + categories = unsupportedAttributes; + values = unsupportedValues; + } + + /** + * @see AttributeException#getUnsupportedAttributes() + */ + public Class[] getUnsupportedAttributes() + { + return categories; + } + + /** + * @see AttributeException#getUnsupportedValues() + */ + public Attribute[] getUnsupportedValues() + { + return values; + } +} diff --git a/libjava/classpath/gnu/javax/print/PrintFlavorException.java b/libjava/classpath/gnu/javax/print/PrintFlavorException.java new file mode 100644 index 000000000..a9342db96 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/PrintFlavorException.java @@ -0,0 +1,120 @@ +/* PrintFlavorException.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.javax.print; + +import javax.print.DocFlavor; +import javax.print.FlavorException; +import javax.print.PrintException; + +/** + * A PrintException further refining the exception + * cause by providing an implementation of the print exception + * interface FlavorException. + * + * @see javax.print.PrintException + * @see javax.print.FlavorException + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public class PrintFlavorException extends PrintException + implements FlavorException +{ + private DocFlavor[] flavors; + + /** + * Constructs a PrintFlavorException + * with the given unsupported doc flavor array + * + * @param unsupportedFlavors the unsupported document flavors. + */ + public PrintFlavorException(DocFlavor[] unsupportedFlavors) + { + super(); + flavors = unsupportedFlavors; + } + + /** + * Constructs a PrintFlavorException + * with the given unsupported doc flavor array + * + * @param e chained exception + * @param unsupportedFlavors the unsupported document flavors. + */ + public PrintFlavorException(Exception e, DocFlavor[] unsupportedFlavors) + { + super(e); + flavors = unsupportedFlavors; + } + + /** + * Constructs a PrintFlavorException + * with the given unsupported doc flavor array + * + * @param s detailed message + * @param unsupportedFlavors the unsupported document flavors. + */ + public PrintFlavorException(String s, DocFlavor[] unsupportedFlavors) + { + super(s); + flavors = unsupportedFlavors; + } + + /** + * Constructs a PrintFlavorException + * with the given unsupported doc flavor array + * + * @param s detailed message + * @param e chained exception + * @param unsupportedFlavors the unsupported document flavors. + */ + public PrintFlavorException(String s, Exception e, + DocFlavor[] unsupportedFlavors) + { + super(s, e); + flavors = unsupportedFlavors; + } + + /** + * @see FlavorException#getUnsupportedFlavors() + */ + public DocFlavor[] getUnsupportedFlavors() + { + return flavors; + } +} diff --git a/libjava/classpath/gnu/javax/print/PrintUriException.java b/libjava/classpath/gnu/javax/print/PrintUriException.java new file mode 100644 index 000000000..9c13c132a --- /dev/null +++ b/libjava/classpath/gnu/javax/print/PrintUriException.java @@ -0,0 +1,140 @@ +/* PrintUriException.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.javax.print; + +import java.net.URI; + +import javax.print.PrintException; +import javax.print.URIException; + +/** + * A PrintException further refining the exception + * cause by providing an implementation of the print exception + * interface URIException. + * + * @see javax.print.PrintException + * @see javax.print.URIException + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class PrintUriException extends PrintException + implements URIException +{ + private int reason; + private URI uri; + + /** + * Constructs a PrintUriException with the given reason + * and unsupported URI instance. + * + * @param reason the reason for the exception. + * @param unsupportedUri the URI which is unsupported. + * + * @see URIException + */ + public PrintUriException(int reason, URI unsupportedUri) + { + super(); + this.reason = reason; + uri = unsupportedUri; + } + + /** + * Constructs a PrintUriException with the given reason + * and unsupported URI instance. + * + * @param e chained exception + * @param reason the reason for the exception. + * @param unsupportedUri the URI which is unsupported. + */ + public PrintUriException(Exception e, int reason, URI unsupportedUri) + { + super(e); + this.reason = reason; + uri = unsupportedUri; + } + + /** + * Constructs a PrintUriException with the given reason + * and unsupported URI instance. + * + * @param s detailed message + * @param reason the reason for the exception. + * @param unsupportedUri the URI which is unsupported. + */ + public PrintUriException(String s, int reason, URI unsupportedUri) + { + super(s); + this.reason = reason; + uri = unsupportedUri; + } + + /** + * Constructs a PrintUriException with the given reason + * and unsupported URI instance. + * + * @param s detailed message + * @param e chained exception + * @param reason the reason for the exception. + * @param unsupportedUri the URI which is unsupported. + */ + public PrintUriException(String s, Exception e, + int reason, URI unsupportedUri) + { + super(s, e); + this.reason = reason; + uri = unsupportedUri; + } + + /** + * @see URIException#getReason() + */ + public int getReason() + { + return reason; + } + + /** + * @see URIException#getUnsupportedURI() + */ + public URI getUnsupportedURI() + { + return uri; + } +} diff --git a/libjava/classpath/gnu/javax/print/PrinterDialog.java b/libjava/classpath/gnu/javax/print/PrinterDialog.java new file mode 100644 index 000000000..6557baf4f --- /dev/null +++ b/libjava/classpath/gnu/javax/print/PrinterDialog.java @@ -0,0 +1,1722 @@ +/* PrinterDialog.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.javax.print; + +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.GraphicsConfiguration; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.HeadlessException; +import java.awt.Insets; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.util.ArrayList; +import java.util.ResourceBundle; + +import javax.print.DocFlavor; +import javax.print.PrintService; +import javax.print.attribute.Attribute; +import javax.print.attribute.HashPrintRequestAttributeSet; +import javax.print.attribute.PrintRequestAttributeSet; +import javax.print.attribute.standard.Chromaticity; +import javax.print.attribute.standard.Copies; +import javax.print.attribute.standard.Destination; +import javax.print.attribute.standard.JobName; +import javax.print.attribute.standard.JobPriority; +import javax.print.attribute.standard.JobSheets; +import javax.print.attribute.standard.Media; +import javax.print.attribute.standard.MediaPrintableArea; +import javax.print.attribute.standard.OrientationRequested; +import javax.print.attribute.standard.PageRanges; +import javax.print.attribute.standard.PrintQuality; +import javax.print.attribute.standard.PrinterInfo; +import javax.print.attribute.standard.PrinterIsAcceptingJobs; +import javax.print.attribute.standard.PrinterMakeAndModel; +import javax.print.attribute.standard.PrinterState; +import javax.print.attribute.standard.RequestingUserName; +import javax.print.attribute.standard.SheetCollate; +import javax.print.attribute.standard.Sides; +import javax.swing.BorderFactory; +import javax.swing.Box; +import javax.swing.BoxLayout; +import javax.swing.ButtonGroup; +import javax.swing.JButton; +import javax.swing.JCheckBox; +import javax.swing.JComboBox; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JRadioButton; +import javax.swing.JSpinner; +import javax.swing.JTabbedPane; +import javax.swing.JTextField; +import javax.swing.SpinnerNumberModel; +import javax.swing.border.TitledBorder; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; + +/** + * Implementation of the PrinterDialog used by + * {@link javax.print.ServiceUI} for visual selection + * of print services and its attributes. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class PrinterDialog extends JDialog implements ActionListener +{ + + /** + * The General Panel used in the printing dialog. + * @author Wolfgang Baer (WBaer@gmx.de) + */ + final class GeneralPanel extends JPanel + { + /** + * Handles the copies attribute. + * @author Wolfgang Baer (WBaer@gmx.de) + */ + final class CopiesAndSorted extends JPanel + implements ChangeListener, ActionListener + { + private JCheckBox sort; + private JSpinner copies; + private JLabel copies_lb; + private SpinnerNumberModel copiesModel; + + CopiesAndSorted() + { + copies_lb = new JLabel(getLocalizedString("lb.copies")); + sort = new JCheckBox(getLocalizedString("cb.sort")); + sort.addActionListener(this); + + copiesModel = new SpinnerNumberModel(1, 1, 9999, 1); + copies = new JSpinner(copiesModel); + copies.addChangeListener(this); + + GridBagLayout layout = new GridBagLayout(); + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.BOTH; + c.insets = new Insets(5, 5, 5, 5); + + setLayout(layout); + setBorder(new TitledBorder(getLocalizedString("title.copies"))); + + c.anchor = GridBagConstraints.WEST; + + c.gridx = 0; + c.gridy = 0; + add(copies_lb, c); + + c.gridx = 1; + c.gridy = 0; + add(copies, c); + + c.gridx = 0; + c.gridy = 1; + add(sort, c); + } + + // copies jspinner state + public void stateChanged(ChangeEvent event) + { + int value = ((Integer) copies.getValue()).intValue(); + atts.add(new Copies(value)); + + if (value > 1 && categorySupported(SheetCollate.class)) + sort.setEnabled(true); + else + sort.setEnabled(false); + } + + // sorted checkbox state + public void actionPerformed(ActionEvent event) + { + if (sort.isSelected()) + atts.add(SheetCollate.COLLATED); + } + + /** + * Called to update for new selected + * print service. Tests if currently + * selected attributes are supported. + */ + void updateForSelectedService() + { + if (categorySupported(Copies.class)) + { + copies.setEnabled(true); + copies_lb.setEnabled(true); + + Copies copies = (Copies) attribute(Copies.class); + if (copies != null) + copiesModel.setValue(new Integer(copies.getValue())); + + if (((Integer)copiesModel.getValue()).intValue() > 1 + && categorySupported(SheetCollate.class)) + { + sort.setEnabled(true); + Attribute collate = attribute(SheetCollate.class); + if (collate != null && collate.equals(SheetCollate.COLLATED)) + sort.setSelected(true); + } + else + sort.setEnabled(false); + } + else + { + copies.setEnabled(false); + copies_lb.setEnabled(false); + } + } + } + + /** + * Handles the print ranges attribute. + * @author Wolfgang Baer (WBaer@gmx.de) + */ + final class PrintRange extends JPanel + implements ActionListener, FocusListener + { + private JLabel to; + private JRadioButton all_rb, pages_rb; + private JTextField from_tf, to_tf; + + PrintRange() + { + to = new JLabel(getLocalizedString("lb.to")); + to.setEnabled(false); + + all_rb = new JRadioButton(getLocalizedString("rbt.all")); + all_rb.setSelected(true); + all_rb.setActionCommand("ALL"); + all_rb.addActionListener(this); + pages_rb = new JRadioButton(getLocalizedString("rbt.pages")); + pages_rb.setActionCommand("PAGES"); + pages_rb.setEnabled(false); + pages_rb.addActionListener(this); + + ButtonGroup group = new ButtonGroup(); + group.add(all_rb); + group.add(pages_rb); + + from_tf = new JTextField("1", 4); + from_tf.setEnabled(false); + from_tf.addFocusListener(this); + to_tf = new JTextField("1", 4); + to_tf.setEnabled(false); + to_tf.addFocusListener(this); + + GridBagLayout layout = new GridBagLayout(); + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.BOTH; + + setLayout(layout); + setBorder(new TitledBorder(getLocalizedString("title.printrange"))); + + c.insets = new Insets(15, 5, 5, 5); + c.gridx = 0; + c.gridy = 0; + add(all_rb, c); + + c.insets = new Insets(5, 5, 15, 5); + c.gridx = 0; + c.gridy = 1; + add(pages_rb, c); + + c.gridx = 1; + c.gridy = 1; + add(from_tf, c); + + c.gridx = 2; + c.gridy = 1; + add(to, c); + + c.insets = new Insets(5, 5, 15, 15); + c.gridx = 3; + c.gridy = 1; + add(to_tf, c); + } + + // focus pagerange + public void focusGained(FocusEvent event) + { + updatePageRanges(); + } + + public void focusLost(FocusEvent event) + { + updatePageRanges(); + } + + // updates the range after user changed it + private void updatePageRanges() + { + int lower = Integer.parseInt(from_tf.getText()); + int upper = Integer.parseInt(to_tf.getText()); + + if (lower > upper) + { + upper = lower; + to_tf.setText("" + lower); + } + + PageRanges range = new PageRanges(lower, upper); + atts.add(range); + } + + // page range change + public void actionPerformed(ActionEvent e) + { + // if ALL is selected we must use a full-range object + if (e.getActionCommand().equals("ALL")) + { + from_tf.setEnabled(false); + to.setEnabled(false); + to_tf.setEnabled(false); + + atts.add(new PageRanges(1, Integer.MAX_VALUE)); + } + else + { + from_tf.setEnabled(true); + to.setEnabled(true); + to_tf.setEnabled(true); + all_rb.setSelected(false); + } + } + + /** + * Called to update for new selected + * print service. Tests if currently + * selected attributes are supported. + */ + void updateForSelectedService() + { + if (categorySupported(PageRanges.class)) + { + pages_rb.setEnabled(true); + PageRanges range = (PageRanges) attribute(PageRanges.class); + if (range != null) + { + from_tf.setEnabled(true); + to.setEnabled(true); + to_tf.setEnabled(true); + all_rb.setSelected(false); + pages_rb.setSelected(true); + + int[][] members = range.getMembers(); + // Although passed in attributes may contain more than one + // range we only take the first one + from_tf.setText("" + members[0][0]); + to_tf.setText("" + members[0][1]); + } + } + else + { + from_tf.setEnabled(false); + to.setEnabled(false); + to_tf.setEnabled(false); + all_rb.setSelected(true); + } + } + } + + /** + * Handles the selection of the print services + * and its location and description attributes. + * @author Wolfgang Baer (WBaer@gmx.de) + */ + final class PrintServices extends JPanel + implements ActionListener + { + private JLabel name, status, typ, info; + private JLabel statusValue, typValue, infoValue; + private JButton attributes; + private JComboBox services_cob; + private JCheckBox fileRedirection_cb; + + PrintServices() + { + name = new JLabel(getLocalizedString("lb.name")); + status = new JLabel(getLocalizedString("lb.status")); + typ = new JLabel(getLocalizedString("lb.typ")); + info = new JLabel(getLocalizedString("lb.info")); + typValue = new JLabel(); + infoValue = new JLabel(); + statusValue = new JLabel(); + + attributes = new JButton(getLocalizedString("bt.attributes")); + attributes.setEnabled(false); + attributes.setActionCommand("ATTRIBUTES"); + attributes.addActionListener(this); + + services_cob = new JComboBox(getPrintServices()); + services_cob.setActionCommand("SERVICE"); + services_cob.addActionListener(this); + + fileRedirection_cb = new JCheckBox(getLocalizedString("cb.output")); + fileRedirection_cb.setEnabled(false); + + GridBagLayout layout = new GridBagLayout(); + GridBagConstraints c = new GridBagConstraints(); + + setLayout(layout); + setBorder(new TitledBorder(getLocalizedString("title.printservice"))); + + c.insets = new Insets(5, 5, 5, 5); + c.anchor = GridBagConstraints.LINE_END; + c.gridx = 0; + c.gridy = 0; + add(name, c); + + c.gridx = 0; + c.gridy = 1; + add(status, c); + + c.gridx = 0; + c.gridy = 2; + add(typ, c); + + c.gridx = 0; + c.gridy = 3; + add(info, c); + + c.gridx = 2; + c.gridy = 3; + c.weightx = 1; + add(fileRedirection_cb, c); + + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.HORIZONTAL; + c.gridx = 1; + c.gridy = 0; + c.weightx = 1.5; + add(services_cob, c); + + c.gridx = 1; + c.gridy = 1; + c.gridwidth = 2; + c.weightx = 1; + add(statusValue, c); + + c.gridx = 1; + c.gridy = 2; + c.gridwidth = 2; + c.weightx = 1; + add(typValue, c); + + c.gridx = 1; + c.gridy = 3; + c.gridwidth = 2; + c.weightx = 1; + add(infoValue, c); + + c.gridx = 2; + c.gridy = 0; + c.weightx = 1.5; + add(attributes, c); + } + + public void actionPerformed(ActionEvent e) + { + if (e.getActionCommand().equals("SERVICE")) + { + setSelectedPrintService((PrintService) services_cob.getSelectedItem()); + updateAll(); + } + else if (e.getActionCommand().equals("ATTRIBUTES")) + { + // TODO LowPriority-Enhancement: As tests have shown this button + // is even gray and not enabled under Windows - Its a good place + // to provide a classpath specific browsing dialog for all + // attributes not in the default printing dialog. + } + } + + /** + * Called to update for new selected + * print service. Tests if currently + * selected attributes are supported. + */ + void updateForSelectedService() + { + PrinterMakeAndModel att1 = + getSelectedPrintService().getAttribute(PrinterMakeAndModel.class); + typValue.setText(att1 == null ? "" : att1.getValue()); + + PrinterInfo att2 = + getSelectedPrintService().getAttribute(PrinterInfo.class); + infoValue.setText(att2 == null ? "" : att2.getValue()); + + PrinterIsAcceptingJobs att3 = + getSelectedPrintService().getAttribute(PrinterIsAcceptingJobs.class); + PrinterState att4 = + getSelectedPrintService().getAttribute(PrinterState.class); + + String status = att4.toString(); + if (att3 == PrinterIsAcceptingJobs.ACCEPTING_JOBS) + status += " - " + getLocalizedString("lb.acceptingjobs"); + else if (att3 == PrinterIsAcceptingJobs.NOT_ACCEPTING_JOBS) + status += " - " + getLocalizedString("lb.notacceptingjobs"); + + statusValue.setText(status); + + if (categorySupported(Destination.class)) + { + fileRedirection_cb.setEnabled(false); + } + } + + } + + private PrintServices printserv_panel; + private PrintRange printrange_panel; + private CopiesAndSorted copies; + + /** + * Constructs the General Panel. + */ + public GeneralPanel() + { + setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + + printserv_panel = new PrintServices(); + printrange_panel = new PrintRange(); + copies = new CopiesAndSorted(); + + JPanel layout_panel = new JPanel(); + layout_panel.setLayout(new BoxLayout(layout_panel, BoxLayout.LINE_AXIS)); + layout_panel.add(printrange_panel); + layout_panel.add(Box.createRigidArea(new Dimension(10, 0))); + layout_panel.add(copies); + + setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); + add(printserv_panel); + add(Box.createRigidArea(new Dimension(0, 12))); + add(layout_panel); + } + + /** + * Calls update on all internal panels to adjust + * for a new selected print service. + */ + void update() + { + printserv_panel.updateForSelectedService(); + printrange_panel.updateForSelectedService(); + copies.updateForSelectedService(); + } + } + + /** + * The Page setup Panel. + * @author Wolfgang Baer (WBaer@gmx.de) + */ + final class PageSetupPanel extends JPanel + { + /** + * Handles the orientation attribute. + * @author Wolfgang Baer (WBaer@gmx.de) + */ + final class Orientation extends JPanel implements ActionListener + { + private JRadioButton portrait, landscape, rev_portrait, rev_landscape; + + Orientation() + { + portrait = new JRadioButton(getLocalizedString("rbt.portrait")); + portrait.addActionListener(this); + landscape = new JRadioButton(getLocalizedString("rbt.landscape")); + landscape.addActionListener(this); + rev_portrait = new JRadioButton(getLocalizedString("rbt.revportrait")); + rev_portrait.addActionListener(this); + rev_landscape = new JRadioButton(getLocalizedString("rbt.revlandscape")); + rev_landscape.addActionListener(this); + + ButtonGroup group = new ButtonGroup(); + group.add(portrait); + group.add(landscape); + group.add(rev_portrait); + group.add(rev_landscape); + + GridBagLayout layout = new GridBagLayout(); + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.BOTH; + + setLayout(layout); + setBorder(new TitledBorder(getLocalizedString("title.orientation"))); + + c.insets = new Insets(5, 5, 5, 5); + c.gridx = 0; + c.gridy = 0; + add(portrait, c); + + c.gridx = 0; + c.gridy = 1; + add(landscape, c); + + c.gridx = 0; + c.gridy = 2; + add(rev_portrait, c); + + c.gridx = 0; + c.gridy = 3; + add(rev_landscape, c); + } + + // event handling orientation + public void actionPerformed(ActionEvent e) + { + if (e.getSource() == portrait) + atts.add(OrientationRequested.PORTRAIT); + else if (e.getSource() == landscape) + atts.add(OrientationRequested.LANDSCAPE); + else if (e.getSource() == rev_portrait) + atts.add(OrientationRequested.REVERSE_PORTRAIT); + else + atts.add(OrientationRequested.REVERSE_LANDSCAPE); + } + + /** + * Called to update for new selected + * print service. Tests if currently + * selected attributes are supported. + */ + void updateForSelectedService() + { + if (categorySupported(OrientationRequested.class)) + { + portrait.setEnabled(true); + landscape.setEnabled(true); + rev_landscape.setEnabled(true); + rev_portrait.setEnabled(true); + + Attribute orientation = attribute(OrientationRequested.class); + if (orientation != null) + { + if (orientation.equals(OrientationRequested.LANDSCAPE)) + landscape.setSelected(true); + else if (orientation.equals(OrientationRequested.PORTRAIT)) + portrait.setSelected(true); + else if (orientation.equals(OrientationRequested.REVERSE_PORTRAIT)) + rev_portrait.setSelected(true); + else + rev_landscape.setSelected(true); + } + else + { + Object defaultValue = defaultValue(OrientationRequested.class); + if (defaultValue.equals(OrientationRequested.LANDSCAPE)) + landscape.setSelected(true); + else if (defaultValue.equals(OrientationRequested.PORTRAIT)) + portrait.setSelected(true); + else if (defaultValue.equals(OrientationRequested.REVERSE_PORTRAIT)) + rev_portrait.setSelected(true); + else + rev_landscape.setSelected(true); + } + } + else + { + portrait.setEnabled(false); + landscape.setEnabled(false); + rev_landscape.setEnabled(false); + rev_portrait.setEnabled(false); + } + } + } + + /** + * Handles the media attribute. + * @author Wolfgang Baer (WBaer@gmx.de) + */ + final class MediaTypes extends JPanel implements ActionListener + { + private JLabel size_lb, source_lb; + private JComboBox size, source; + + MediaTypes() + { + size_lb = new JLabel(getLocalizedString("lb.size")); + source_lb = new JLabel(getLocalizedString("lb.source")); + + size = new JComboBox(); + size.setEditable(false); + size.addActionListener(this); + source = new JComboBox(); + source.setEditable(false); + size.addActionListener(this); + + GridBagLayout layout = new GridBagLayout(); + GridBagConstraints c = new GridBagConstraints(); + + setLayout(layout); + setBorder(new TitledBorder(getLocalizedString("title.medias"))); + + c.insets = new Insets(5, 5, 5, 5); + c.anchor = GridBagConstraints.LINE_END; + c.gridx = 0; + c.gridy = 0; + add(size_lb, c); + + c.gridx = 0; + c.gridy = 1; + add(source_lb, c); + + c.anchor = GridBagConstraints.LINE_START; + c.fill = GridBagConstraints.HORIZONTAL; + c.gridx = 1; + c.gridy = 0; + c.weightx = 1.5; + add(size, c); + + c.gridx = 1; + c.gridy = 1; + c.weightx = 1.5; + add(source, c); + } + + public void actionPerformed(ActionEvent event) + { + if (event.getSource() == size) + { + Object obj = size.getSelectedItem(); + if (obj instanceof Media) + atts.add((Media) obj); + } + + // we ignore source events currently + // as only the automatic selection is used. + } + + /** + * Called to update for new selected + * print service. Tests if currently + * selected attributes are supported. + */ + void updateForSelectedService() + { + if (categorySupported(Media.class)) + { + Media[] medias = (Media[]) getSelectedPrintService() + .getSupportedAttributeValues(Media.class, flavor, null); + + size.removeAllItems(); + if (medias.length == 0) + size.addItem(getLocalizedString("lb.automatically")); + else + for (int i=0; i < medias.length; i++) + size.addItem(medias[i]); + + Media media = (Media) attribute(Media.class); + if (media != null) + size.setSelectedItem(media); + + // this is currently ignored + source.removeAllItems(); + source.addItem(getLocalizedString("lb.automatically")); + } + else + { + size.removeAllItems(); + source.removeAllItems(); + + size.addItem(getLocalizedString("lb.automatically")); + source.addItem(getLocalizedString("lb.automatically")); + } + } + } + + /** + * Handles the media printable area attribute. + * @author Wolfgang Baer (WBaer@gmx.de) + */ + final class Margins extends JPanel implements FocusListener + { + private JLabel left, right, top, bottom; + private JTextField left_tf, right_tf, top_tf, bottom_tf; + + Margins() + { + left = new JLabel(getLocalizedString("lb.left")); + right = new JLabel(getLocalizedString("lb.right")); + top = new JLabel(getLocalizedString("lb.top")); + bottom = new JLabel(getLocalizedString("lb.bottom")); + + left_tf = new JTextField(7); + left_tf.addFocusListener(this); + right_tf = new JTextField(7); + right_tf.addFocusListener(this); + top_tf = new JTextField(7); + top_tf.addFocusListener(this); + bottom_tf = new JTextField(7); + bottom_tf.addFocusListener(this); + + GridBagLayout layout = new GridBagLayout(); + GridBagConstraints c = new GridBagConstraints(); + + setLayout(layout); + setBorder(new TitledBorder(getLocalizedString("title.margins"))); + + c.insets = new Insets(5, 5, 5, 5); + c.gridx = 0; + c.gridy = 0; + add(left, c); + + c.gridx = 1; + c.gridy = 0; + add(right, c); + + c.insets = new Insets(5, 5, 5, 5); + c.gridx = 0; + c.gridy = 1; + add(left_tf, c); + + c.gridx = 1; + c.gridy = 1; + add(right_tf, c); + + c.insets = new Insets(10, 5, 5, 5); + c.gridx = 0; + c.gridy = 2; + add(top, c); + + c.gridx = 1; + c.gridy = 2; + add(bottom, c); + + c.insets = new Insets(0, 5, 5, 5); + c.gridx = 0; + c.gridy = 3; + add(top_tf, c); + + c.gridx = 1; + c.gridy = 3; + add(bottom_tf, c); + } + + public void focusGained(FocusEvent event) + { + updateMargins(); + } + + public void focusLost(FocusEvent event) + { + updateMargins(); + } + + // updates the margins after user changed it + private void updateMargins() + { + // We currently do not support this attribute + // as it is not in the IPP spec and therefore not in CUPS + } + + /** + * Called to update for new selected + * print service. Tests if currently + * selected attributes are supported. + */ + void updateForSelectedService() + { + if (categorySupported(MediaPrintableArea.class)) + { + left.setEnabled(true); + right.setEnabled(true); + top.setEnabled(true); + bottom.setEnabled(true); + left_tf.setEnabled(true); + right_tf.setEnabled(true); + top_tf.setEnabled(true); + bottom_tf.setEnabled(true); + } + else + { + left.setEnabled(false); + right.setEnabled(false); + top.setEnabled(false); + bottom.setEnabled(false); + left_tf.setEnabled(false); + right_tf.setEnabled(false); + top_tf.setEnabled(false); + bottom_tf.setEnabled(false); + } + } + } + + private MediaTypes media_panel; + private Orientation orientation_panel; + private Margins margins_panel; + + /** + * Constructs the page setup user interface. + */ + public PageSetupPanel() + { + setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + + media_panel = new MediaTypes(); + orientation_panel = new Orientation(); + margins_panel = new Margins(); + + JPanel layout_panel = new JPanel(); + layout_panel.setLayout(new BoxLayout(layout_panel, BoxLayout.LINE_AXIS)); + layout_panel.add(orientation_panel); + layout_panel.add(Box.createRigidArea(new Dimension(10, 0))); + layout_panel.add(margins_panel); + + setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); + add(media_panel); + add(Box.createRigidArea(new Dimension(0, 12))); + add(layout_panel); + } + + /** + * Calls update on all internal panels to adjust + * for a new selected print service. + */ + void update() + { + media_panel.updateForSelectedService(); + orientation_panel.updateForSelectedService(); + margins_panel.updateForSelectedService(); + } + } + + /** + * The Appearance panel for quality, color etc. + * @author Wolfgang Baer (WBaer@gmx.de) + */ + final class AppearancePanel extends JPanel + { + /** + * Handles the print quality attribute. + * @author Wolfgang Baer (WBaer@gmx.de) + */ + final class Quality extends JPanel implements ActionListener + { + private JRadioButton low, normal, high; + private ButtonGroup group; + + Quality() + { + low = new JRadioButton(getLocalizedString("rbt.low")); + low.addActionListener(this); + normal = new JRadioButton(getLocalizedString("rbt.normal")); + normal.addActionListener(this); + high = new JRadioButton(getLocalizedString("rbt.high")); + high.addActionListener(this); + + group = new ButtonGroup(); + group.add(low); + group.add(normal); + group.add(high); + + GridBagLayout layout = new GridBagLayout(); + GridBagConstraints c = new GridBagConstraints(); + + setLayout(layout); + setBorder(new TitledBorder(getLocalizedString("title.quality"))); + + c.fill = GridBagConstraints.HORIZONTAL; + c.insets = new Insets(5, 5, 5, 5); + c.gridx = 0; + c.gridy = 0; + add(low, c); + + c.gridx = 0; + c.gridy = 1; + add(normal, c); + + c.gridx = 0; + c.gridy = 2; + add(high, c); + } + + public void actionPerformed(ActionEvent e) + { + if (e.getSource() == low) + atts.add(PrintQuality.DRAFT); + else if (e.getSource() == normal) + atts.add(PrintQuality.NORMAL); + else + atts.add(PrintQuality.HIGH); + } + + /** + * Called to update for new selected + * print service. Tests if currently + * selected attributes are supported. + */ + void updateForSelectedService() + { + if (categorySupported(PrintQuality.class)) + { + low.setEnabled(true); + normal.setEnabled(true); + high.setEnabled(true); + + Object defaultValue = defaultValue(PrintQuality.class); + Attribute quality = attribute(PrintQuality.class); + + if (quality != null) + { + if (quality.equals(PrintQuality.DRAFT)) + low.setSelected(true); + else if (quality.equals(PrintQuality.NORMAL)) + normal.setSelected(true); + else + high.setSelected(true); + } + else + { + if (defaultValue.equals(PrintQuality.DRAFT)) + low.setSelected(true); + else if (defaultValue.equals(PrintQuality.NORMAL)) + normal.setSelected(true); + else + high.setSelected(true); + } + } + else + { + low.setEnabled(false); + normal.setEnabled(false); + high.setEnabled(false); + } + } + } + + /** + * Handles the job attributes as requesting username, jobname etc. + * @author Wolfgang Baer (WBaer@gmx.de) + */ + final class JobAttributes extends JPanel + implements ActionListener, ChangeListener, FocusListener + { + private JLabel jobname, username, priority_lb; + private JTextField jobname_tf, username_tf; + private JCheckBox cover; + private JSpinner priority; + private SpinnerNumberModel model; + + JobAttributes() + { + jobname = new JLabel(getLocalizedString("lb.jobname")); + username = new JLabel(getLocalizedString("lb.username")); + priority_lb = new JLabel(getLocalizedString("lb.priority")); + + cover = new JCheckBox(getLocalizedString("cb.cover")); + cover.addActionListener(this); + + model = new SpinnerNumberModel(1, 1, 100, 1); + priority = new JSpinner(model); + priority.addChangeListener(this); + + jobname_tf = new JTextField(); + jobname_tf.addFocusListener(this); + username_tf = new JTextField(); + username_tf.addFocusListener(this); + + GridBagLayout layout = new GridBagLayout(); + GridBagConstraints c = new GridBagConstraints(); + + setLayout(layout); + setBorder(new TitledBorder(getLocalizedString("title.jobattributes"))); + + c.insets = new Insets(10, 5, 10, 5); + c.gridx = 0; + c.gridy = 0; + add(cover, c); + + c.anchor = GridBagConstraints.LINE_END; + c.gridx = 1; + c.gridy = 0; + c.weightx = 2; + add(priority_lb, c); + + c.gridx = 2; + c.gridy = 0; + c.weightx = 0.5; + add(priority, c); + + c.anchor = GridBagConstraints.LINE_END; + c.gridx = 0; + c.gridy = 1; + add(jobname, c); + + c.gridx = 0; + c.gridy = 2; + add(username, c); + + c.anchor = GridBagConstraints.CENTER; + c.fill = GridBagConstraints.HORIZONTAL; + c.gridx = 1; + c.gridy = 1; + c.gridwidth = 2; + c.weightx = 1.5; + add(jobname_tf, c); + + c.insets = new Insets(10, 5, 15, 5); + c.gridx = 1; + c.gridy = 2; + add(username_tf, c); + } + + public void actionPerformed(ActionEvent event) + { + if (cover.isSelected()) + atts.add(JobSheets.STANDARD); + else + atts.add(JobSheets.NONE); + } + + public void stateChanged(ChangeEvent event) + { + int value = ((Integer) priority.getValue()).intValue(); + atts.add(new JobPriority(value)); + } + + public void focusGained(FocusEvent event) + { + updateTextfields(event); + } + + public void focusLost(FocusEvent event) + { + updateTextfields(event); + } + + private void updateTextfields(FocusEvent event) + { + if (event.getSource() == jobname_tf) + atts.add(new JobName(jobname_tf.getText(), null)); + else + atts.add(new RequestingUserName(username_tf.getText(), null)); + } + + /** + * Called to update for new selected + * print service. Tests if currently + * selected attributes are supported. + */ + void updateForSelectedService() + { + // JobPriority + if (categorySupported(JobPriority.class)) + { + JobPriority prio = (JobPriority) attribute(JobPriority.class); + JobPriority value = (JobPriority) defaultValue(JobPriority.class); + priority.setEnabled(true); + if (prio != null) + model.setValue(new Integer(prio.getValue())); + else + model.setValue(new Integer(value.getValue())); + } + else + priority.setEnabled(false); + + // Requesting username + if (categorySupported(RequestingUserName.class)) + { + Attribute user = attribute(RequestingUserName.class); + Object value = defaultValue(RequestingUserName.class); + username.setEnabled(true); + if (user != null) + username_tf.setText(user.toString()); + else + username_tf.setText(value.toString()); + } + else + username.setEnabled(false); + + // Job Name + if (categorySupported(JobName.class)) + { + Attribute job = attribute(JobName.class); + Object value = defaultValue(JobName.class); + jobname.setEnabled(true); + if (job != null) + jobname_tf.setText(job.toString()); + else + jobname_tf.setText(value.toString()); + } + else + jobname.setEnabled(false); + + // Job sheets + if (categorySupported(JobSheets.class)) + { + Attribute sheet = attribute(JobSheets.class); + Object value = defaultValue(JobSheets.class); + cover.setEnabled(true); + if (sheet != null) + { + if (sheet.equals(JobSheets.NONE)) + cover.setSelected(false); + else + cover.setSelected(true); + } + else + { + if (value.equals(JobSheets.NONE)) + cover.setSelected(false); + else + cover.setSelected(true); + } + } + else + cover.setEnabled(false); + } + } + + /** + * Handles the sides attributes. + * @author Wolfgang Baer (WBaer@gmx.de) + */ + final class SidesPanel extends JPanel implements ActionListener + { + private JRadioButton oneside, calendar, duplex; + + SidesPanel() + { + oneside = new JRadioButton(getLocalizedString("rbt.onesided")); + oneside.addActionListener(this); + calendar = new JRadioButton(getLocalizedString("rbt.calendar")); + calendar.addActionListener(this); + duplex = new JRadioButton(getLocalizedString("rbt.duplex")); + duplex.addActionListener(this); + + ButtonGroup group = new ButtonGroup(); + group.add(oneside); + group.add(calendar); + group.add(duplex); + + GridBagLayout layout = new GridBagLayout(); + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.BOTH; + + setLayout(layout); + setBorder(new TitledBorder(getLocalizedString("title.sides"))); + + c.insets = new Insets(5, 5, 5, 5); + c.gridx = 0; + c.gridy = 0; + add(oneside, c); + + c.gridx = 0; + c.gridy = 1; + add(calendar, c); + + c.gridx = 0; + c.gridy = 2; + add(duplex, c); + } + + public void actionPerformed(ActionEvent e) + { + if (e.getSource() == calendar) + atts.add(Sides.TWO_SIDED_SHORT_EDGE); + else if (e.getSource() == oneside) + atts.add(Sides.ONE_SIDED); + else + atts.add(Sides.TWO_SIDED_LONG_EDGE); + } + + /** + * Called to update for new selected + * print service. Tests if currently + * selected attributes are supported. + */ + void updateForSelectedService() + { + if (categorySupported(Sides.class)) + { + oneside.setEnabled(true); + calendar.setEnabled(true); + duplex.setEnabled(true); + + Object defaultValue = defaultValue(Sides.class); + Attribute sides = attribute(Sides.class); + if (sides != null) + { + if (sides.equals(Sides.TWO_SIDED_SHORT_EDGE)) + calendar.setSelected(true); + else if (sides.equals(Sides.ONE_SIDED)) + oneside.setSelected(true); + else + duplex.setSelected(true); + } + else + { + if (defaultValue.equals(Sides.TWO_SIDED_SHORT_EDGE)) + calendar.setSelected(true); + else if (defaultValue.equals(Sides.ONE_SIDED)) + oneside.setSelected(true); + else + duplex.setSelected(true); + } + } + else + { + oneside.setEnabled(false); + calendar.setEnabled(false); + duplex.setEnabled(false); + } + } + } + + /** + * Handles the chromaticity attributes. + * @author Wolfgang Baer (WBaer@gmx.de) + */ + final class Color extends JPanel implements ActionListener + { + private JRadioButton bw, color; + + Color() + { + bw = new JRadioButton(getLocalizedString("rbt.blackwhite")); + bw.addActionListener(this); + color = new JRadioButton(getLocalizedString("rbt.color")); + color.addActionListener(this); + + ButtonGroup group = new ButtonGroup(); + group.add(bw); + group.add(color); + + GridBagLayout layout = new GridBagLayout(); + GridBagConstraints c = new GridBagConstraints(); + + setLayout(layout); + setBorder(new TitledBorder(getLocalizedString("title.color"))); + + c.fill = GridBagConstraints.HORIZONTAL; + c.insets = new Insets(5, 5, 5, 5); + c.gridx = 0; + c.gridy = 0; + add(bw, c); + + c.gridx = 0; + c.gridy = 1; + add(color, c); + } + + public void actionPerformed(ActionEvent e) + { + if (e.getSource() == bw) + atts.add(Chromaticity.MONOCHROME); + else + atts.add(Chromaticity.COLOR); + } + + /** + * Called to update for new selected + * print service. Tests if currently + * selected attributes are supported. + */ + void updateForSelectedService() + { + if (categorySupported(Chromaticity.class)) + { + bw.setEnabled(true); + color.setEnabled(true); + + Object defaultValue = defaultValue(Chromaticity.class); + Attribute chromaticity = attribute(Chromaticity.class); + if (chromaticity != null) + { + if (chromaticity.equals(Chromaticity.MONOCHROME)) + bw.setSelected(true); + else + color.setSelected(true); + } + else + { + if (defaultValue.equals(Chromaticity.MONOCHROME)) + bw.setSelected(true); + else + color.setSelected(true); + } + } + else + { + bw.setEnabled(false); + color.setEnabled(false); + } + } + } + + private Quality quality_panel; + private JobAttributes jobAttr_panel; + private SidesPanel sides_panel; + private Color chromaticy_panel; + + /** + * Creates the panel for appearance attributes. + */ + public AppearancePanel() + { + setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + + quality_panel = new Quality(); + jobAttr_panel = new JobAttributes(); + sides_panel = new SidesPanel(); + chromaticy_panel = new Color(); + + JPanel layout_panel = new JPanel(); + layout_panel.setLayout(new BoxLayout(layout_panel, BoxLayout.LINE_AXIS)); + layout_panel.add(chromaticy_panel); + layout_panel.add(Box.createRigidArea(new Dimension(10, 0))); + layout_panel.add(quality_panel); + + JPanel layout2_panel = new JPanel(); + layout2_panel.setLayout(new BoxLayout(layout2_panel, BoxLayout.LINE_AXIS)); + layout2_panel.add(sides_panel); + layout2_panel.add(Box.createRigidArea(new Dimension(10, 0))); + layout2_panel.add(jobAttr_panel); + + setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); + add(layout_panel); + add(Box.createRigidArea(new Dimension(0, 12))); + add(layout2_panel); + } + + /** + * Calls update on all internal panels to adjust + * for a new selected print service. + */ + void update() + { + quality_panel.updateForSelectedService(); + jobAttr_panel.updateForSelectedService(); + sides_panel.updateForSelectedService(); + chromaticy_panel.updateForSelectedService(); + } + } + + // on main contentpane + private JButton ok_bt; + private JButton cancel_bt; + + // the tabs + private GeneralPanel general_panel; + private PageSetupPanel pagesetup_panel; + private AppearancePanel appearance_panel; + + private PrintService[] services; + private PrintService defaultService; + private PrintService selectedService; + private DocFlavor flavor; + private PrintRequestAttributeSet attributes; + + private boolean onlyPageDialog; + private PrintRequestAttributeSet atts; + + private final static ResourceBundle messages; + + static + { + messages = ResourceBundle.getBundle("gnu/javax/print/PrinterDialog"); + } + + // TODO LowPriority: Include checks so that if a specific value formerly + // selected is no more supported by the new service changes to the default. + + /** + * Class private constructs a printer dialog. + * + * @param gc the screen to use. null is default screen. + * @param services the print services to browse (not null). + * @param defaultService the default service. If null + * the first of the print services in the services array will be used. + * @param flavor the flavours to be printed. + * @param attributes the attributes requested. Will be updated + * by selections done by the user in the dialog. + * @param onlyPageDialog if true a page settings only dialog is constructed. + * + * @throws HeadlessException if GraphicsEnvironment is headless + */ + private PrinterDialog(GraphicsConfiguration gc, PrintService[] services, + PrintService defaultService, DocFlavor flavor, + PrintRequestAttributeSet attributes, boolean onlyPageDialog, String title) + throws HeadlessException + { + super((Frame)null, title, true, gc); + + setResizable(false); + setDefaultCloseOperation(DISPOSE_ON_CLOSE); + + // check and remove service not supporting the flavor + if (flavor != null) + { + ArrayList list = new ArrayList(services.length); + for(int i=0; i < services.length; i++) + if (services[i].isDocFlavorSupported(flavor)) + list.add(services[i]); + + if (defaultService != null + && (! list.contains(defaultService))) + defaultService = (PrintService) list.get(0); + + PrintService[] newServices = new PrintService[list.size()]; + this.services = (PrintService[]) list.toArray(newServices); + } + else + this.services = services; + + if (defaultService == null) + this.defaultService = services[0]; + else + this.defaultService = defaultService; + + this.selectedService = this.defaultService; + this.flavor = flavor; + + // the attributes given by the user + this.attributes = attributes; + // the one to work with during browsing + this.atts = new HashPrintRequestAttributeSet(attributes); + + this.onlyPageDialog = onlyPageDialog; + + initUI(onlyPageDialog); + pack(); + updateAll(); + } + + /** + * Constructs a page settings only dialog. + * + * @param gc the screen to use. null is default screen. + * @param service the print service for the page dialog. + * the first of the print services in the services array will be used. + * @param flavor the flavours to be printed. + * @param attributes the attributes requested. Will be updated + * by selections done by the user in the dialog. + * + * @throws HeadlessException if GraphicsEnvironment is headless + */ + public PrinterDialog(GraphicsConfiguration gc, PrintService service, + DocFlavor flavor, PrintRequestAttributeSet attributes) + throws HeadlessException + { + this(gc, new PrintService[] {service}, service, flavor, attributes, + true, getLocalizedString("title.pagedialog")); + } + + /** + * Constructs a printer dialog. + * + * @param gc the screen to use. null is default screen. + * @param services the print services to browse (not null). + * @param defaultService the default service. If null + * the first of the print services in the services array will be used. + * @param flavor the flavours to be printed. + * @param attributes the attributes requested. Will be updated + * by selections done by the user in the dialog. + * + * @throws HeadlessException if GraphicsEnvironment is headless + */ + public PrinterDialog(GraphicsConfiguration gc, PrintService[] services, + PrintService defaultService, DocFlavor flavor, + PrintRequestAttributeSet attributes) + throws HeadlessException + { + this(gc, services, defaultService, flavor, attributes, + false, getLocalizedString("title.printdialog")); + } + + // initializes the gui parts + private void initUI(boolean onlyPageDialog) + { + JPanel buttonPane = new JPanel(); + + if (onlyPageDialog) + { + JPanel pane = new JPanel(); + pane.setLayout(new BorderLayout()); + pagesetup_panel = new PageSetupPanel(); + pane.add(pagesetup_panel, BorderLayout.CENTER); + + ok_bt = new JButton(getLocalizedString("bt.OK")); + ok_bt.addActionListener(this); + cancel_bt = new JButton(getLocalizedString("bt.cancel")); + cancel_bt.addActionListener(this); + + getContentPane().add(pane, BorderLayout.CENTER); + } + else + { + general_panel = new GeneralPanel(); + pagesetup_panel = new PageSetupPanel(); + appearance_panel = new AppearancePanel(); + + JTabbedPane pane = new JTabbedPane(); + pane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + + ok_bt = new JButton(getLocalizedString("bt.print")); + ok_bt.addActionListener(this); + cancel_bt = new JButton(getLocalizedString("bt.cancel")); + cancel_bt.addActionListener(this); + + // populate jtabbedpane + pane.addTab(getLocalizedString("tab.general"), general_panel); + pane.addTab(getLocalizedString("tab.pagesetup"), pagesetup_panel); + pane.addTab(getLocalizedString("tab.appearance"), appearance_panel); + + // Put everything together + getContentPane().add(pane, BorderLayout.CENTER); + } + + buttonPane.setLayout(new BoxLayout(buttonPane, BoxLayout.LINE_AXIS)); + buttonPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); + buttonPane.add(Box.createHorizontalGlue()); + buttonPane.add(ok_bt); + buttonPane.add(Box.createRigidArea(new Dimension(5, 0))); + buttonPane.add(cancel_bt); + + getContentPane().add(buttonPane, BorderLayout.PAGE_END); + } + + /** + * Returns the modified attributes set. + * @return The attributes. + */ + public PrintRequestAttributeSet getAttributes() + { + return attributes; + } + + /** + * Returns the print service selected by the user. + * @return The selected print service. + */ + public PrintService getSelectedPrintService() + { + return selectedService; + } + + /** + * Sets the currently selected print service. + * + * @param service the service selected. + */ + protected void setSelectedPrintService(PrintService service) + { + selectedService = service; + } + + /** + * Returns the print service array. + * @return The print services. + */ + protected PrintService[] getPrintServices() + { + return services; + } + + /** + * Calls update on all panels to adjust + * for a new selected print service. + */ + void updateAll() + { + pagesetup_panel.update(); + + if (! onlyPageDialog) + { + general_panel.update(); + appearance_panel.update(); + } + } + + boolean categorySupported(Class category) + { + return getSelectedPrintService(). + isAttributeCategorySupported(category); + } + + Object defaultValue(Class category) + { + return getSelectedPrintService(). + getDefaultAttributeValue(category); + } + + Attribute attribute(Class category) + { + return atts.get(category); + } + + /** + * Action handler for Print/Cancel buttons. + * If cancel is pressed we reset the attributes + * and the selected service. + * + * @param e the ActionEvent + */ + public void actionPerformed(ActionEvent e) + { + if (e.getSource() == ok_bt) + { + setVisible(false); + attributes.addAll(atts); + dispose(); + } + else + { + setVisible(false); + selectedService = null; + dispose(); + } + } + + /** + * Retrieves localized messages from the resource bundle. + * + * @param key the key + * @return The localized value for the key. + */ + static final String getLocalizedString(String key) { + return messages.getString(key); + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/DocPrintJobImpl.java b/libjava/classpath/gnu/javax/print/ipp/DocPrintJobImpl.java new file mode 100644 index 000000000..8cfd6880d --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/DocPrintJobImpl.java @@ -0,0 +1,471 @@ +/* DocPrintJobImpl.java -- Implementation of DocPrintJob. + 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.print.ipp; + +import gnu.javax.print.PrintFlavorException; +import gnu.javax.print.ipp.attribute.job.JobId; +import gnu.javax.print.ipp.attribute.job.JobUri; +import gnu.javax.print.ipp.attribute.printer.DocumentFormat; +import gnu.javax.print.ipp.attribute.supported.OperationsSupported; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.print.CancelablePrintJob; +import javax.print.Doc; +import javax.print.DocFlavor; +import javax.print.DocPrintJob; +import javax.print.PrintException; +import javax.print.PrintService; +import javax.print.attribute.AttributeSetUtilities; +import javax.print.attribute.DocAttributeSet; +import javax.print.attribute.HashAttributeSet; +import javax.print.attribute.HashPrintJobAttributeSet; +import javax.print.attribute.PrintJobAttributeSet; +import javax.print.attribute.PrintRequestAttributeSet; +import javax.print.attribute.standard.JobName; +import javax.print.attribute.standard.PrinterURI; +import javax.print.attribute.standard.RequestingUserName; +import javax.print.event.PrintJobAttributeListener; +import javax.print.event.PrintJobEvent; +import javax.print.event.PrintJobListener; + +/** + * Implementation of the DocPrintJob interface. Implementation is + * specific to the IppPrintService implementation. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public class DocPrintJobImpl implements CancelablePrintJob +{ + /** The print service this job is bound to. */ + private IppPrintService service; + + /** The set of print job listeners. */ + private HashSet printJobListener = new HashSet(); + + /** The print job attributes listeners. */ + private ArrayList attributesListener = new ArrayList(); + /** The print job attributes listeners associated attribute set. */ + private ArrayList attributesListenerAttributes = new ArrayList(); + + /** The username. */ + private String username; + /** The password of the user. */ + private String password; + + /** Returned job uri. */ + private JobUri jobUri = null; + /** Returned job id. */ + private JobId jobId = null; + + /** The requesting-username for later canceling */ + private RequestingUserName requestingUser; + + /** The print job sets. */ + private PrintJobAttributeSet oldSet = new HashPrintJobAttributeSet(); + private PrintJobAttributeSet currentSet = new HashPrintJobAttributeSet(); + + /** + * State variable if we already started printing. + */ + private boolean printing = false; + + // TODO Implement complete PrintJobListener notification + // TODO Implement PrintJobAttributeListener notification + + /** + * Constructs a DocPrintJobImpl instance bound to the given print service. + * + * @param service the print service instance. + * @param user the user of this print service. + * @param passwd the password of the user. + */ + public DocPrintJobImpl(IppPrintService service, String user, String passwd) + { + this.service = service; + username = user; + password = passwd; + } + + /** + * @see DocPrintJob#addPrintJobAttributeListener(PrintJobAttributeListener, PrintJobAttributeSet) + */ + public void addPrintJobAttributeListener(PrintJobAttributeListener listener, + PrintJobAttributeSet attributes) + { + if (listener == null) + return; + + attributesListener.add(listener); + attributesListenerAttributes.add(attributes); + } + + /** + * @see DocPrintJob#addPrintJobListener(PrintJobListener) + */ + public void addPrintJobListener(PrintJobListener listener) + { + if (listener == null) + return; + + printJobListener.add(listener); + } + + /** + * @see javax.print.DocPrintJob#getAttributes() + */ + public PrintJobAttributeSet getAttributes() + { + return AttributeSetUtilities.unmodifiableView(currentSet); + } + + /** + * @see javax.print.DocPrintJob#getPrintService() + */ + public PrintService getPrintService() + { + return service; + } + + /** + * @see DocPrintJob#print(Doc, PrintRequestAttributeSet) + */ + public void print(Doc doc, PrintRequestAttributeSet attributes) + throws PrintException + { + if (printing) + throw new PrintException("already printing"); + + printing = true; + + DocAttributeSet docAtts = doc.getAttributes(); + DocFlavor flavor = doc.getDocFlavor(); + + if (flavor == null || (!service.isDocFlavorSupported(flavor))) + { + notifyPrintJobListeners(new PrintJobEvent(this, PrintJobEvent.JOB_FAILED)); + throw new PrintFlavorException("Invalid flavor", new DocFlavor[] {flavor}); + } + + // merge attributes as doc attributes take precendence + // over the print request attributes + HashAttributeSet mergedAtts = new HashAttributeSet(); + + if (attributes != null) + mergedAtts.addAll(attributes); + if (docAtts != null) + mergedAtts.addAll(docAtts); + + // check for requesting-user-name -add the + // executing username if no other is specified + // save user name so we can make a cancel operation under same user + if (! mergedAtts.containsKey(RequestingUserName.class)) + { + mergedAtts.add(IppPrintService.REQUESTING_USER_NAME); + requestingUser = IppPrintService.REQUESTING_USER_NAME; + } + else + { + requestingUser = (RequestingUserName) + mergedAtts.get(RequestingUserName.class); + } + + // same for job-name + if (! mergedAtts.containsKey(JobName.class)) + mergedAtts.add(IppPrintService.JOB_NAME); + + IppResponse response = null; + + try + { + PrinterURI printerUri = service.getPrinterURI(); + String printerUriStr = "http" + printerUri.toString().substring(3); + + URI uri = null; + try + { + uri = new URI(printerUriStr); + } + catch (URISyntaxException e) + { + // does not happen + } + + IppRequest request = + new IppRequest(uri, username, password); + + request.setOperationID( (short) OperationsSupported.PRINT_JOB.getValue()); + request.setOperationAttributeDefaults(); + request.addOperationAttribute(printerUri); + + if (mergedAtts != null) + { + request.addAndFilterJobOperationAttributes(mergedAtts); + request.addAndFilterJobTemplateAttributes(mergedAtts); + } + + // DocFlavor getMimeType returns charset quoted + DocumentFormat format = DocumentFormat.createDocumentFormat(flavor); + request.addOperationAttribute(format); + + // Get and set the printdata based on the + // representation classname + String className = flavor.getRepresentationClassName(); + + if (className.equals("[B")) + { + request.setData((byte[]) doc.getPrintData()); + response = request.send(); + } + else if (className.equals("java.io.InputStream")) + { + InputStream stream = (InputStream) doc.getPrintData(); + request.setData(stream); + response = request.send(); + stream.close(); + } + else if (className.equals("[C")) + { + try + { + // CUPS only supports UTF-8 currently so we convert + // We also assume that char[] is always utf-16 - correct ? + String str = new String((char[]) doc.getPrintData()); + request.setData(str.getBytes("utf-16")); + response = request.send(); + } + catch (UnsupportedEncodingException e) + { + notifyPrintJobListeners(new PrintJobEvent(this, PrintJobEvent.JOB_FAILED)); + throw new PrintFlavorException("Invalid charset of flavor", e, new DocFlavor[] {flavor}); + } + } + else if (className.equals("java.io.Reader")) + { + try + { + // FIXME Implement + // Convert a Reader into a InputStream properly encoded + response = request.send(); + throw new UnsupportedEncodingException("not supported yet"); + } + catch (UnsupportedEncodingException e) + { + notifyPrintJobListeners(new PrintJobEvent(this, PrintJobEvent.JOB_FAILED)); + throw new PrintFlavorException("Invalid charset of flavor", e, new DocFlavor[] {flavor}); + } + } + else if (className.equals("java.lang.String")) + { + try + { + // CUPS only supports UTF-8 currently so we convert + // We also assume that String is always utf-16 - correct ? + String str = (String) doc.getPrintData(); + request.setData(str.getBytes("utf-16")); + response = request.send(); + } + catch (UnsupportedEncodingException e) + { + notifyPrintJobListeners(new PrintJobEvent(this, PrintJobEvent.JOB_FAILED)); + throw new PrintFlavorException("Invalid charset of flavor", e, new DocFlavor[] {flavor}); + } + } + else if (className.equals("java.net.URL")) + { + URL url = (URL) doc.getPrintData(); + InputStream stream = url.openStream(); + request.setData(stream); + response = request.send(); + stream.close(); + } + else if (className.equals("java.awt.image.renderable.RenderableImage") + || className.equals("java.awt.print.Printable") + || className.equals("java.awt.print.Pageable")) + { + // For the future :-) + throw new PrintException("Not yet supported."); + } + else + { + // should not happen - however + notifyPrintJobListeners(new PrintJobEvent(this, PrintJobEvent.JOB_FAILED)); + throw new PrintFlavorException("Invalid flavor", new DocFlavor[] {flavor}); + } + + // at this point the data is transfered + notifyPrintJobListeners(new PrintJobEvent( + this, PrintJobEvent.DATA_TRANSFER_COMPLETE)); + } + catch (IOException e) + { + throw new PrintException("IOException occured.", e); + } + + int status = response.getStatusCode(); + if (! (status == IppStatusCode.SUCCESSFUL_OK + || status == IppStatusCode.SUCCESSFUL_OK_IGNORED_OR_SUBSTITUED_ATTRIBUTES + || status == IppStatusCode.SUCCESSFUL_OK_CONFLICTING_ATTRIBUTES) ) + { + notifyPrintJobListeners(new PrintJobEvent( + this, PrintJobEvent.JOB_FAILED)); + throw new PrintException("Printing failed - received statuscode " + Integer.toHexString(status)); + + // TODO maybe specific status codes may require to throw a specific + // detailed attribute exception + } + else + { + // start print job progress monitoring thread + // FIXME Implement + + // for now we just notify as finished + notifyPrintJobListeners( + new PrintJobEvent(this, PrintJobEvent.JOB_COMPLETE)); + } + + List jobAtts = response.getJobAttributes(); + + // extract the uri and id of job for canceling and further monitoring + Map jobAttributes = (Map) jobAtts.get(0); + jobUri = (JobUri) ((HashSet)jobAttributes.get(JobUri.class)).toArray()[0]; + jobId = (JobId) ((HashSet)jobAttributes.get(JobId.class)).toArray()[0]; + } + + /** + * @see DocPrintJob#removePrintJobAttributeListener(PrintJobAttributeListener) + */ + public void removePrintJobAttributeListener(PrintJobAttributeListener listener) + { + if (listener == null) + return; + + int index = attributesListener.indexOf(listener); + if (index != -1) + { + attributesListener.remove(index); + attributesListenerAttributes.remove(index); + } + } + + /** + * @see DocPrintJob#removePrintJobListener(PrintJobListener) + */ + public void removePrintJobListener(PrintJobListener listener) + { + if (listener == null) + return; + + printJobListener.remove(listener); + } + + /** + * @see CancelablePrintJob#cancel() + */ + public void cancel() throws PrintException + { + if (jobUri == null) + { + throw new PrintException("print job is not yet send"); + } + + IppResponse response = null; + + try + { + IppRequest request = new IppRequest(jobUri.getURI(), username, password); + request.setOperationID( (short) OperationsSupported.CANCEL_JOB.getValue()); + request.setOperationAttributeDefaults(); + request.addOperationAttribute(jobUri); + request.addOperationAttribute(requestingUser); + response = request.send(); + } + catch (IOException e) + { + throw new IppException("IOException occured during cancel request.", e); + } + + int status = response.getStatusCode(); + if (! (status == IppStatusCode.SUCCESSFUL_OK + || status == IppStatusCode.SUCCESSFUL_OK_IGNORED_OR_SUBSTITUED_ATTRIBUTES + || status == IppStatusCode.SUCCESSFUL_OK_CONFLICTING_ATTRIBUTES) ) + { + notifyPrintJobListeners(new PrintJobEvent( + this, PrintJobEvent.JOB_FAILED)); + throw new PrintException("Canceling failed - received statuscode " + Integer.toHexString(status)); + } + else + { + notifyPrintJobListeners(new PrintJobEvent( + this, PrintJobEvent.JOB_CANCELED)); + } + } + + private void notifyPrintJobListeners(PrintJobEvent e) + { + Iterator it = printJobListener.iterator(); + while (it.hasNext()) + { + PrintJobListener l = (PrintJobListener) it.next(); + if (e.getPrintEventType() == PrintJobEvent.DATA_TRANSFER_COMPLETE) + l.printDataTransferCompleted(e); + else if (e.getPrintEventType() == PrintJobEvent.JOB_CANCELED) + l.printJobCanceled(e); + else if (e.getPrintEventType() == PrintJobEvent.JOB_COMPLETE) + l.printJobCompleted(e); + else if (e.getPrintEventType() == PrintJobEvent.JOB_FAILED) + l.printJobFailed(e); + else if (e.getPrintEventType() == PrintJobEvent.NO_MORE_EVENTS) + l.printJobNoMoreEvents(e); + else + l.printJobRequiresAttention(e); + } + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/IppDelimiterTag.java b/libjava/classpath/gnu/javax/print/ipp/IppDelimiterTag.java new file mode 100644 index 000000000..1c074a8dd --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/IppDelimiterTag.java @@ -0,0 +1,99 @@ +/* IppDelimiterTag.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.javax.print.ipp; + + +/** + * IPP Delimiter Tags as described in RFC 2910 section 3.5.1. + *

      + * Every delimiter tag value can occur in the protocol field + * begin-attribute-group-tag and indicates that the following + * attributes will be part of the named group.
      + * The end-of-attributes-tag signals the end of the attributes + * section in the IPP request/response and therefore the beginning + * of the data section (if any). + *

      + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class IppDelimiterTag +{ + /** Start of the operation attributes group section. */ + public static final byte OPERATION_ATTRIBUTES_TAG = 0x01; + + /** Start of the job attributes group section. */ + public static final byte JOB_ATTRIBUTES_TAG = 0x02; + + /** End of the attributes section and begin of data section. */ + public static final byte END_OF_ATTRIBUTES_TAG = 0x03; + + /** Start of the printer attributes group section. */ + public static final byte PRINTER_ATTRIBUTES_TAG = 0x04; + + /** Start of the unsupported attributes group section. */ + public static final byte UNSUPPORTED_ATTRIBUTES_TAG = 0x05; + + + // 0x00 reserved for definition in a future IETF + // standards track document + + // 0x06-0x0f reserved for future delimiters in IETF + // standards track documents + + private IppDelimiterTag() + { + // not to be instantiated + } + + /** + * Tests if given value corresponds to a + * delimiter tag value. + * + * @param value the value to test for + * @return true if, false otherwise. + */ + public static boolean isDelimiterTag(byte value) + { + if (value >= 0x01 && value <= 0x05) + return true; + + return false; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/IppException.java b/libjava/classpath/gnu/javax/print/ipp/IppException.java new file mode 100644 index 000000000..c34a8f227 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/IppException.java @@ -0,0 +1,88 @@ +/* IppException.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.javax.print.ipp; + +import javax.print.PrintException; + +/** + * IppException signals exception thrown by + * the IPP implementation for various things like a failed + * ipp request or a wrapped io exception. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public class IppException extends PrintException +{ + /** + * Creates an IppException. + */ + public IppException() + { + super(); + } + + /** + * Creates an IppException. + * @param s the message of the exception. + */ + public IppException(String s) + { + super(s); + } + + /** + * Creates an IppException. + * @param e the exception cause this one. + */ + public IppException(Exception e) + { + super(e); + } + + /** + * Creates an IppException. + * @param s the message of the exception. + * @param e the exception cause this one. + */ + public IppException(String s, Exception e) + { + super(s, e); + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/IppMultiDocPrintService.java b/libjava/classpath/gnu/javax/print/ipp/IppMultiDocPrintService.java new file mode 100644 index 000000000..59c3408d5 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/IppMultiDocPrintService.java @@ -0,0 +1,87 @@ +/* IppMultiDocPrintService.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.javax.print.ipp; + + +import java.net.URI; + +import javax.print.MultiDocPrintJob; +import javax.print.MultiDocPrintService; + +/** + * Implementation of the MultiDocPrintService interface + * for IPP based printers. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public class IppMultiDocPrintService extends IppPrintService + implements MultiDocPrintService +{ + /** The username. */ + private transient String user; + + /** The password of the user. */ + private transient String passwd; + + /** + * Creates a IppMultiDocPrintService object. + * + * @param uri the URI of the IPP printer. + * @param username the user of this print service. + * @param password the password of the user. + * + * @throws IppException if an error during connection occurs. + */ + public IppMultiDocPrintService(URI uri, String username, String password) + throws IppException + { + super(uri, username, password); + user = username; + passwd = password; + } + + /** + * @see MultiDocPrintService#createMultiDocPrintJob() + */ + public MultiDocPrintJob createMultiDocPrintJob() + { + return new MultiDocPrintJobImpl(this, user, passwd); + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/IppPrintService.java b/libjava/classpath/gnu/javax/print/ipp/IppPrintService.java new file mode 100644 index 000000000..9ce41c774 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/IppPrintService.java @@ -0,0 +1,924 @@ +/* IppPrintService.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.javax.print.ipp; + +import gnu.classpath.SystemProperties; +import gnu.classpath.debug.Component; +import gnu.classpath.debug.SystemLogger; +import gnu.javax.print.ipp.attribute.DefaultValueAttribute; +import gnu.javax.print.ipp.attribute.RequestedAttributes; +import gnu.javax.print.ipp.attribute.defaults.CopiesDefault; +import gnu.javax.print.ipp.attribute.defaults.FinishingsDefault; +import gnu.javax.print.ipp.attribute.defaults.JobHoldUntilDefault; +import gnu.javax.print.ipp.attribute.defaults.JobPriorityDefault; +import gnu.javax.print.ipp.attribute.defaults.JobSheetsDefault; +import gnu.javax.print.ipp.attribute.defaults.MediaDefault; +import gnu.javax.print.ipp.attribute.defaults.MultipleDocumentHandlingDefault; +import gnu.javax.print.ipp.attribute.defaults.NumberUpDefault; +import gnu.javax.print.ipp.attribute.defaults.OrientationRequestedDefault; +import gnu.javax.print.ipp.attribute.defaults.PrintQualityDefault; +import gnu.javax.print.ipp.attribute.defaults.PrinterResolutionDefault; +import gnu.javax.print.ipp.attribute.defaults.SidesDefault; +import gnu.javax.print.ipp.attribute.printer.DocumentFormat; +import gnu.javax.print.ipp.attribute.supported.CompressionSupported; +import gnu.javax.print.ipp.attribute.supported.DocumentFormatSupported; +import gnu.javax.print.ipp.attribute.supported.FinishingsSupported; +import gnu.javax.print.ipp.attribute.supported.JobHoldUntilSupported; +import gnu.javax.print.ipp.attribute.supported.JobSheetsSupported; +import gnu.javax.print.ipp.attribute.supported.MediaSupported; +import gnu.javax.print.ipp.attribute.supported.MultipleDocumentHandlingSupported; +import gnu.javax.print.ipp.attribute.supported.OperationsSupported; +import gnu.javax.print.ipp.attribute.supported.OrientationRequestedSupported; +import gnu.javax.print.ipp.attribute.supported.PageRangesSupported; +import gnu.javax.print.ipp.attribute.supported.PrintQualitySupported; +import gnu.javax.print.ipp.attribute.supported.PrinterResolutionSupported; +import gnu.javax.print.ipp.attribute.supported.PrinterUriSupported; +import gnu.javax.print.ipp.attribute.supported.SidesSupported; + +import java.io.IOException; +import java.lang.reflect.Field; +import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.logging.Logger; + +import javax.print.DocFlavor; +import javax.print.DocPrintJob; +import javax.print.PrintService; +import javax.print.ServiceUIFactory; +import javax.print.attribute.Attribute; +import javax.print.attribute.AttributeSet; +import javax.print.attribute.AttributeSetUtilities; +import javax.print.attribute.HashAttributeSet; +import javax.print.attribute.HashPrintServiceAttributeSet; +import javax.print.attribute.IntegerSyntax; +import javax.print.attribute.PrintServiceAttribute; +import javax.print.attribute.PrintServiceAttributeSet; +import javax.print.attribute.standard.Compression; +import javax.print.attribute.standard.Copies; +import javax.print.attribute.standard.CopiesSupported; +import javax.print.attribute.standard.Fidelity; +import javax.print.attribute.standard.Finishings; +import javax.print.attribute.standard.JobHoldUntil; +import javax.print.attribute.standard.JobImpressions; +import javax.print.attribute.standard.JobImpressionsSupported; +import javax.print.attribute.standard.JobKOctets; +import javax.print.attribute.standard.JobKOctetsSupported; +import javax.print.attribute.standard.JobMediaSheets; +import javax.print.attribute.standard.JobMediaSheetsSupported; +import javax.print.attribute.standard.JobName; +import javax.print.attribute.standard.JobPriority; +import javax.print.attribute.standard.JobPrioritySupported; +import javax.print.attribute.standard.JobSheets; +import javax.print.attribute.standard.Media; +import javax.print.attribute.standard.MultipleDocumentHandling; +import javax.print.attribute.standard.NumberUp; +import javax.print.attribute.standard.NumberUpSupported; +import javax.print.attribute.standard.OrientationRequested; +import javax.print.attribute.standard.PageRanges; +import javax.print.attribute.standard.PrintQuality; +import javax.print.attribute.standard.PrinterName; +import javax.print.attribute.standard.PrinterResolution; +import javax.print.attribute.standard.PrinterURI; +import javax.print.attribute.standard.RequestingUserName; +import javax.print.attribute.standard.Sides; +import javax.print.event.PrintServiceAttributeListener; + + +/** + * Implementation of the PrintService interface + * for IPP based printers. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public class IppPrintService implements PrintService +{ + /** + * A Map with sets of attributes. + * key: A attribute category + * value: A set with values + * + * IPP may return sets of attributes e.g. for supported + * compression methods so we need to map to sets here. + */ + private Map, Set> printerAttr; + + /** The set of listeners.*/ + private HashSet printServiceAttributeListener; + + /** The username. */ + private transient String user; + + /** The password of the user. */ + private transient String passwd; + + /** The name of this print service. */ + private String name; + + /** The list of supported document flavors. */ + private List flavors; + + /** The standard printer URI. */ + private PrinterURI printerUri; + + /** The list of all supported printer URIs. */ + private ArrayList printerUris; + + /** + * Logger for tracing - enable by passing + * -Dgnu.classpath.debug.components=ipp to the vm. + */ + static final Logger logger = SystemLogger.SYSTEM; + + /** + * requesting-user-name defaults to the executing user. + */ + public static final RequestingUserName REQUESTING_USER_NAME; + + /** + * job-name defaults to "Java Printing". + */ + public static final JobName JOB_NAME; + + static + { + JOB_NAME = new JobName("Java Printing", null); + REQUESTING_USER_NAME = new RequestingUserName( + SystemProperties.getProperty("user.name", ""), null); + } + + // TODO Implement service listener notification and change detection. + + /** + * Creates a IppPrintService object. + * + * @param uri the URI of the IPP printer. + * @param username the user of this print service. + * @param password the password of the user. + * + * @throws IppException if an error during connection occurs. + */ + public IppPrintService(URI uri, String username, String password) + throws IppException + { + printerUri = new PrinterURI(uri); + user = username; + passwd = password; + + printServiceAttributeListener = + new HashSet(); + + printerAttr = getPrinterAttributes(); + processResponse(); + } + + /** + * Fetches all printer attributes from the IPP printer. + * + * @return The Map with the printer attributes. + * @throws IppException if an error occurs. + */ + private Map, Set> getPrinterAttributes() + throws IppException + { + IppResponse response = null; + + try + { + IppRequest request = new IppRequest(printerUri.getURI(), user, passwd); + + int operation = OperationsSupported.GET_PRINTER_ATTRIBUTES.getValue(); + request.setOperationID((short) operation); + request.setOperationAttributeDefaults(); + request.addOperationAttribute(printerUri); + + response = request.send(); + } + catch (IOException e) + { + throw new IppException("IOException in IPP request/response.", e); + } + + return response.getPrinterAttributes().get(0); + } + + /** + * Extracts the set of attribute values for a given + * attribute category from the printer attributes map. + * + * @param attributeClass the category + * @return The set of attributes of the category. + */ + private Set getPrinterAttributeSet(Class attributeClass) + { + Set set = printerAttr.get(attributeClass); + Set attSet = new HashSet(); + for (Attribute att : set) + attSet.add(attributeClass.cast(att)); + return attSet; + } + + /** + * Extracts the default attribute value for the given + * default attribute category from the printer attributes map. + * + * @param attributeClass the category + * @return The default attribute. + * + * @throws ClassCastException if attributClass is not an + * instance of DefaultValueAttribute. + */ + private Attribute getPrinterDefaultAttribute(Class attributeClass) + { + Set set = printerAttr.get(attributeClass); + return ((DefaultValueAttribute) set.toArray()[0]).getAssociatedAttribute(); + } + + /** + * Processes the response, sorts and splits the attributes. + */ + private void processResponse() + { + // printer name + PrinterName[] tmp = getPrinterAttributeSet(PrinterName.class).toArray(new PrinterName[1]); + name = tmp[0].getValue(); + + // supported flavors + // TODO Check if charsets-supported are charsets that are actually supported + // for text doc flavors as cups doesn't send charset parameters + + // utf-8 is supported at least - so we go with this only for now + flavors = new ArrayList(); + Set flavorAttributes = getPrinterAttributeSet(DocumentFormatSupported.class); + if (flavorAttributes != null) + { + for (DocumentFormatSupported dfs : flavorAttributes) + { + String mimeType = dfs.getValue(); + + if (mimeType.equals("text/plain")) + { + flavors.add(DocFlavor.CHAR_ARRAY.TEXT_PLAIN); + flavors.add(DocFlavor.READER.TEXT_PLAIN); + flavors.add(DocFlavor.STRING.TEXT_PLAIN); + + // add utf-8 + mimeType = mimeType + "; charset=utf-8"; + } + else if (mimeType.equals("text/html")) + { + flavors.add(DocFlavor.CHAR_ARRAY.TEXT_HTML); + flavors.add(DocFlavor.READER.TEXT_HTML); + flavors.add(DocFlavor.STRING.TEXT_HTML); + + // add utf-8 + mimeType = mimeType + "; charset=utf-8"; + } + + // Process the predefined DocFlavors and if mimetype is + // equal put them into the flavors array - otherwise + // just build them as binarie class representation. + boolean changed = false; + try + { + Class[] clazzes = new Class[] { DocFlavor.BYTE_ARRAY.class, + DocFlavor.INPUT_STREAM.class, + DocFlavor.URL.class + }; + + for (int j = 0; j < clazzes.length; j++) + { + Field[] fields = clazzes[j].getDeclaredFields(); + for (int i = 0; i < fields.length; i++) + { + if (fields[i].getType().equals(clazzes[j])) + { + DocFlavor flavor = (DocFlavor) fields[i].get(null); + if (flavor.getMimeType().equals(mimeType)) + changed = flavors.add(flavor); + } + } + } + if (!changed) // not in predefined constants of DocFlavor + { + // everything should be supported as binary stuff + flavors.add(new DocFlavor(mimeType, "[B")); + flavors.add(new DocFlavor(mimeType, "java.io.InputStream")); + flavors.add(new DocFlavor(mimeType, "java.net.URL")); + } + } + catch (SecurityException e) + { + // should not happen + } + catch (IllegalArgumentException e) + { + // should not happen + } + catch (IllegalAccessException e) + { + // should not happen, all fields are public + } + } + + if (this.getClass() + .isAssignableFrom(gnu.javax.print.CupsPrintService.class)) + { +// CUPS always provides filters to convert from Postscript. +// This logic looks odd, but it's what OpenJDK does. + flavors.add(DocFlavor.SERVICE_FORMATTED.PAGEABLE); + flavors.add(DocFlavor.SERVICE_FORMATTED.PRINTABLE); + } + } + + // printer uris + Set uris = getPrinterAttributeSet(PrinterUriSupported.class); + printerUris = new ArrayList(uris.size()); + for (PrinterUriSupported uri : uris) + { + printerUris.add( new PrinterURI(uri.getURI())); + } + } + + /** + * We always return a implementation implementing CancelablePrintJob. + * + * @see javax.print.PrintService#createPrintJob() + */ + public DocPrintJob createPrintJob() + { + return new DocPrintJobImpl(this, user, passwd); + } + + + /** + * @see javax.print.PrintService#getAttribute(java.lang.Class) + */ + public T getAttribute(Class category) + { + if (category == null) + throw new NullPointerException("category may not be null"); + + if (! PrintServiceAttribute.class.isAssignableFrom(category)) + throw new IllegalArgumentException( + "category must be of type PrintServiceAttribute"); + + Set set = getPrinterAttributeSet(category); + if (set != null && set.size() > 0) + return set.iterator().next(); + + return null; + } + + /** + * @see javax.print.PrintService#getAttributes() + */ + public PrintServiceAttributeSet getAttributes() + { + PrintServiceAttributeSet set = new HashPrintServiceAttributeSet(); + + for (Set attrSet : printerAttr.values()) + { + for (Attribute attr : attrSet) + { + if (attr instanceof PrintServiceAttribute) + set.add(attr); + } + } + + return AttributeSetUtilities.unmodifiableView(set); + } + + /** + * @see javax.print.PrintService#getDefaultAttributeValue(java.lang.Class) + */ + public Object getDefaultAttributeValue(Class category) + { + // required attributes + if (category.equals(Fidelity.class)) + return Fidelity.FIDELITY_FALSE; + if (category.equals(JobName.class)) + return JOB_NAME; + if (category.equals(RequestingUserName.class)) + return REQUESTING_USER_NAME; + + // optional attributes + if (category.equals(JobPriority.class) + && printerAttr.containsKey(JobPriorityDefault.class)) + return getPrinterDefaultAttribute(JobPriorityDefault.class); + if (category.equals(JobHoldUntil.class) + && printerAttr.containsKey(JobHoldUntilDefault.class)) + return getPrinterDefaultAttribute(JobHoldUntilDefault.class); + if (category.equals(JobSheets.class) + && printerAttr.containsKey(JobSheetsDefault.class)) + return getPrinterDefaultAttribute(JobSheetsDefault .class); + if (category.equals(MultipleDocumentHandling.class) + && printerAttr.containsKey(MultipleDocumentHandlingDefault.class)) + return getPrinterDefaultAttribute(MultipleDocumentHandlingDefault.class); + if (category.equals(Copies.class) + && printerAttr.containsKey(CopiesDefault.class)) + return getPrinterDefaultAttribute(CopiesDefault.class); + if (category.equals(Finishings.class) + && printerAttr.containsKey(FinishingsDefault.class)) + return getPrinterDefaultAttribute(FinishingsDefault.class); + if (category.equals(Sides.class) + && printerAttr.containsKey(SidesDefault.class)) + return getPrinterDefaultAttribute(SidesDefault.class); + if (category.equals(NumberUp.class) + && printerAttr.containsKey(NumberUpDefault.class)) + return getPrinterDefaultAttribute(NumberUpDefault.class); + if (category.equals(OrientationRequested.class) + && printerAttr.containsKey(OrientationRequestedDefault.class)) + return getPrinterDefaultAttribute(OrientationRequestedDefault.class); + if (category.equals(Media.class) + && printerAttr.containsKey(MediaDefault.class)) + return getPrinterDefaultAttribute(MediaDefault.class); + if (category.equals(PrinterResolution.class) + && printerAttr.containsKey(PrinterResolutionDefault.class)) + return getPrinterDefaultAttribute(PrinterResolutionDefault.class); + if (category.equals(PrintQuality.class) + && printerAttr.containsKey(PrintQualityDefault.class)) + return getPrinterDefaultAttribute(PrintQualityDefault.class); + if (category.equals(Compression.class) + && printerAttr.containsKey(CompressionSupported.class)) + return Compression.NONE; + if (category.equals(PageRanges.class)) + return new PageRanges(1, Integer.MAX_VALUE); + + return null; + } + + /** + * We return the value of PrinterName here. + * @see javax.print.PrintService#getName() + */ + public String getName() + { + return name; + } + + /** + * We currently provide no factories - just returns null. + * @see javax.print.PrintService#getServiceUIFactory() + */ + public ServiceUIFactory getServiceUIFactory() + { + // SUN does not provide any service factory for + // print services (tested on linux/windows) + + // for the moment we do the same - just return null + // later on we could provide at least the about UI dialog + return null; + } + + /** + * @see javax.print.PrintService#getSupportedAttributeCategories() + */ + public Class[] getSupportedAttributeCategories() + { + Set> categories = + new HashSet>(); + + // Should only be job template attributes as of section 4.2 + if (printerAttr.containsKey(JobPrioritySupported.class)) + categories.add(JobPriority.class); + if (printerAttr.containsKey(JobHoldUntilSupported.class)) + categories.add(JobHoldUntil.class); + if (printerAttr.containsKey(JobSheetsSupported.class)) + categories.add(JobSheets.class); + if (printerAttr.containsKey(MultipleDocumentHandlingSupported.class)) + categories.add(MultipleDocumentHandling.class); + if (printerAttr.containsKey(CopiesSupported.class)) + categories.add(Copies.class); + if (printerAttr.containsKey(FinishingsSupported.class)) + { + // if only none finishing is supported - it does not count as supported + Set set = getPrinterAttributeSet(FinishingsSupported.class); + if (! (set.size() == 1 && set.contains(FinishingsSupported.NONE))) + categories.add(Finishings.class); + } + if (printerAttr.containsKey(PageRangesSupported.class)) + categories.add(PageRanges.class); + if (printerAttr.containsKey(SidesSupported.class)) + categories.add(Sides.class); + if (printerAttr.containsKey(NumberUpSupported.class)) + categories.add(NumberUp.class); + if (printerAttr.containsKey(OrientationRequestedSupported.class)) + categories.add(OrientationRequested.class); + if (printerAttr.containsKey(MediaSupported.class)) + categories.add(Media.class); + if (printerAttr.containsKey(PrinterResolutionSupported.class)) + categories.add(PrinterResolution.class); + if (printerAttr.containsKey(PrintQualitySupported.class)) + categories.add(PrintQuality.class); + + // Chromaticity, Destination, MediaPrintableArea, + // SheetCollate, PresentationDirection - not IPP attributes + + // attributes outside section 4.2 + if (printerAttr.containsKey(CompressionSupported.class)) + categories.add(Compression.class); + if (printerAttr.containsKey(JobImpressionsSupported.class)) + categories.add(JobImpressions.class); + if (printerAttr.containsKey(JobKOctetsSupported.class)) + categories.add(JobKOctets.class); + if (printerAttr.containsKey(JobMediaSheetsSupported.class)) + categories.add(JobMediaSheets.class); + + // always supported as required by IPP specification + categories.add(Fidelity.class); + categories.add(JobName.class); + categories.add(RequestingUserName.class); + + return categories.toArray(new Class[categories.size()]); + } + + /** + * Implemented by a GetPrinterAttributes request. Subclasses providing supported + * attribute values totally different may override this methods. Subclass only in + * need of handling the response differently may override the method + * handleSupportedAttributeValuesResponse(IppResponse, Class) only. + * + * @see PrintService#getSupportedAttributeValues(Class, DocFlavor, AttributeSet) + * @see #handleSupportedAttributeValuesResponse(IppResponse, Class) + */ + public Object getSupportedAttributeValues(Class category, + DocFlavor flavor, AttributeSet attributes) + { + // We currently ignore the attribute set - there is nothing in the IPP + // specification which would come closer to what we do here. + + if (category == null) + throw new NullPointerException("category may not be null"); + + if (!Attribute.class.isAssignableFrom(category)) + throw new IllegalArgumentException("category must be of type Attribute"); + + if (flavor != null && !isDocFlavorSupported(flavor)) + throw new IllegalArgumentException("flavor is not supported"); + + if (!isAttributeCategorySupported(category)) + return null; + + // always supported + if (category.equals(Fidelity.class)) + return new Fidelity[] { Fidelity.FIDELITY_FALSE, Fidelity.FIDELITY_TRUE }; + if (category.equals(JobName.class)) + return JOB_NAME; + if (category.equals(RequestingUserName.class)) + return REQUESTING_USER_NAME; + + // map category to category-supported + String categoryName = IppUtilities.getSupportedAttrName(category); + + IppResponse response = null; + try + { + IppRequest request = new IppRequest(printerUri.getURI(), user, passwd); + request.setOperationID( + (short) OperationsSupported.GET_PRINTER_ATTRIBUTES.getValue()); + request.setOperationAttributeDefaults(); + request.addOperationAttribute(new RequestedAttributes(categoryName)); + request.addOperationAttribute(printerUri); + + if (flavor != null) + { + DocumentFormat f = DocumentFormat.createDocumentFormat(flavor); + request.addOperationAttribute(f); + } + + response = request.send(); + + int status = response.getStatusCode(); + if (! (status == IppStatusCode.SUCCESSFUL_OK + || status == IppStatusCode.SUCCESSFUL_OK_IGNORED_OR_SUBSTITUED_ATTRIBUTES + || status == IppStatusCode.SUCCESSFUL_OK_CONFLICTING_ATTRIBUTES) ) + { + logger.log(Component.IPP, "Statuscode not OK - got:" + status); + } + } + catch (IOException e) + { + // method cannot throw exception - just log + logger.log(Component.IPP, "IOException", e); + } + catch (IppException e) + { + // method cannot throw exception - just log + logger.log(Component.IPP, "IPPException", e); + } + + return handleSupportedAttributeValuesResponse(response, category); + } + + /** + * Called to handle the supported attribute values response for the given + * category. This might be overridden by subclasses with different requirements + * for parsing/handling the response from the GetPrinterAttributes. + * + * @param response the response of the GetPrinterAttributes IPP request + * @param category the category for which the supported values are requested + * @return A object indicating the supported values for the given attribute + * category, or null if this print service doesn't support the + * given attribute category at all. + * + * @see #getSupportedAttributeValues(Class, DocFlavor, AttributeSet) + */ + protected Object handleSupportedAttributeValuesResponse(IppResponse response, + Class category) + { + List, Set>> printerAtts = + response.getPrinterAttributes(); + + // only one will be returned + Map, Set> printerAttribute = printerAtts.get(0); + Class suppCategory = IppUtilities.getSupportedCategory(category); + Set attr = printerAttribute.get(suppCategory); + + // We sometime assume its a single instance with arbritrary value just indicating + // support or an array which is returned. This is because I sometimes just choosed + // what sounds right to me - as I have yet to find a printer which supports every + // special category in the SUN implementation to see what they return :-) + + // Map whats in the JSP API + if (suppCategory.equals(JobPrioritySupported.class)) + return (JobPrioritySupported) attr.iterator().next(); + if (suppCategory.equals(JobHoldUntilSupported.class)) + return new JobHoldUntil(new Date()); + if (suppCategory.equals(JobSheetsSupported.class)) + return JobSheetsSupported.getAssociatedAttributeArray(attr); + if (suppCategory.equals(MultipleDocumentHandlingSupported.class)) + return MultipleDocumentHandlingSupported.getAssociatedAttributeArray(attr); + if (suppCategory.equals(CopiesSupported.class)) + return (CopiesSupported) attr.iterator().next(); + if (suppCategory.equals(FinishingsSupported.class)) + return FinishingsSupported.getAssociatedAttributeArray(attr); + if (suppCategory.equals(PageRangesSupported.class)) + return new PageRanges[] { new PageRanges(1, Integer.MAX_VALUE) }; + if (suppCategory.equals(OrientationRequestedSupported.class)) + return OrientationRequestedSupported.getAssociatedAttributeArray(attr); + if (suppCategory.equals(MediaSupported.class)) + return MediaSupported.getAssociatedAttributeArray(attr); + if (suppCategory.equals(PrinterResolutionSupported.class)) + return PrinterResolutionSupported.getAssociatedAttributeArray(attr); + if (suppCategory.equals(PrintQualitySupported.class)) + return PrintQualitySupported.getAssociatedAttributeArray(attr); + if (suppCategory.equals(CompressionSupported.class)) + return CompressionSupported.getAssociatedAttributeArray(attr); + // Special handling as it might also be in range of integers + if (suppCategory.equals(NumberUpSupported.class)) + { + if (attr.size() == 1) // number-up maybe in rangeofintegers + return attr.iterator().next(); + + int[][] members = new int[attr.size()][2]; + Iterator it = attr.iterator(); + for (int j = 0; j < attr.size(); j++) + { + int value = ((NumberUpSupported) it.next()).getMembers()[0][0]; + members[j] = new int[] { value, value }; + } + + NumberUpSupported supported = new NumberUpSupported(members); + return supported; + } + + return null; + } + + /** + * @see javax.print.PrintService#getSupportedDocFlavors() + */ + public DocFlavor[] getSupportedDocFlavors() + { + return flavors.toArray(new DocFlavor[flavors.size()]); + } + + /** + * This is done by a validate-job operation and actually implemented in + * this generic IPP reference implementation. Subclasses which does + * not correctly support Validate-Job operation might want to override this. + * + * @see PrintService#getUnsupportedAttributes(DocFlavor, AttributeSet) + */ + public AttributeSet getUnsupportedAttributes(DocFlavor flavor, + AttributeSet attributes) + { + if (flavor != null && !isDocFlavorSupported(flavor)) + throw new IllegalArgumentException("flavor is not supported"); + + IppResponse response = null; + try + { + IppRequest request = new IppRequest(printerUri.getURI(), user, passwd); + short operationId = (short) OperationsSupported.VALIDATE_JOB.getValue(); + request.setOperationID(operationId); + request.setOperationAttributeDefaults(); + request.addOperationAttribute(printerUri); + request.addOperationAttribute(Fidelity.FIDELITY_TRUE); + + if (attributes != null && attributes.size() > 0) + { + request.addAndFilterJobOperationAttributes(attributes); + request.addAndFilterJobTemplateAttributes(attributes); + } + + if (flavor != null) + { + DocumentFormat f = DocumentFormat.createDocumentFormat(flavor); + request.addOperationAttribute(f); + } + + response = request.send(); + + int status = response.getStatusCode(); + if (! (status == IppStatusCode.SUCCESSFUL_OK + || status == IppStatusCode.SUCCESSFUL_OK_IGNORED_OR_SUBSTITUED_ATTRIBUTES + || status == IppStatusCode.SUCCESSFUL_OK_CONFLICTING_ATTRIBUTES) ) + { + logger.log(Component.IPP, "Statuscode not OK - got:" + status); + } + } + catch (IOException e) + { + // method cannot throw exception - just log + logger.log(Component.IPP, "IOException", e); + } + catch (IppException e) + { + // method cannot throw exception - just log + logger.log(Component.IPP, "IPPException", e); + } + + // Validate Jobs returns only Unsupported and Operation + List, Set>> unsupportedMaps = + response.getUnsupportedAttributes(); + if (unsupportedMaps.size() == 0) + return null; + + Map, Set> unsupportedAttr = unsupportedMaps.get(0); + if (unsupportedAttr.size() == 0) + return null; + + // Convert the return map with unsupported attributes + // into an AttribueSet instance + HashAttributeSet set = new HashAttributeSet(); + for (Set unsupported : unsupportedAttr.values()) + { + for (Attribute att : unsupported) + set.add(att); + } + + return set; + } + + /** + * @see PrintService#isAttributeCategorySupported(Class) + */ + public boolean isAttributeCategorySupported(Class category) + { + if (category == null) + throw new NullPointerException("category may not be null"); + + if (! Attribute.class.isAssignableFrom(category)) + throw new IllegalArgumentException("category must be of type Attribute"); + + return Arrays.asList(getSupportedAttributeCategories()).contains(category); + } + + /** + * @see PrintService#isAttributeValueSupported(Attribute, DocFlavor, AttributeSet) + */ + public boolean isAttributeValueSupported(Attribute attrval, DocFlavor flavor, + AttributeSet attributes) + { + // just redirect to getSupportedAttributeValues + Object values = getSupportedAttributeValues(attrval.getCategory(), + flavor, attributes); + // null means none supported + if (values == null) + return false; + + // object may be an array + if (values.getClass().isArray()) + return Arrays.asList((Object[]) values).contains(attrval); + + // may be a single instance of the category (value is irrelevant) + if (values.getClass().equals(attrval.getCategory())) + return true; + + // a single instance of another class to give the bounds + // copies + if (values.getClass().equals(CopiesSupported.class)) + return ((CopiesSupported) values).contains((IntegerSyntax) attrval); + // number up + if (values.getClass().equals(NumberUpSupported.class)) + return ((NumberUpSupported) values).contains((IntegerSyntax) attrval); + // job priority + if (values.getClass().equals(JobPrioritySupported.class)) + { + JobPriority priority = (JobPriority) attrval; + JobPrioritySupported maxSupported = (JobPrioritySupported) values; + if (priority.getValue() < maxSupported.getValue()) + return true; + } + + // I am unsure if these might also show up - not yet found a printer where + // Suns implementation supports them: + // JobImpressionsSupported, JobKOctetsSupported, JobMediaSheetsSupported + + return false; + } + + + /** + * @see javax.print.PrintService#isDocFlavorSupported(DocFlavor) + */ + public boolean isDocFlavorSupported(DocFlavor flavor) + { + if (flavor == null) + throw new NullPointerException("DocFlavor may not be null."); + + return flavors.contains(flavor); + } + + + /** + * @see PrintService#addPrintServiceAttributeListener(PrintServiceAttributeListener) + */ + public void addPrintServiceAttributeListener( + PrintServiceAttributeListener listener) + { + printServiceAttributeListener.add(listener); + } + + /** + * @see PrintService#removePrintServiceAttributeListener(PrintServiceAttributeListener) + */ + public void removePrintServiceAttributeListener( + PrintServiceAttributeListener listener) + { + printServiceAttributeListener.remove(listener); + } + + /** + * Returns "IppPrinter: " + getName() + * @return The string representation. + */ + public String toString() + { + return "IppPrinter: " + getName(); + } + + /** + * Returns the printer-uri of this print service. + * + * @return The printer-uri attribute. + */ + public PrinterURI getPrinterURI() + { + return printerUri; + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/IppRequest.java b/libjava/classpath/gnu/javax/print/ipp/IppRequest.java new file mode 100644 index 000000000..ae1f2c409 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/IppRequest.java @@ -0,0 +1,875 @@ +/* IppRequest.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.javax.print.ipp; + +import gnu.classpath.debug.Component; +import gnu.classpath.debug.SystemLogger; +import gnu.javax.print.ipp.attribute.CharsetSyntax; +import gnu.javax.print.ipp.attribute.NaturalLanguageSyntax; +import gnu.javax.print.ipp.attribute.RequestedAttributes; +import gnu.javax.print.ipp.attribute.job.AttributesCharset; +import gnu.javax.print.ipp.attribute.job.AttributesNaturalLanguage; +import gnu.javax.print.ipp.attribute.job.JobId; +import gnu.javax.print.ipp.attribute.job.JobUri; +import gnu.javax.print.ipp.attribute.printer.DocumentFormat; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URI; +import java.net.URL; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.List; +import java.util.logging.Logger; + +import javax.print.attribute.Attribute; +import javax.print.attribute.AttributeSet; +import javax.print.attribute.DateTimeSyntax; +import javax.print.attribute.EnumSyntax; +import javax.print.attribute.HashAttributeSet; +import javax.print.attribute.IntegerSyntax; +import javax.print.attribute.ResolutionSyntax; +import javax.print.attribute.SetOfIntegerSyntax; +import javax.print.attribute.TextSyntax; +import javax.print.attribute.URISyntax; +import javax.print.attribute.standard.Compression; +import javax.print.attribute.standard.Copies; +import javax.print.attribute.standard.DocumentName; +import javax.print.attribute.standard.Fidelity; +import javax.print.attribute.standard.Finishings; +import javax.print.attribute.standard.JobHoldUntil; +import javax.print.attribute.standard.JobImpressions; +import javax.print.attribute.standard.JobKOctets; +import javax.print.attribute.standard.JobMediaSheets; +import javax.print.attribute.standard.JobName; +import javax.print.attribute.standard.JobOriginatingUserName; +import javax.print.attribute.standard.JobPriority; +import javax.print.attribute.standard.JobSheets; +import javax.print.attribute.standard.Media; +import javax.print.attribute.standard.MultipleDocumentHandling; +import javax.print.attribute.standard.NumberUp; +import javax.print.attribute.standard.OrientationRequested; +import javax.print.attribute.standard.PageRanges; +import javax.print.attribute.standard.PrintQuality; +import javax.print.attribute.standard.PrinterResolution; +import javax.print.attribute.standard.PrinterURI; +import javax.print.attribute.standard.RequestingUserName; +import javax.print.attribute.standard.SheetCollate; +import javax.print.attribute.standard.Sides; + +/** + * IppRequest models a request to an IPP compatible + * server as described in RFC 2910 - IPP/1.1: Encoding and Transport. + *

      + * The byte stream is structured as follows (for an official description + * please have a look at the RFC document mentioned above): + *

        + *
      • version-number - 2 bytes - required
      • + *
      • operation-id - 2 bytes - required
      • + *
      • request-id - 4 bytes - required
      • + *
      • attribute-group - n bytes - 0 or more
      • + *
      • end-of-attributes-tag - 1 byte - required
      • + *
      • data - q bytes - optional
      • + *
      + *

      + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public class IppRequest +{ + + /** + * The printer-poll timeout. + */ + private static final int timeout = 1000; + + /** + * Helper class used to write the attributes of a request + * into the supplied data output stream in the correct way. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ + class RequestWriter + { + private DataOutputStream out; + + /** + * Creates a RequestWriter. + * + * @param stream the stream to write to. + */ + RequestWriter(DataOutputStream stream) + { + out = stream; + } + + /** + * Writes an attribute in IntegerSyntax into the stream. + * @param attribute the attribute + * @throws IOException if thrown by the stream + */ + private void write(IntegerSyntax attribute) throws IOException + { + String name = ((Attribute) attribute).getName(); + out.writeByte(IppValueTag.INTEGER); + out.writeShort(name.length()); + out.write(name.getBytes()); + out.writeShort(4); // length, integer is 4 bytes + out.writeInt(attribute.getValue()); + } + + /** + * Writes an attribute in EnumSyntax into the stream. + * @param attribute the attribute + * @throws IOException if thrown by the stream + */ + private void write(EnumSyntax attribute) throws IOException + { + // in JPS API enum syntax is used for enums, keyword and boolean types + String name = ((Attribute) attribute).getName(); + + // the enum value types + if (attribute instanceof Finishings + || attribute instanceof OrientationRequested + || attribute instanceof PrintQuality) + { + out.writeByte(IppValueTag.ENUM); + out.writeShort(name.length()); + out.write(name.getBytes()); + out.writeShort(4); // length, enum is 4 bytes + out.writeInt(attribute.getValue()); + } + // the boolean value type + else if (attribute instanceof Fidelity) + { + out.writeByte(IppValueTag.BOOLEAN); + out.writeShort(name.length()); + out.write(name.getBytes()); + out.writeShort(1); // length, boolean is 1 bytes + out.writeByte(attribute.getValue() == 0 ? 0x00 : 0x01); + } + // the keyword value types + else + { + String keyword = attribute.toString(); + out.writeByte(IppValueTag.KEYWORD); + out.writeShort(name.length()); + out.write(name.getBytes()); + out.writeShort(keyword.length()); + out.write(keyword.getBytes()); + } + } + + /** + * Writes an attribute in SetOfIntegerSyntax into the stream. + * @param attribute the attribute + * @throws IOException if thrown by the stream + */ + private void write(SetOfIntegerSyntax attribute) throws IOException + { + String name = ((Attribute) attribute).getName(); + int[][] ranges = attribute.getMembers(); + for (int i = 0; i < ranges.length; i++) + { + out.writeByte(IppValueTag.RANGEOFINTEGER); + if (i == 0) + { + out.writeShort(name.length()); + out.write(name.getBytes()); + } + else + out.writeShort(0x0000); // only name-length + + out.writeShort(8); // range is 8 bytes + out.writeInt(ranges[i][0]); + out.writeInt(ranges[i][1]); + } + } + + /** + * Writes an attribute in ResolutionSyntax into the stream. + * @param attribute the attribute + * @throws IOException if thrown by the stream + */ + private void write(ResolutionSyntax attribute) throws IOException + { + String name = ((Attribute) attribute).getName(); + out.writeByte(IppValueTag.RESOLUTION); + out.writeShort(name.length()); + out.write(name.getBytes()); + out.writeShort(9); // length fixed to 9 + out.writeInt(attribute.getCrossFeedResolution(ResolutionSyntax.DPI)); + out.writeInt(attribute.getFeedResolution(ResolutionSyntax.DPI)); + out.writeByte(ResolutionSyntax.DPI); + } + + /** + * Writes an attribute in DateTimeSyntax into the stream. + *

      + * The syntax value is defined as 11 octets follwing the + * DateAndTime format of RFC 1903. (see IppResponse) + *

      + * + * @param attribute the attribute + * @throws IOException if thrown by the stream + */ + private void write(DateTimeSyntax attribute) throws IOException + { + String name = ((Attribute) attribute).getName(); + out.writeByte(IppValueTag.DATETIME); + out.writeShort(name.length()); + out.write(name.getBytes()); + out.writeShort(11); // length fixed to 11 + + Date date = attribute.getValue(); + Calendar cal = new GregorianCalendar(); + cal.setTime(date); + + out.writeShort(cal.get(Calendar.YEAR)); + out.writeByte(cal.get(Calendar.MONTH)); + out.writeByte(cal.get(Calendar.DAY_OF_MONTH)); + out.writeByte(cal.get(Calendar.HOUR_OF_DAY)); + out.writeByte(cal.get(Calendar.MINUTE)); + int second = cal.get(Calendar.SECOND); + out.writeByte(second == 0 ? 60 : second); + out.writeByte(cal.get(Calendar.MILLISECOND) / 100); + + int offsetInMillis = cal.get(Calendar.ZONE_OFFSET); + char directionFromUTC = '+'; + if (offsetInMillis < 0) + { + directionFromUTC = '-'; + offsetInMillis = offsetInMillis * (-1); + } + + out.writeByte(directionFromUTC); + out.writeByte(offsetInMillis / 3600000); // hours + out.writeByte((offsetInMillis % 3600000) / 60000); // minutes + } + + /** + * Writes an attribute in TextSyntax into the stream. + *

      + * By default attributes are qritten as TEXT_WITHOUT_LANGUAGE value-tag. + * As some attributes in the JPS are TextSyntax attributes but actually + * of NAME value-tag in IPP this method checks for these attributes and + * writes them as NAME_WITHOUT_LANGUAGE value-tag into the stream. + *

      + * + * @param attribute the attribute + * @param out the stream to write to + * @throws IOException if thrown by the stream + */ + private void write(TextSyntax attribute) throws IOException + { + // We only use *WithoutLanguage, correct according to spec. + String name = ((Attribute) attribute).getName(); + + if (attribute instanceof RequestingUserName + || attribute instanceof JobName + || attribute instanceof DocumentName + || attribute instanceof JobOriginatingUserName) + out.writeByte(IppValueTag.NAME_WITHOUT_LANGUAGE); + else if (attribute instanceof DocumentFormat) + out.writeByte(IppValueTag.MIME_MEDIA_TYPE); + else + out.writeByte(IppValueTag.TEXT_WITHOUT_LANGUAGE); + + out.writeShort(name.length()); + out.write(name.getBytes()); + out.writeShort(attribute.getValue().length()); + out.write(attribute.getValue().getBytes()); + } + + /** + * Writes an attribute in URISyntax into the stream. + * @param attribute the attribute + * @param out the stream to write to + * @throws IOException if thrown by the stream + */ + private void write(URISyntax attribute) throws IOException + { + // only uriScheme syntax type should not appear + // in a request (reference-uri-schemes-supported) + String name = ((Attribute) attribute).getName(); + String uriAscii = attribute.getURI().toASCIIString(); + out.writeByte(IppValueTag.URI); + out.writeShort(name.length()); + out.write(name.getBytes()); + out.writeShort(uriAscii.length()); + out.write(uriAscii.getBytes()); + } + + /** + * Writes an attribute in CharsetSyntax into the stream. + * @param attribute the attribute + * @param out the stream to write to + * @throws IOException if thrown by the stream + */ + private void write(CharsetSyntax attribute) throws IOException + { + String name = ((Attribute) attribute).getName(); + out.writeByte(IppValueTag.CHARSET); + out.writeShort(name.length()); + out.write(name.getBytes()); + out.writeShort(attribute.getValue().length()); + out.write(attribute.getValue().getBytes()); + } + + /** + * Writes an attribute in NaturalLanguageSyntax into the stream. + * @param attribute the attribute + * @param out the stream to write to + * @throws IOException if thrown by the stream + */ + private void write(NaturalLanguageSyntax attribute) throws IOException + { + String name = ((Attribute) attribute).getName(); + out.writeByte(IppValueTag.NATURAL_LANGUAGE); + out.writeShort(name.length()); + out.write(name.getBytes()); + out.writeShort(attribute.getValue().length()); + out.write(attribute.getValue().getBytes()); + } + + /** + * Writes an attribute in RequestedAttributes into the stream. + * @param attribute the attribute + * @param out the stream to write to + * @throws IOException if thrown by the stream + */ + private void write(RequestedAttributes attribute) throws IOException + { + String[] values = attribute.getValues(); + + String name = ((Attribute) attribute).getName(); + out.writeByte(IppValueTag.KEYWORD); + out.writeShort(name.length()); + out.write(name.getBytes()); + out.writeShort(values[0].length()); + out.write(values[0].getBytes()); + + for (int i=1; i < values.length; i++) + { + out.writeByte(IppValueTag.KEYWORD); + out.writeShort(0x0000); // length for additional value + out.writeShort(values[i].length()); + out.write(values[i].getBytes()); + } + } + + + /** + * Writes the given operation attribute group of the given map instance + * (key=group, values=set of attributes) into the supplied data + * output stream. + * + * @param attributes the set with the attributes. + * + * @throws IOException if thrown by the used DataOutputStream. + * @throws IppException if unknown attributes occur. + */ + public void writeOperationAttributes(AttributeSet attributes) + throws IOException, IppException + { + out.write(IppDelimiterTag.OPERATION_ATTRIBUTES_TAG); + + // its essential to write these two in this order and as first ones + Attribute att = attributes.get(AttributesCharset.class); + write((CharsetSyntax) att); + + logger.log(Component.IPP, "Attribute: Name: <" + + att.getCategory().getName() + "> Value: <" + att.toString() + ">"); + + attributes.remove(AttributesCharset.class); + + att = attributes.get(AttributesNaturalLanguage.class); + write((NaturalLanguageSyntax) att); + attributes.remove(AttributesNaturalLanguage.class); + + logger.log(Component.IPP, "Attribute: Name: <" + + att.getCategory().getName() + "> Value: <" + att.toString() + ">"); + + // furthermore its essential to now write out the target attribute + PrinterURI printerUri = (PrinterURI) attributes.get(PrinterURI.class); + JobUri jobUri = (JobUri) attributes.get(JobUri.class); + JobId jobId = (JobId) attributes.get(JobId.class); + RequestedAttributes reqAttrs + = (RequestedAttributes)attributes.get(RequestedAttributes.class); + if (printerUri != null && jobId == null && jobUri == null) + { + write(printerUri); + attributes.remove(PrinterURI.class); + logger.log(Component.IPP, "Attribute: Name: <" + printerUri + .getCategory().getName() + "> Value: <" + printerUri.toString() + ">"); + } + else if (jobUri != null && jobId == null && printerUri == null) + { + write(jobUri); + attributes.remove(JobUri.class); + logger.log(Component.IPP, "Attribute: Name: <" + jobUri + .getCategory().getName() + "> Value: <" + jobUri.toString() + ">"); + } + else if (printerUri != null && jobId != null && jobUri == null) + { + write(printerUri); // must be third + write(jobId); + attributes.remove(PrinterURI.class); + attributes.remove(JobId.class); + logger.log(Component.IPP, "Attribute: Name: <" + printerUri + .getCategory().getName() + "> Value: <" + printerUri.toString() + ">"); + logger.log(Component.IPP, "Attribute: Name: <" + jobId.getCategory() + .getName() + "> Value: <" + jobId.toString() + ">"); + } + else if (jobUri != null && jobId != null) + { + write(jobUri); + attributes.remove(JobUri.class); + attributes.remove(JobId.class); // MUST NOT redundant + logger.log(Component.IPP, "Attribute: Name: <" + jobUri.getCategory() + .getName() + "> Value: <" + jobUri.toString() + ">"); + } + else if (reqAttrs != null) + { + write(reqAttrs); + attributes.remove(RequestedAttributes.class); + logger.log(Component.IPP, "RequestedAttributes: <" + reqAttrs + ">"); + } + else + { + throw new IppException("Unknown target operation attribute combination."); + } + + writeAttributes(attributes); + } + + /** + * Writes the given attribute groups of the given map instance + * (key=group, values=set of attributes) into the supplied data + * output stream. + * + * @param attributes the set with the attributes. + * + * @throws IOException if thrown by the used DataOutputStream. + * @throws IppException if unknown attributes occur. + */ + public void writeAttributes(AttributeSet attributes) + throws IOException, IppException + { + Attribute[] attributeArray = attributes.toArray(); + for (int i = 0; i < attributeArray.length; i++) + { + logger.log(Component.IPP, "Attribute: Name: <" + attributeArray[i] + .getCategory().getName() + "> Value: <" + + attributeArray[i].toString() + ">"); + + if (attributeArray[i] instanceof IntegerSyntax) + write((IntegerSyntax) attributeArray[i]); + else if (attributeArray[i] instanceof TextSyntax) + write((TextSyntax) attributeArray[i]); + else if (attributeArray[i] instanceof DateTimeSyntax) + write((DateTimeSyntax) attributeArray[i]); + else if (attributeArray[i] instanceof ResolutionSyntax) + write((ResolutionSyntax) attributeArray[i]); + else if (attributeArray[i] instanceof SetOfIntegerSyntax) + write((SetOfIntegerSyntax) attributeArray[i]); + else if (attributeArray[i] instanceof EnumSyntax) + write((EnumSyntax) attributeArray[i]); + else if (attributeArray[i] instanceof URISyntax) + write((URISyntax) attributeArray[i]); + else if (attributeArray[i] instanceof CharsetSyntax) + write((CharsetSyntax) attributeArray[i]); + else if (attributeArray[i] instanceof NaturalLanguageSyntax) + write((NaturalLanguageSyntax) attributeArray[i]); + else if (attributeArray[i] instanceof RequestedAttributes) + write((RequestedAttributes) attributeArray[i]); + else + throw new IppException("Unknown syntax type"); + } + } + + } + + /** + * Logger for tracing - enable by passing + * -Dgnu.classpath.debug.components=ipp to the vm. + */ + static final Logger logger = SystemLogger.SYSTEM; + + /** + * The request id counter simply counts up + * to give unique request ids per JVM instance. + */ + private static int requestIdCounter = 1; + + /** The IPP version defaults to 1.1 */ + private static final short VERSION = 0x0101; + + /** Signals if the request is already on its way */ + private boolean alreadySent = false; + + /** The operation type of this request. */ + private short operation_id; + + /** + * The request id of this request. This is + * assigned automatically by the constructor. + */ + private final int request_id; + + private AttributeSet operationAttributes; + + private AttributeSet printerAttributes; + + private AttributeSet jobAttributes; + + private Object data; + + private URI requestUri; + + /** The underlying connection - IPP is http based */ + private HttpURLConnection connection; + + /** + * Creates an IPPRequest instance. + * + * @param uri the URI of the request + * @param user the user if any + * @param password the password of the supplied user + */ + public IppRequest(URI uri, String user, String password) + { + request_id = incrementRequestIdCounter(); + requestUri = uri; + + try + { + URL url = new URL("http", + user == null + ? uri.getHost() : user + ":" + + password + "@" + uri.getHost(), + uri.getPort(), uri.getPath()); + + connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("POST"); + connection.setDoOutput(true); + + connection.setRequestProperty("Content-type", "application/ipp"); + connection.setRequestProperty("Accept", "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2"); + } + catch (IOException e) + { + // MalformedURLException - uri is already checked + // ProtocolException - POST is correct method type + // IOException -HTTPURLConnection constructor actually + // does never throw this exception. + logger.log(Component.IPP, "Unexpected IOException", e); + } + + logger.log(Component.IPP, "[IppConnection] Host: " + uri.getHost() + + " Port: " + uri.getPort() + " Path: " + + uri.getPath()); + } + + /** + * Synchronized method to be called by the constructor + * to assign a unique request id to this request. + * + * @return The unique request id. + */ + private synchronized int incrementRequestIdCounter() + { + return IppRequest.requestIdCounter++; + } + + /** + * Returns the id of this request. + * + * @return The request ID. + */ + public int getRequestID() + { + return request_id; + } + + /** + * Sets the data of the request. The data used in this + * request will be the one of the supplied inputstream + * instead of the alternative byte array possibility. + * + * @param stream the input stream to use for the data. + */ + public void setData(InputStream stream) + { + data = stream; + } + + /** + * Sets the data of the request. The data used in this + * request will be the one of the supplied byte[] + * instead of the alternative input stream possibility. + * + * @param bytes the byte[] to use for the data. + */ + public void setData(byte[] bytes) + { + data = bytes; + } + + /** + * Sets the operation id for this request. + * + * @param id the operation id. + */ + public void setOperationID(short id) + { + operation_id = id; + } + + /** + * Adds the default values for the operation + * attributes "attributes-charset" and + * "attributes-natural-language" + */ + public void setOperationAttributeDefaults() + { + if (operationAttributes == null) + operationAttributes = new HashAttributeSet(); + + operationAttributes.add(AttributesCharset.UTF8); + operationAttributes.add(AttributesNaturalLanguage.EN); + } + + /** + * Add the job attribute of this request to the given + * attribute set. + * + * @param attribute the job attribute. + */ + public void addJobAttribute(Attribute attribute) + { + if (jobAttributes == null) + jobAttributes = new HashAttributeSet(); + + jobAttributes.add(attribute); + } + + /** + * Sets the printer attribute of this request to the given + * attribute set. + * + * @param attribute the printer attribute. + */ + public void addPrinterAttributes(Attribute attribute) + { + if (printerAttributes == null) + printerAttributes = new HashAttributeSet(); + + printerAttributes.add(attribute); + } + + /** + * Adds the given attribute to the operation attributes set. + * + * @param attribute the operation attribute to add. + */ + public void addOperationAttribute(Attribute attribute) + { + if (operationAttributes == null) + operationAttributes = new HashAttributeSet(); + + operationAttributes.add(attribute); + } + + /** + * Filters from the given attribute set the job operation out + * and adds them to the operation attributes set. + * + * @param set the attributes to filter, may not be null. + */ + public void addAndFilterJobOperationAttributes(AttributeSet set) + { + if (operationAttributes == null) + operationAttributes = new HashAttributeSet(); + + // document-natural-language - not defined in JPS attributes + // document-format - specified outside, special treatment + Attribute[] tmp = set.toArray(); + for (int i = 0; i < tmp.length; i++) + { + if (tmp[i].getCategory().equals(JobName.class) + || tmp[i].getCategory().equals(Fidelity.class) + || tmp[i].getCategory().equals(JobImpressions.class) + || tmp[i].getCategory().equals(JobKOctets.class) + || tmp[i].getCategory().equals(JobMediaSheets.class) + || tmp[i].getCategory().equals(Compression.class) + || tmp[i].getCategory().equals(DocumentName.class) + || tmp[i].getCategory().equals(RequestingUserName.class)) + + operationAttributes.add(tmp[i]); + } + } + + /** + * Filters from the given attribute set the job template attributes + * out and adds them to the job attributes set. + * + * @param set the attributes to filter, may not be null. + */ + public void addAndFilterJobTemplateAttributes(AttributeSet set) + { + if (jobAttributes == null) + jobAttributes = new HashAttributeSet(); + + // document-natural-language - not defined in JPS attributes + // document-format - specified outside, special treatment + Attribute[] tmp = set.toArray(); + for (int i = 0; i < tmp.length; i++) + { + if (tmp[i].getCategory().equals(JobPriority.class) + || tmp[i].getCategory().equals(JobHoldUntil.class) + || tmp[i].getCategory().equals(JobSheets.class) + || tmp[i].getCategory().equals(MultipleDocumentHandling.class) + || tmp[i].getCategory().equals(Copies.class) + || tmp[i].getCategory().equals(Finishings.class) + || tmp[i].getCategory().equals(PageRanges.class) + || tmp[i].getCategory().equals(NumberUp.class) + || tmp[i].getCategory().equals(OrientationRequested.class) + || tmp[i].getCategory().equals(Media.class) + || tmp[i].getCategory().equals(PrinterResolution.class) + || tmp[i].getCategory().equals(PrintQuality.class) + || tmp[i].getCategory().equals(SheetCollate.class) + || tmp[i].getCategory().equals(Sides.class)) + + jobAttributes.add(tmp[i]); + } + } + + /** + * Does some validation of the supplied parameters and then + * sends the request to the ipp server or service. + * + * @return The response if any. + * + * @throws IllegalStateException if request is already sent + * @throws IppException if connection or request failed. + * @throws IOException if writing of the header, attributes or footer fails. + */ + public IppResponse send() throws IppException, IOException + { + if (alreadySent) + throw new IllegalStateException("Request is already sent"); + + alreadySent = true; + + OutputStream stream = connection.getOutputStream(); + DataOutputStream out = new DataOutputStream(stream); + + // the header 8 bytes long + out.writeShort(VERSION); + out.writeShort(operation_id); + out.writeInt(request_id); + + logger.log(Component.IPP, "OperationID: " + Integer.toHexString(operation_id) + + " RequestID: " + request_id); + + // Pass stuff the the attribute writer which knows how to + // write the attributes in correct order + logger.log(Component.IPP, "Operation Attributes"); + + RequestWriter writer = new RequestWriter(out); + writer.writeOperationAttributes(operationAttributes); + + if (jobAttributes != null) + { + logger.log(Component.IPP, "Job Attributes"); + out.write(IppDelimiterTag.JOB_ATTRIBUTES_TAG); + writer.writeAttributes(jobAttributes); + } + if (printerAttributes != null) + { + logger.log(Component.IPP, "Printer Attributes"); + out.write(IppDelimiterTag.PRINTER_ATTRIBUTES_TAG); + writer.writeAttributes(printerAttributes); + } + + // write the delimiter to the data + out.write(IppDelimiterTag.END_OF_ATTRIBUTES_TAG); + + // check if data is byte[] or inputstream + if (data instanceof InputStream) + { + byte[] readbuf = new byte[2048]; + int len = 0; + while( (len = ((InputStream) data).read(readbuf)) > 0) + out.write(readbuf, 0, len); + } + else if (data != null) + { + out.write((byte[]) data); + } + + out.flush(); + stream.flush(); + + // Set the connection timeout, for if the printer is offline. + // FIXME: The print services polling should probably be done in its + // own thread. + connection.setConnectTimeout( timeout ); + + int responseCode = connection.getResponseCode(); + + if (responseCode == HttpURLConnection.HTTP_OK) + { + IppResponse response = new IppResponse(requestUri, operation_id); + response.setResponseData(connection.getInputStream()); + return response; + } + + logger.log(Component.IPP, "HTTP-Statuscode: " + responseCode); + + throw new IppException("Request failed got HTTP status code " + + responseCode); + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/IppResponse.java b/libjava/classpath/gnu/javax/print/ipp/IppResponse.java new file mode 100644 index 000000000..703bdc1eb --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/IppResponse.java @@ -0,0 +1,787 @@ +/* IppResponse.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.javax.print.ipp; + +import gnu.classpath.debug.Component; +import gnu.classpath.debug.SystemLogger; +import gnu.javax.print.ipp.attribute.UnknownAttribute; +import gnu.javax.print.ipp.attribute.defaults.DocumentFormatDefault; +import gnu.javax.print.ipp.attribute.defaults.JobHoldUntilDefault; +import gnu.javax.print.ipp.attribute.defaults.JobSheetsDefault; +import gnu.javax.print.ipp.attribute.defaults.MediaDefault; +import gnu.javax.print.ipp.attribute.defaults.PrinterResolutionDefault; +import gnu.javax.print.ipp.attribute.job.AttributesCharset; +import gnu.javax.print.ipp.attribute.job.AttributesNaturalLanguage; +import gnu.javax.print.ipp.attribute.job.JobMoreInfo; +import gnu.javax.print.ipp.attribute.job.JobPrinterUri; +import gnu.javax.print.ipp.attribute.job.JobUri; +import gnu.javax.print.ipp.attribute.printer.CharsetConfigured; +import gnu.javax.print.ipp.attribute.printer.DocumentFormat; +import gnu.javax.print.ipp.attribute.printer.NaturalLanguageConfigured; +import gnu.javax.print.ipp.attribute.printer.PrinterCurrentTime; +import gnu.javax.print.ipp.attribute.printer.PrinterDriverInstaller; +import gnu.javax.print.ipp.attribute.supported.CharsetSupported; +import gnu.javax.print.ipp.attribute.supported.DocumentFormatSupported; +import gnu.javax.print.ipp.attribute.supported.GeneratedNaturalLanguageSupported; +import gnu.javax.print.ipp.attribute.supported.JobHoldUntilSupported; +import gnu.javax.print.ipp.attribute.supported.JobSheetsSupported; +import gnu.javax.print.ipp.attribute.supported.MediaSupported; +import gnu.javax.print.ipp.attribute.supported.PrinterResolutionSupported; +import gnu.javax.print.ipp.attribute.supported.PrinterUriSupported; + +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.logging.Logger; + +import javax.print.attribute.Attribute; +import javax.print.attribute.standard.CopiesSupported; +import javax.print.attribute.standard.DateTimeAtCompleted; +import javax.print.attribute.standard.DateTimeAtCreation; +import javax.print.attribute.standard.DateTimeAtProcessing; +import javax.print.attribute.standard.JobImpressionsSupported; +import javax.print.attribute.standard.JobKOctetsSupported; +import javax.print.attribute.standard.JobMediaSheetsSupported; +import javax.print.attribute.standard.JobStateReason; +import javax.print.attribute.standard.JobStateReasons; +import javax.print.attribute.standard.NumberUpSupported; +import javax.print.attribute.standard.PrinterMoreInfo; +import javax.print.attribute.standard.PrinterMoreInfoManufacturer; +import javax.print.attribute.standard.PrinterStateReason; +import javax.print.attribute.standard.PrinterStateReasons; +import javax.print.attribute.standard.Severity; + +/** + * IppResponse models a response received from an IPP + * compatible server as described in RFC 2910 IPP 1.1 Encoding and Transport. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public class IppResponse +{ + + /** + * ResponseReader is responsible for parsing an IPP 1.1 + * response stream. It provides access to the attribute groups after parsing + * via getter methods. + *

      + * The enconding of a response is structured as follows (for an official + * description please have a look at the RFC document mentioned above): + *

        + *
      • version-number - 2 bytes - required
      • + *
      • status-code - 2 bytes - required
      • + *
      • request-id - 4 bytes - required
      • + *
      • attribute-group - n bytes - 0 or more
      • + *
      • end-of-attributes-tag - 1 byte - required
      • + *
      • data - q bytes - optional
      • + *
      + *

      + * Where each attribute-group (if any) is encoded as follows: + *

        + *
      • begin-attribute-group-tag - 1 byte
      • + *
      • attribute - p bytes - 0 or more
      • + *
      + *

      + * Encoding of attributes: + *

        + *
      • attribute-with-one-value - q bytes
      • + *
      • additional-value - r bytes - 0 or more
      • + *
      + *

      + * Encoding of attribute-with-one-value: + *

        + *
      • value-tag - 1 byte
      • + *
      • name-length (value is u) - 2 bytes
      • + *
      • name - u bytes
      • + *
      • value-length (value is v) - 2 bytes
      • + *
      • value - v bytes
      • + *
      + *

      + * Encoding of additional value: + *

        + *
      • value-tag - 1 byte
      • + *
      • name-length (value is 0x0000) - 2 bytes
      • + *
      • value-length (value is w) - 2 bytes
      • + *
      • value - w bytes
      • + *
      + *

      + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ + class ResponseReader + { + /** The IPP version defaults to 1.1 */ + private static final short VERSION = 0x0101; + + /** + * Parses the inputstream containing the response of the IPP request. + * @param input the inputstream + * @throws IppException if unexpected exceptions occur. + * @throws IOException if IO problems with the underlying inputstream occur. + */ + public void parseResponse(InputStream input) + throws IppException, IOException + { + DataInputStream stream = new DataInputStream(input); + + short version = stream.readShort(); + status_code = stream.readShort(); + request_id = stream.readInt(); + + if (VERSION != version) + throw new IppException("Version mismatch - " + + "implementation does not support other versions than IPP 1.1"); + + logger.log(Component.IPP, "Statuscode: " + + Integer.toHexString(status_code) + " Request-ID: " + request_id); + + byte tag = 0; + boolean proceed = true; + HashMap, Set> tmp; + // iterate over attribute-groups until end-of-attributes-tag is found + while (proceed) + { + if (tag == 0) // only at start time + tag = stream.readByte(); + + logger.log(Component.IPP, "DelimiterTag: " + Integer.toHexString(tag)); + + // check if end of attributes + switch (tag) + { + case IppDelimiterTag.END_OF_ATTRIBUTES_TAG: + proceed = false; + break; + case IppDelimiterTag.OPERATION_ATTRIBUTES_TAG: + tmp = new HashMap, Set>(); + tag = parseAttributes(tmp, stream); + operationAttributes.add(tmp); + break; + case IppDelimiterTag.JOB_ATTRIBUTES_TAG: + tmp = new HashMap, Set>(); + tag = parseAttributes(tmp, stream); + jobAttributes.add(tmp); + break; + case IppDelimiterTag.PRINTER_ATTRIBUTES_TAG: + tmp = new HashMap, Set>(); + tag = parseAttributes(tmp, stream); + printerAttributes.add(tmp); + break; + case IppDelimiterTag.UNSUPPORTED_ATTRIBUTES_TAG: + System.out.println("Called"); + tmp = new HashMap, Set>(); + tag = parseAttributes(tmp, stream); + unsupportedAttributes.add(tmp); + break; + default: + throw new IppException("Unknown tag with value " + + Integer.toHexString(tag) + " occured."); + } + } + + // if there are more bytes that has to be data. + ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); + byte[] readbuf = new byte[2048]; + int len = 0; + + while ((len = stream.read(readbuf)) > 0) + byteStream.write(readbuf, 0, len); + + byteStream.flush(); + data = byteStream.toByteArray(); + } + + /** + * The actual parsing of the attributes and further putting into the + * provided group maps. + * @param attributes the provided attribute group map. + * @param stream the provided stream to read from. + * @return The last read tag byte (normally a DelimiterTag) + * @throws IppException if unexpected exceptions occur. + * @throws IOException if IO problems with the underlying inputstream occur. + */ + private byte parseAttributes(Map, Set> attributes, + DataInputStream stream) + throws IppException, IOException + { + Attribute lastAttribute = null; + Attribute attribute = null; + + // declaration of variables + short nameLength; + String name; + short valueLength; + byte[] value; + + // tmp variables for parsing + // declared here so no name duplication occurs + URI uri; + String str; + + while (true) + { + byte tag = stream.readByte(); + + if (IppDelimiterTag.isDelimiterTag(tag)) + return tag; + + // it must be a value tag now + // so we have either a attribute-with-one-value + // or (if setOf is possible) an additional-value + + // (1) Length of the name + nameLength = stream.readShort(); + + // (2) The name itself + // may be an additional-value + if (nameLength == 0x0000) + name = lastAttribute.getName(); + else + { + byte[] nameBytes = new byte[nameLength]; + stream.read(nameBytes); + name = new String(nameBytes); + } + + // (3) Length of the value + valueLength = stream.readShort(); + + // (4) The value itself + value = new byte[valueLength]; + stream.read(value); + + // the value itself + switch (tag) + { + // out-of-band values + case IppValueTag.UNSUPPORTED: + case IppValueTag.UNKNOWN: + // TODO implement out-of-band handling + // We currently throw an exception to see when it occurs - not yet :-) + throw new IppException( + "Unexpected name value for out-of-band value tag " + tag); + case IppValueTag.NO_VALUE: + attribute = null; + + break; + case IppValueTag.INTEGER: + int intValue = IppUtilities.convertToInt(value); + attribute = IppUtilities.getIntegerAttribute(name, intValue); + + break; + case IppValueTag.BOOLEAN: + // JPS API models boolean syntax type as enums + // 0x01 = true, 0x00 = false - all are enums + attribute = IppUtilities.getEnumAttribute(name, new Integer(value[0])); + + break; + case IppValueTag.ENUM: + int intVal = IppUtilities.convertToInt(value); + attribute = IppUtilities.getEnumAttribute(name, new Integer(intVal)); + + break; + case IppValueTag.OCTECTSTRING_UNSPECIFIED: + // none exists according to spec + // so lets report as exception to see when it occurs + throw new IppException("Unspecified octet string occured."); + + case IppValueTag.DATETIME: + Date date = parseDate(value); + if (name.equals("printer-current-time")) + attribute = new PrinterCurrentTime(date); + else if (name.equals("date-time-at-creation")) + attribute = new DateTimeAtCreation(date); + else if (name.equals("date-time-at-processing")) + attribute = new DateTimeAtProcessing(date); + else if (name.equals("date-time-at-completed")) + attribute = new DateTimeAtCompleted(date); + + break; + case IppValueTag.RESOLUTION: + int crossFeed = IppUtilities.convertToInt(value[0], value[1], value[2], value[3]); + int feed = IppUtilities.convertToInt(value[4], value[5], value[6], value[7]); + int units = value[8]; + + if (name.equals("printer-resolution-default")) + attribute = new PrinterResolutionDefault(crossFeed, feed, units); + else if (name.equals("printer-resolution-supported")) // may be here also + attribute = new PrinterResolutionSupported(crossFeed, feed, units); + + break; + case IppValueTag.RANGEOFINTEGER: + int lower = IppUtilities.convertToInt(value[0], value[1], value[2], value[3]); + int upper = IppUtilities.convertToInt(value[4], value[5], value[6], value[7]); + + if (name.equals("copies-supported")) + attribute = new CopiesSupported(lower, upper); + else if (name.equals("number-up-supported")) + attribute = new NumberUpSupported(lower, upper); + else if (name.equals("job-k-octets-supported")) + attribute = new JobKOctetsSupported(lower, upper); + else if (name.equals("job-impressions-supported")) + attribute = new JobImpressionsSupported(lower, upper); + else if (name.equals("job-media-sheets-supported")) + attribute = new JobMediaSheetsSupported(lower, upper); + + break; + case IppValueTag.TEXT_WITH_LANGUAGE: + case IppValueTag.TEXT_WITHOUT_LANGUAGE: + case IppValueTag.NAME_WITH_LANGUAGE: + case IppValueTag.NAME_WITHOUT_LANGUAGE: + attribute = IppUtilities.getTextAttribute(name, tag, value); + + break; + case IppValueTag.KEYWORD: + str = new String(value); + if (name.equals("job-hold-until-supported")) // may also be name type + attribute = new JobHoldUntilSupported(str, null); + else if (name.equals("job-hold-until-default")) + attribute = new JobHoldUntilDefault(str, null); + else if (name.equals("media-supported")) + attribute = new MediaSupported(str, null); + else if (name.equals("media-default")) + attribute = new MediaDefault(str, null); + else if (name.equals("job-sheets-default")) + attribute = new JobSheetsDefault(str, null); + else if (name.equals("job-sheets-supported")) + attribute = new JobSheetsSupported(str, null); + else if (name.equals("job-state-reasons")) // setOf + attribute = parseJobStateReasons(value, lastAttribute); + else if (name.equals("printer-state-reasons")) // setOf + attribute = parsePrinterStateReasons(value, lastAttribute); + else + attribute = IppUtilities.getEnumAttribute(name, str); + + // all other stuff is either an enum or needs to be mapped to an + // UnknownAttribute instance. Enums catched here are: + // ipp-versions-supported, pdl-override-supported, compression-supported + // uri-authentication-supported, uri-security-supported, sides-supported + // sides-default, multiple-document-handling-supported, multiple-document-handling-default + + break; + case IppValueTag.URI: + try + { + uri = new URI(new String(value)); + } + catch (URISyntaxException e) + { + throw new IppException("Wrong URI syntax encountered.", e); + } + + if (name.equals("job-uri")) + attribute = new JobUri(uri); + else if (name.equals("job-printer-uri")) + attribute = new JobPrinterUri(uri); + else if (name.equals("job-more-info")) + attribute = new JobMoreInfo(uri); + else if (name.equals("printer-uri-supported")) // setOf + attribute = new PrinterUriSupported(uri); + else if (name.equals("printer-more-info")) + attribute = new PrinterMoreInfo(uri); + else if (name.equals("printer-driver-installer")) + attribute = new PrinterDriverInstaller(uri); + else if (name.equals("printer-more-info-manufacturer")) + attribute = new PrinterMoreInfoManufacturer(uri); + + break; + case IppValueTag.URI_SCHEME: + // only one uri-scheme exists - and its an enum + if (name.equals("reference-uri-schemes-supported")) + attribute = IppUtilities.getEnumAttribute(name, new String(value)); + + break; + case IppValueTag.CHARSET: + str = new String(value); + if (name.equals("attributes-charset")) + attribute = new AttributesCharset(str); + else if (name.equals("charset-configured")) + attribute = new CharsetConfigured(str); + else if (name.equals("charset-supported")) // setOf + attribute = new CharsetSupported(str); + + break; + case IppValueTag.NATURAL_LANGUAGE: + str = new String(value); + if (name.equals("attributes-natural-language")) + attribute = new AttributesNaturalLanguage(str); + else if (name.equals("natural-language-configured")) + attribute = new NaturalLanguageConfigured(str); + else if (name.equals("generated-natural-language-supported")) // setOf + attribute = new GeneratedNaturalLanguageSupported(str); + + break; + case IppValueTag.MIME_MEDIA_TYPE: + str = new String(value); + if (name.equals("document-format-default")) + attribute = new DocumentFormatDefault(str, null); + else if (name.equals("document-format-supported")) // setOf + attribute = new DocumentFormatSupported(str, null); + else if (name.equals("document-format")) // setOf + attribute = new DocumentFormat(str, null); + + break; + default: + throw new IppException("Unknown tag with value " + + Integer.toHexString(tag) + " found."); + } + + if (attribute == null) + attribute = new UnknownAttribute(tag, name, value); + + addAttribute(attributes, attribute); + lastAttribute = attribute; + + logger.log(Component.IPP, "Attribute: " + name + + " Value: " + attribute.toString()); + } + } + + /** + * Adds a new attribute to the given attribute group. If this is the fist + * occurence of this attribute category a new set is created and associated + * with its category as key. + * @param attributeGroup + * the attribute group + * @param attribute + * the attribute to add + */ + private void addAttribute(Map, Set> attributeGroup, + Attribute attribute) + { + Class clazz = attribute.getCategory(); + Set attributeValues = attributeGroup.get(clazz); + + if (attributeValues == null) // first attribute of this category + { + attributeValues = new HashSet(); + attributeGroup.put(clazz, attributeValues); + } + + attributeValues.add(attribute); + } + + /** + * Parses a name with or without language attribute value from the byte[] + * and returns the result as an object[]. + * @param value the byte[] + * @param lastAttr the last attribute + * @return The attribute. + */ + private PrinterStateReasons parsePrinterStateReasons(byte[] value, Attribute lastAttr) + { + String str = new String(value); + PrinterStateReasons attribute; + + if (lastAttr instanceof PrinterStateReasons) + attribute = (PrinterStateReasons) lastAttr; + else + attribute = new PrinterStateReasons(); + + // special case indicating no reasons + if (str.equals("none")) + return attribute; + + Severity severity = null; + PrinterStateReason reason = null; + + if (str.endsWith(Severity.WARNING.toString())) + severity = Severity.WARNING; + else if (str.endsWith(Severity.REPORT.toString())) + severity = Severity.REPORT; + else if (str.endsWith(Severity.ERROR.toString())) + severity = Severity.ERROR; + + if (severity != null) + str = str.substring(0, str.lastIndexOf('-')); + else // we must associate a severity + severity = Severity.REPORT; + + reason = (PrinterStateReason) + IppUtilities.getEnumAttribute("printer-state-reason", str); + + attribute.put(reason , severity); + return attribute; + } + + /** + * Parses a name with or without language attribute value from the byte[] + * and returns the result as an object[]. + * @param value the byte[] + * @param lastAttr the last attribute + * @return The attribute. + */ + private JobStateReasons parseJobStateReasons(byte[] value, Attribute lastAttr) + { + String str = new String(value); + JobStateReasons attribute; + + if (lastAttr instanceof JobStateReasons) + attribute = (JobStateReasons) lastAttr; + else + attribute = new JobStateReasons(); + + // special case indicating no reasons + if (str.equals("none")) + return attribute; + + JobStateReason reason = (JobStateReason) + IppUtilities.getEnumAttribute("job-state-reason", str); + + attribute.add(reason); + return attribute; + } + + /** + * Parses a DateTime syntax attribute and returns the constructed Date + * object. + *

      + * The syntax value is defined as 11 octets follwing the DateAndTime format + * of RFC 1903: + *

        + *
      • field | octets | contents | range
      • + *
      • 1 | 1-2 | year | 0..65536
      • + *
      • 2 | 3 | month | 1..12
      • + *
      • 3 | 4 | day | 1..31
      • + *
      • 4 | 5 | hour | 0..23
      • + *
      • 5 | 6 | minutes | 0..59
      • + *
      • 6 | 7 | seconds | 0..60 (use 60 for leap-second)
      • + *
      • 7 | 8 | deci-seconds | 0..9
      • + *
      • 8 | 9 | direction from UTC | '+' / '-'
      • + *
      • 9 | 10 | hours from UTC | 0..11
      • + *
      • 10 | 11 | minutes from UTC | 0..59
      • + *
      + *

      + * + * @param value the byte[] + * @return The date object. + */ + private Date parseDate(byte[] value) + { + short year = IppUtilities.convertToShort(value[0], value[1]); + + Calendar cal = Calendar.getInstance(); + cal.set(Calendar.YEAR, year); + cal.set(Calendar.MONTH, value[2]); + cal.set(Calendar.DAY_OF_MONTH, value[3]); + cal.set(Calendar.HOUR_OF_DAY, value[4]); + cal.set(Calendar.MINUTE, value[5]); + cal.set(Calendar.SECOND, value[6]); + cal.set(Calendar.MILLISECOND, value[7] * 100); // deci-seconds + + // offset from timezone + int offsetMilli = value[9] * 3600000; // hours to millis + offsetMilli = offsetMilli + value[10] * 60000; // minutes to millis + + if (((char) value[8]) == '-') + offsetMilli = offsetMilli * (-1); + + cal.set(Calendar.ZONE_OFFSET, offsetMilli); + return cal.getTime(); + } + } + + /** + * Logger for tracing - enable by passing + * -Dgnu.classpath.debug.components=ipp to the vm. + */ + static final Logger logger = SystemLogger.SYSTEM; + + URI uri; + short operation_id; + short status_code; + int request_id; + + List, Set>> operationAttributes; + List, Set>> printerAttributes; + List, Set>> jobAttributes; + List, Set>> unsupportedAttributes; + + byte[] data; + + /** + * Creates an IppResponse instance. + * + * @param uri the uri the request was directy to. + * @param operation_id the operation id of the request. + */ + public IppResponse(URI uri, short operation_id) + { + this.uri = uri; + this.operation_id = operation_id; + operationAttributes = + new ArrayList, Set>>(); + jobAttributes = + new ArrayList, Set>>(); + printerAttributes = + new ArrayList, Set>>(); + unsupportedAttributes = + new ArrayList, Set>>(); + } + + /** + * Sets the data received from the request sent. + * + * @param input the input stream received. + * @throws IppException if parsing fails. + */ + protected void setResponseData(InputStream input) throws IppException + { + ResponseReader reader = new ResponseReader(); + + try + { + reader.parseResponse(input); + } + catch (IOException e) + { + throw new IppException( + "Exception during response parsing caused by IOException", e); + } + } + + /** + * Returns the uri of the original request. + * @return The URI of the request. + */ + public URI getURI() + { + return uri; + } + + /** + * Returns the operation id of the original request. + * @return The operation id of the request. + */ + public int getOperationID() + { + return operation_id; + } + + /** + * Returns the set of job attributes group maps. + * There may occur more than one group of type job attribute in a response + * because of e.g. multiple job or print service informations requested. + * + * @return The list of job attribute group maps. + */ + public List, Set>> getJobAttributes() + { + return jobAttributes; + } + + /** + * Returns the set of operation attributes group maps. + * There may occur more than one group of type job attribute in a response + * because of e.g. multiple job or print service informations requested. + * + * @return The list of operation attribute group maps. + */ + public List, Set>> getOperationAttributes() + { + return operationAttributes; + } + + /** + * Returns the set of printer attributes group maps. + * There may occur more than one group of type job attribute in a response + * because of e.g. multiple job or print service informations requested. + * + * @return The list of printer attribute group maps. + */ + public List, Set>> getPrinterAttributes() + { + return printerAttributes; + } + + /** + * Returns the ID of the initial request. + * + * @return The request ID. + */ + public int getRequestID() + { + return request_id; + } + + /** + * Returns the status code of the response. + * Defined in {@link IppStatusCode}. + * + * @return The status code. + */ + public short getStatusCode() + { + return status_code; + } + + /** + * Returns the set of unsupported attributes group maps. + * There may occur more than one group of type job attribute in a response + * because of e.g. multiple job or print service informations requested. + * + * @return The list of unsupported attribute group maps. + */ + public List, Set>> getUnsupportedAttributes() + { + return unsupportedAttributes; + } + + /** + * Returns the data of the response. + * + * @return The data as byte[]. + */ + public byte[] getData() + { + return data; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/IppStatusCode.java b/libjava/classpath/gnu/javax/print/ipp/IppStatusCode.java new file mode 100644 index 000000000..a3b245c43 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/IppStatusCode.java @@ -0,0 +1,185 @@ +/* IppStatusCode.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.javax.print.ipp; + +/** + * IPP Status codes as described in RFC 2911 APPENDIX B + * (Status Codes and Suggested Status Code Messages) + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class IppStatusCode +{ + /** + * Indicates a successful request with no attributes being + * ignored or substituted. + */ + public static final int SUCCESSFUL_OK = 0x0000; + + /** + * Indicates a successful request, however some of the supplied + * attributes are ignored or substituted. + */ + public static final int SUCCESSFUL_OK_IGNORED_OR_SUBSTITUED_ATTRIBUTES = 0x0001; + + /** + * Indicates a successful request, however some of the supplied + * attributes conflicted and therefore were ignored or substituted. + */ + public static final int SUCCESSFUL_OK_CONFLICTING_ATTRIBUTES = 0x0002; + + // Client Error Status Codes + // Indicates that the client has done something wrong in its + // requests send to the IPP server object + + /** Indicates a bad request e.g. malformed syntax. */ + public static final int CLIENT_ERROR_BAD_REQUEST = 0x0400; + + /** Indicates that the client is forbidden to access the server. */ + public static final int CLIENT_ERROR_FORBIDDEN = 0x0401; + + /** Indicates that the client needs to authenticate. */ + public static final int CLIENT_ERROR_NOT_AUTHENTICATED = 0x0402; + + /** Indicates that the client is not authorized. */ + public static final int CLIENT_ERROR_NOT_AUTHORIZED = 0x0403; + + /** + * Indicates a request which is not possible to process. + * For example if the request is directed at a job already finished. + */ + public static final int CLIENT_ERROR_NOT_POSSIBLE = 0x0404; + + /** Indicates that the client got a timeout for additional action. */ + public static final int CLIENT_ERROR_TIMEOUT = 0x0405; + + /** Indicates that nothing was found for the request uri. */ + public static final int CLIENT_ERROR_NOT_FOUND = 0x0406; + + /** Indicates that the requested object is gone. */ + public static final int CLIENT_ERROR_GONE = 0x0407; + + /** Indicates that the request entities are too long. */ + public static final int CLIENT_ERROR_REQUEST_ENTITY_TOO_LONG = 0x0408; + + /** Indicates that a request value is too long. */ + public static final int CLIENT_ERROR_REQUEST_VALUE_TOO_LONG = 0x0409; + + /** Indicates that the supplied document format is not supported. */ + public static final int CLIENT_ERROR_DOCUMENT_FORMAT_NOT_SUPPORTED = 0x040A; + + /** + * Indicates that the supplied attributes or values of attributes are not + * supported by the printer object. Returning this code depends on the + * given "ipp-attribute-fidelity" operation attribute value. + */ + public static final int CLIENT_ERROR_ATTRIBUTES_OR_VALUES_NOT_SUPPORTED + = 0x040B; + + /** + * Indicates the the URI scheme in a supplied print-uri or send-uri attribute + * is not supported. + */ + public static final int CLIENT_ERROR_URI_SCHEME_NOT_SUPPORTED = 0x040C; + + /** Indicates that a supplied attributes-charset is not supported. */ + public static final int CLIENT_ERROR_CHARSET_NOT_SUPPORTED = 0x040D; + + /** Indicates that conflicting attributes are in the request. */ + public static final int CLIENT_ERROR_CONFLICTING_ATTRIBUTES = 0x040E; + + /** Indicates that the specified algorithm is not supported. */ + public static final int CLIENT_ERROR_COMPRESSION_NOT_SUPPORTED = 0x040F; + + /** + * Indicates that the document cannot be decompressed with the client + * compression algorithm specified by the client. + */ + public static final int CLIENT_ERROR_COMPRESSION_ERROR = 0x0410; + + /** Indicates an error in the document format of the document. */ + public static final int CLIENT_ERROR_DOCUMENT_FORMAT_ERROR = 0x0411; + + /** + * Indicates that the document supplied via print-uri or send-uri cannot be + * accessed by the printer object. + */ + public static final int CLIENT_ERROR_DOCUMENT_ACCESS_ERROR = 0x0412; + + + /** Indicates an internal server error. */ + public static final int SERVER_ERROR_INTERNAL_ERROR = 0x0500; + + /** Indicates that the server does not support the operation. */ + public static final int SERVER_ERROR_OPERATION_NOT_SUPPORTED = 0x0501; + + /** Indicates that the server' service is not available. */ + public static final int SERVER_ERROR_SERVICE_UNAVAILABLE = 0x0502; + + /** Indicates that the server does not support the IPP version. */ + public static final int SERVER_ERROR_VERSION_NOT_SUPPORTED = 0x0503; + + /** Indicates that the server has a device error e.g. paper jam. */ + public static final int SERVER_ERROR_DEVICE_ERROR = 0x0504; + + /** Indicates that the server has a temporary error. */ + public static final int SERVER_ERROR_TEMPORARY_ERROR = 0x0505; + + /** Indicates that the server is currently not accepting jobs. */ + public static final int SERVER_ERROR_NOT_ACCEPTING_JOBS = 0x0506; + + /** + * Indicates that the server is currently busy with processing. + * Requests may be tried later again. + */ + public static final int SERVER_ERROR_BUSY = 0x0507; + + /** Indicates that the server has canceled the job for various reasons. */ + public static final int SERVER_ERROR_JOB_CANCELED = 0x0508; + + /** Indicates that the server does not support multidocument jobs. */ + public static final int SERVER_ERROR_MULTIPLE_DOCUMENT_JOBS_NOT_SUPPORTED + = 0x0509; + + private IppStatusCode() + { + // not to be instantiated + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/IppUtilities.java b/libjava/classpath/gnu/javax/print/ipp/IppUtilities.java new file mode 100644 index 000000000..fa987ec3f --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/IppUtilities.java @@ -0,0 +1,553 @@ +/* IppUtilities.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.javax.print.ipp; + +import gnu.javax.print.ipp.attribute.DetailedStatusMessage; +import gnu.javax.print.ipp.attribute.DocumentAccessError; +import gnu.javax.print.ipp.attribute.StatusMessage; +import gnu.javax.print.ipp.attribute.defaults.CopiesDefault; +import gnu.javax.print.ipp.attribute.defaults.FinishingsDefault; +import gnu.javax.print.ipp.attribute.defaults.JobHoldUntilDefault; +import gnu.javax.print.ipp.attribute.defaults.JobPriorityDefault; +import gnu.javax.print.ipp.attribute.defaults.JobSheetsDefault; +import gnu.javax.print.ipp.attribute.defaults.MediaDefault; +import gnu.javax.print.ipp.attribute.defaults.MultipleDocumentHandlingDefault; +import gnu.javax.print.ipp.attribute.defaults.NumberUpDefault; +import gnu.javax.print.ipp.attribute.defaults.OrientationRequestedDefault; +import gnu.javax.print.ipp.attribute.defaults.PrintQualityDefault; +import gnu.javax.print.ipp.attribute.defaults.SidesDefault; +import gnu.javax.print.ipp.attribute.job.JobDetailedStatusMessages; +import gnu.javax.print.ipp.attribute.job.JobDocumentAccessErrors; +import gnu.javax.print.ipp.attribute.job.JobId; +import gnu.javax.print.ipp.attribute.job.JobStateMessage; +import gnu.javax.print.ipp.attribute.printer.MultipleOperationTimeOut; +import gnu.javax.print.ipp.attribute.printer.PrinterStateMessage; +import gnu.javax.print.ipp.attribute.printer.PrinterUpTime; +import gnu.javax.print.ipp.attribute.supported.CompressionSupported; +import gnu.javax.print.ipp.attribute.supported.FinishingsSupported; +import gnu.javax.print.ipp.attribute.supported.IppVersionsSupported; +import gnu.javax.print.ipp.attribute.supported.JobHoldUntilSupported; +import gnu.javax.print.ipp.attribute.supported.JobSheetsSupported; +import gnu.javax.print.ipp.attribute.supported.MediaSupported; +import gnu.javax.print.ipp.attribute.supported.MultipleDocumentHandlingSupported; +import gnu.javax.print.ipp.attribute.supported.MultipleDocumentJobsSupported; +import gnu.javax.print.ipp.attribute.supported.OperationsSupported; +import gnu.javax.print.ipp.attribute.supported.OrientationRequestedSupported; +import gnu.javax.print.ipp.attribute.supported.PageRangesSupported; +import gnu.javax.print.ipp.attribute.supported.PrintQualitySupported; +import gnu.javax.print.ipp.attribute.supported.PrinterResolutionSupported; +import gnu.javax.print.ipp.attribute.supported.SidesSupported; +import gnu.javax.print.ipp.attribute.supported.UriAuthenticationSupported; +import gnu.javax.print.ipp.attribute.supported.UriSecuritySupported; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; +import java.util.Locale; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; +import javax.print.attribute.SupportedValuesAttribute; +import javax.print.attribute.standard.Chromaticity; +import javax.print.attribute.standard.ColorSupported; +import javax.print.attribute.standard.Compression; +import javax.print.attribute.standard.Copies; +import javax.print.attribute.standard.CopiesSupported; +import javax.print.attribute.standard.Fidelity; +import javax.print.attribute.standard.Finishings; +import javax.print.attribute.standard.JobHoldUntil; +import javax.print.attribute.standard.JobImpressionsCompleted; +import javax.print.attribute.standard.JobKOctetsProcessed; +import javax.print.attribute.standard.JobMediaSheetsCompleted; +import javax.print.attribute.standard.JobMessageFromOperator; +import javax.print.attribute.standard.JobName; +import javax.print.attribute.standard.JobOriginatingUserName; +import javax.print.attribute.standard.JobPriority; +import javax.print.attribute.standard.JobPrioritySupported; +import javax.print.attribute.standard.JobSheets; +import javax.print.attribute.standard.JobState; +import javax.print.attribute.standard.JobStateReason; +import javax.print.attribute.standard.Media; +import javax.print.attribute.standard.MediaSizeName; +import javax.print.attribute.standard.MultipleDocumentHandling; +import javax.print.attribute.standard.NumberOfInterveningJobs; +import javax.print.attribute.standard.NumberUp; +import javax.print.attribute.standard.NumberUpSupported; +import javax.print.attribute.standard.OrientationRequested; +import javax.print.attribute.standard.OutputDeviceAssigned; +import javax.print.attribute.standard.PDLOverrideSupported; +import javax.print.attribute.standard.PageRanges; +import javax.print.attribute.standard.PagesPerMinute; +import javax.print.attribute.standard.PagesPerMinuteColor; +import javax.print.attribute.standard.PresentationDirection; +import javax.print.attribute.standard.PrintQuality; +import javax.print.attribute.standard.PrinterInfo; +import javax.print.attribute.standard.PrinterIsAcceptingJobs; +import javax.print.attribute.standard.PrinterLocation; +import javax.print.attribute.standard.PrinterMakeAndModel; +import javax.print.attribute.standard.PrinterMessageFromOperator; +import javax.print.attribute.standard.PrinterName; +import javax.print.attribute.standard.PrinterResolution; +import javax.print.attribute.standard.PrinterState; +import javax.print.attribute.standard.PrinterStateReason; +import javax.print.attribute.standard.QueuedJobCount; +import javax.print.attribute.standard.ReferenceUriSchemesSupported; +import javax.print.attribute.standard.Severity; +import javax.print.attribute.standard.SheetCollate; +import javax.print.attribute.standard.Sides; + +/** + * Collection of static utilities methods used in + * IPP response parsing and all over the place. + *

      + * Also provides mapping from the attribute name values to + * the actual class object. Used to construct objects via reflection. + *

      + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class IppUtilities +{ + // These are reused in the reflection code to not instantiate an array everytime + private static Object[] INTEGER_ATT_VALUE = new Object[1]; + private static Class[] INTEGER_CLASS_ARRAY = new Class[] {int.class}; + private static Object[] TEXT_ATT_VALUE = new Object[2]; + private static Class[] TEXT_CLASS_ARRAY = new Class[] {String.class, Locale.class}; + + // The map -> Attribute name to Attribute class + private static HashMap> classesByName = + new HashMap>(); + // The map -> StandardAttribute class to SupportedAttribute category name + private static HashMap,SupportedValuesAttribute> instanceByClass = + new HashMap,SupportedValuesAttribute>(); + + /** + * All the currently needed attributes + */ + static + { + // enums + classesByName.put(JobState.ABORTED.getName(), JobState.class); + classesByName.put(Sides.DUPLEX.getName(), Sides.class); + classesByName.put(SheetCollate.COLLATED.getName(), SheetCollate.class); + classesByName.put(Severity.ERROR.getName(), Severity.class); + classesByName.put(JobSheets.NONE.getName(), JobSheets.class); + classesByName.put(Finishings.BIND.getName(), Finishings.class); + classesByName.put(Fidelity.FIDELITY_FALSE.getName(), Fidelity.class); + classesByName.put(Compression.GZIP.getName(), Compression.class); + classesByName.put(Chromaticity.COLOR.getName(), Chromaticity.class); + classesByName.put(PrintQuality.DRAFT.getName(), PrintQuality.class); + classesByName.put(PrinterState.IDLE.getName(), PrinterState.class); + classesByName.put(SidesDefault.ONE_SIDED.getName(), SidesDefault.class); + classesByName.put(ReferenceUriSchemesSupported.FILE.getName(), + ReferenceUriSchemesSupported.class); + classesByName.put(PrinterStateReason.DOOR_OPEN.getName(), + PrinterStateReason.class); + classesByName.put(PresentationDirection.TOLEFT_TOTOP.getName(), + PresentationDirection.class); + classesByName.put(PDLOverrideSupported.ATTEMPTED.getName(), + PDLOverrideSupported.class); + classesByName.put(OrientationRequested.PORTRAIT.getName(), + OrientationRequested.class); + classesByName.put(MultipleDocumentHandling.SINGLE_DOCUMENT.getName(), + MultipleDocumentHandling.class); + classesByName.put(JobStateReason.JOB_QUEUED.getName(), + JobStateReason.class); + classesByName.put(UriAuthenticationSupported.NONE.getName(), + UriAuthenticationSupported.class); + classesByName.put(OperationsSupported.GET_JOBS.getName(), + OperationsSupported.class); + classesByName.put(UriSecuritySupported.NONE.getName(), + UriSecuritySupported.class); + classesByName.put(FinishingsSupported.NONE.getName(), + FinishingsSupported.class); + classesByName.put(FinishingsDefault.NONE.getName(), + FinishingsDefault.class); + classesByName.put(IppVersionsSupported.V_1_0.getName(), + IppVersionsSupported.class); + classesByName.put(MultipleDocumentHandlingSupported.SINGLE_DOCUMENT.getName(), + MultipleDocumentHandlingSupported.class); + classesByName.put(MultipleDocumentHandlingDefault.SINGLE_DOCUMENT.getName(), + MultipleDocumentHandlingDefault.class); + classesByName.put(CompressionSupported.NONE.getName(), + CompressionSupported.class); + classesByName.put(OrientationRequestedSupported.PORTRAIT.getName(), + OrientationRequestedSupported.class); + classesByName.put(OrientationRequestedDefault.PORTRAIT.getName(), + OrientationRequestedDefault.class); + classesByName.put(SidesSupported.ONE_SIDED.getName(), + SidesSupported.class); + classesByName.put(PrintQualityDefault.DRAFT.getName(), + PrintQualityDefault.class); + classesByName.put(PrintQualitySupported.DRAFT.getName(), + PrintQualitySupported.class); + classesByName.put(ReferenceUriSchemesSupported.FTP.getName(), + ReferenceUriSchemesSupported.class); + + // the boolean types + classesByName.put(ColorSupported.SUPPORTED.getName(), ColorSupported.class); + classesByName.put(PrinterIsAcceptingJobs.ACCEPTING_JOBS.getName(), + PrinterIsAcceptingJobs.class); + classesByName.put(MultipleDocumentJobsSupported.SUPPORTED.getName(), + MultipleDocumentJobsSupported.class); + classesByName.put(PageRangesSupported.SUPPORTED.getName(), + PageRangesSupported.class); + + // TextSyntax derived attributes + classesByName.put("media-default", MediaDefault.class); + classesByName.put("media-supported", MediaSupported.class); + classesByName.put("media", MediaSizeName.class); + classesByName.put("printer-location", PrinterLocation.class); + classesByName.put("printer-info", PrinterInfo.class); + classesByName.put("printer-make-and-model", PrinterMakeAndModel.class); + classesByName.put("printer-state-message", PrinterStateMessage.class); + classesByName.put("job-state-message", JobStateMessage.class); + classesByName.put("job-sheets-default", JobSheetsDefault.class); + classesByName.put("job-sheets-supported", JobSheetsSupported.class); + classesByName.put("job-name", JobName.class); + classesByName.put("printer-name", PrinterName.class); + classesByName.put("status-message", StatusMessage.class); + classesByName.put("detailed-status-message", DetailedStatusMessage.class); + classesByName.put("document-access-error", DocumentAccessError.class); + classesByName.put("output-device-assigned", OutputDeviceAssigned.class); + classesByName.put("job-hold-until-default", JobHoldUntilDefault.class); + classesByName.put("job-originating-user-name", + JobOriginatingUserName.class); + classesByName.put("job-hold-until-supported", + JobHoldUntilSupported.class); + classesByName.put("job-message-from-operator", + JobMessageFromOperator.class); + classesByName.put("printer-message-from-operator", + PrinterMessageFromOperator.class); + classesByName.put("job-detailed-status-messages", + JobDetailedStatusMessages.class); + classesByName.put("job-document-access-errors", + JobDocumentAccessErrors.class); + + // IntegerSyntax derived Attributes + classesByName.put("copies-default", CopiesDefault.class); + classesByName.put("job-id", JobId.class); + classesByName.put("job-priority-supported", JobPrioritySupported.class); + classesByName.put("job-priority-default", JobPriorityDefault.class); + classesByName.put("number-up-supported", NumberUpSupported.class); + classesByName.put("number-up-default", NumberUpDefault.class); + classesByName.put("queued-job-count", QueuedJobCount.class); + classesByName.put("printer-up-time", PrinterUpTime.class); + classesByName.put("pages-per-minute", PagesPerMinute.class); + classesByName.put("pages-per-minute-color", PagesPerMinuteColor.class); + classesByName.put("job-k-octets-processed", JobKOctetsProcessed.class); + classesByName.put("number-of-intervening-jobs", + NumberOfInterveningJobs.class); + classesByName.put("job-impressions-completed", + JobImpressionsCompleted.class); + classesByName.put("job-media-sheets-completed", + JobMediaSheetsCompleted.class); + classesByName.put("multiple-operation-time-out", + MultipleOperationTimeOut.class); + + + // 4.2 job template attributes + instanceByClass.put(JobPriority.class, new JobPrioritySupported(1)); + instanceByClass.put(JobHoldUntil.class, new JobHoldUntilSupported("", null)); + instanceByClass.put(JobSheets.class, new JobSheetsSupported("", null)); + instanceByClass.put(MultipleDocumentHandling.class, MultipleDocumentHandlingSupported.SINGLE_DOCUMENT); + instanceByClass.put(Copies.class, new CopiesSupported(1)); + instanceByClass.put(Finishings.class, FinishingsSupported.BIND); + instanceByClass.put(PageRanges.class, PageRangesSupported.SUPPORTED); + instanceByClass.put(Sides.class, SidesSupported.DUPLEX); + instanceByClass.put(NumberUp.class, new NumberUpSupported(1)); + instanceByClass.put(OrientationRequested.class, OrientationRequestedSupported.LANDSCAPE); + instanceByClass.put(Media.class, new MediaSupported("", null)); + instanceByClass.put(PrinterResolution.class, new PrinterResolutionSupported(1,1,1)); + instanceByClass.put(PrintQuality.class, PrintQualitySupported.DRAFT); + + // 4.4 printer attributes + instanceByClass.put(Compression.class, CompressionSupported.COMPRESS); + } + + private IppUtilities() + { + // not to be instantiated + } + + /** + * Returns the implementing class object for given + * attribute name objects. + * + * @param name the attribute name + * @return The Class object. + */ + public static Class getClass(String name) + { + return classesByName.get(name); + } + + /** + * Returns the name of the supported attribute + * based on the given standard attribute category. + * + * @param clazz the standard attribute category + * @return The name of the supported attribute category. + */ + public static String getSupportedAttrName(Class clazz) + { + return instanceByClass.get(clazz).getName(); + } + + /** + * Returns the category of the supported attribute + * based on the given standard attribute category. + * + * @param clazz the standard attribute category + * @return The supported attribute category. + */ + public static Class getSupportedCategory(Class clazz) + { + return instanceByClass.get(clazz).getCategory(); + } + + /** + * Helper method to convert to an int. + * @param b the byte array + * @return The converted int. + */ + public static int convertToInt(byte[] b) + { + return (((b[0] & 0xff) << 24) | ((b[1] & 0xff) << 16) + | ((b[2] & 0xff) << 8) | (b[3] & 0xff)); + } + + /** + * Helper method to convert to an int. + * @param b1 the 1th byte + * @param b2 the 2th byte + * @param b3 the 3th byte + * @param b4 the 4th byte + * @return The converted int. + */ + public static int convertToInt(byte b1, byte b2, byte b3, byte b4) + { + return (((b1 & 0xff) << 24) | ((b2 & 0xff) << 16) + | ((b3 & 0xff) << 8) | (b4 & 0xff)); + } + + /** + * Helper method to convert to a short. + * @param b1 the 1th byte + * @param b2 the 2th byte + * @return The converted short. + */ + public static short convertToShort(byte b1, byte b2) + { + return (short) ((b1 << 8) | (b2 & 0xff)); + } + + /** + * Instantiates an EnumSyntax based attribute with the given IPP + * name and the given value (Enums maybe int or String based). + * + * @param name the attribute name of the subclass. + * @param value the integer value of the specific enum. + * @return The Attribute (a subclass of EnumSyntax) + */ + public static Attribute getEnumAttribute(String name, Object value) + { + Class attrClass = getClass(name); + + // There might be unknown enums we have no mapped class for + if (attrClass == null) + return null; + + try + { + Field[] fields = attrClass.getDeclaredFields(); + for (int i = 0; i < fields.length; i++) + { + Field field = fields[i]; + if (field.getType().equals(attrClass)) + { + EnumSyntax attr = (EnumSyntax) field.get(null); + if (value instanceof Integer + && attr.getValue() == ((Integer) value).intValue()) + return (Attribute) attr; + else if (value instanceof String + && attr.toString().equals(value)) + return (Attribute) attr; + } + } + } + catch (SecurityException e) + { + // should not happen + } + catch (IllegalArgumentException e) + { + // should not happen + } + catch (IllegalAccessException e) + { + // should not happen, all fields are public + } + + return null; + } + + + + /** + * Instantiates an IntegerSyntax based attribute with the + * given IPP name for the given int value. + * + * @param name the attribute name of the subclass. + * @param value the integer value + * @return The Attribute (a subclass of IntegerSyntax) + */ + public static Attribute getIntegerAttribute(String name, int value) + { + Class attrClass = getClass(name); + + // There might be unknown attributes we have no mapped class for + if (attrClass == null) + return null; + + try + { + INTEGER_ATT_VALUE[0] = Integer.valueOf(value); + Constructor c = attrClass.getDeclaredConstructor(INTEGER_CLASS_ARRAY); + return (Attribute) c.newInstance(INTEGER_ATT_VALUE); + } + catch (SecurityException e) + { + // should not happen + } + catch (NoSuchMethodException e) + { + // should not happen + } + catch (IllegalAccessException e) + { + // should not happen, all fields are public + } + catch (InstantiationException e) + { + // should not happen, all fields are public + } + catch (InvocationTargetException e) + { + // should not happen, all fields are public + } + + return null; + } + + /** + * Instantiates an TextSyntax based attribute with the given + * IPP name for the given text value (will be decoded). + * + * @param name the attribute name of the subclass. + * @param tag the tag defined in {@link IppValueTag} + * @param value the byte[] value to be decoded based on the tag value. + * @return The Attribute (a subclass of TextSyntax) + */ + public static Attribute getTextAttribute(String name, byte tag, byte[] value) + { + // without language tag is rather easy - default locale + if (tag == IppValueTag.NAME_WITHOUT_LANGUAGE + || tag == IppValueTag.TEXT_WITHOUT_LANGUAGE) + { + TEXT_ATT_VALUE[0] = new String(value); + TEXT_ATT_VALUE[1] = Locale.getDefault(); + } + else + { + short langLength = convertToShort(value[0], value[1]); + byte[] tmp = new byte[langLength]; + byte[] tmp2 = new byte[value.length - 4 - langLength]; + System.arraycopy(value, 2, tmp, 0, langLength); + + // parse into language/region + String language = new String(tmp); + String text = new String(tmp2); + Locale locale = null; + + if (language.length() > 2) + locale = new Locale(language.substring(0, 2), language.substring(3)); + else + locale = new Locale(language); + + TEXT_ATT_VALUE[0] = text; + TEXT_ATT_VALUE[1] = locale; + } + + Class attrClass = getClass(name); + + // There might be unknown attributes we have no mapped class for + if (attrClass == null) + return null; + + try + { + Constructor c = attrClass.getDeclaredConstructor(TEXT_CLASS_ARRAY); + return (Attribute) c.newInstance(TEXT_ATT_VALUE); + } + catch (SecurityException e) + { + // should not happen + } + catch (NoSuchMethodException e) + { + // should not happen + } + catch (IllegalAccessException e) + { + // should not happen, all fields are public + } + catch (InstantiationException e) + { + // should not happen, all fields are public + } + catch (InvocationTargetException e) + { + // should not happen, all fields are public + } + + return null; + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/IppValueTag.java b/libjava/classpath/gnu/javax/print/ipp/IppValueTag.java new file mode 100644 index 000000000..def9545a3 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/IppValueTag.java @@ -0,0 +1,170 @@ +/* IppValueTag.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.javax.print.ipp; + +/** + * IPP Value Tags as described in RFC 2910 section 3.5.2. + *

      + * Attributes are always of a special type syntax (e.g. boolean or + * interger attribute). These value types are specified by the tag + * constants provided in this class. Beside the syntax types some + * out of band values for reporting requested attributes as + * unsupported, unknown etc. back to the client. + *

      + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class IppValueTag +{ + + /** Out of band value for unsupported attributes. */ + public static final byte UNSUPPORTED = 0x10; + + // 0x11 reserved for 'default' for definition in a future + // IETF standards track document + + /** Out of band value for unknown attributes. */ + public static final byte UNKNOWN = 0x12; + + /** Out of band value for attribute without a value. */ + public static final byte NO_VALUE = 0x13; + + // 0x14-0x1F reserved for "out-of-band" values in future IETF + // standards track documents. + + // 0x20 reserved for definition in a future IETF + // standards track document + + /** Indicates a value of syntax type integer. */ + public static final byte INTEGER = 0x21; + + /** Indicates a value of syntax type boolean. */ + public static final byte BOOLEAN = 0x22; + + /** Indicates a value of syntax type enum (enumeration). */ + public static final byte ENUM = 0x23; + + // 0x24-0x2F reserved for integer types for definition in + // future IETF standards track documents + + /** Indicates a value of syntax type octect string. */ + public static final byte OCTECTSTRING_UNSPECIFIED = 0x30; + + /** Indicates a value of syntax type datetime. */ + public static final byte DATETIME = 0x31; + + /** Indicates a value of syntax type resolution. */ + public static final byte RESOLUTION = 0x32; + + /** Indicates a value of syntax type range of integers. */ + public static final byte RANGEOFINTEGER = 0x33; + + // 0x34 reserved for definition in a future IETF + // standards track document + + /** Indicates a value of syntax type text with language. */ + public static final byte TEXT_WITH_LANGUAGE = 0x35; + + /** Indicates a value of syntax type name with language. */ + public static final byte NAME_WITH_LANGUAGE = 0x36; + + // 0x37-0x3F reserved for octetString type definitions in + // future IETF standards track documents + + // 0x40 reserved for definition in a future IETF + // standards track document + + /** Indicates a value of syntax type text without language. */ + public static final byte TEXT_WITHOUT_LANGUAGE = 0x41; + + /** Indicates a value of syntax type name without language. */ + public static final byte NAME_WITHOUT_LANGUAGE = 0x42; + + // 0x43 reserved for definition in a future IETF + // standards track document + + /** Indicates a value of syntax type keyword. */ + public static final byte KEYWORD = 0x44; + + /** Indicates a value of syntax type URI. */ + public static final byte URI = 0x45; + + /** Indicates a value of syntax type URI scheme. */ + public static final byte URI_SCHEME = 0x46; + + /** Indicates a value of syntax type charset. */ + public static final byte CHARSET = 0x47; + + /** Indicates a value of syntax type language. */ + public static final byte NATURAL_LANGUAGE =0x48; + + /** Indicates a value of syntax type mime media. */ + public static final byte MIME_MEDIA_TYPE = 0x49; + + // 0x4A-0x5F reserved for character string type definitions + // in future IETF standards track documents + + + private IppValueTag() + { + // not to be instantiated; + } + + /** + * Tests if given value corresponds to a + * value tag value. + * + * @param value the value to test for + * @return true if, false otherwise. + */ + public static boolean isValueTag(byte value) + { + if(value == 0x10 || value == 0x12 || value == 0x13 + || value == 0x21 || value == 0x22 || value == 0x23 + || value == 0x30 || value == 0x31 || value == 0x32 + || value == 0x33 || value == 0x35 || value == 0x36 + || value == 0x41 || value == 0x42 || value == 0x44 + || value == 0x45 || value == 0x46 || value == 0x47 + || value == 0x48 || value == 0x49 ) + return true; + + return false; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/MultiDocPrintJobImpl.java b/libjava/classpath/gnu/javax/print/ipp/MultiDocPrintJobImpl.java new file mode 100644 index 000000000..89163dc99 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/MultiDocPrintJobImpl.java @@ -0,0 +1,80 @@ +/* MultiDocPrintJobImpl.java -- GNU implementation of MultiDocPrintJob + 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.print.ipp; + + +import javax.print.MultiDoc; +import javax.print.MultiDocPrintJob; +import javax.print.PrintException; +import javax.print.attribute.PrintRequestAttributeSet; + +/** + * Implementation of the MultiDocPrintJob interface. Implementation + * is specific to the IppPrintService implementation. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public class MultiDocPrintJobImpl extends DocPrintJobImpl + implements MultiDocPrintJob +{ + + /** + * Constructor forwarding arguments to the super constructor. + * + * @param service the print service instance. + * @param user the user of this print service. + * @param passwd the password of the user. + */ + public MultiDocPrintJobImpl(IppPrintService service, String user, + String passwd) + { + super(service, user, passwd); + } + + /** + * @see MultiDocPrintJob#print(MultiDoc, PrintRequestAttributeSet) + */ + public void print(MultiDoc multiDoc, PrintRequestAttributeSet attributes) + throws PrintException + { + // FIXME Implement + throw new PrintException("Multidoc not yet supported by implementation."); + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/CharsetSyntax.java b/libjava/classpath/gnu/javax/print/ipp/attribute/CharsetSyntax.java new file mode 100644 index 000000000..cd112f459 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/CharsetSyntax.java @@ -0,0 +1,115 @@ +/* CharsetSyntax.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.javax.print.ipp.attribute; + +import java.io.Serializable; + +/** + * CharsetSyntax is the abstract base class of all attribute + * classes which provide a charset (US-ASCII) string as value. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public abstract class CharsetSyntax implements Cloneable, Serializable +{ + private final String value; + + /** + * Creates a CharsetSyntax object with the given value + * and locale. + * + * @param value the value for this syntax + * + * @exception NullPointerException if value is null + */ + protected CharsetSyntax(String value) + { + if (value == null) + throw new NullPointerException("value may not be null"); + + this.value = value; + } + + /** + * Returns the value of this syntax object. + * + * @return The value. + */ + public String getValue() + { + return value; + } + + /** + * Returns the hashcode for this object. + * + * @return The hashcode. + */ + public int hashCode() + { + return value.hashCode(); + } + + /** + * Tests if the given object is equal to this object. + * + * @param obj the object to test + * + * @return true if both objects are equal, false otherwise. + */ + public boolean equals(Object obj) + { + if (! (obj instanceof CharsetSyntax)) + return false; + + CharsetSyntax tmp = (CharsetSyntax) obj; + return value.equals(tmp.getValue()); + } + + /** + * Returns a string representing the object. The returned + * string is the underlying text value of this object. + * + * @return The string representation. + */ + public String toString() + { + return getValue(); + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/DefaultValueAttribute.java b/libjava/classpath/gnu/javax/print/ipp/attribute/DefaultValueAttribute.java new file mode 100644 index 000000000..cc40db22e --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/DefaultValueAttribute.java @@ -0,0 +1,59 @@ +/* DefaultValueAttribute.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.javax.print.ipp.attribute; + +import javax.print.attribute.Attribute; + +/** + * Marker interface for all attribute classes describing attributes + * providing default values. Often there exist a sequence of an + * attribute name like: Name - > Name-default -> Name-supported. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public interface DefaultValueAttribute extends Attribute +{ + /** + * Returns the equally enum of the standard attribute class + * of this SupportedValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public Attribute getAssociatedAttribute(); +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/DetailedStatusMessage.java b/libjava/classpath/gnu/javax/print/ipp/attribute/DetailedStatusMessage.java new file mode 100644 index 000000000..2d005a82e --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/DetailedStatusMessage.java @@ -0,0 +1,93 @@ +/* DetailedStatusMessage.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.javax.print.ipp.attribute; + +import java.util.Locale; + +import javax.print.attribute.Attribute; +import javax.print.attribute.TextSyntax; + +/** + * DetailedStatusMessage attribute as described in RFC 2911 section + * 3.1.6 Operation Response Status Codes and Status Message + * provides a short description of the status of the operation. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class DetailedStatusMessage extends TextSyntax + implements Attribute +{ + + /** + * Creates a DetailedStatusMessage object with the given value + * and locale. + * + * @param value the value for this syntax + * @param locale the locale to use, if null the default + * locale is used. + * + * @exception NullPointerException if value is null + */ + public DetailedStatusMessage(String value, Locale locale) + { + super(value, locale); + } + + /** + * Returns category of this class. + * + * @return The class DetailedStatusMessage itself. + */ + public Class getCategory() + { + return DetailedStatusMessage.class; + } + + + /** + * Returns the name of this attribute. + * + * @return The name "detailed-status-message". + */ + public String getName() + { + return "detailed-status-message"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/DocumentAccessError.java b/libjava/classpath/gnu/javax/print/ipp/attribute/DocumentAccessError.java new file mode 100644 index 000000000..56b55ba76 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/DocumentAccessError.java @@ -0,0 +1,93 @@ +/* DocumentAccessError.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.javax.print.ipp.attribute; + +import java.util.Locale; + +import javax.print.attribute.Attribute; +import javax.print.attribute.TextSyntax; + +/** + * DocumentAccessError attribute as described in RFC 2911 section + * 3.1.6 Operation Response Status Codes and Status Message + * provides additional information for document access errors. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class DocumentAccessError extends TextSyntax + implements Attribute +{ + + /** + * Creates a DocumentAccessError object with the given value + * and locale. + * + * @param value the value for this syntax + * @param locale the locale to use, if null the default + * locale is used. + * + * @exception NullPointerException if value is null + */ + public DocumentAccessError(String value, Locale locale) + { + super(value, locale); + } + + /** + * Returns category of this class. + * + * @return The class DocumentAccessError itself. + */ + public Class getCategory() + { + return DocumentAccessError.class; + } + + + /** + * Returns the name of this attribute. + * + * @return The name "document-access-error". + */ + public String getName() + { + return "document-access-error"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/NaturalLanguageSyntax.java b/libjava/classpath/gnu/javax/print/ipp/attribute/NaturalLanguageSyntax.java new file mode 100644 index 000000000..a648c8cec --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/NaturalLanguageSyntax.java @@ -0,0 +1,117 @@ +/* NaturalLanguageSyntax.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.javax.print.ipp.attribute; + +import java.io.Serializable; + +/** + * NaturalLanguageSyntax is the abstract base class of all + * attribute classes which provide a natural language (US-ASCII) + * string as value. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public abstract class NaturalLanguageSyntax + implements Cloneable, Serializable +{ + private final String value; + + /** + * Creates a NaturalLanguageSyntax object with the given value + * and locale. + * + * @param value the value for this syntax + * + * @exception NullPointerException if value is null + */ + protected NaturalLanguageSyntax(String value) + { + if (value == null) + throw new NullPointerException("value may not be null"); + + this.value = value; + } + + /** + * Returns the value of this syntax object. + * + * @return The value. + */ + public String getValue() + { + return value; + } + + /** + * Returns the hashcode for this object. + * + * @return The hashcode. + */ + public int hashCode() + { + return value.hashCode(); + } + + /** + * Tests if the given object is equal to this object. + * + * @param obj the object to test + * + * @return true if both objects are equal, false otherwise. + */ + public boolean equals(Object obj) + { + if (! (obj instanceof NaturalLanguageSyntax)) + return false; + + NaturalLanguageSyntax tmp = (NaturalLanguageSyntax) obj; + return value.equals(tmp.getValue()); + } + + /** + * Returns a string representing the object. The returned + * string is the underlying text value of this object. + * + * @return The string representation. + */ + public String toString() + { + return getValue(); + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/RequestedAttributes.java b/libjava/classpath/gnu/javax/print/ipp/attribute/RequestedAttributes.java new file mode 100644 index 000000000..4c129f6d5 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/RequestedAttributes.java @@ -0,0 +1,132 @@ +/* RequestedAttributes.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.javax.print.ipp.attribute; + +import gnu.java.lang.CPStringBuilder; + +import java.util.ArrayList; +import java.util.List; + +import javax.print.attribute.Attribute; + +/** + * RequestedAttributes specifies the requested + * attributes in an IPP request operation. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class RequestedAttributes implements Attribute +{ + private ArrayList attributes; + + /** + * Creates a RequestedAttributes object with + * the initial value. + * + * @param value the string for the ipp name + * + * @exception NullPointerException if value is null + */ + public RequestedAttributes(String value) + { + if (value == null) + throw new NullPointerException(); + + attributes = new ArrayList(); + attributes.add(value); + } + + /** + * Adds the IPP name value to the set. + * + * @param value the string for the ipp name + */ + public void addValue(String value) + { + attributes.add(value); + } + + /** + * Returns the values. + * + * @return The values as list. + */ + public String[] getValues() + { + return attributes.toArray(new String[attributes.size()]); + } + + /** + * Returns category of this class. + * + * @return The class DocumentFormat itself. + */ + public Class getCategory() + { + return RequestedAttributes.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "requested-attributes". + */ + public String getName() + { + return "requested-attributes"; + } + + /** + * Returns the string representation for this object. + * + * @return The string representation. + */ + public String toString() + { + CPStringBuilder b = new CPStringBuilder(); + + if (attributes.size() > 0) + b.append(attributes.get(0)); + + for (int i=1; i < attributes.size(); i++) + b.append(", " + attributes.get(i)); + + return b.toString(); + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/StatusMessage.java b/libjava/classpath/gnu/javax/print/ipp/attribute/StatusMessage.java new file mode 100644 index 000000000..0701008ef --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/StatusMessage.java @@ -0,0 +1,92 @@ +/* StatusMessage.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.javax.print.ipp.attribute; + +import java.util.Locale; + +import javax.print.attribute.Attribute; +import javax.print.attribute.TextSyntax; + +/** + * StatusMessage attribute as described in RFC 2911 section + * 3.1.6 Operation Response Status Codes and Status Message + * provides a short description of the status of the operation. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class StatusMessage extends TextSyntax implements Attribute +{ + + /** + * Creates a StatusMessage object with the given value + * and locale. + * + * @param value the value for this syntax + * @param locale the locale to use, if null the default + * locale is used. + * + * @exception NullPointerException if value is null + */ + public StatusMessage(String value, Locale locale) + { + super(value, locale); + } + + /** + * Returns category of this class. + * + * @return The class StatusMessage itself. + */ + public Class getCategory() + { + return StatusMessage.class; + } + + + /** + * Returns the name of this attribute. + * + * @return The name "status-message". + */ + public String getName() + { + return "status-message"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/UnknownAttribute.java b/libjava/classpath/gnu/javax/print/ipp/attribute/UnknownAttribute.java new file mode 100644 index 000000000..a03beccbe --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/UnknownAttribute.java @@ -0,0 +1,190 @@ +/* UnknownAttribute.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.javax.print.ipp.attribute; + +import gnu.javax.print.ipp.IppUtilities; +import gnu.javax.print.ipp.IppValueTag; + +import java.net.URI; +import java.net.URISyntaxException; + +import javax.print.attribute.Attribute; + +/** + * UnknownAttribute holds all the parsed Attribute information. + * It provides methods to get the value-tag, name and value. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class UnknownAttribute implements Attribute +{ + private byte tag; + private String name; + private byte[] value; + + /** + * Creates a UnknownAttribute object with the given values. + * + * @param tag the value tag + * @param name the attribute name + * @param value the byte[] with the value + */ + public UnknownAttribute(byte tag, String name, byte[] value) + { + this.tag = tag; + this.name = name; + this.value = value; + } + + /** + * Returns category of this class. + * + * @return The class UnknownAttribute itself. + */ + public Class getCategory() + { + return UnknownAttribute.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name attributes IPP name. + */ + public String getName() + { + return name; + } + + /** + * Returns the value tag + * @return The tag. + * + * @see gnu.javax.print.ipp.IppValueTag + */ + public byte getValueTag() + { + return tag; + } + + /** + * Returns the name of the attribute. + * @return The name. + */ + public String getAttributeName() + { + return name; + } + + /** + * Returns the attribute value origin byte array. + * @return The value. + */ + public byte[] getAttributeValue() + { + return value; + } + + /** + * Returns the attribute value decoded as String. + * @return The value as String. + */ + public String getAttributeValueAsString() + { + return new String(value); + } + + /** + * Returns the attribute value decoded as int. + * @return The value as int. + */ + public int getAttributeValueAsInt() + { + return IppUtilities.convertToInt(value); + } + + /** + * Returns the attribute value decoded as an URI. + * @return The value as URI. + */ + public URI getAttributeValueAsUri() + { + try + { + return new URI(new String(value)); + } + catch (URISyntaxException e) + { + return null; + } + } + + /** + * Provides a string representation for some default + * tag types (e.g. int, rangeofinteger, string, uri). + * For other more complex types "No conversion found." + * is returned. + */ + public String toString() + { + switch (tag) + { + case IppValueTag.INTEGER: + return "" + getAttributeValueAsInt(); + case IppValueTag.RANGEOFINTEGER: + int lower = IppUtilities.convertToInt(value[0], value[1], + value[2], value[3]); + int upper = IppUtilities.convertToInt(value[4], value[5], + value[6], value[7]); + return lower + "-" + upper; + case IppValueTag.URI: + return getAttributeValueAsUri().toString(); + case IppValueTag.KEYWORD: + case IppValueTag.URI_SCHEME: + case IppValueTag.CHARSET: + case IppValueTag.NATURAL_LANGUAGE: + case IppValueTag.MIME_MEDIA_TYPE: + case IppValueTag.NAME_WITHOUT_LANGUAGE: + case IppValueTag.TEXT_WITHOUT_LANGUAGE: + return getAttributeValueAsString(); + default: + return "No conversion found."; + } + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/CopiesDefault.java b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/CopiesDefault.java new file mode 100644 index 000000000..39d8fe1c0 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/CopiesDefault.java @@ -0,0 +1,118 @@ +/* CopiesDefault.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.javax.print.ipp.attribute.defaults; + +import gnu.javax.print.ipp.attribute.DefaultValueAttribute; + +import javax.print.attribute.Attribute; +import javax.print.attribute.IntegerSyntax; +import javax.print.attribute.standard.Copies; + +/** + * CopiesDefault provides the default value + * for the copies attribute. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class CopiesDefault extends IntegerSyntax + implements DefaultValueAttribute +{ + + /** + * Creates a CopiesDefault object. + * + * @param value the number of copies + * + * @exception IllegalArgumentException if value < 1 + */ + public CopiesDefault(int value) + { + super(value); + + if (value < 1) + throw new IllegalArgumentException("value may not be less than 1"); + } + + /** + * Tests if the given object is equal to this object. + * + * @param obj the object to test + * + * @return true if both objects are equal, + * false otherwise. + */ + public boolean equals(Object obj) + { + if(! (obj instanceof CopiesDefault)) + return false; + + return super.equals(obj); + } + + /** + * Returns category of this class. + * + * @return The class CopiesDefault itself. + */ + public Class getCategory() + { + return CopiesDefault.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "copies-default". + */ + public String getName() + { + return "copies-default"; + } + + /** + * Returns the equally enum of the standard attribute class + * of this DefaultValuesAttribute enum. + *

      May return null if no value exists in JPS API.

      + * + * @return The enum of the standard attribute class. + */ + public Attribute getAssociatedAttribute() + { + return new Copies(getValue()); + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/DocumentFormatDefault.java b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/DocumentFormatDefault.java new file mode 100644 index 000000000..5eff91498 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/DocumentFormatDefault.java @@ -0,0 +1,106 @@ +/* DocumentFormatDefault.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.javax.print.ipp.attribute.defaults; + +import gnu.javax.print.ipp.attribute.DefaultValueAttribute; +import gnu.javax.print.ipp.attribute.printer.DocumentFormat; + +import java.util.Locale; + +import javax.print.attribute.Attribute; +import javax.print.attribute.TextSyntax; + +/** + * DocumentFormatDefault specifies the default document + * format of a printer. + * + * @author Wolfgang Baer (WBaer@gmx.de) + * + */ +public final class DocumentFormatDefault extends TextSyntax + implements DefaultValueAttribute +{ + + /** + * Creates a DocumentFormatDefault object with the + * given value and locale. + * + * @param value the value for this syntax + * @param locale the locale to use, if null the default + * locale is used. + * + * @exception NullPointerException if value is null + */ + public DocumentFormatDefault(String value, Locale locale) + { + super(value, locale); + } + + /** + * Returns category of this class. + * + * @return The class DocumentFormatDefault itself. + */ + public Class getCategory() + { + return DocumentFormatDefault.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "document-format-default". + */ + public String getName() + { + return "document-format-default"; + } + + /** + * Returns the equally enum of the standard attribute class + * of this DefaultValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public Attribute getAssociatedAttribute() + { + return new DocumentFormat(getValue(), getLocale()); + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/FinishingsDefault.java b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/FinishingsDefault.java new file mode 100644 index 000000000..9d4a06002 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/FinishingsDefault.java @@ -0,0 +1,263 @@ +/* FinishingsDefault.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.javax.print.ipp.attribute.defaults; + +import gnu.javax.print.ipp.IppUtilities; +import gnu.javax.print.ipp.attribute.DefaultValueAttribute; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; + + +/** + * The FinishingsDefault attribute provides the supported + * values for finishings of a job. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class FinishingsDefault extends EnumSyntax + implements DefaultValueAttribute +{ + + /** No finishing. */ + public static final FinishingsDefault NONE = new FinishingsDefault(3); + + /** Staple the document(s) */ + public static final FinishingsDefault STAPLE = new FinishingsDefault(4); + + /** Cover a document */ + public static final FinishingsDefault COVER = new FinishingsDefault(6); + + /** + * This value indicates that a binding is to be applied to the document. + * The type and placement of the binding is site-defined. + */ + public static final FinishingsDefault BIND = new FinishingsDefault(7); + + /** + * Bind the document(s) with one or more staples (wire stitches) + * along the middle fold. + */ + public static final FinishingsDefault SADDLE_STITCH = new FinishingsDefault(8); + + /** + * Bind the document(s) with one or more staples (wire stitches) + * along one edge. + */ + public static final FinishingsDefault EDGE_STITCH = new FinishingsDefault(9); + + /** + * Bind the document(s) with one or more staples in the top left + * corner. + */ + public static final FinishingsDefault STAPLE_TOP_LEFT = new FinishingsDefault(20); + + /** + * Bind the document(s) with one or more staples in the bottom + * left corner. + */ + public static final FinishingsDefault STAPLE_BOTTOM_LEFT = new FinishingsDefault(21); + + /** + * Bind the document(s) with one or more staples in the top right corner. + */ + public static final FinishingsDefault STAPLE_TOP_RIGHT = new FinishingsDefault(22); + + /** + * Bind the document(s) with one or more staples in the bottom right corner. + */ + public static final FinishingsDefault STAPLE_BOTTOM_RIGHT = new FinishingsDefault(23); + + /** + * Bind the document(s) with one or more staples (wire stitches) + * along the left edge. + */ + public static final FinishingsDefault EDGE_STITCH_LEFT = new FinishingsDefault(24); + + /** + * Bind the document(s) with one or more staples (wire stitches) along + * the top edge. + */ + public static final FinishingsDefault EDGE_STITCH_TOP = new FinishingsDefault(25); + + /** + * Bind the document(s) with one or more staples (wire stitches) along + * the right edge. + */ + public static final FinishingsDefault EDGE_STITCH_RIGHT = new FinishingsDefault(26); + + /** + * Bind the document(s) with one or more staples (wire stitches) along + * the bottom edge. + */ + public static final FinishingsDefault EDGE_STITCH_BOTTOM = new FinishingsDefault(27); + + /** + * Bind the document(s) with two staples (wire stitches) along the + * left edge assuming a portrait document. + */ + public static final FinishingsDefault STAPLE_DUAL_LEFT = new FinishingsDefault(28); + + /** + * Bind the document(s) with two staples (wire stitches) along the + * top edge assuming a portrait document. + */ + public static final FinishingsDefault STAPLE_DUAL_TOP = new FinishingsDefault(29); + + /** + * Bind the document(s) with two staples (wire stitches) along the + * right edge assuming a portrait document. + */ + public static final FinishingsDefault STAPLE_DUAL_RIGHT = new FinishingsDefault(30); + + /** + * Bind the document(s) with two staples (wire stitches) along the + * bottom edge assuming a portrait document. + */ + public static final FinishingsDefault STAPLE_DUAL_BOTTOM = new FinishingsDefault(31); + + private static final String[] stringTable = { "none", "staple", null, + "cover", "bind", "saddle-stitch", + "edge-stitch", null, null, null, + null, null, null, null, null, + null, null, "staple-top-left", + "staple-bottom-left", + "staple-top-right", + "staple-bottom-right", + "edge-stitch-left", + "edge-stitch-top", + "edge-stitch-right", + "edge-stitch-bottom", + "staple-dual-left", + "staple-dual-top", + "staple-dual-right", + "staple-dual-bottom" }; + + private static final FinishingsDefault[] enumValueTable = { NONE, STAPLE, null, + COVER, BIND, + SADDLE_STITCH, + EDGE_STITCH, null, + null, null, null, + null, null, null, + null, null, null, + STAPLE_TOP_LEFT, + STAPLE_BOTTOM_LEFT, + STAPLE_TOP_RIGHT, + STAPLE_BOTTOM_RIGHT, + EDGE_STITCH_LEFT, + EDGE_STITCH_TOP, + EDGE_STITCH_RIGHT, + EDGE_STITCH_BOTTOM, + STAPLE_DUAL_LEFT, + STAPLE_DUAL_TOP, + STAPLE_DUAL_RIGHT, + STAPLE_DUAL_BOTTOM }; + + /** + * Constructs a FinishingsDefault object. + * + * @param value the value + */ + protected FinishingsDefault(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return the class FinishingsDefault itself + */ + public Class getCategory() + { + return FinishingsDefault.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "finishings-default". + */ + public String getName() + { + return "finishings-default"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } + + /** + * Returns the lowest used value by the enumerations of this class. + * . + * @return The lowest value used. + */ + protected int getOffset() + { + return 3; + } + + /** + * Returns the equally enum of the standard attribute class + * of this DefaultValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public Attribute getAssociatedAttribute() + { + return IppUtilities.getEnumAttribute("finishings", new Integer(getValue())); + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/JobHoldUntilDefault.java b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/JobHoldUntilDefault.java new file mode 100644 index 000000000..7c29f231c --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/JobHoldUntilDefault.java @@ -0,0 +1,149 @@ +/* JobHoldUntilDefault.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.javax.print.ipp.attribute.defaults; + +import gnu.javax.print.ipp.attribute.DefaultValueAttribute; + +import java.util.Date; +import java.util.Locale; + +import javax.print.attribute.Attribute; +import javax.print.attribute.TextSyntax; +import javax.print.attribute.standard.JobHoldUntil; + +/** + * JobHoldUntilDefault attribute provides the default value + * for the attribute type job-hold-until. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class JobHoldUntilDefault extends TextSyntax + implements DefaultValueAttribute +{ + + // a keyword/name based attribute in IPP + // can be extended by administrators + // standard values are predefined + + /** Job should be printed immediately. */ + public static final JobHoldUntilDefault NO_HOLD = + new JobHoldUntilDefault("no-hold", null); + + /** Job should be hold indefinitely. */ + public static final JobHoldUntilDefault INDEFINITE = + new JobHoldUntilDefault("indefinite", null); + + /** Job should be processed during the day. */ + public static final JobHoldUntilDefault DAY_TIME = + new JobHoldUntilDefault("day-time", null); + + /** Job should be processed in the evening. */ + public static final JobHoldUntilDefault EVENING = + new JobHoldUntilDefault("evening", null); + + /** Job should be processed during night. */ + public static final JobHoldUntilDefault NIGHT = + new JobHoldUntilDefault("night", null); + + /** Job should be processed during the weekend. */ + public static final JobHoldUntilDefault WEEKEND = + new JobHoldUntilDefault("weekend", null); + + /** + * Job should be processed as second-shift + * (after close of business). + */ + public static final JobHoldUntilDefault SECOND_SHIFT = + new JobHoldUntilDefault("second-shift", null); + + /** + * Job should be processed as third-shift + * (after midnight). + */ + public static final JobHoldUntilDefault THIRD_SHIFT = + new JobHoldUntilDefault("third-shift", null); + + /** + * Creates a JobHoldUntilDefault object with the + * given value and locale. + * + * @param value the value for this syntax + * @param locale the locale to use, if null the default + * locale is used. + * + * @throws NullPointerException if value is null + */ + public JobHoldUntilDefault(String value, Locale locale) + { + super(value, locale); + } + + /** + * Returns category of this class. + * + * @return The class JobHoldUntilDefault itself. + */ + public Class getCategory() + { + return JobHoldUntilDefault.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "job-hold-until-default". + */ + public String getName() + { + return "job-hold-until-default"; + } + + /** + * Returns the equally enum of the standard attribute class + * of this DefaultValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public Attribute getAssociatedAttribute() + { + // FIXME Same Mapping problem as in IppPrintService + return new JobHoldUntil(new Date()); + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/JobPriorityDefault.java b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/JobPriorityDefault.java new file mode 100644 index 000000000..9430250ae --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/JobPriorityDefault.java @@ -0,0 +1,118 @@ +/* JobPriorityDefault.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.javax.print.ipp.attribute.defaults; + +import gnu.javax.print.ipp.attribute.DefaultValueAttribute; + +import javax.print.attribute.Attribute; +import javax.print.attribute.IntegerSyntax; +import javax.print.attribute.standard.JobPriority; + + +/** + * JobPriorityDefault attribute provides the default value of + * the printer object for the job-priority attribute. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class JobPriorityDefault extends IntegerSyntax + implements DefaultValueAttribute +{ + + /** + * Creates a JobPriorityDefault object. + * + * @param value the priority + * + * @exception IllegalArgumentException if value < 1 or value > 100 + */ + public JobPriorityDefault(int value) + { + super(value); + + if (value < 1 || value > 100) + throw new IllegalArgumentException("value out of range"); + } + + /** + * Tests if the given object is equal to this object. + * + * @param obj the object to test + * + * @return true if both objects are equal, + * false otherwise. + */ + public boolean equals(Object obj) + { + if(! (obj instanceof JobPriorityDefault)) + return false; + + return super.equals(obj); + } + + /** + * Returns category of this class. + * + * @return The class JobPriorityDefault itself. + */ + public Class getCategory() + { + return JobPriorityDefault.class; + } + + /** + * Returns name of this class. + * + * @return The anme "job-priority-default". + */ + public String getName() + { + return "job-priority-default"; + } + + /** + * Returns the equally enum of the standard attribute class + * of this DefaultValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public Attribute getAssociatedAttribute() + { + return new JobPriority(getValue()); + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/JobSheetsDefault.java b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/JobSheetsDefault.java new file mode 100644 index 000000000..6bf027eda --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/JobSheetsDefault.java @@ -0,0 +1,122 @@ +/* JobSheetsDefault.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.javax.print.ipp.attribute.defaults; + +import gnu.javax.print.ipp.attribute.DefaultValueAttribute; + +import java.util.Locale; + +import javax.print.attribute.Attribute; +import javax.print.attribute.TextSyntax; +import javax.print.attribute.standard.JobSheets; + +/** + * JobSheetsDefault attribute provides the default value of + * the printer object for the job-sheets attribute. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class JobSheetsDefault extends TextSyntax + implements DefaultValueAttribute +{ + //a keyword/name based attribute in IPP + // can be extended by administrators + // standard values are predefined + + /** No job sheet is the default */ + public static final JobSheetsDefault NONE = + new JobSheetsDefault("none", Locale.getDefault()); + + /** A job sheet is the default */ + public static final JobSheetsDefault STANDARD = + new JobSheetsDefault("standard", Locale.getDefault()); + + /** + * Creates a JobSheetsDefault object with the + * given value and locale. + * + * @param value the value for this syntax + * @param locale the locale to use, if null the default + * locale is used. + * + * @throws NullPointerException if value is null + */ + public JobSheetsDefault(String value, Locale locale) + { + super(value, locale); + } + + /** + * Returns category of this class. + * + * @return The class JobSheetsDefault itself. + */ + public Class getCategory() + { + return JobSheetsDefault.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "job-sheets-default". + */ + public String getName() + { + return "job-sheets-default"; + } + + /** + * Returns the equally enum of the standard attribute class + * of this DefaultValuesAttribute enum. + *

      May return null if no value exists in JPS API.

      + * + * @return The enum of the standard attribute class. + */ + public Attribute getAssociatedAttribute() + { + if (this.equals(JobSheetsDefault.NONE)) + return JobSheets.NONE; + if (this.equals(JobSheetsDefault.STANDARD)) + return JobSheets.STANDARD; + + return null; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/MediaDefault.java b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/MediaDefault.java new file mode 100644 index 000000000..5945d0b9b --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/MediaDefault.java @@ -0,0 +1,105 @@ +/* MediaDefault.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.javax.print.ipp.attribute.defaults; + +import gnu.javax.print.ipp.IppUtilities; +import gnu.javax.print.ipp.attribute.DefaultValueAttribute; + +import java.util.Locale; + +import javax.print.attribute.Attribute; +import javax.print.attribute.TextSyntax; + +/** + * MediaDefault attribute provides the default value of + * the printer object for the media attribute. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class MediaDefault extends TextSyntax + implements DefaultValueAttribute +{ + + /** + * Creates a MediaDefault object with the + * given value and locale. + * + * @param value the value for this syntax + * @param locale the locale to use, if null the default + * locale is used. + * + * @throws NullPointerException if value is null + */ + public MediaDefault(String value, Locale locale) + { + super(value, locale); + } + + /** + * Returns category of this class. + * + * @return The class MediaDefault itself. + */ + public Class getCategory() + { + return MediaDefault.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "media-default". + */ + public String getName() + { + return "media-default"; + } + + /** + * Returns the equally enum of the standard attribute class + * of this DefaultValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public Attribute getAssociatedAttribute() + { + return IppUtilities.getEnumAttribute("media" , getValue()); + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/MultipleDocumentHandlingDefault.java b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/MultipleDocumentHandlingDefault.java new file mode 100644 index 000000000..1563db82c --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/MultipleDocumentHandlingDefault.java @@ -0,0 +1,152 @@ +/* MultipleDocumentHandlingDefault.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.javax.print.ipp.attribute.defaults; + +import gnu.javax.print.ipp.IppUtilities; +import gnu.javax.print.ipp.attribute.DefaultValueAttribute; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; + + +/** + * MultipleDocumentHandlingDefault provides the + * default value for the MultipleDocumentHandling attribute. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class MultipleDocumentHandlingDefault extends EnumSyntax + implements DefaultValueAttribute +{ + + //a keyword based attribute in IPP - int values just starting at 0 + + /** + * Supports only multiple documents treated as a single document. This + * applies to attributes which specify treatment of multiple document jobs. + */ + public static final MultipleDocumentHandlingDefault SINGLE_DOCUMENT = + new MultipleDocumentHandlingDefault(0); + + /** Supports multiple documents as uncollated copies */ + public static final MultipleDocumentHandlingDefault SEPARATE_DOCUMENTS_UNCOLLATED_COPIES = + new MultipleDocumentHandlingDefault(1); + + /** Supports multiple documents as collated copies */ + public static final MultipleDocumentHandlingDefault SEPARATE_DOCUMENTS_COLLATED_COPIES = + new MultipleDocumentHandlingDefault(2); + + /** + * Supports multiple documents where every single document starts + * with a new sheet. + */ + public static final MultipleDocumentHandlingDefault SINGLE_DOCUMENT_NEW_SHEET = + new MultipleDocumentHandlingDefault(3); + + private static final String[] stringTable = { "single-document", + "separate-documents-uncollated-copies", + "separate-documents-collated-copies", + "single-document-new-sheet" }; + + private static final MultipleDocumentHandlingDefault[] enumValueTable = + { SINGLE_DOCUMENT, SEPARATE_DOCUMENTS_UNCOLLATED_COPIES, + SEPARATE_DOCUMENTS_COLLATED_COPIES, SINGLE_DOCUMENT_NEW_SHEET}; + + /** + * Constructs a MultipleDocumentHandlingDefault object. + * + * @param value the enum value + */ + protected MultipleDocumentHandlingDefault(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class MultipleDocumentHandlingDefault itself. + */ + public Class getCategory() + { + return MultipleDocumentHandlingDefault.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "multiple-document-handling-default". + */ + public String getName() + { + return "multiple-document-handling-default"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } + + /** + * Returns the equally enum of the standard attribute class + * of this DefaultValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public Attribute getAssociatedAttribute() + { + return IppUtilities.getEnumAttribute("multiple-document-handling", + new Integer(getValue())); + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/NumberUpDefault.java b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/NumberUpDefault.java new file mode 100644 index 000000000..8e2d076d5 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/NumberUpDefault.java @@ -0,0 +1,114 @@ +/* NumberUpDefault.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.javax.print.ipp.attribute.defaults; + +import gnu.javax.print.ipp.attribute.DefaultValueAttribute; + +import javax.print.attribute.Attribute; +import javax.print.attribute.IntegerSyntax; +import javax.print.attribute.standard.NumberUp; + +/** + * NumberUpDefault attribute provides the default value of + * the numper up attribute. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class NumberUpDefault extends IntegerSyntax + implements DefaultValueAttribute +{ + + /** + * Creates a NumberUpDefault object. + * + * @param value the value + * @throws IllegalArgumentException if value < 1 + */ + public NumberUpDefault(int value) + { + super(value); + } + + /** + * Tests if the given object is equal to this object. + * + * @param obj the object to test + * + * @return true if both objects are equal, + * false otherwise. + */ + public boolean equals(Object obj) + { + if(! (obj instanceof NumberUpDefault)) + return false; + + return super.equals(obj); + } + + /** + * Returns category of this class. + * + * @return The class NumberUpDefault itself. + */ + public Class getCategory() + { + return NumberUpDefault.class; + } + + /** + * Returns name of this class. + * + * @return The name "number-up-default". + */ + public String getName() + { + return "number-up-default"; + } + + /** + * Returns the equally enum of the standard attribute class + * of this DefaultValuesAttribute enum. + *

      May return null if no value exists in JPS API.

      + * + * @return The enum of the standard attribute class. + */ + public Attribute getAssociatedAttribute() + { + return new NumberUp(getValue()); + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/OrientationRequestedDefault.java b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/OrientationRequestedDefault.java new file mode 100644 index 000000000..4563ec525 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/OrientationRequestedDefault.java @@ -0,0 +1,154 @@ +/* OrientationRequestedDefault.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.javax.print.ipp.attribute.defaults; + +import gnu.javax.print.ipp.IppUtilities; +import gnu.javax.print.ipp.attribute.DefaultValueAttribute; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; + + +/** + * The OrientationRequestedDefault attribute provides + * the default value for the job attribute orientation-requested. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class OrientationRequestedDefault extends EnumSyntax + implements DefaultValueAttribute +{ + + /** Orientation as portrait. */ + public static final OrientationRequestedDefault PORTRAIT = + new OrientationRequestedDefault(3); + + /** Orientation as landscape. */ + public static final OrientationRequestedDefault LANDSCAPE = + new OrientationRequestedDefault(4); + + /** Orientation as reversed landscape. */ + public static final OrientationRequestedDefault REVERSE_LANDSCAPE = + new OrientationRequestedDefault(5); + + /** Orientation as reversed portrait. */ + public static final OrientationRequestedDefault REVERSE_PORTRAIT = + new OrientationRequestedDefault(6); + + + private static final String[] stringTable = { "portrait", "landscape", + "reverse-landscape", + "reverse-portrait" }; + + private static final OrientationRequestedDefault[] + enumValueTable = { PORTRAIT, LANDSCAPE, + REVERSE_LANDSCAPE, REVERSE_PORTRAIT }; + + /** + * Constructs a OrientationRequestedDefault object. + * + * @param value the value + */ + protected OrientationRequestedDefault(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class OrientationRequestedDefault itself. + */ + public Class getCategory() + { + return OrientationRequestedDefault.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "orientation-requested-default". + */ + public String getName() + { + return "orientation-requested-default"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } + + /** + * Returns the lowest used value by the enumerations of this class. + * . + * @return The lowest value used. + */ + protected int getOffset() + { + return 3; + } + + /** + * Returns the equally enum of the standard attribute class + * of this DefaultValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public Attribute getAssociatedAttribute() + { + return IppUtilities.getEnumAttribute("orientation-requested", + new Integer(getValue())); + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/PrintQualityDefault.java b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/PrintQualityDefault.java new file mode 100644 index 000000000..7b123eeb4 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/PrintQualityDefault.java @@ -0,0 +1,141 @@ +/* PrintQualityDefault.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.javax.print.ipp.attribute.defaults; + +import gnu.javax.print.ipp.IppUtilities; +import gnu.javax.print.ipp.attribute.DefaultValueAttribute; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; + + +/** + * PrintQualityDefault provides the + * default value for the print-quality attribute. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class PrintQualityDefault extends EnumSyntax + implements DefaultValueAttribute +{ + /** Draft quality of the printer. */ + public static final PrintQualityDefault DRAFT = new PrintQualityDefault(3); + + /** Normal quality of the printer. */ + public static final PrintQualityDefault NORMAL = new PrintQualityDefault(4); + + /** High quality of the printer. */ + public static final PrintQualityDefault HIGH = new PrintQualityDefault(5); + + private static final String[] stringTable = { "draft", "normal", "high" }; + + private static final PrintQualityDefault[] enumValueTable = { DRAFT, NORMAL, HIGH }; + + /** + * Constructs a PrintQualityDefault object. + * + * @param value the value of the enum + */ + protected PrintQualityDefault(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class PrintQualityDefault itself. + */ + public Class getCategory() + { + return PrintQualityDefault.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "print-quality-default". + */ + public String getName() + { + return "print-quality-default"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } + + /** + * Returns the lowest used value by the enumerations of this class. + * . + * @return The lowest value used. + */ + protected int getOffset() + { + return 3; + } + + /** + * Returns the equally enum of the standard attribute class + * of this DefaultValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public Attribute getAssociatedAttribute() + { + return IppUtilities.getEnumAttribute( + "print-quality", new Integer(getValue())); + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/PrinterResolutionDefault.java b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/PrinterResolutionDefault.java new file mode 100644 index 000000000..2c84b99ba --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/PrinterResolutionDefault.java @@ -0,0 +1,119 @@ +/* PrinterResolutionDefault.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.javax.print.ipp.attribute.defaults; + +import gnu.javax.print.ipp.attribute.DefaultValueAttribute; + +import javax.print.attribute.Attribute; +import javax.print.attribute.ResolutionSyntax; +import javax.print.attribute.standard.PrinterResolution; + + +/** + * The PrinterResolutionDefault attribute provides + * the default value for the job attribute printer-resolution. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class PrinterResolutionDefault extends ResolutionSyntax + implements DefaultValueAttribute +{ + + /** + * Creates a ResolutionSyntax object with the given arguments. + * + * @param crossFeedResolution the cross feed resolution + * @param feedResolution the feed resolution + * @param units the unit to use (e.g. {@link #DPCM} or {@link #DPI}) + * + * @exception IllegalArgumentException if preconditions fail + */ + public PrinterResolutionDefault(int crossFeedResolution, int feedResolution, + int units) + { + super(crossFeedResolution, feedResolution, units); + } + + /** + * Tests if the given object is equal to this object. + * + * @param obj the object to test + * + * @return true if both objects are equal, + * false otherwise. + */ + public boolean equals(Object obj) + { + if(! (obj instanceof PrinterResolutionDefault)) + return false; + + return super.equals(obj); + } + + /** + * Returns category of this class. + * + * @return The class PrinterResolutionDefault itself. + */ + public Class getCategory() + { + return PrinterResolutionDefault.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "printer-resolution-default". + */ + public String getName() + { + return "printer-resolution-default"; + } + + /** + * Returns the equally enum of the standard attribute class + * of this DefaultValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public Attribute getAssociatedAttribute() + { + return new PrinterResolution(getCrossFeedResolutionDphi(), + getFeedResolutionDphi(), 1); + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/SidesDefault.java b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/SidesDefault.java new file mode 100644 index 000000000..a50560ae9 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/defaults/SidesDefault.java @@ -0,0 +1,150 @@ +/* SidesDefault.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.javax.print.ipp.attribute.defaults; + +import gnu.javax.print.ipp.IppUtilities; +import gnu.javax.print.ipp.attribute.DefaultValueAttribute; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; + + +/** + * SidesDefault provides the + * default for the sides attribute. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class SidesDefault extends EnumSyntax + implements DefaultValueAttribute +{ + + /** Specifies that each page should be printed on one sheet. */ + public static final SidesDefault ONE_SIDED = new SidesDefault(0); + + /** + * Specifies that two following pages should be printed on the + * front and back of one sheet for binding on the long edge. + */ + public static final SidesDefault TWO_SIDED_LONG_EDGE = + new SidesDefault(1); + + /** + * Specifies that two following pages should be printed on the + * front and back of one sheet for binding on the short edge. + */ + public static final SidesDefault TWO_SIDED_SHORT_EDGE = + new SidesDefault(2); + + /** An alias constant for "two sided long edge". */ + public static final SidesDefault DUPLEX = new SidesDefault(1); + + /** An alias constant for "two sided short edge". */ + public static final SidesDefault TUMBLE = new SidesDefault(2); + + private static final String[] stringTable = { "one-sided", + "two-sided-long-edge", + "two-sided-short-edge" }; + + private static final SidesDefault[] enumValueTable = { ONE_SIDED, + TWO_SIDED_LONG_EDGE, + TWO_SIDED_SHORT_EDGE }; + + + /** + * Creates a SidesDefault object. + * + * @param value the value of the enum + */ + protected SidesDefault(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class SidesDefault itself. + */ + public Class getCategory() + { + return SidesDefault.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "sides-default". + */ + public String getName() + { + return "sides-default"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } + + /** + * Returns the equally enum of the standard attribute class + * of this DefaultValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public Attribute getAssociatedAttribute() + { + return IppUtilities.getEnumAttribute("sides", new Integer(getValue())); + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/job/AttributesCharset.java b/libjava/classpath/gnu/javax/print/ipp/attribute/job/AttributesCharset.java new file mode 100644 index 000000000..4fe2ce0d5 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/job/AttributesCharset.java @@ -0,0 +1,93 @@ +/* AttributesCharset.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.javax.print.ipp.attribute.job; + +import gnu.javax.print.ipp.attribute.CharsetSyntax; + +import javax.print.attribute.Attribute; + +/** + * AttributesCharset attribute as described in RFC 2911 chapter + * 3.1.4 Character Set and Natural Language Operation Attributes. + *

      + * This operation attribute identifies the charset used by any text + * and name attribute supplied by the client in the request. This + * charset must be used by the printer object in the response.
      + * All clients and IPP objects must support the 'utf-8' charset. + *

      + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class AttributesCharset extends CharsetSyntax + implements Attribute +{ + + /** Defines a default UTF-8 charset instance */ + public static final AttributesCharset UTF8 = new AttributesCharset("utf-8"); + + /** + * Creates a AttributesCharset object. + * + * @param value the charset string value. + */ + public AttributesCharset(String value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class AttributesCharset itself. + */ + public Class getCategory() + { + return AttributesCharset.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "attributes-charset". + */ + public String getName() + { + return "attributes-charset"; + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/job/AttributesNaturalLanguage.java b/libjava/classpath/gnu/javax/print/ipp/attribute/job/AttributesNaturalLanguage.java new file mode 100644 index 000000000..151cec439 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/job/AttributesNaturalLanguage.java @@ -0,0 +1,95 @@ +/* AttributesNaturalLanguage.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.javax.print.ipp.attribute.job; + + +import gnu.javax.print.ipp.attribute.NaturalLanguageSyntax; + +import javax.print.attribute.Attribute; + +/** + * AttributesNaturalLanguage attribute as described in RFC 2911 chapter + * 3.1.4 Character Set and Natural Language Operation Attributes. + *

      + * This operation attribute identifies the natural language used + * by any text and name attribute supplied by the client in the request. + * The printer object should use this natural language for the response + * to this request. + *

      + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class AttributesNaturalLanguage extends NaturalLanguageSyntax + implements Attribute +{ + + /** Defines the default language EN */ + public static final AttributesNaturalLanguage EN = + new AttributesNaturalLanguage("en"); + + /** + * Creates a AttributesNaturalLanguage object. + * + * @param value the language string value. + */ + public AttributesNaturalLanguage(String value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class AttributesNaturalLanguage itself. + */ + public Class getCategory() + { + return AttributesNaturalLanguage.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "attributes-natural-language". + */ + public String getName() + { + return "attributes-natural-language"; + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobDetailedStatusMessages.java b/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobDetailedStatusMessages.java new file mode 100644 index 000000000..5b83344a9 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobDetailedStatusMessages.java @@ -0,0 +1,92 @@ +/* JobDetailedStatusMessages.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.javax.print.ipp.attribute.job; + +import java.util.Locale; + +import javax.print.attribute.Attribute; +import javax.print.attribute.TextSyntax; + +/** + * JobDetailedStatusMessages provides additional detailed and + * technical job informations. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class JobDetailedStatusMessages + extends TextSyntax implements Attribute +{ + + /** + * Creates a JobDetailedStatusMessages object with the given value + * and locale. + * + * @param value the value for this syntax + * @param locale the locale to use, if null the default + * locale is used. + * + * @exception NullPointerException if value is null + */ + public JobDetailedStatusMessages(String value, Locale locale) + { + super(value, locale); + } + + /** + * Returns category of this class. + * + * @return The class JobDetailedStatusMessages itself. + */ + public Class getCategory() + { + return JobDetailedStatusMessages.class; + } + + + /** + * Returns the name of this attribute. + * + * @return The name "job-detailed-status-messages". + */ + public String getName() + { + return "job-detailed-status-messages"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobDocumentAccessErrors.java b/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobDocumentAccessErrors.java new file mode 100644 index 000000000..c3fff057c --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobDocumentAccessErrors.java @@ -0,0 +1,93 @@ +/* JobDocumentAccessErrors.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.javax.print.ipp.attribute.job; + +import java.util.Locale; + +import javax.print.attribute.Attribute; +import javax.print.attribute.TextSyntax; + +/** + * JobDocumentAccessErrors provides additional information + * for each access error for print-uri or document-uri jobs. + * technical job informations. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class JobDocumentAccessErrors + extends TextSyntax implements Attribute +{ + + /** + * Creates a JobDocumentAccessErrors object with the given value + * and locale. + * + * @param value the value for this syntax + * @param locale the locale to use, if null the default + * locale is used. + * + * @exception NullPointerException if value is null + */ + public JobDocumentAccessErrors(String value, Locale locale) + { + super(value, locale); + } + + /** + * Returns category of this class. + * + * @return The class JobDocumentAccessErrors itself. + */ + public Class getCategory() + { + return JobDocumentAccessErrors.class; + } + + + /** + * Returns the name of this attribute. + * + * @return The name "job-document-access-errors". + */ + public String getName() + { + return "job-document-access-errors"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobId.java b/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobId.java new file mode 100644 index 000000000..78c866723 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobId.java @@ -0,0 +1,87 @@ +/* JobId.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.javax.print.ipp.attribute.job; + +import javax.print.attribute.Attribute; +import javax.print.attribute.IntegerSyntax; + +/** + * The JobId attribute contains the ID of a + * print job created or currently being processed. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class JobId extends IntegerSyntax implements Attribute +{ + + /** + * Creates a IntegerSyntax with the given value. + * + * @param value the integer to set + * @throws IllegalArgumentException if value is < 1 + */ + public JobId(int value) + { + super(value); + + if (value < 1) + throw new IllegalArgumentException("job-id may not be less than 1"); + } + + /** + * Returns category of this class. + * + * @return The class JobId itself. + */ + public Class getCategory() + { + return JobId.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "job-id". + */ + public String getName() + { + return "job-id"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobMoreInfo.java b/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobMoreInfo.java new file mode 100644 index 000000000..569400f40 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobMoreInfo.java @@ -0,0 +1,87 @@ +/* JobMoreInfo.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.javax.print.ipp.attribute.job; + +import java.net.URI; + +import javax.print.attribute.Attribute; +import javax.print.attribute.URISyntax; + +/** + * JobMoreInfo attribute as described in RFC 2911 section + * 4.3.4 contains the URI where more information about a job + * (e.g. through a HTML page) can be found. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class JobMoreInfo extends URISyntax implements Attribute +{ + + /** + * Creates a JobMoreInfo object. + * + * @param uri the URI value for the syntax + * @throws NullPointerException if uri is null + */ + public JobMoreInfo(URI uri) + { + super(uri); + } + + /** + * Returns category of this class. + * + * @return The class JobMoreInfo itself. + */ + public Class getCategory() + { + return JobMoreInfo.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "job-more-info". + */ + public String getName() + { + return "job-more-info"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobPrinterUri.java b/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobPrinterUri.java new file mode 100644 index 000000000..1375a2419 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobPrinterUri.java @@ -0,0 +1,87 @@ +/* JobPrinterUri.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.javax.print.ipp.attribute.job; + +import java.net.URI; + +import javax.print.attribute.Attribute; +import javax.print.attribute.URISyntax; + +/** + * JobPrinterUri attribute as described in RFC 2911 section + * 4.3.3 contains the URI of the printer which created and + * processes a job. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class JobPrinterUri extends URISyntax implements Attribute +{ + + /** + * Creates a JobPrinterUri object. + * + * @param uri the URI value for the syntax + * @throws NullPointerException if uri is null + */ + public JobPrinterUri(URI uri) + { + super(uri); + } + + /** + * Returns category of this class. + * + * @return The class JobPrinterUri itself. + */ + public Class getCategory() + { + return JobPrinterUri.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "job-printer-uri". + */ + public String getName() + { + return "job-printer-uri"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobStateMessage.java b/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobStateMessage.java new file mode 100644 index 000000000..d65126621 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobStateMessage.java @@ -0,0 +1,92 @@ +/* JobStateMessage.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.javax.print.ipp.attribute.job; + +import java.util.Locale; + +import javax.print.attribute.Attribute; +import javax.print.attribute.TextSyntax; + +/** + * JobStateMessage attribute describes information about the + * job-state and job-state-reasons in human readable form. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class JobStateMessage + extends TextSyntax implements Attribute +{ + + /** + * Creates a JobStateMessage object with the given value + * and locale. + * + * @param value the value for this syntax + * @param locale the locale to use, if null the default + * locale is used. + * + * @exception NullPointerException if value is null + */ + public JobStateMessage(String value, Locale locale) + { + super(value, locale); + } + + /** + * Returns category of this class. + * + * @return The class JobStateMessage itself. + */ + public Class getCategory() + { + return JobStateMessage.class; + } + + + /** + * Returns the name of this attribute. + * + * @return The name "job-state-message". + */ + public String getName() + { + return "job-state-message"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobUri.java b/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobUri.java new file mode 100644 index 000000000..4b545b956 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/job/JobUri.java @@ -0,0 +1,87 @@ +/* JobUri.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.javax.print.ipp.attribute.job; + +import java.net.URI; + +import javax.print.attribute.Attribute; +import javax.print.attribute.URISyntax; + +/** + * JobUri attribute as described in RFC 2911 section + * 4.3.1 contains the URI for a job generated by the printer + * after a create request. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class JobUri extends URISyntax implements Attribute +{ + + /** + * Creates a JobUri object. + * + * @param uri the URI value for the syntax + * @throws NullPointerException if uri is null + */ + public JobUri(URI uri) + { + super(uri); + } + + /** + * Returns category of this class. + * + * @return The class JobUri itself. + */ + public Class getCategory() + { + return JobUri.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "job-uri". + */ + public String getName() + { + return "job-uri"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/printer/CharsetConfigured.java b/libjava/classpath/gnu/javax/print/ipp/attribute/printer/CharsetConfigured.java new file mode 100644 index 000000000..42430377c --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/printer/CharsetConfigured.java @@ -0,0 +1,86 @@ +/* CharsetConfigured.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.javax.print.ipp.attribute.printer; + +import gnu.javax.print.ipp.attribute.CharsetSyntax; + +import javax.print.attribute.Attribute; + +/** + * CharsetConfigured attribute as described in RFC 2911 section + * 4.4.17 provides the charset which is configured by the + * server to be used in the name and text syntax attribute types. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class CharsetConfigured extends CharsetSyntax + implements Attribute +{ + + /** + * Creates a CharsetConfigured object. + * + * @param value the charset string value. + */ + public CharsetConfigured(String value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class CharsetConfigured itself. + */ + public Class getCategory() + { + return CharsetConfigured.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "charset-configured". + */ + public String getName() + { + return "charset-configured"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/printer/DocumentFormat.java b/libjava/classpath/gnu/javax/print/ipp/attribute/printer/DocumentFormat.java new file mode 100644 index 000000000..9a5e01e1d --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/printer/DocumentFormat.java @@ -0,0 +1,111 @@ +/* DocumentFormat.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.javax.print.ipp.attribute.printer; + +import java.util.Locale; + +import javax.print.DocFlavor; +import javax.print.attribute.Attribute; +import javax.print.attribute.SupportedValuesAttribute; +import javax.print.attribute.TextSyntax; + +/** + * DocumentFormatSupported specifies the supported document + * formats of a printer. Printer are supplying a set of this attribute. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class DocumentFormat extends TextSyntax + implements SupportedValuesAttribute +{ + + /** + * Creates a DocumentFormat object with the + * given value and locale. + * + * @param value the value for this syntax + * @param locale the locale to use, if null the default + * locale is used. + * + * @exception NullPointerException if value is null + */ + public DocumentFormat(String value, Locale locale) + { + super(value, locale); + } + + /** + * Constructs a document format object for the given flavor. + * The constructor reworkes the mimetype of the given flavor + * to remove the quoted charset parameter if present. + * + * @param flavor the flavor with the mimetype + * @return The created document format. + */ + public static DocumentFormat createDocumentFormat(DocFlavor flavor) + { + String charset = flavor.getParameter("charset"); + String mimetype = flavor.getMediaType() + "/" + flavor.getMediaSubtype(); + if (charset != null) + mimetype += "; charset=" + charset; + + return new DocumentFormat(mimetype, null); + } + + /** + * Returns category of this class. + * + * @return The class DocumentFormat itself. + */ + public Class getCategory() + { + return DocumentFormat.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "document-format". + */ + public String getName() + { + return "document-format"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/printer/MultipleOperationTimeOut.java b/libjava/classpath/gnu/javax/print/ipp/attribute/printer/MultipleOperationTimeOut.java new file mode 100644 index 000000000..bb00b8891 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/printer/MultipleOperationTimeOut.java @@ -0,0 +1,86 @@ +/* MultipleOperationTimeOut.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.javax.print.ipp.attribute.printer; + +import javax.print.attribute.Attribute; +import javax.print.attribute.IntegerSyntax; + +/** + * MultipleOperationTimeOut attribute as described in RFC 2911 section + * 4.4.31 provides the minimum time ins second a printer object waits + * before time out and recovery. The printer object waits e.g. for + * additional SendDocument or SendUri operations. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class MultipleOperationTimeOut extends IntegerSyntax + implements Attribute +{ + + /** + * Creates a MultipleOperationTimeOut with the given value. + * + * @param value the integer to set + */ + public MultipleOperationTimeOut(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class MultipleOperationTimeOut itself. + */ + public Class getCategory() + { + return MultipleOperationTimeOut.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "multiple-operation-time-out". + */ + public String getName() + { + return "multiple-operation-time-out"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/printer/NaturalLanguageConfigured.java b/libjava/classpath/gnu/javax/print/ipp/attribute/printer/NaturalLanguageConfigured.java new file mode 100644 index 000000000..8dc05fe58 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/printer/NaturalLanguageConfigured.java @@ -0,0 +1,86 @@ +/* NaturalLanguageConfigured.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.javax.print.ipp.attribute.printer; + +import gnu.javax.print.ipp.attribute.NaturalLanguageSyntax; + +import javax.print.attribute.Attribute; + +/** + * NaturalLanguageConfigured attribute as described in RFC 2911 + * section 4.4.19 provides the natural language which is configured + * by the server to be used in the name and text syntax attribute types. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class NaturalLanguageConfigured extends NaturalLanguageSyntax + implements Attribute +{ + + /** + * Creates a NaturalLanguageConfigured object. + * + * @param value the charset string value. + */ + public NaturalLanguageConfigured(String value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class NaturalLanguageConfigured itself. + */ + public Class getCategory() + { + return NaturalLanguageConfigured.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "natural-language-configured". + */ + public String getName() + { + return "natural-language-configured"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterCurrentTime.java b/libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterCurrentTime.java new file mode 100644 index 000000000..361916773 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterCurrentTime.java @@ -0,0 +1,107 @@ +/* PrinterCurrentTime.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.javax.print.ipp.attribute.printer; + +import java.util.Date; + +import javax.print.attribute.Attribute; +import javax.print.attribute.DateTimeSyntax; +import javax.print.attribute.PrintServiceAttribute; + +/** + * PrinterCurrentTime attribute as described in RFC 2911 section + * 4.4.30 provides the current time of the print service. + * Its to be used by other attributes like the date-time-at-xxx + * attributes in the creation process. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class PrinterCurrentTime extends DateTimeSyntax + implements PrintServiceAttribute +{ + + /** + * Creates a PrinterCurrentTime object. + * + * @param value the date at creation time + * + * @exception NullPointerException if value is null + */ + public PrinterCurrentTime(Date value) + { + super(value); + } + + /** + * Tests if the given object is equal to this object. + * + * @param obj the object to test + * + * @return true if both objects are equal, + * false otherwise. + */ + public boolean equals(Object obj) + { + if(! (obj instanceof PrinterCurrentTime)) + return false; + + return super.equals(obj); + } + + /** + * Returns category of this class. + * + * @return The class PrinterCurrentTime itself. + */ + public Class getCategory() + { + return PrinterCurrentTime.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "printer-current-time". + */ + public String getName() + { + return "printer-current-time"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterDriverInstaller.java b/libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterDriverInstaller.java new file mode 100644 index 000000000..28a2f4485 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterDriverInstaller.java @@ -0,0 +1,88 @@ +/* PrinterDriverInstaller.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.javax.print.ipp.attribute.printer; + +import java.net.URI; + +import javax.print.attribute.Attribute; +import javax.print.attribute.URISyntax; + +/** + * PrinterDriverInstaller attribute as described in RFC 2911 section + * 4.4.81 provides the URI where a printer driver installer + * can be found. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class PrinterDriverInstaller extends URISyntax + implements Attribute +{ + + /** + * Creates a PrinterDriverInstaller object. + * + * @param uri the URI value for the syntax + * @throws NullPointerException if uri is null + */ + public PrinterDriverInstaller(URI uri) + { + super(uri); + } + + /** + * Returns category of this class. + * + * @return The class PrinterDriverInstaller itself. + */ + public Class getCategory() + { + return PrinterDriverInstaller.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "printer-driver-installer". + */ + public String getName() + { + return "printer-driver-installer"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterStateMessage.java b/libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterStateMessage.java new file mode 100644 index 000000000..07c458889 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterStateMessage.java @@ -0,0 +1,94 @@ +/* PrinterStateMessage.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.javax.print.ipp.attribute.printer; + +import java.util.Locale; + +import javax.print.attribute.Attribute; +import javax.print.attribute.PrintServiceAttribute; +import javax.print.attribute.TextSyntax; + +/** + * PrinterStateMessage attribute as described in RFC 2911 section + * 4.4.13 provides a textual representation of the attributes + * printer-state and printer-state-reasons for consumption by + * humans. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class PrinterStateMessage extends TextSyntax + implements PrintServiceAttribute +{ + + /** + * Creates a PrinterStateMessage object with the + * given value and locale. + * + * @param value the value for this syntax + * @param locale the locale to use, if null the default + * locale is used. + * + * @exception NullPointerException if value is null + */ + public PrinterStateMessage(String value, Locale locale) + { + super(value, locale); + } + + /** + * Returns category of this class. + * + * @return The class PrinterStateMessage itself. + */ + public Class getCategory() + { + return PrinterStateMessage.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "printer-state-message". + */ + public String getName() + { + return "printer-state-message"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterUpTime.java b/libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterUpTime.java new file mode 100644 index 000000000..7bec92ed3 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterUpTime.java @@ -0,0 +1,86 @@ +/* PrinterUpTime.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.javax.print.ipp.attribute.printer; + +import javax.print.attribute.Attribute; +import javax.print.attribute.IntegerSyntax; + +/** + * PrinterUpTime attribute as described in RFC 2911 section + * 4.4.29 provides the uptime of the printer object. This + * is a value in second starting at 1 after a initialization + * or reboot of the printer object. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class PrinterUpTime extends IntegerSyntax + implements Attribute +{ + + /** + * Creates a PrinterUpTime with the given value. + * + * @param value the integer to set + */ + public PrinterUpTime(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class PrinterUpTime itself. + */ + public Class getCategory() + { + return PrinterUpTime.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "printer-up-time". + */ + public String getName() + { + return "printer-up-time"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/CharsetSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/CharsetSupported.java new file mode 100644 index 000000000..22b484ef8 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/CharsetSupported.java @@ -0,0 +1,88 @@ +/* CharsetSupported.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.javax.print.ipp.attribute.supported; + +import gnu.javax.print.ipp.attribute.CharsetSyntax; + +import javax.print.attribute.Attribute; +import javax.print.attribute.SupportedValuesAttribute; + +/** + * CharsetSupported attribute as described in RFC 2911 section + * 4.4.18 provides the charset which are supported by the + * IPP implementation to be used in the name and text syntax + * attribute types. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class CharsetSupported extends CharsetSyntax + implements SupportedValuesAttribute +{ + + /** + * Creates a CharsetSupported object. + * + * @param value the charset string value. + */ + public CharsetSupported(String value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class CharsetSupported itself. + */ + public Class getCategory() + { + return CharsetSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "charset-supported". + */ + public String getName() + { + return "charset-supported"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/CompressionSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/CompressionSupported.java new file mode 100644 index 000000000..768091cb2 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/CompressionSupported.java @@ -0,0 +1,161 @@ +/* CompressionSupported.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.javax.print.ipp.attribute.supported; + +import gnu.javax.print.ipp.IppUtilities; + +import java.util.Iterator; +import java.util.Set; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; +import javax.print.attribute.SupportedValuesAttribute; +import javax.print.attribute.standard.Compression; + + +/** + * CompressionSupported provides the values which are + * supported for the compression attribute. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class CompressionSupported extends EnumSyntax + implements SupportedValuesAttribute +{ + + /** The print data is not compressed. */ + public static final CompressionSupported NONE = new CompressionSupported(0); + + /** The print data is ZIP compressed. */ + public static final CompressionSupported DEFLATE = new CompressionSupported(1); + + /** The print data is GNU Zip compressed. */ + public static final CompressionSupported GZIP = new CompressionSupported(2); + + /** The print data is UNIX compressed. */ + public static final CompressionSupported COMPRESS = new CompressionSupported(3); + + private static final String[] stringTable = { "none", "deflate", + "gzip", "compress" }; + + private static final CompressionSupported[] enumValueTable = { NONE, DEFLATE, + GZIP, COMPRESS }; + + /** + * Constructs a CompressionSupported object. + * + * @param value the enum value + */ + protected CompressionSupported(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class CompressionSupported itself. + */ + public Class getCategory() + { + return CompressionSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "compression-supported". + */ + public String getName() + { + return "compression-supported"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } + + /** + * Returns the equally enum of the standard attribute class + * of this SupportedValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public Compression getAssociatedAttribute() + { + return (Compression) IppUtilities.getEnumAttribute( + "compression", new Integer(getValue())); + } + + /** + * Constructs an array from a set of -supported attributes. + * @param set set to process + * @return The constructed array. + * + * @see #getAssociatedAttribute() + */ + public static Compression[] + getAssociatedAttributeArray(Set set) + { + Compression[] result = new Compression[set.size()]; + int j = 0; + for (Attribute tmp : set) + { + result[j] = ((CompressionSupported) tmp).getAssociatedAttribute(); + j++; + } + return result; + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/DocumentFormatSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/DocumentFormatSupported.java new file mode 100644 index 000000000..03449fa4f --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/DocumentFormatSupported.java @@ -0,0 +1,92 @@ +/* DocumentFormatSupported.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.javax.print.ipp.attribute.supported; + +import java.util.Locale; + +import javax.print.attribute.Attribute; +import javax.print.attribute.SupportedValuesAttribute; +import javax.print.attribute.TextSyntax; + +/** + * DocumentFormatSupported specifies the supported document + * formats of a printer. Printer are supplying a set of this attribute. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class DocumentFormatSupported extends TextSyntax + implements SupportedValuesAttribute +{ + + /** + * Creates a DocumentFormatSupported object with the + * given value and locale. + * + * @param value the value for this syntax + * @param locale the locale to use, if null the default + * locale is used. + * + * @exception NullPointerException if value is null + */ + public DocumentFormatSupported(String value, Locale locale) + { + super(value, locale); + } + + /** + * Returns category of this class. + * + * @return The class DocumentFormatSupported itself. + */ + public Class getCategory() + { + return DocumentFormatSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "document-format-supported". + */ + public String getName() + { + return "document-format-supported"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/FinishingsSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/FinishingsSupported.java new file mode 100644 index 000000000..f271fa71b --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/FinishingsSupported.java @@ -0,0 +1,302 @@ +/* FinishingsSupported.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.javax.print.ipp.attribute.supported; + +import gnu.javax.print.ipp.IppUtilities; + +import java.util.Iterator; +import java.util.Set; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; +import javax.print.attribute.SupportedValuesAttribute; +import javax.print.attribute.standard.Finishings; + + +/** + * The FinishingsSupported attribute provides the supported + * values for finishings of a job. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class FinishingsSupported extends EnumSyntax + implements SupportedValuesAttribute +{ + + /** No finishing. */ + public static final FinishingsSupported NONE = new FinishingsSupported(3); + + /** Staple the document(s) */ + public static final FinishingsSupported STAPLE = new FinishingsSupported(4); + + /** Cover a document */ + public static final FinishingsSupported COVER = new FinishingsSupported(6); + + /** + * This value indicates that a binding is to be applied to the document. + * The type and placement of the binding is site-defined. + */ + public static final FinishingsSupported BIND = new FinishingsSupported(7); + + /** + * Bind the document(s) with one or more staples (wire stitches) + * along the middle fold. + */ + public static final FinishingsSupported SADDLE_STITCH = + new FinishingsSupported(8); + + /** + * Bind the document(s) with one or more staples (wire stitches) + * along one edge. + */ + public static final FinishingsSupported EDGE_STITCH = + new FinishingsSupported(9); + + /** + * Bind the document(s) with one or more staples in the top left + * corner. + */ + public static final FinishingsSupported STAPLE_TOP_LEFT = + new FinishingsSupported(20); + + /** + * Bind the document(s) with one or more staples in the bottom + * left corner. + */ + public static final FinishingsSupported STAPLE_BOTTOM_LEFT = + new FinishingsSupported(21); + + /** + * Bind the document(s) with one or more staples in the top right corner. + */ + public static final FinishingsSupported STAPLE_TOP_RIGHT = + new FinishingsSupported(22); + + /** + * Bind the document(s) with one or more staples in the bottom right corner. + */ + public static final FinishingsSupported STAPLE_BOTTOM_RIGHT = + new FinishingsSupported(23); + + /** + * Bind the document(s) with one or more staples (wire stitches) + * along the left edge. + */ + public static final FinishingsSupported EDGE_STITCH_LEFT = + new FinishingsSupported(24); + + /** + * Bind the document(s) with one or more staples (wire stitches) along + * the top edge. + */ + public static final FinishingsSupported EDGE_STITCH_TOP = + new FinishingsSupported(25); + + /** + * Bind the document(s) with one or more staples (wire stitches) along + * the right edge. + */ + public static final FinishingsSupported EDGE_STITCH_RIGHT = + new FinishingsSupported(26); + + /** + * Bind the document(s) with one or more staples (wire stitches) along + * the bottom edge. + */ + public static final FinishingsSupported EDGE_STITCH_BOTTOM = + new FinishingsSupported(27); + + /** + * Bind the document(s) with two staples (wire stitches) along the + * left edge assuming a portrait document. + */ + public static final FinishingsSupported STAPLE_DUAL_LEFT = + new FinishingsSupported(28); + + /** + * Bind the document(s) with two staples (wire stitches) along the + * top edge assuming a portrait document. + */ + public static final FinishingsSupported STAPLE_DUAL_TOP = + new FinishingsSupported(29); + + /** + * Bind the document(s) with two staples (wire stitches) along the + * right edge assuming a portrait document. + */ + public static final FinishingsSupported STAPLE_DUAL_RIGHT = + new FinishingsSupported(30); + + /** + * Bind the document(s) with two staples (wire stitches) along the + * bottom edge assuming a portrait document. + */ + public static final FinishingsSupported STAPLE_DUAL_BOTTOM = + new FinishingsSupported(31); + + private static final String[] stringTable = { "none", "staple", null, + "cover", "bind", "saddle-stitch", + "edge-stitch", null, null, null, + null, null, null, null, null, + null, null, "staple-top-left", + "staple-bottom-left", + "staple-top-right", + "staple-bottom-right", + "edge-stitch-left", + "edge-stitch-top", + "edge-stitch-right", + "edge-stitch-bottom", + "staple-dual-left", + "staple-dual-top", + "staple-dual-right", + "staple-dual-bottom" }; + + private static final FinishingsSupported[] enumValueTable = { NONE, STAPLE, + null, COVER, BIND, + SADDLE_STITCH, + EDGE_STITCH, null, + null, null, null, + null, null, null, + null, null, null, + STAPLE_TOP_LEFT, + STAPLE_BOTTOM_LEFT, + STAPLE_TOP_RIGHT, + STAPLE_BOTTOM_RIGHT, + EDGE_STITCH_LEFT, + EDGE_STITCH_TOP, + EDGE_STITCH_RIGHT, + EDGE_STITCH_BOTTOM, + STAPLE_DUAL_LEFT, + STAPLE_DUAL_TOP, + STAPLE_DUAL_RIGHT, + STAPLE_DUAL_BOTTOM }; + + /** + * Constructs a FinishingsSupported object. + * + * @param value the value + */ + protected FinishingsSupported(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return the class FinishingsSupported itself + */ + public Class getCategory() + { + return FinishingsSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "finishings-supported". + */ + public String getName() + { + return "finishings-supported"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } + + /** + * Returns the lowest used value by the enumerations of this class. + * . + * @return The lowest value used. + */ + protected int getOffset() + { + return 3; + } + + /** + * Returns the equally enum of the standard attribute class + * of this SupportedValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public Finishings getAssociatedAttribute() + { + return (Finishings) IppUtilities.getEnumAttribute( + "finishings", new Integer(getValue())); + } + + /** + * Constructs an array from a set of -supported attributes. + * @param set set to process + * @return The constructed array. + * + * @see #getAssociatedAttribute() + */ + public static Finishings[] + getAssociatedAttributeArray(Set set) + { + Finishings[] result = new Finishings[set.size()]; + int j = 0; + for (Attribute tmp : set) + { + result[j] = ((FinishingsSupported) tmp).getAssociatedAttribute(); + j++; + } + return result; + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/GeneratedNaturalLanguageSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/GeneratedNaturalLanguageSupported.java new file mode 100644 index 000000000..df1d33007 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/GeneratedNaturalLanguageSupported.java @@ -0,0 +1,89 @@ +/* GeneratedNaturalLanguageSupported.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.javax.print.ipp.attribute.supported; + +import gnu.javax.print.ipp.attribute.NaturalLanguageSyntax; + +import javax.print.attribute.Attribute; +import javax.print.attribute.SupportedValuesAttribute; + +/** + * GeneratedNaturalLanguageSupported attribute as described + * in RFC 2911 section 4.4.20 provides the natural languages + * which are supported by the IPP implementation to be used + * in the name and text syntax attribute types. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class GeneratedNaturalLanguageSupported + extends NaturalLanguageSyntax + implements SupportedValuesAttribute +{ + + /** + * Creates a GeneratedNaturalLanguageSupported object. + * + * @param value the charset string value. + */ + public GeneratedNaturalLanguageSupported(String value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class GeneratedNaturalLanguageSupported itself. + */ + public Class getCategory() + { + return GeneratedNaturalLanguageSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "generated-natural-language-supported". + */ + public String getName() + { + return "generated-natural-language-supported"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/IppVersionsSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/IppVersionsSupported.java new file mode 100644 index 000000000..072d7499a --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/IppVersionsSupported.java @@ -0,0 +1,122 @@ +/* IppVersionsSupported.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.javax.print.ipp.attribute.supported; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; +import javax.print.attribute.SupportedValuesAttribute; + +/** + * IppVersionsSupported attribute as described in RFC 2911 section + * 4.4.14 provides the value(s) (implemented as EnumSyntax) + * of the supported IPP versions. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class IppVersionsSupported extends EnumSyntax + implements SupportedValuesAttribute +{ + + // a keyword based attribute in IPP - int values just starting at 0 + + /** IPP version 1.0 */ + public static final IppVersionsSupported V_1_0 = + new IppVersionsSupported(0); + + /** IPP version 1.1 */ + public static final IppVersionsSupported V_1_1 = + new IppVersionsSupported(1); + + private static final String[] stringTable = { "1.0", "1.1" }; + + private static final IppVersionsSupported[] enumValueTable = { V_1_0, + V_1_1 }; + + /** + * Constructs a IppVersionsSupported object. + * + * @param value the enum value + */ + public IppVersionsSupported(int value) + { + super(value); + } + + /** + * Returns the category of this class. + * + * @return The class IppVersionsSupported itself. + */ + public Class getCategory() + { + return IppVersionsSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "ipp-versions-supported". + */ + public String getName() + { + return "ipp-versions-supported"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/JobHoldUntilSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/JobHoldUntilSupported.java new file mode 100644 index 000000000..2add4a0cd --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/JobHoldUntilSupported.java @@ -0,0 +1,134 @@ +/* JobHoldUntilSupported.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.javax.print.ipp.attribute.supported; + +import java.util.Locale; + +import javax.print.attribute.Attribute; +import javax.print.attribute.SupportedValuesAttribute; +import javax.print.attribute.TextSyntax; + +/** + * JobHoldUntilSupported attribute provides the supported + * values for the attribute type job-hold-until. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class JobHoldUntilSupported extends TextSyntax + implements SupportedValuesAttribute +{ + + // a keyword/name based attribute in IPP + // can be extended by administrators + // standard values are predefined + + /** Job should be printed immediately. */ + public static final JobHoldUntilSupported NO_HOLD = + new JobHoldUntilSupported("no-hold", null); + + /** Job should be hold indefinitely. */ + public static final JobHoldUntilSupported INDEFINITE = + new JobHoldUntilSupported("indefinite", null); + + /** Job should be processed during the day. */ + public static final JobHoldUntilSupported DAY_TIME = + new JobHoldUntilSupported("day-time", null); + + /** Job should be processed in the evening. */ + public static final JobHoldUntilSupported EVENING = + new JobHoldUntilSupported("evening", null); + + /** Job should be processed during night. */ + public static final JobHoldUntilSupported NIGHT = + new JobHoldUntilSupported("night", null); + + /** Job should be processed during the weekend. */ + public static final JobHoldUntilSupported WEEKEND = + new JobHoldUntilSupported("weekend", null); + + /** + * Job should be processed as second-shift + * (after close of business). + */ + public static final JobHoldUntilSupported SECOND_SHIFT = + new JobHoldUntilSupported("second-shift", null); + + /** + * Job should be processed as third-shift + * (after midnight). + */ + public static final JobHoldUntilSupported THIRD_SHIFT = + new JobHoldUntilSupported("third-shift", null); + + /** + * Creates a JobHoldUntilSupported object with the + * given value and locale. + * + * @param value the value for this syntax + * @param locale the locale to use, if null the default + * locale is used. + * + * @throws NullPointerException if value is null + */ + public JobHoldUntilSupported(String value, Locale locale) + { + super(value, locale); + } + + /** + * Returns category of this class. + * + * @return The class JobHoldUntilSupported itself. + */ + public Class getCategory() + { + return JobHoldUntilSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "job-hold-until-supported". + */ + public String getName() + { + return "job-hold-until-supported"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/JobSheetsSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/JobSheetsSupported.java new file mode 100644 index 000000000..aeb86ff10 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/JobSheetsSupported.java @@ -0,0 +1,148 @@ +/* JobSheetsSupported.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.javax.print.ipp.attribute.supported; + +import gnu.javax.print.ipp.attribute.defaults.JobSheetsDefault; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Locale; +import java.util.Set; + +import javax.print.attribute.Attribute; +import javax.print.attribute.SupportedValuesAttribute; +import javax.print.attribute.TextSyntax; +import javax.print.attribute.standard.JobSheets; + +/** + * JobSheetsSupported attribute provides the supported values + * of the job-sheets attribute. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class JobSheetsSupported extends TextSyntax + implements SupportedValuesAttribute +{ + //a keyword/name based attribute in IPP + // can be extended by administrators + // standard values are predefined + + /** No job sheet is the default */ + public static final JobSheetsDefault NONE = + new JobSheetsDefault("none", Locale.getDefault()); + + /** A job sheet is the default */ + public static final JobSheetsDefault STANDARD = + new JobSheetsDefault("standard", Locale.getDefault()); + + /** + * Creates a JobSheetsSupported object with the + * given value and locale. + * + * @param value the value for this syntax + * @param locale the locale to use, if null the default + * locale is used. + * + * @throws NullPointerException if value is null + */ + public JobSheetsSupported(String value, Locale locale) + { + super(value, locale); + } + + /** + * Returns category of this class. + * + * @return The class JobSheetsSupported itself. + */ + public Class getCategory() + { + return JobSheetsSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "job-sheets-supported". + */ + public String getName() + { + return "job-sheets-supported"; + } + + /** + * Returns the equally enum of the standard attribute class + * of this SupportedValuesAttribute enum. + *

      May return null if no value exists in JPS API.

      + * + * @return The enum of the standard attribute class. + */ + public JobSheets getAssociatedAttribute() + { + if (this.equals(JobSheetsDefault.NONE)) + return JobSheets.NONE; + if (this.equals(JobSheetsDefault.STANDARD)) + return JobSheets.STANDARD; + + return null; + } + + /** + * Constructs an array from a set of -supported attributes. + * @param set set to process + * @return The constructed array. + * + * @see #getAssociatedAttribute() + */ + public static JobSheets[] + getAssociatedAttributeArray(Set set) + { + ArrayList result = new ArrayList(); + int j = 0; + for (Attribute tmp : set) + { + JobSheets att = ((JobSheetsSupported) tmp).getAssociatedAttribute(); + if (att != null) + result.add(att); + j++; + } + return result.toArray(new JobSheets[result.size()]); + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/MediaSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/MediaSupported.java new file mode 100644 index 000000000..2684ebbec --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/MediaSupported.java @@ -0,0 +1,116 @@ +/* MediaSupported.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.javax.print.ipp.attribute.supported; + +import gnu.javax.print.ipp.IppUtilities; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Locale; +import java.util.Set; + +import javax.print.attribute.Attribute; +import javax.print.attribute.SupportedValuesAttribute; +import javax.print.attribute.TextSyntax; +import javax.print.attribute.standard.Media; + +/** + * MediaSupported attribute provides the keyword values + * of the media types supported by the printer object. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class MediaSupported extends TextSyntax + implements SupportedValuesAttribute +{ + + /** + * Creates a MediaSupported object with the + * given value and locale. + * + * @param value the value for this syntax + * @param locale the locale to use, if null the default + * locale is used. + * + * @throws NullPointerException if value is null + */ + public MediaSupported(String value, Locale locale) + { + super(value, locale); + } + + /** + * Returns category of this class. + * + * @return The class MediaSupported itself. + */ + public Class getCategory() + { + return MediaSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "media-supported". + */ + public String getName() + { + return "media-supported"; + } + + /** + * Constructs an array from a set of -supported attributes. + * @param set set to process + * @return The constructed array. + */ + public static Media[] getAssociatedAttributeArray(Set set) + { + Media tmp2; + ArrayList result = new ArrayList(); + for (Attribute tmp : set) + { + tmp2 = (Media) IppUtilities.getEnumAttribute("media", tmp.toString()); + if (tmp2 != null) + result.add(tmp2); + } + return result.toArray(new Media[result.size()]); + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/MultipleDocumentHandlingSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/MultipleDocumentHandlingSupported.java new file mode 100644 index 000000000..73e5921f1 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/MultipleDocumentHandlingSupported.java @@ -0,0 +1,176 @@ +/* MultipleDocumentHandlingSupported.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.javax.print.ipp.attribute.supported; + +import gnu.javax.print.ipp.IppUtilities; + +import java.util.Iterator; +import java.util.Set; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; +import javax.print.attribute.SupportedValuesAttribute; +import javax.print.attribute.standard.MultipleDocumentHandling; + + +/** + * MultipleDocumentHandlingSupported provides the + * supported values for the MultipleDocumentHandling attribute. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class MultipleDocumentHandlingSupported extends EnumSyntax + implements SupportedValuesAttribute +{ + + //a keyword based attribute in IPP - int values just starting at 0 + + /** + * Supports only multiple documents treated as a single document. This + * applies to attributes which specify treatment of multiple document jobs. + */ + public static final MultipleDocumentHandlingSupported SINGLE_DOCUMENT = + new MultipleDocumentHandlingSupported(0); + + /** Supports multiple documents as uncollated copies */ + public static final MultipleDocumentHandlingSupported SEPARATE_DOCUMENTS_UNCOLLATED_COPIES = + new MultipleDocumentHandlingSupported(1); + + /** Supports multiple documents as collated copies */ + public static final MultipleDocumentHandlingSupported SEPARATE_DOCUMENTS_COLLATED_COPIES = + new MultipleDocumentHandlingSupported(2); + + /** + * Supports multiple documents where every single document starts + * with a new sheet. + */ + public static final MultipleDocumentHandlingSupported SINGLE_DOCUMENT_NEW_SHEET = + new MultipleDocumentHandlingSupported(3); + + private static final String[] stringTable = { "single-document", + "separate-documents-uncollated-copies", + "separate-documents-collated-copies", + "single-document-new-sheet" }; + + private static final MultipleDocumentHandlingSupported[] enumValueTable = + { SINGLE_DOCUMENT, SEPARATE_DOCUMENTS_UNCOLLATED_COPIES, + SEPARATE_DOCUMENTS_COLLATED_COPIES, SINGLE_DOCUMENT_NEW_SHEET}; + + /** + * Constructs a MultipleDocumentHandlingSupported object. + * + * @param value the enum value + */ + protected MultipleDocumentHandlingSupported(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class MultipleDocumentHandlingSupported itself. + */ + public Class getCategory() + { + return MultipleDocumentHandlingSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "multiple-document-handling-supported". + */ + public String getName() + { + return "multiple-document-handling-supported"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } + + /** + * Returns the equally enum of the standard attribute class + * of this SupportedValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public MultipleDocumentHandling getAssociatedAttribute() + { + return (MultipleDocumentHandling) IppUtilities.getEnumAttribute( + "multiple-document-handling", new Integer(getValue())); + } + + /** + * Constructs an array from a set of -supported attributes. + * @param set set to process + * @return The constructed array. + * + * @see #getAssociatedAttribute() + */ + public static MultipleDocumentHandling[] + getAssociatedAttributeArray(Set set) + { + MultipleDocumentHandling[] result = new MultipleDocumentHandling[set.size()]; + int j = 0; + for (Attribute tmp : set) + { + result[j] = ((MultipleDocumentHandlingSupported) tmp).getAssociatedAttribute(); + j++; + } + return result; + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/MultipleDocumentJobsSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/MultipleDocumentJobsSupported.java new file mode 100644 index 000000000..1b2998456 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/MultipleDocumentJobsSupported.java @@ -0,0 +1,119 @@ +/* MultipleDocumentJobsSupported.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.javax.print.ipp.attribute.supported; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; +import javax.print.attribute.SupportedValuesAttribute; + +/** + * MultipleDocumentJobsSupported specifies if a printer + * supported multiple documents in one job. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public class MultipleDocumentJobsSupported extends EnumSyntax + implements SupportedValuesAttribute +{ + + /** Multiple documents per job are not supported. */ + public static final MultipleDocumentJobsSupported NOT_SUPPORTED = + new MultipleDocumentJobsSupported(0); + + /** Multiple documents per job are supported. */ + public static final MultipleDocumentJobsSupported SUPPORTED = + new MultipleDocumentJobsSupported(1); + + private static final String[] stringTable = { "not-supported", "supported" }; + + private static final MultipleDocumentJobsSupported[] enumValueTable = + { NOT_SUPPORTED, SUPPORTED }; + + /** + * Constructs a MultipleDocumentJobsSupported object. + * + * @param value the enum value + */ + protected MultipleDocumentJobsSupported(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class MultipleDocumentJobsSupported itself. + */ + public Class getCategory() + { + return MultipleDocumentJobsSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "multiple-document-jobs-supported". + */ + public String getName() + { + return "multiple-document-jobs-supported"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/OperationsSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/OperationsSupported.java new file mode 100644 index 000000000..a059c89a5 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/OperationsSupported.java @@ -0,0 +1,231 @@ +/* OperationsSupported.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.javax.print.ipp.attribute.supported; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; +import javax.print.attribute.SupportedValuesAttribute; + +/** + * OperationsSupported specifies the enums of the operations + * supported by a given printer or job object. The attribute is further + * specified in RFC 2911 section 4.4.15. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class OperationsSupported extends EnumSyntax + implements SupportedValuesAttribute +{ + /* + * Value Operation Name + ----------------- ------------------------------------- + 0x0000 reserved, not used + 0x0001 reserved, not used + 0x0002 Print-Job + 0x0003 Print-URI + 0x0004 Validate-Job + 0x0005 Create-Job + 0x0006 Send-Document + 0x0007 Send-URI + 0x0008 Cancel-Job + 0x0009 Get-Job-Attributes + 0x000A Get-Jobs + 0x000B Get-Printer-Attributes + 0x000C Hold-Job + 0x000D Release-Job + 0x000E Restart-Job + 0x000F reserved for a future operation + 0x0010 Pause-Printer + 0x0011 Resume-Printer + 0x0012 Purge-Jobs + 0x0013-0x3FFF reserved for future IETF standards track operations + 0x4000-0x8FFF reserved for vendor extensions + */ + + // standard ipp 1.1 operations + + /** + * Operation to print a job in one request/response. */ + public static final OperationsSupported PRINT_JOB = + new OperationsSupported(0x02); + + /** Operation to print a document from an URI */ + public static final OperationsSupported PRINT_URI = + new OperationsSupported(0x03); + + /** Operation to validate a job before submission. */ + public static final OperationsSupported VALIDATE_JOB = + new OperationsSupported(0x04); + + /** + * Operation to create an initial job for use with multiple document per job. + */ + public static final OperationsSupported CREATE_JOB = + new OperationsSupported(0x05); + + /** + * Operation to send a document to a multidoc job created via CREATE_JOB + */ + public static final OperationsSupported SEND_DOCUMENT = + new OperationsSupported(0x06); + + /** + * Operation to send a document uri to a multidoc job created + * via CREATE_JOB. The document accessible from this URI will be printed. + */ + public static final OperationsSupported SEND_URI = + new OperationsSupported(0x07); + + /** Operation to cancel a job by its ID or name. */ + public static final OperationsSupported CANCEL_JOB = + new OperationsSupported(0x08); + + /** Operation to get job attributes of a current job. */ + public static final OperationsSupported GET_JOB_ATTRIBUTES = + new OperationsSupported(0x09); + + /** Operation to pause a printer. */ + public static final OperationsSupported PAUSE_PRINTER = + new OperationsSupported(0x10); + + /** Operation to get all currently queued or processed jobs. */ + public static final OperationsSupported GET_JOBS = + new OperationsSupported(0x0A); + + /** Operation to get the attributes of a printer. */ + public static final OperationsSupported GET_PRINTER_ATTRIBUTES = + new OperationsSupported(0x0B); + + /** Operation to put a job on hold by its ID or name. */ + public static final OperationsSupported HOLD_JOB = + new OperationsSupported(0x0C); + + /** Operation to release a job by its ID or name. */ + public static final OperationsSupported RELEASE_JOB = + new OperationsSupported(0x0D); + + /** Operation to restart a job by its ID or name. */ + public static final OperationsSupported RESTART_JOB = + new OperationsSupported(0x0E); + + /** Not yet an operation - reserved for futher use. */ + public static final OperationsSupported RESERVED = + new OperationsSupported(0x0F); + + /** Operation to resume a printer. */ + public static final OperationsSupported RESUME_PRINTER = + new OperationsSupported(0x11); + + /** Operation to remove all jobs from a printer regardless of state. */ + public static final OperationsSupported PURGE_JOBS = + new OperationsSupported(0x12); + + + private static final String[] stringTable = { "print-job", "print-uri", + "validate-job", "create-job", + "send-document", "send-uri", + "cancel-job", "get-job-attributes", + "pause-printer", "get-jobs", + "get-printer-attributes", "hold-job", + "release-job", "restart-job", "reserved", + "resume-printer", "purge-job"}; + + private static final OperationsSupported[] enumValueTable = + { PRINT_JOB, PRINT_URI, VALIDATE_JOB, CREATE_JOB, SEND_DOCUMENT, SEND_URI, + CANCEL_JOB, GET_JOB_ATTRIBUTES, PAUSE_PRINTER, GET_JOBS, GET_PRINTER_ATTRIBUTES, + HOLD_JOB, RELEASE_JOB, RESTART_JOB, RESERVED, RESUME_PRINTER, PURGE_JOBS}; + + + /** + * Constructs a OperationsSupported object. + * + * @param value the enum value + */ + protected OperationsSupported(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class OperationsSupported itself. + */ + public Class getCategory() + { + return OperationsSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "operations-supported". + */ + public String getName() + { + return "operations-supported"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } + + // we start with 2 + protected int getOffset() + { + return 2; + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/OrientationRequestedSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/OrientationRequestedSupported.java new file mode 100644 index 000000000..4b87c53a5 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/OrientationRequestedSupported.java @@ -0,0 +1,178 @@ +/* OrientationRequestedSupported.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.javax.print.ipp.attribute.supported; + +import gnu.javax.print.ipp.IppUtilities; + +import java.util.Iterator; +import java.util.Set; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; +import javax.print.attribute.SupportedValuesAttribute; +import javax.print.attribute.standard.OrientationRequested; + + +/** + * The OrientationRequestedSupported attribute provides + * the supported values for the job attribute orientation-requested. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class OrientationRequestedSupported extends EnumSyntax + implements SupportedValuesAttribute +{ + + /** Orientation as portrait. */ + public static final OrientationRequestedSupported PORTRAIT = + new OrientationRequestedSupported(3); + + /** Orientation as landscape. */ + public static final OrientationRequestedSupported LANDSCAPE = + new OrientationRequestedSupported(4); + + /** Orientation as reversed landscape. */ + public static final OrientationRequestedSupported REVERSE_LANDSCAPE = + new OrientationRequestedSupported(5); + + /** Orientation as reversed portrait. */ + public static final OrientationRequestedSupported REVERSE_PORTRAIT = + new OrientationRequestedSupported(6); + + + private static final String[] stringTable = { "portrait", "landscape", + "reverse-landscape", + "reverse-portrait" }; + + private static final OrientationRequestedSupported[] + enumValueTable = { PORTRAIT, LANDSCAPE, + REVERSE_LANDSCAPE, REVERSE_PORTRAIT }; + + /** + * Constructs a OrientationRequestedSupported object. + * + * @param value the value + */ + protected OrientationRequestedSupported(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class OrientationRequestedSupported itself. + */ + public Class getCategory() + { + return OrientationRequestedSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "orientation-requested-supported". + */ + public String getName() + { + return "orientation-requested-supported"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } + + /** + * Returns the lowest used value by the enumerations of this class. + * . + * @return The lowest value used. + */ + protected int getOffset() + { + return 3; + } + + /** + * Returns the equally enum of the standard attribute class + * of this SupportedValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public OrientationRequested getAssociatedAttribute() + { + return (OrientationRequested) IppUtilities.getEnumAttribute( + "orientation-requested", new Integer(getValue())); + } + + /** + * Constructs an array from a set of -supported attributes. + * @param set set to process + * @return The constructed array. + * + * @see #getAssociatedAttribute() + */ + public static OrientationRequested[] + getAssociatedAttributeArray(Set set) + { + OrientationRequested[] result = new OrientationRequested[set.size()]; + int j = 0; + for (Attribute tmp : set) + { + result[j] = ((OrientationRequestedSupported) tmp).getAssociatedAttribute(); + j++; + } + return result; + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/PageRangesSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/PageRangesSupported.java new file mode 100644 index 000000000..c58f76748 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/PageRangesSupported.java @@ -0,0 +1,117 @@ +/* PageRangesSupported.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.javax.print.ipp.attribute.supported; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; +import javax.print.attribute.SupportedValuesAttribute; + +/** + * PageRangesSupported is a boolean typed + * attribute indicating (as EnumSyntax) if page ranges + * are supported. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class PageRangesSupported extends EnumSyntax + implements SupportedValuesAttribute +{ + /** Page ranges are not supported. */ + public static final PageRangesSupported NOT_SUPPORTED = + new PageRangesSupported(0); + + /** Page ranges are supported. */ + public static final PageRangesSupported SUPPORTED = + new PageRangesSupported(1); + + private static final String[] stringTable = { "not-supported", "supported" }; + + private static final PageRangesSupported[] enumValueTable = { NOT_SUPPORTED, + SUPPORTED }; + + /** + * Constructs a PageRangesSupported object. + * + * @param value the enum value + */ + protected PageRangesSupported(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class PageRangesSupported itself. + */ + public Class getCategory() + { + return PageRangesSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "page-ranges-supported". + */ + public String getName() + { + return "page-ranges-supported"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/PrintQualitySupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/PrintQualitySupported.java new file mode 100644 index 000000000..25cbf9f0b --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/PrintQualitySupported.java @@ -0,0 +1,169 @@ +/* PrintQualitySupported.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.javax.print.ipp.attribute.supported; + +import gnu.javax.print.ipp.IppUtilities; + +import java.util.Iterator; +import java.util.Set; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; +import javax.print.attribute.SupportedValuesAttribute; +import javax.print.attribute.standard.PrintQuality; + + +/** + * PrintQualitySupported provides the + * supported values for the print-quality attribute. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class PrintQualitySupported extends EnumSyntax + implements SupportedValuesAttribute +{ + /** Draft quality of the printer. */ + public static final PrintQualitySupported DRAFT = + new PrintQualitySupported(3); + + /** Normal quality of the printer. */ + public static final PrintQualitySupported NORMAL = + new PrintQualitySupported(4); + + /** High quality of the printer. */ + public static final PrintQualitySupported HIGH = + new PrintQualitySupported(5); + + private static final String[] stringTable = { "draft", "normal", "high" }; + + private static final PrintQualitySupported[] enumValueTable = { DRAFT, + NORMAL, + HIGH }; + + /** + * Constructs a PrintQualitySupported object. + * + * @param value the value of the enum + */ + protected PrintQualitySupported(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class PrintQualitySupported itself. + */ + public Class getCategory() + { + return PrintQualitySupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "print-quality-supported". + */ + public String getName() + { + return "print-quality-supported"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } + + /** + * Returns the lowest used value by the enumerations of this class. + * . + * @return The lowest value used. + */ + protected int getOffset() + { + return 3; + } + + /** + * Returns the equally enum of the standard attribute class + * of this SupportedValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public PrintQuality getAssociatedAttribute() + { + return (PrintQuality) IppUtilities.getEnumAttribute( + "print-quality", new Integer(getValue())); + } + + /** + * Constructs an array from a set of -supported attributes. + * @param set set to process + * @return The constructed array. + * + * @see #getAssociatedAttribute() + */ + public static PrintQuality[] getAssociatedAttributeArray(Set set) + { + PrintQuality[] result = new PrintQuality[set.size()]; + int j = 0; + for (Attribute tmp : set) + { + result[j] = ((PrintQualitySupported) tmp).getAssociatedAttribute(); + j++; + } + return result; + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/PrinterResolutionSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/PrinterResolutionSupported.java new file mode 100644 index 000000000..eb50aaac5 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/PrinterResolutionSupported.java @@ -0,0 +1,142 @@ +/* PrinterResolutionSupported.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.javax.print.ipp.attribute.supported; + +import java.util.Iterator; +import java.util.Set; + +import javax.print.attribute.Attribute; +import javax.print.attribute.ResolutionSyntax; +import javax.print.attribute.SupportedValuesAttribute; +import javax.print.attribute.standard.PrinterResolution; + + +/** + * The PrinterResolutionSupported attribute provides + * the supported values for the job attribute printer-resolution. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class PrinterResolutionSupported extends ResolutionSyntax + implements SupportedValuesAttribute +{ + + /** + * Creates a PrinterResolutionSupported object with the + * given arguments. + * + * @param crossFeedResolution the cross feed resolution + * @param feedResolution the feed resolution + * @param units the unit to use (e.g. {@link #DPCM} or {@link #DPI}) + * + * @exception IllegalArgumentException if preconditions fail + */ + public PrinterResolutionSupported(int crossFeedResolution, + int feedResolution, int units) + { + super(crossFeedResolution, feedResolution, units); + } + + /** + * Tests if the given object is equal to this object. + * + * @param obj the object to test + * + * @return true if both objects are equal, + * false otherwise. + */ + public boolean equals(Object obj) + { + if(! (obj instanceof PrinterResolutionSupported)) + return false; + + return super.equals(obj); + } + + /** + * Returns category of this class. + * + * @return The class PrinterResolutionSupported itself. + */ + public Class getCategory() + { + return PrinterResolutionSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "printer-resolution-supported". + */ + public String getName() + { + return "printer-resolution-supported"; + } + + /** + * Returns the equally enum of the standard attribute class + * of this SupportedValuesAttribute enum. + * + * @return The enum of the standard attribute class. + */ + public PrinterResolution getAssociatedAttribute() + { + return new PrinterResolution(getCrossFeedResolutionDphi(), + getFeedResolutionDphi(), 1); + } + + /** + * Constructs an array from a set of -supported attributes. + * @param set set to process + * @return The constructed array. + * + * @see #getAssociatedAttribute() + */ + public static PrinterResolution[] + getAssociatedAttributeArray(Set set) + { + PrinterResolution[] result = new PrinterResolution[set.size()]; + int j = 0; + for (Attribute tmp : set) + { + result[j] = ((PrinterResolutionSupported) tmp).getAssociatedAttribute(); + j++; + } + return result; + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/PrinterUriSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/PrinterUriSupported.java new file mode 100644 index 000000000..0eed39c6c --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/PrinterUriSupported.java @@ -0,0 +1,89 @@ +/* PrinterUriSupported.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.javax.print.ipp.attribute.supported; + +import java.net.URI; + +import javax.print.attribute.Attribute; +import javax.print.attribute.SupportedValuesAttribute; +import javax.print.attribute.URISyntax; + +/** + * PrinterUriSupported attribute as described in RFC 2911 section + * 4.4.1 contains one of the URIs the printer supported for + * job processing (e.g. one with authentication). + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class PrinterUriSupported extends URISyntax + implements SupportedValuesAttribute +{ + + /** + * Creates a PrinterUriSupported object. + * + * @param uri the URI value for the syntax + * @throws NullPointerException if uri is null + */ + public PrinterUriSupported(URI uri) + { + super(uri); + } + + /** + * Returns category of this class. + * + * @return The class PrinterUriSupported itself. + */ + public Class getCategory() + { + return PrinterUriSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "printer-uri-supported". + */ + public String getName() + { + return "printer-uri-supported"; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/SidesSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/SidesSupported.java new file mode 100644 index 000000000..eff82c143 --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/SidesSupported.java @@ -0,0 +1,137 @@ +/* SidesSupported.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.javax.print.ipp.attribute.supported; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; +import javax.print.attribute.SupportedValuesAttribute; + + +/** + * SidesSupported provides the + * supported values for the sides attribute. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class SidesSupported extends EnumSyntax + implements SupportedValuesAttribute +{ + + /** Specifies that each page should be printed on one sheet. */ + public static final SidesSupported ONE_SIDED = new SidesSupported(0); + + /** + * Specifies that two following pages should be printed on the + * front and back of one sheet for binding on the long edge. + */ + public static final SidesSupported TWO_SIDED_LONG_EDGE = + new SidesSupported(1); + + /** + * Specifies that two following pages should be printed on the + * front and back of one sheet for binding on the short edge. + */ + public static final SidesSupported TWO_SIDED_SHORT_EDGE = + new SidesSupported(2); + + /** An alias constant for "two sided long edge". */ + public static final SidesSupported DUPLEX = new SidesSupported(1); + + /** An alias constant for "two sided short edge". */ + public static final SidesSupported TUMBLE = new SidesSupported(2); + + private static final String[] stringTable = { "one-sided", + "two-sided-long-edge", + "two-sided-short-edge" }; + + private static final SidesSupported[] + enumValueTable = { ONE_SIDED, TWO_SIDED_LONG_EDGE, + TWO_SIDED_SHORT_EDGE }; + + + /** + * Creates a SidesSupported object. + * + * @param value the value of the enum + */ + protected SidesSupported(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class SidesSupported itself. + */ + public Class getCategory() + { + return SidesSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "sides-supported". + */ + public String getName() + { + return "sides-supported"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/UriAuthenticationSupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/UriAuthenticationSupported.java new file mode 100644 index 000000000..dc1a29f5c --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/UriAuthenticationSupported.java @@ -0,0 +1,142 @@ +/* UriAuthenticationSupported.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.javax.print.ipp.attribute.supported; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; +import javax.print.attribute.SupportedValuesAttribute; + +/** + * UriAuthenticationSupported attribute as described in RFC 2911 section + * 4.4.2 provides the keywords (implemented as EnumSyntax) which + * authentication methods are supported by the printer object. This + * includes a value of none. + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class UriAuthenticationSupported extends EnumSyntax + implements SupportedValuesAttribute +{ + + // a keyword based attribute in IPP - int values just starting at 0 + + /** Supports no authentication - assumes anonymous process */ + public static final UriAuthenticationSupported NONE = + new UriAuthenticationSupported(0); + + /** + * The authenticated user assumed is the value of the + * "requesting-user-name" operation attribute supplied + * with the operation. + */ + public static final UriAuthenticationSupported REQUESTING_USER_NAME = + new UriAuthenticationSupported(1); + + /** Supports HTTP basic authentication (RFC 2617) */ + public static final UriAuthenticationSupported BASIC = + new UriAuthenticationSupported(2); + + /** Supports HTTP digest authentication (RFC 2617) */ + public static final UriAuthenticationSupported DIGEST = + new UriAuthenticationSupported(3); + + /** Supports authentication through a client provided certificate */ + public static final UriAuthenticationSupported CERTIFICATE = + new UriAuthenticationSupported(4); + + private static final String[] stringTable = { "none", + "requesting-user-name", + "basic", "digest", + "certificate" }; + + private static final UriAuthenticationSupported[] enumValueTable = + { NONE, REQUESTING_USER_NAME, BASIC, DIGEST, CERTIFICATE }; + + /** + * Constructs a UriAuthenticationSupported object. + * + * @param value the enum value + */ + public UriAuthenticationSupported(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class UriAuthenticationSupported itself. + */ + public Class getCategory() + { + return UriAuthenticationSupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "uri-authentication-supported". + */ + public String getName() + { + return "uri-authentication-supported"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } + +} diff --git a/libjava/classpath/gnu/javax/print/ipp/attribute/supported/UriSecuritySupported.java b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/UriSecuritySupported.java new file mode 100644 index 000000000..03396978f --- /dev/null +++ b/libjava/classpath/gnu/javax/print/ipp/attribute/supported/UriSecuritySupported.java @@ -0,0 +1,127 @@ +/* UriSecuritySupported.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.javax.print.ipp.attribute.supported; + +import javax.print.attribute.Attribute; +import javax.print.attribute.EnumSyntax; +import javax.print.attribute.SupportedValuesAttribute; + +/** + * UriSecuritySupported attribute as described in RFC 2911 section + * 4.4.3 provides the keywords (implemented as EnumSyntax) for + * the security mechanisms supported by the corresponding uri's + * supported (same place in setOf). + * + * @author Wolfgang Baer (WBaer@gmx.de) + */ +public final class UriSecuritySupported extends EnumSyntax + implements SupportedValuesAttribute +{ + + // a keyword based attribute in IPP - int values just starting at 0 + + /** The URI has no secure communication */ + public static final UriSecuritySupported NONE = + new UriSecuritySupported(0); + + /** The URI has SSL3 communication */ + public static final UriSecuritySupported SSL3 = + new UriSecuritySupported(1); + + /** The URI has TLS (RFC 2246) communication */ + public static final UriSecuritySupported TLS = + new UriSecuritySupported(2); + + private static final String[] stringTable = { "none", "ssl3", "tls" }; + + private static final UriSecuritySupported[] enumValueTable = { NONE, + SSL3, TLS }; + + /** + * Constructs a UriSecuritySupported object. + * + * @param value the enum value + */ + public UriSecuritySupported(int value) + { + super(value); + } + + /** + * Returns category of this class. + * + * @return The class UriSecuritySupported itself. + */ + public Class getCategory() + { + return UriSecuritySupported.class; + } + + /** + * Returns the name of this attribute. + * + * @return The name "uri-security-supported". + */ + public String getName() + { + return "uri-security-supported"; + } + + /** + * Returns a table with the enumeration values represented as strings + * for this object. + * + * @return The enumeration values as strings. + */ + protected String[] getStringTable() + { + return stringTable; + } + + /** + * Returns a table with the enumeration values for this object. + * + * @return The enumeration values. + */ + protected EnumSyntax[] getEnumValueTable() + { + return enumValueTable; + } + +} diff --git a/libjava/classpath/gnu/javax/rmi/CORBA/CorbaInput.java b/libjava/classpath/gnu/javax/rmi/CORBA/CorbaInput.java new file mode 100644 index 000000000..5880c85c5 --- /dev/null +++ b/libjava/classpath/gnu/javax/rmi/CORBA/CorbaInput.java @@ -0,0 +1,297 @@ +/* CorbaInput.java -- + 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.rmi.CORBA; + +import gnu.CORBA.CDR.gnuRuntime; + +import org.omg.CORBA_2_3.portable.InputStream; + +import java.io.DataInputStream; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectInputStream; +import java.io.Serializable; + +/** + * Converts calls on java ObjectOutputStream to calls on CORBA OutputStream. A + * class to substitute for objects using readObject method. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class CorbaInput + extends ObjectInputStream + implements ObjectInput +{ + + /** + * The underlying CORBA stream from where the actual input is taken. + */ + public InputStream stream; + + /** + * The utility class to write the object fields in default way. + */ + final RmiUtilities util; + + /** + * The object currently being read. + */ + Object current; + + /** + * The offset of the object currently being read. + */ + int offset; + + /** + * The repository id of the object currently being read. + */ + String rid; + + /** + * The runtime, related to the object currently being read. + */ + gnuRuntime runtime; + + /** + * Create an instance, delegating calls to the given CORBA stream. + */ + public CorbaInput(InputStream an_input, Object firstObject, + RmiUtilities an_util, int an_offset, String a_rid, + gnuRuntime a_runtime) + throws Exception + { + stream = an_input; + current = firstObject; + util = an_util; + + offset = an_offset; + rid = a_rid; + runtime = a_runtime; + } + + /** @inheritDoc */ + public int available() + throws IOException + { + return stream.available(); + } + + /** + * No action. + */ + public void close() + throws IOException + { + } + + /** @inheritDoc */ + public void defaultReadObject() + throws IOException, ClassNotFoundException + { + util.readFields(offset, rid, (Serializable) current, stream, runtime); + } + + /** @inheritDoc */ + public void mark(int readlimit) + { + stream.mark(readlimit); + } + + /** @inheritDoc */ + public boolean markSupported() + { + return stream.markSupported(); + } + + /** @inheritDoc */ + public int read() + throws IOException + { + return stream.read(); + } + + /** @inheritDoc */ + public int read(byte[] buf, int off, int len) + throws IOException + { + return stream.read(buf, off, len); + } + + /** @inheritDoc */ + public int read(byte[] b) + throws IOException + { + return stream.read(b); + } + + /** @inheritDoc */ + public boolean readBoolean() + throws IOException + { + return stream.read_boolean(); + } + + /** @inheritDoc */ + public byte readByte() + throws IOException + { + return (byte) stream.read(); + } + + /** @inheritDoc */ + public char readChar() + throws IOException + { + return stream.read_char(); + } + + /** @inheritDoc */ + public double readDouble() + throws IOException + { + return stream.read_double(); + } + + /** @inheritDoc */ + public float readFloat() + throws IOException + { + return stream.read_float(); + } + + /** @inheritDoc */ + public void readFully(byte[] buf, int off, int len) + throws IOException + { + // This class only reads from the buffered streams. + stream.read(buf, off, len); + } + + /** @inheritDoc */ + public void readFully(byte[] buf) + throws IOException + { + // This class only reads from the buffered streams. + stream.read(buf); + } + + /** @inheritDoc */ + public int readInt() + throws IOException + { + return stream.read_long(); + } + + /** @inheritDoc */ + public String readLine() + throws IOException + { + return new DataInputStream(this).readLine(); + } + + /** @inheritDoc */ + public long readLong() + throws IOException + { + return stream.read_longlong(); + } + + /** @inheritDoc */ + public short read_short() + throws IOException + { + return stream.read_short(); + } + + /** @inheritDoc */ + public int readUnsignedByte() + throws IOException + { + return (stream.read() & 0xFF); + } + + /** @inheritDoc */ + public int readUnsignedShort() + throws IOException + { + return (stream.read_short() & 0xFFFF); + } + + /** + * Read as wide string (not as UTF). + */ + public String readUTF() + throws IOException + { + return stream.read_wstring(); + } + + /** @inheritDoc */ + public void reset() + throws IOException + { + stream.reset(); + } + + /** @inheritDoc */ + public long skip(long n) + throws IOException + { + return stream.skip(n); + } + + /** @inheritDoc */ + public int skipBytes(int len) + throws IOException + { + return (int) stream.skip(len); + } + + /** + * Objects are read as abstract interfaces. + */ + protected Object readObjectOverride() + throws IOException, ClassNotFoundException + { + current = stream.read_abstract_interface(); + return current; + } + +} diff --git a/libjava/classpath/gnu/javax/rmi/CORBA/CorbaOutput.java b/libjava/classpath/gnu/javax/rmi/CORBA/CorbaOutput.java new file mode 100644 index 000000000..1d1480511 --- /dev/null +++ b/libjava/classpath/gnu/javax/rmi/CORBA/CorbaOutput.java @@ -0,0 +1,219 @@ +/* CorbaOutput.java -- + 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.rmi.CORBA; + +import org.omg.CORBA_2_3.portable.OutputStream; + +import java.io.IOException; +import java.io.ObjectOutput; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +/** + * A class to substitute as an ObjectOutputStream for objects using writeObject + * method. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class CorbaOutput + extends ObjectOutputStream + implements ObjectOutput +{ + /** + * A CORBA stream where the output is forwarded. + */ + final OutputStream stream; + + /** + * The utility class to write the object fields in default way. + */ + final RmiUtilities util; + + /** + * The object currently being written. + */ + Object current; + + /** + * Create an instance, delegating calls to the given CORBA stream. + */ + public CorbaOutput(OutputStream an_output, Object firstObject, + RmiUtilities an_util) + throws Exception + { + stream = an_output; + current = firstObject; + util = an_util; + } + + /** + * No action. + */ + public void close() + throws IOException + { + } + + /** @inheritDoc */ + public void flush() + throws IOException + { + stream.flush(); + } + + /** @inheritDoc */ + public void write(byte[] buf, int off, int len) + throws IOException + { + stream.write(buf, off, len); + } + + /** @inheritDoc */ + public void write(byte[] buf) + throws IOException + { + stream.write(buf); + } + + /** @inheritDoc */ + public void write(int val) + throws IOException + { + stream.write(val); + } + + /** @inheritDoc */ + public void writeBoolean(boolean val) + throws IOException + { + stream.write_boolean(val); + } + + /** @inheritDoc */ + public void writeByte(int val) + throws IOException + { + stream.write(val); + } + + /** @inheritDoc */ + public void writeBytes(String str) + throws IOException + { + stream.write_string(str); + } + + /** @inheritDoc */ + public void writeChar(int val) + throws IOException + { + stream.write_wchar((char) val); + } + + /** @inheritDoc */ + public void writeChars(String str) + throws IOException + { + stream.write_char_array(str.toCharArray(), 0, str.length()); + } + + /** @inheritDoc */ + public void writeDouble(double val) + throws IOException + { + stream.write_double(val); + } + + /** @inheritDoc */ + public void writeFloat(float val) + throws IOException + { + stream.write_float(val); + } + + /** @inheritDoc */ + public void writeInt(int val) + throws IOException + { + stream.write_long(val); + } + + /** @inheritDoc */ + public void writeLong(long val) + throws IOException + { + stream.write_longlong(val); + } + + /** + * Objects are written as abstract interfaces. + */ + protected void writeObjectOverride(Object obj) + throws IOException + { + current = obj; + stream.write_abstract_interface(obj); + } + + /** @inheritDoc */ + public void writeShort(int val) + throws IOException + { + stream.write_short((short) val); + } + + /** + * Such strings are written as wide strings, not as UTF. + */ + public void writeUTF(String str) + throws IOException + { + stream.write_wstring(str); + } + + /** + * @inheritDoc + */ + public void defaultWriteObject() + throws IOException + { + util.writeFields(stream, (Serializable) current); + } + +} diff --git a/libjava/classpath/gnu/javax/rmi/CORBA/DefaultWriteObjectTester.java b/libjava/classpath/gnu/javax/rmi/CORBA/DefaultWriteObjectTester.java new file mode 100644 index 000000000..b925428b0 --- /dev/null +++ b/libjava/classpath/gnu/javax/rmi/CORBA/DefaultWriteObjectTester.java @@ -0,0 +1,85 @@ +/* DefaultWriteObjectTester.java -- + 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.rmi.CORBA; + +import gnu.CORBA.CDR.BufferedCdrOutput; + +import java.io.IOException; + +/** + * Tests if the defaultWriteObject method has been called. + * This information is required by RMI-IIOP header. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class DefaultWriteObjectTester + extends CorbaOutput +{ + /** + * The flag, indicating, that the defaultWriteObject method was called. + */ + public boolean dwo_called; + + /** + * Create an instance, delegating calls to the given CORBA stream. + */ + public DefaultWriteObjectTester(Object firstObject) + throws Exception + { + super(new BufferedCdrOutput(), firstObject, null); + } + + /** + * Set the flag that defaultWriteObject was called. + */ + public void defaultWriteObject() + throws IOException + { + dwo_called = true; + } + + /** + * Do not write other objects. + */ + protected void writeObjectOverride(Object obj) + throws IOException + { + } + +} diff --git a/libjava/classpath/gnu/javax/rmi/CORBA/DelegateFactory.java b/libjava/classpath/gnu/javax/rmi/CORBA/DelegateFactory.java new file mode 100644 index 000000000..a12afd51e --- /dev/null +++ b/libjava/classpath/gnu/javax/rmi/CORBA/DelegateFactory.java @@ -0,0 +1,107 @@ +/* DelegateFactory.java -- + Copyright (C) 2002, 2004, 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.rmi.CORBA; + +import gnu.CORBA.ObjectCreator; + + +/** + * This class produces delegates, using the system properties. If not + * corresponding property is specified, returns default implementations. + * + * @author Wu Gansha (gansha.wu@intel.com) + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class DelegateFactory +{ + /** + * The name to get a stub delegate. + */ + public static final String STUB = "Stub"; + + /** + * The name to get the util delegate. + */ + public static final String UTIL = "Util"; + + /** + * The name to get the ValueHandler delegate. + */ + public static final String VALUEHANDLER = "ValueHandler"; + + /** + * The name to get the PortableRemoteObject delegate. + */ + public static final String PORTABLE_REMOTE_OBJECT = "PortableRemoteObject"; + + /** + * Get an instance of the given delegate. As in all cases the singleton + * instance is used, the caching here would be redundant. + * + * @param type a delegate type. + * + * @return the associated delegate. + * + * @throws InternalError if the delegate class, indicated in the system + * properties, cannot be instantiated. + */ + public static Object getInstance(String type) + throws InternalError + { + String propertyName = "javax.rmi.CORBA." + type + "Class"; + String dcname = System.getProperty(propertyName); + if (dcname == null) + { + // // No javax.rmi.CORBA.XXXClass property sepcified. + dcname = "gnu.javax.rmi.CORBA." + type + "DelegateImpl"; + } + try + { + Class dclass = ObjectCreator.forName(dcname); + return dclass.newInstance(); + } + catch (Exception e) + { + InternalError ierr = new InternalError("Exception when trying to get " + + type + "delegate instance:" + dcname); + ierr.initCause(e); + throw ierr; + } + } +} diff --git a/libjava/classpath/gnu/javax/rmi/CORBA/GetDelegateInstanceException.java b/libjava/classpath/gnu/javax/rmi/CORBA/GetDelegateInstanceException.java new file mode 100644 index 000000000..f8aca0d47 --- /dev/null +++ b/libjava/classpath/gnu/javax/rmi/CORBA/GetDelegateInstanceException.java @@ -0,0 +1,55 @@ +/* GetDelegateInstanceException.java -- + Copyright (C) 2002, 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.javax.rmi.CORBA; + +public class GetDelegateInstanceException + extends Exception +{ + private Throwable next; + + public GetDelegateInstanceException(String msg) + { + super(msg); + } + + public GetDelegateInstanceException(String msg, Throwable next) + { + super(msg, next); + } +} diff --git a/libjava/classpath/gnu/javax/rmi/CORBA/PortableRemoteObjectDelegateImpl.java b/libjava/classpath/gnu/javax/rmi/CORBA/PortableRemoteObjectDelegateImpl.java new file mode 100644 index 000000000..f430ac123 --- /dev/null +++ b/libjava/classpath/gnu/javax/rmi/CORBA/PortableRemoteObjectDelegateImpl.java @@ -0,0 +1,362 @@ +/* PortableRemoteObjectDelegateImpl.java -- + Copyright (C) 2002, 2004, 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.rmi.CORBA; + +import gnu.CORBA.SimpleDelegate; +import gnu.CORBA.Unexpected; +import gnu.CORBA.Poa.LocalDelegate; +import gnu.CORBA.Poa.ORB_1_4; +import gnu.CORBA.Poa.AOM; + +import java.rmi.NoSuchObjectException; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.server.RMIClassLoader; + +import javax.rmi.CORBA.PortableRemoteObjectDelegate; +import javax.rmi.CORBA.Stub; +import javax.rmi.CORBA.Tie; +import javax.rmi.CORBA.Util; + +import org.omg.CORBA.BAD_PARAM; +import org.omg.CORBA.ORB; +import org.omg.CORBA.portable.Delegate; +import org.omg.CORBA.portable.ObjectImpl; +import org.omg.PortableServer.POA; +import org.omg.PortableServer.POAHelper; +import org.omg.PortableServer.Servant; +import org.omg.PortableServer.POAManagerPackage.State; + +/** + * Implements PortableRemoteObjectDelegate. + * + * @author Wu Gansha (gansha.wu@intel.com) (stub) + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) (implementation) + */ +public class PortableRemoteObjectDelegateImpl + implements PortableRemoteObjectDelegate +{ + /** + *

      + * Makes the remote object a_target ready for remote + * communication using the same communications runtime as for the passed + * a_source parameter. The a_target is connected to the same + * ORB (and, if applicable, to the same POA) as the a_source. + * + * @param a_target the target to connect to ORB, must be an instance of either + * {@link ObjectImpl} (Stubs and old-style ties) or {@link Servant} (POA-bases + * ties). + * + * @param a_source the object, providing the connection information, must be + * an instance of either {@link ObjectImpl} (Stubs and old-style ties) or + * {@link Servant} (POA-bases ties). + * + * @throws RemoteException if the target is already connected to another ORB. + */ + public void connect(Remote a_target, Remote a_source) + throws RemoteException + { + ORB orb = null; + POA poa = null; + boolean ok = false; + + try + { + if (a_source instanceof Servant) + { + Servant s = (Servant) a_source; + orb = s._orb(); + poa = s._poa(); + ok = true; + } + + if (!ok && a_source instanceof ObjectImpl) + { + ObjectImpl o = (ObjectImpl) a_source; + orb = o._orb(); + ok = true; + try + { + if (orb instanceof ORB_1_4) + { + // POA information available. + ORB_1_4 xorb = (ORB_1_4) orb; + Delegate d = o._get_delegate(); + + if (d instanceof LocalDelegate) + { + LocalDelegate l = (LocalDelegate) d; + poa = l.poa; + } + else if (d instanceof SimpleDelegate) + { + byte[] ior_key = ((SimpleDelegate) d).getIor().key; + AOM.Obj ref = xorb.rootPOA.findIorKey(ior_key); + if (ref != null) + poa = ref.poa; + } + } + } + catch (Exception ex) + { + // OK, POA info is not available, but as ORB is available, we + // will connect in a default way. + } + } + } + catch (Exception ex) + { + RuntimeException rex = new RuntimeException("Unable to get info from " + + a_source); + rex.initCause(ex); + throw rex; + } + + if (!ok && a_source instanceof Tie) + { + Tie t = (Tie) a_source; + orb = t.orb(); + poa = null; + ok = true; + } + + if (orb == null) + throw new RemoteException("Unable to determine ORB from " + a_source); + + if (a_target instanceof Stub) + { + StubDelegateImpl.connect((Stub) a_target, orb, poa); + } + else if (a_target instanceof Servant) + { + try + { + if (poa == null) + { + poa = POAHelper.narrow(orb.resolve_initial_references("RootPOA")); + // Activate if not active. + if (poa.the_POAManager().get_state().value() == State._HOLDING) + poa.the_POAManager().activate(); + } + poa.servant_to_reference((Servant) a_target); + } + catch (Exception ex) + { + throw new Unexpected(ex); + } + } + else if (a_target instanceof org.omg.CORBA.Object) + { + // Connect as object. + orb.connect((org.omg.CORBA.Object) a_target); + } + else if (a_target instanceof Tie) + { + // We avoid calling this because it will aways connect to the root poa. + ((Tie) a_target).orb(orb); + } + } + + /** + * Narrow the given object to the instance of the given class. The currently + * supported narrowing types are: + * + * 1. Simple widening conversion.
      + * 2. ObjectImpl -> RMI interface.
      + * 3. ObjectImpl -> ObjectImpl.
      + * 4. Tie -> Remote (implementation)
      + * 5. Remote (implementation) -> Tie.
      + * + * The narrowing has sense only for derived classes. + */ + public Object narrow(Object narrowFrom, Class narrowTo) + throws ClassCastException + { + if (narrowTo == null) + throw new ClassCastException("Can't narrow to null class"); + else if (narrowFrom == null) + return null; + else + // Simple narrowing case. + if (narrowTo.isAssignableFrom(narrowFrom.getClass())) + return narrowFrom; + else if (narrowTo.isInterface() || narrowFrom instanceof ObjectImpl) + { + // Narrow CORBA object to passed interface. + + String interf = narrowTo.getName(); + String stubClassName; + + stubClassName = getStubClassName(interf); + + try + { + // Replace the interface class by the stub class. + narrowTo = Util.loadClass(stubClassName, null, + narrowTo.getClassLoader()); + } + catch (ClassNotFoundException e) + { + ClassCastException cex = new ClassCastException("Class not found: " + + stubClassName); + cex.initCause(e); + throw cex; + } + } + else if (narrowFrom instanceof Tie) + { + // Try to substitute the return tie target as a return value. + Remote target = ((Tie) narrowFrom).getTarget(); + if (target != null && narrowTo.isAssignableFrom(target.getClass())) + return target; + } + + Object narrowed; + try + { + narrowed = narrowTo.newInstance(); + } + catch (Exception e) + { + ClassCastException cex = new ClassCastException("Cannot instantiate " + + narrowTo.getName()); + cex.initCause(e); + throw cex; + } + + if (narrowed instanceof ObjectImpl) + { + // This also works for the instances of the Stub. + ObjectImpl target = (ObjectImpl) narrowed; + // Set the delegate, as is done in *Helper.narrow(..). + target._set_delegate(((ObjectImpl) narrowFrom)._get_delegate()); + } + else if (narrowed instanceof Tie && narrowFrom instanceof Remote) + { + // Try to set the narrowing object as a target for the Tie. + ((Tie) narrowed).setTarget((Remote) narrowFrom); + } + else + throw new ClassCastException("Narrowing of " + narrowFrom.getClass() + + " to " + narrowTo + " is either not possible or not implemented."); + + return narrowed; + } + + /** + * Get the Stub class name for the name, representing the given interface. + */ + static String getStubClassName(String interf) + { + String stubClassName; + int p = interf.lastIndexOf('.'); + + if (p < 0) + // The interface is defined in the default package. + stubClassName = "_" + interf + "_Stub"; + else + stubClassName = interf.substring(0, p + 1) + "_" + + interf.substring(p + 1) + "_Stub"; + return stubClassName; + } + + /** + * Get stub for the given implementation, searching by class name pattern. The + * found stub must implement Remote for this method to succeed. + */ + public Remote toStub(Remote ObjImpl) + throws NoSuchObjectException + { + String icn = ObjImpl.getClass().getName(); + if (!icn.endsWith("Impl")) + throw new BAD_PARAM("Invalid class name '" + icn + + "', must end with 'Impl'"); + + String sn = "_" + icn.substring(0, icn.length() - "Impl".length()) + + "_Stub"; + + Class stubClass; + Object o_stub; + + try + { + stubClass = RMIClassLoader.loadClass(sn); + o_stub = stubClass.newInstance(); + } + catch (Exception e) + { + NoSuchObjectException n = new NoSuchObjectException(sn); + n.initCause(e); + throw n; + } + + if (!Remote.class.isAssignableFrom(stubClass)) + throw new ClassCastException(stubClass.getName() + + " exists but cannot be returned as it does not inherit from " + + Remote.class.getName()); + + return (Remote) o_stub; + } + + /** + * If the object tie is no longer in use, disconnet it from the orb. + */ + public void unexportObject(Remote obj) + throws NoSuchObjectException + { + Util.unexportObject(obj); + } + + /** + * Find or create a tie for this target and mark it as being used by the given + * object. + */ + public void exportObject(Remote obj) + throws RemoteException + { + if (obj instanceof Stub) + Util.registerTarget(StubDelegateImpl.getTieFromStub((Stub) obj), obj); + else if (obj instanceof Tie) + { + Tie t = (Tie) obj; + Util.registerTarget(t, null); + } + } + +} diff --git a/libjava/classpath/gnu/javax/rmi/CORBA/RmiUtilities.java b/libjava/classpath/gnu/javax/rmi/CORBA/RmiUtilities.java new file mode 100644 index 000000000..ac6b90705 --- /dev/null +++ b/libjava/classpath/gnu/javax/rmi/CORBA/RmiUtilities.java @@ -0,0 +1,949 @@ +/* RmiUtilities.java -- + 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.rmi.CORBA; + +import gnu.CORBA.OrbFunctional; +import gnu.CORBA.Minor; +import gnu.CORBA.Unexpected; +import gnu.CORBA.CDR.Vio; +import gnu.CORBA.CDR.gnuRuntime; +import gnu.CORBA.CDR.gnuValueStream; +import gnu.CORBA.CDR.HeadlessInput; + +import gnu.java.lang.CPStringBuilder; + +import org.omg.CORBA.MARSHAL; +import org.omg.CORBA.StringValueHelper; +import org.omg.CORBA.WStringValueHelper; +import org.omg.CORBA.portable.Delegate; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.ObjectImpl; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.ValueBase; +import org.omg.PortableServer.POA; +import org.omg.PortableServer.POAHelper; +import org.omg.PortableServer.Servant; +import org.omg.PortableServer.POAManagerPackage.State; +import org.omg.SendingContext.RunTime; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.rmi.Remote; +import java.security.MessageDigest; +import java.util.Arrays; +import java.util.Comparator; +import java.util.Iterator; +import java.util.TreeSet; +import java.util.WeakHashMap; + +import javax.rmi.PortableRemoteObject; +import javax.rmi.CORBA.Stub; +import javax.rmi.CORBA.Tie; +import javax.rmi.CORBA.Util; + +/** + * Defines methods that must be accessible in several derived classes. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class RmiUtilities +{ + /** + * The currently used RMI-IIOP version format. + */ + public static byte VERSION = 1; + + /** + * The non - writable class fields. + */ + static final int NON_WRITABLE = Modifier.STATIC | Modifier.TRANSIENT; + + /** + * The standard String repository Id. + */ + public static final String RMI_STRING_ID = StringValueHelper.id(); + + /** + * The standard Class repository Id. + */ + public static final String RMI_CLASS_ID = "RMI:javax.rmi.CORBA.ClassDesc:2BABDA04587ADCCC:CFBF02CF5294176B"; + + /** + * The standard string array repository Id. + */ + public static final String RMI_STRING_ARRAY_ID = "RMI:[Ljava.lang.String;:071DA8BE7F971128:A0F0A4387A3BB342"; + + /** + * An instance of the wide string value helper for writing strings. + */ + static WStringValueHelper wStringValueHelper = new WStringValueHelper(); + + /** + * Set of serializable classes that have .writeObject and .readObject defined. + * Contains weak references to ensure that the classes will be unloadable. + */ + WeakHashMap io_format = new WeakHashMap(); + + /** + * The standard IO format with no .writeObject and .readObject defined. + */ + static final Object STANDARD = new Object(); + + /** + * The custom IO format with .writeObject and .readObject defined, + * defaultWriteObject called. + */ + static final Object CUSTOM_DWO = new Object(); + + /** + * The custom IO format with .writeObject and .readObject defined, + * defaultWriteObject has not been called. + */ + static final Object CUSTOM_NO_DWO = new Object(); + + /** + * The arguments for readObject. + */ + static final Class[] READ_OBJECT_ARGS = new Class[] { ObjectInputStream.class }; + + /** + * The arguments for writeObject. + */ + static final Class[] WRITE_OBJECT_ARGS = new Class[] { ObjectOutputStream.class }; + + /** + * The undocumented field that is heading the Sun's object data, written with + * writeObject. + */ + static final int S_X = 16908034; + + /** + * Write all fields of the passed value. + */ + void writeFields(OutputStream an_output, Serializable object) + { + org.omg.CORBA_2_3.portable.OutputStream output = (org.omg.CORBA_2_3.portable.OutputStream) an_output; + try + { + Class o_class = object.getClass(); + Field[] fields = getWritableFields(o_class); + Field f; + + Class fc; + + for (int i = 0; i < fields.length; i++) + { + f = fields[i]; + fc = f.getType(); + Object v = f.get(object); + + if (fc == String.class) + { + output.write_value((Serializable) v, wStringValueHelper); + } + else if (fc == int.class) + output.write_long(((Integer) v).intValue()); + else if (fc == long.class) + output.write_longlong(((Number) v).longValue()); + else if (fc == double.class) + output.write_double(((Number) v).doubleValue()); + else if (fc == float.class) + output.write_float(((Number) v).floatValue()); + else if (fc == boolean.class) + output.write_boolean(((Boolean) v).booleanValue()); + else if (fc == short.class) + output.write_short(((Number) v).shortValue()); + else if (fc == byte.class) + output.write_octet(((Number) v).byteValue()); + else if (fc == char.class) + output.write_wchar(((Character) v).charValue()); + else + { + if (!fc.isInterface() && Remote.class.isAssignableFrom(fc)) + fc = getExportedInterface(fc); + writeMember(output, v, fc); + } + } + } + catch (Exception ex) + { + MARSHAL m = new MARSHAL("Cannot write " + object); + m.minor = Minor.ValueFields; + m.initCause(ex); + throw m; + } + } + + /** + * Write a memeber (field) of the data structure. + */ + void writeMember(org.omg.CORBA_2_3.portable.OutputStream output, + Object object, Class xClass) + { + if (output instanceof gnuValueStream) + { + gnuRuntime g = ((gnuValueStream) output).getRunTime(); + // Reset the target as we are already beyond the critical point + // where is must have the value being written. + if (g != null) + g.target = null; + } + if (Serializable.class.isAssignableFrom(xClass) + || Remote.class.isAssignableFrom(xClass)) + { + // Object handles null reference on its own. + if (org.omg.CORBA.Object.class.isAssignableFrom(xClass) + || Remote.class.isAssignableFrom(xClass)) + { + if (object == null) + output.write_Object(null); + else if (isTieRequired(object)) + exportTie(output, object, xClass); + else + writeValue(output, (Serializable) object); + } + else + output.write_value((Serializable) object, xClass); + } + else + { + MARSHAL m = new MARSHAL(xClass + " is not Serializable"); + m.minor = Minor.NonSerializable; + throw m; + } + } + + /** + * Check if the object must be wrapped into Tie, connected to the ORB and then + * the corresponding Stub be written. + */ + public boolean isTieRequired(Object object) + { + return object instanceof Remote && !(object instanceof Stub); + } + + /** + * Get the interface under that the class of this object must be exposed. The + * interface must be derived from Remote. + */ + Class getExportedInterface(Object object) + throws MARSHAL + { + Class fc = null; + Class[] interfaces = object.getClass().getInterfaces(); + for (int i = 0; i < interfaces.length; i++) + { + if (!Remote.class.equals(interfaces[i])) + if (Remote.class.isAssignableFrom(interfaces[i])) + { + if (fc == null) + fc = interfaces[i]; + else + { + MARSHAL m = new MARSHAL("Both " + fc + " and " + interfaces[i] + + " extends Remote"); + m.minor = Minor.TargetConversion; + throw m; + } + } + } + if (fc == null) + { + MARSHAL m = new MARSHAL(object.getClass() + + " does not implement any interface, derived from Remote"); + m.minor = Minor.TargetConversion; + throw m; + } + return fc; + } + + /** + * Get the persistent hash code for the given class, as defined by OMG + * standard. The inheritance, field names and types (but not the visibility) + * are taken into consideration as well as the presence of the writeObject + * method are taken into consideration. The class name and methods, if any, + * are not taken into consideration. + */ + public static long getHashCode(Class c) + { + Class of = c.isArray() ? c.getComponentType() : null; + if (c.isArray() + && ((!Serializable.class.isAssignableFrom(of) || of.isPrimitive() || Remote.class.isAssignableFrom(of)))) + return 0; + if (!Serializable.class.isAssignableFrom(c)) + return 0; + try + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(bout); + + Class superClass = c.getSuperclass(); + if (superClass != null) + out.writeLong(getHashCode(superClass)); + + int writeObjectPresentCode; + try + { + c.getDeclaredMethod("writeObject", + new Class[] { ObjectOutputStream.class }); + writeObjectPresentCode = 2; // Exists. + } + catch (NoSuchMethodException e) + { + writeObjectPresentCode = 1; // Missing. + } + out.writeInt(writeObjectPresentCode); + + Field[] fields = c.getDeclaredFields(); + + Arrays.sort(fields, new Comparator() + { + public int compare(Object a, Object b) + { + Field fa = (Field) a; + Field fb = (Field) b; + return fa.getName().compareTo(fb.getName()); + } + }); + + Field f; + for (int i = 0; i < fields.length; i++) + { + f = fields[i]; + if ((f.getModifiers() & NON_WRITABLE) == 0) + { + out.writeUTF(f.getName()); + out.writeUTF(getDescriptor(f.getType())); + } + } + + out.flush(); + out.close(); + MessageDigest shaDigest; + try + { + shaDigest = MessageDigest.getInstance("SHA"); + } + catch (Exception ex) + { + throw new InternalError("SHA digesting algorithm is not available"); + } + + // Return the digest value to the calling + // method as an array of bytes. + byte[] sha = shaDigest.digest(bout.toByteArray()); + + long hash = 0; + for (int i = 0; i < Math.min(8, sha.length); i++) + { + hash += (long) (sha[i] & 255) << (i * 8); + } + return hash; + } + catch (IOException ioex) + { + throw new Unexpected(ioex); + } + } + + /** + * Converts to hexadecimal string, supplementing leading zeros. + */ + public static String toHex(long l) + { + CPStringBuilder b = new CPStringBuilder(); + b.append(Long.toHexString(l).toUpperCase()); + while (b.length() < 16) + b.insert(0, '0'); + return b.toString(); + } + + /** + * Returns a String representing the type-encoding of a class. + */ + static String getDescriptor(Class type) + { + if (type.equals(boolean.class)) + return "Z"; + if (type.equals(byte.class)) + return "B"; + if (type.equals(short.class)) + return "S"; + if (type.equals(char.class)) + return "C"; + if (type.equals(int.class)) + return "I"; + if (type.equals(long.class)) + return "J"; + if (type.equals(float.class)) + return "F"; + if (type.equals(double.class)) + return "D"; + if (type.equals(void.class)) + return "V"; + else if (type.isArray()) + { + CPStringBuilder l = new CPStringBuilder("["); + Class component = type.getComponentType(); + + while (component.isArray()) + { + l.append('['); + component = component.getComponentType(); + } + + l.append('L'); + l.append(component.getName().replace('.', '/')); + l.append(';'); + return l.toString(); + } + else + return "L" + type.getName().replace('.', '/') + ';'; + } + + public static Field[] getWritableFields(Class c) + { + TreeSet set = new TreeSet(new Comparator() + { + public int compare(Object a, Object b) + { + return ((Field) a).getName().compareTo(((Field) b).getName()); + } + }); + + while (!c.equals(Object.class)) + { + Field[] f = c.getDeclaredFields(); + for (int i = 0; i < f.length; i++) + { + if ((f[i].getModifiers() & NON_WRITABLE) == 0) + { + f[i].setAccessible(true); + set.add(f[i]); + } + } + c = c.getSuperclass(); + } + + Field[] r = new Field[set.size()]; + int p = 0; + Iterator it = set.iterator(); + while (it.hasNext()) + { + r[p++] = (Field) it.next(); + } + return r; + } + + /** + * The method is called for Remotes that are not Stubs. It is assumed, that + * the Remote is an implementation. The method searches for the suitable tie + * and, if found, exports it by creating and connecting the stub. Such export + * is supported since jdk 1.5. + */ + void exportTie(org.omg.CORBA_2_3.portable.OutputStream output, + Object implementation, Class interfaceClass) + { + try + { + // Remote, but non - stub class (implementation) + // must be replaced by stub. + Tie t = Util.getTie((Remote) implementation); + if (t instanceof Servant) + { + POA rootPoa = POAHelper.narrow(output.orb().resolve_initial_references( + "RootPOA")); + org.omg.CORBA.Object co = rootPoa.servant_to_reference((Servant) t); + Stub stub = (Stub) PortableRemoteObject.narrow(co, interfaceClass); + writeRemoteObject(output, stub); + + if (rootPoa.the_POAManager().get_state().value() == State._HOLDING) + rootPoa.the_POAManager().activate(); + } + else if (t instanceof org.omg.CORBA.Object) + { + org.omg.CORBA.Object co = (org.omg.CORBA.Object) t; + output.orb().connect(co); + + Stub stub = (Stub) PortableRemoteObject.narrow(co, interfaceClass); + writeRemoteObject(output, stub); + } + } + catch (Exception ex) + { + MARSHAL m = new MARSHAL("Unable to export " + implementation); + m.minor = Minor.TargetConversion; + m.initCause(ex); + throw m; + } + } + + /** + * Start the ORB, if it is not already runnning. + */ + void ensureOrbRunning(org.omg.CORBA_2_3.portable.OutputStream output) + { + // Ensure ORB is running. + if (output.orb() instanceof OrbFunctional) + { + ((OrbFunctional) output.orb()).ensureRunning(); + } + } + + /** + * Write data to the CORBA output stream. Writes the object contents only; the + * header must be already written. For object, containing objects, may be + * called recursively. + * + * @param an_output a stream to write to, must be + * org.omg.CORBA_2_3.portable.OutputStream + * @param object an object to write. + */ + public void writeRemoteObject(OutputStream an_output, Object object) + { + org.omg.CORBA_2_3.portable.OutputStream output = (org.omg.CORBA_2_3.portable.OutputStream) an_output; + + if (isTieRequired(object)) + { + // Find the interface that is implemented by the object and extends + // Remote. + Class fc = getExportedInterface(object); + exportTie(output, object, fc); + } + else if (object instanceof org.omg.CORBA.Object) + { + ensureOrbRunning(output); + an_output.write_Object((org.omg.CORBA.Object) object); + } + else if (object != null && object instanceof Serializable) + writeFields(an_output, (Serializable) object); + } + + /** + * Write data to the CORBA output stream. Writes the object contents only; the + * header must be already written. For object, containing objects, may be + * called recursively. + * + * @param an_output a stream to write to, must be + * org.omg.CORBA_2_3.portable.OutputStream + * @param object an object to write. + */ + public void writeValue(OutputStream an_output, Serializable object) + { + org.omg.CORBA_2_3.portable.OutputStream output = (org.omg.CORBA_2_3.portable.OutputStream) an_output; + + if (isTieRequired(object)) + { + // Find the interface that is implemented by the object and extends + // Remote. + Class fc = getExportedInterface(object); + exportTie(output, object, fc); + } + else if (object instanceof org.omg.CORBA.Object) + { + ensureOrbRunning(output); + an_output.write_Object((org.omg.CORBA.Object) object); + } + else if (object instanceof Externalizable) + { + try + { + ObjectOutputStream stream = new CorbaOutput(output, object, + this); + stream.write(VERSION); + ((Externalizable) object).writeExternal(stream); + } + catch (Exception ex) + { + MARSHAL m = new MARSHAL("writeExternal failed"); + m.minor = Minor.Value; + m.initCause(ex); + throw m; + } + } + else if (object instanceof Serializable) + { + Object mode = null; + synchronized (io_format) + { + mode = io_format.get(object.getClass()); + if (mode == STANDARD) + { + writeFields(an_output, (Serializable) object); + return; + } + } + try + { + Method m = object.getClass().getDeclaredMethod("writeObject", + WRITE_OBJECT_ARGS); + m.setAccessible(true); // May be private. + + try + { + ObjectOutputStream stream = new CorbaOutput(output, + object, this); + + // Write version. + stream.write(VERSION); + + if (mode == CUSTOM_DWO) + // Write true, supposing that the defaultWriteObject + // has been called. + stream.write(1); + else if (mode == CUSTOM_NO_DWO) + // Write false (has not been called) + stream.write(0); + else + { + // Measure. + DefaultWriteObjectTester tester = new DefaultWriteObjectTester(object); + m.invoke(object, new Object[] { tester }); + + synchronized (io_format) + { + io_format.put(object.getClass(), + tester.dwo_called ? CUSTOM_DWO : CUSTOM_NO_DWO); + stream.write(tester.dwo_called ? 1 : 0); + } + } + + m.invoke(object, new Object[] { stream }); + stream.flush(); + } + catch (Exception ex) + { + MARSHAL mx = new MARSHAL(object.getClass().getName() + + ".writeObject failed"); + mx.initCause(ex); + throw mx; + } + } + catch (NoSuchMethodException e) + { + // Write in a standard way. + writeFields(an_output, (Serializable) object); + synchronized (io_format) + { + io_format.put(object.getClass(), STANDARD); + } + } + } + } + + /** + * Read data from the CDR input stream. Reads the object contents only; the + * header must be already read (the repository id or ids ara passed). For + * object, containing objects, may be called recursively. + * + * @param an_input the stream to read from, must be + * org.omg.CORBA_2_3.portable.InputStream + * @param object the instance of the object being read. + * @param id the repository Id from the stream in the case when single id was + * specified. + * @param ids the repository Ids from the stream in the case when multiple ids + * were specified. + * @param codebase the codebase, if it was included in the header of the value + * type. Null if not codebase was included. + * + * @return the object, extracted from the stream. + */ + /** + * Read value from the input stream in the case when the value is not + * Streamable or CustomMarshalled. + */ + public Serializable readValue(InputStream in, int offset, Class clz, + String repositoryID, RunTime sender) + { + if (in instanceof HeadlessInput) + ((HeadlessInput) in).subsequentCalls = true; + + gnuRuntime g = null; + Serializable object = null; + + try + { + g = (gnuRuntime) sender; + if (sender != null) + object = g.target; + } + catch (ClassCastException e) + { + // Working with the other CORBA implementation. + g = null; + } + + org.omg.CORBA_2_3.portable.InputStream input = (org.omg.CORBA_2_3.portable.InputStream) in; + + if (Remote.class.isAssignableFrom(clz) + || ValueBase.class.isAssignableFrom(clz)) + { + // Interface is narrowed into Stub. + if (clz.isInterface()) + try + { + clz = Util.loadClass( + PortableRemoteObjectDelegateImpl.getStubClassName(clz.getName()), + null, clz.getClassLoader()); + } + catch (ClassNotFoundException e) + { + MARSHAL m = new MARSHAL("Cannot get stub from interface " + + clz.getClass().getName()); + m.minor = Minor.TargetConversion; + m.initCause(e); + throw m; + } + + // Remote needs special handling. + if (ObjectImpl.class.isAssignableFrom(clz)) + { + // First read CORBA object reference. + Object ro = input.read_Object(); + + ObjectImpl obj = (ObjectImpl) ro; + if (obj == null) + return null; + + Delegate delegate = obj._get_delegate(); + object = instantiate(offset, clz, g); + ((ObjectImpl) object)._set_delegate(delegate); + } + // The object - specific data follows. + } + else if (org.omg.CORBA.Object.class.isAssignableFrom(clz)) + object = (Serializable) input.read_Object(); + + if (object == null) + object = instantiate(offset, clz, g); + + // The sentence below prevents attempt to read the internal fields of the + // ObjectImpl (or RMI Stub) that might follow the object definition. + // Sun's jre 1.5 does not write this information. The stubs, generated + // by rmic, does not contain such fields. + if (object instanceof ObjectImpl) + return object; + + if (object instanceof Externalizable) + { + try + { + CorbaInput stream = new CorbaInput(input, object, this, + offset, repositoryID, g); + + byte version = stream.readByte(); + if (version != 1) + throw new MARSHAL("Unsuported RMI-IIOP version " + version); + + ((Externalizable) object).readExternal(stream); + } + catch (Exception ex) + { + MARSHAL m = new MARSHAL("readExternal failed"); + m.initCause(ex); + throw m; + } + } + else + { + Object mode = null; + synchronized (io_format) + { + mode = io_format.get(object.getClass()); + } + + if (mode == STANDARD) + { + readFields(offset, repositoryID, object, input, g); + } + else + { + try + { + Method m = object.getClass().getDeclaredMethod("readObject", + READ_OBJECT_ARGS); + try + { + m.setAccessible(true); // May be private. + + CorbaInput stream = new CorbaInput(input, + object, this, offset, repositoryID, g); + + byte version = stream.readByte(); + if (version != 1) + throw new MARSHAL("Unsuported RMI-IIOP version " + + version); + + // This would indicate is defaultWriteObject has been + // called, + // but the readObject method normally takes care about this. + boolean dwo = stream.readByte() != 0; + + m.invoke(object, new Object[] { stream }); + synchronized (io_format) + { + io_format.put(object.getClass(), dwo ? CUSTOM_DWO + : CUSTOM_NO_DWO); + } + } + catch (Exception ex) + { + ex.printStackTrace(); + MARSHAL mx = new MARSHAL(object.getClass().getName() + + ".readObject failed"); + mx.initCause(ex); + throw mx; + } + } + catch (NoSuchMethodException e) + { + // Read in a standard way. + synchronized (io_format) + { + io_format.put(object.getClass(), STANDARD); + readFields(offset, repositoryID, object, input, g); + } + } + } + } + return object; + } + + /** + * Create an instance. + */ + Serializable instantiate(int offset, Class clz, gnuRuntime g) + throws MARSHAL + { + Serializable object; + try + { + object = (Serializable) Vio.instantiateAnyWay(clz); + g.objectWritten(object, offset); + } + catch (Exception e) + { + MARSHAL m = new MARSHAL("Unable to instantiate " + clz); + m.minor = Minor.Instantiation; + m.initCause(e); + throw m; + } + return object; + } + + /** + * Read fields of the object. + */ + void readFields(int offset, String repositoryID, Serializable object, + org.omg.CORBA_2_3.portable.InputStream input, gnuRuntime r) + throws MARSHAL + { + Field f = null; + Class o_class = object.getClass(); + + try + { + // The returned field array must already be in canonical order. + Field[] fields = getWritableFields(o_class); + + Class fc; + + for (int i = 0; i < fields.length; i++) + { + // Full value type header expected ahead. + if (input instanceof HeadlessInput) + ((HeadlessInput) input).subsequentCalls = true; + + f = fields[i]; + fc = f.getType(); + + Object v; + + if (fc == String.class) + { + v = input.read_value(wStringValueHelper); + } + else if (fc == int.class) + v = new Integer(input.read_long()); + else if (fc == long.class) + v = new Long(input.read_longlong()); + else if (fc == double.class) + v = new Double(input.read_double()); + else if (fc == float.class) + v = new Float(input.read_float()); + else if (fc == boolean.class) + v = input.read_boolean() ? Boolean.TRUE : Boolean.FALSE; + else if (fc == short.class) + v = new Short(input.read_short()); + else if (fc == byte.class) + v = new Byte(input.read_octet()); + else if (fc == char.class) + v = new Character(input.read_char()); + else if (org.omg.CORBA.Object.class.isAssignableFrom(fc) + || Remote.class.isAssignableFrom(fc)) + { + v = readValue(input, offset, fc, null, r); + } + else + { + v = Vio.read(input, fc); + } + + f.set(object, v); + } + } + catch (Exception ex) + { + MARSHAL m = new MARSHAL("Cannot read " + o_class.getName() + " field " + + f); + m.initCause(ex); + m.minor = Minor.ValueFields; + throw m; + } + } + +} diff --git a/libjava/classpath/gnu/javax/rmi/CORBA/StubDelegateImpl.java b/libjava/classpath/gnu/javax/rmi/CORBA/StubDelegateImpl.java new file mode 100644 index 000000000..05c73a709 --- /dev/null +++ b/libjava/classpath/gnu/javax/rmi/CORBA/StubDelegateImpl.java @@ -0,0 +1,310 @@ +/* StubDelegateImpl.java -- + Copyright (C) 2002, 2004, 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.rmi.CORBA; + +import gnu.CORBA.ObjectCreator; +import gnu.CORBA.Unexpected; +import gnu.CORBA.CDR.BufferredCdrInput; +import gnu.CORBA.CDR.BufferedCdrOutput; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.rmi.Remote; +import java.rmi.RemoteException; + +import javax.rmi.PortableRemoteObject; +import javax.rmi.CORBA.Stub; +import javax.rmi.CORBA.StubDelegate; +import javax.rmi.CORBA.Tie; +import javax.rmi.CORBA.Util; + +import org.omg.CORBA.BAD_PARAM; +import org.omg.CORBA.ORB; +import org.omg.CORBA.portable.Delegate; +import org.omg.CORBA.portable.ObjectImpl; +import org.omg.PortableServer.POA; +import org.omg.PortableServer.POAHelper; +import org.omg.PortableServer.Servant; +import org.omg.PortableServer.POAManagerPackage.State; + +/** + * The default stub delegate. + * + * @author Wu Gansha (gansha.wu@intel.com) (stub) + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) (implementation) + */ +public class StubDelegateImpl + implements StubDelegate +{ + /** + *

      + * Finds the suitable {@link Tie} for this Stub and connects it to the given + * ORB. The tie is found by the name pattern. If the found tie is derived from + * {@link org.omg.CORBA.PortableServer.Servant}, it is connected to the root + * POA, also activating it (if not already active). + *

      + *

      + * This method does not allow to specify, to which POA the found Tie must be + * connected and requires to use the deprecated method {@link ORB#connect}. + * Many useful POA features remain unaccessible. A better alternative it might + * be to generate a {@link org.omg.CORBA.PortableServer.Servant} - derived Tie + * (-poa key in rmic) and connect it to POA in one of the many ways, listed in + * the description of the {@link orb.omg.PortableServer} package). The + * obtained CORBA object can be narrowed into stub using + * {@link PortableRemoteObject#narrow}. + *

      + * + * @param orb the ORB where the Stub must be connected. + * + * @throws RemoteException if the stub is already connected to some other ORB. + * If the stub is already connected to the ORB that was passed as parameter, + * the method returns without action. + * + * @throws BAD_PARAM if the name of this stub does not match the stub name + * pattern, "_*_Stub" or if the Tie class, "_*Impl_Tie", does not exists or an + * instance of this class cannot be instantiated. + */ + public void connect(Stub self, ORB orb) + throws RemoteException + { + connect(self, orb, null); + } + + /** + * Connect when the POA is specified. + */ + public static void connect(Stub self, ORB orb, POA poa) + throws RemoteException + { + ORB oorb = null; + try + { + Delegate d = self._get_delegate(); + if (d != null) + oorb = d.orb(self); + } + catch (Exception e) + { + // Failed to get Delegate or ORB. + // (possible ony for user-written Stubs). + } + + if (oorb != null) + { + if (!oorb.equals(orb)) + throw new RemoteException("Stub " + self + + " is connected to another ORB, " + orb); + else + return; + } + + Tie t = null; + if (self instanceof Remote) + t = Util.getTie((Remote) self); + + // Find by name pattern. + if (t == null) + t = getTieFromStub(self); + + Delegate delegate; + + if (t instanceof Servant) + { + try + { + if (poa == null) + { + poa = POAHelper.narrow(orb.resolve_initial_references("RootPOA")); + // Activate if not active. + if (poa.the_POAManager().get_state().value() == State._HOLDING) + poa.the_POAManager().activate(); + } + + ObjectImpl obj = (ObjectImpl) poa.servant_to_reference((Servant) t); + delegate = obj._get_delegate(); + } + catch (Exception ex) + { + throw new Unexpected(ex); + } + } + else if (t instanceof ObjectImpl) + { + ObjectImpl o = (ObjectImpl) t; + orb.connect(o); + delegate = o._get_delegate(); + } + else + throw new BAD_PARAM("The Tie must be either Servant or ObjectImpl"); + + self._set_delegate(delegate); + } + + /** + * Locate a tie class, appropriate to the given stub class, by the name + * pattern. + */ + public static Tie getTieFromStub(java.lang.Object self) + { + Tie t; + String sn = self.getClass().getName(); + if (!sn.endsWith("_Stub")) + throw new BAD_PARAM("The stub name, " + sn + + ", does not match _*_Stub pattern"); + + String tn = sn.substring(0, sn.length() - "_Stub".length()) + "Impl_Tie"; + Class tieClass = null; + + try + { + tieClass = ObjectCreator.forName(tn); + t = (Tie) tieClass.newInstance(); + if (self instanceof Remote) + Util.registerTarget(t, (Remote) self); + } + catch (Exception e) + { + BAD_PARAM bad = new BAD_PARAM("Unable to instantiate '" + tn + "'"); + bad.initCause(e); + throw bad; + } + return t; + } + + /** + * Compare two stubs for equality. + */ + public boolean equals(Stub self, java.lang.Object obj) + { + if (obj instanceof ObjectImpl) + { + ObjectImpl other = (ObjectImpl) obj; + Delegate d1 = other._get_delegate(); + Delegate d2 = self._get_delegate(); + if (d1 == null || d2 == null) + return d1 == d2; + else + return d1.equals(d2); + } + else return false; + } + + /** + * Get the hash code (from IOR reference). + */ + public int hashCode(Stub self) + { + Delegate d = self._get_delegate(); + return d==null?0:d.hashCode(); + } + + /** + * Returns the IOR reference of the connected ORB. + * + * @see ORB#object_to_string(org.omg.CORBA.Object); + */ + public String toString(Stub self) + { + try + { + return self._orb().object_to_string(self); + } + catch (Exception ex) + { + return null; + } + } + + /** + * This should never be called. The ORB must be supplied. + * + * @see #connect + */ + public void readObject(Stub self, ObjectInputStream input) + throws IOException, ClassNotFoundException + { + readObject(self, input, null); + } + + /** + * Read as CORBA object when the ORB is known. The ORB must be set under the + * previous call of Stub.connect. The Stub is automatically registered with + * this ORB. + */ + public void readObject(Stub self, ObjectInputStream input, ORB orb) + throws IOException, ClassNotFoundException + { + byte[] b = (byte[]) input.readObject(); + BufferredCdrInput in = new BufferredCdrInput(b); + + if (orb != null) + in.setOrb(orb); + + ObjectImpl r = (ObjectImpl) in.read_Object(); + + self._set_delegate(r._get_delegate()); + } + + /** + * Write as CORBA object. The ORB is taken from the + * org.omg.CORBA.portable.Delegate. The Stub is automatically registered with + * this ORB (if not already done). + */ + public void writeObject(Stub self, ObjectOutputStream output) + throws IOException + { + writeObject(self, output, null); + } + + /** + * Write as CORBA object. The ORB must be either set under the previous call + * of Stub.connect or it is taken from the org.omg.CORBA.portable.Delegate. + * The Stub is automatically registered with this ORB (if not already done). + */ + public void writeObject(Stub self, ObjectOutputStream output, ORB orb) + throws IOException + { + BufferedCdrOutput out = new BufferedCdrOutput(); + out.setOrb(orb == null ? self._orb() : orb); + out.write_Object(self); + + output.writeObject(out.buffer.toByteArray()); + } +} diff --git a/libjava/classpath/gnu/javax/rmi/CORBA/TieTargetRecord.java b/libjava/classpath/gnu/javax/rmi/CORBA/TieTargetRecord.java new file mode 100644 index 000000000..f39441e38 --- /dev/null +++ b/libjava/classpath/gnu/javax/rmi/CORBA/TieTargetRecord.java @@ -0,0 +1,93 @@ +/* TieTargetRecord.java -- + 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.rmi.CORBA; + +import java.util.HashSet; + +import javax.rmi.CORBA.Tie; + +/** + * Represents a Tie, connected to possibly multiple invocation targets. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class TieTargetRecord +{ + /** + * The associated Tie. + */ + public final Tie tie; + + /** + * The objects, exposing the tie. + */ + public HashSet targets = new HashSet(); + + /** + * Create a new record. + */ + public TieTargetRecord(Tie a_tie) + { + tie = a_tie; + } + + /** + * Add a target. + */ + public void add(Object target) + { + targets.add(target); + } + + /** + * Remove target. + */ + public void remove(Object target) + { + targets.remove(target); + } + + /** + * Return true if the tie has no associated invocation targets. + */ + public boolean unused() + { + return targets.size() == 0; + } +} diff --git a/libjava/classpath/gnu/javax/rmi/CORBA/UtilDelegateImpl.java b/libjava/classpath/gnu/javax/rmi/CORBA/UtilDelegateImpl.java new file mode 100644 index 000000000..dd4e347f2 --- /dev/null +++ b/libjava/classpath/gnu/javax/rmi/CORBA/UtilDelegateImpl.java @@ -0,0 +1,744 @@ +/* UtilDelegateImpl.java -- + Copyright (C) 2002, 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.rmi.CORBA; + +import gnu.classpath.VMStackWalker; + +import gnu.CORBA.Minor; +import gnu.CORBA.ObjectCreator; +import gnu.CORBA.Poa.ORB_1_4; +import gnu.CORBA.Poa.AOM; +import gnu.CORBA.Poa.gnuPOA; +import gnu.CORBA.typecodes.GeneralTypeCode; + +import org.omg.CORBA.Any; +import org.omg.CORBA.BAD_PARAM; +import org.omg.CORBA.COMM_FAILURE; +import org.omg.CORBA.CompletionStatus; +import org.omg.CORBA.INVALID_TRANSACTION; +import org.omg.CORBA.INV_OBJREF; +import org.omg.CORBA.MARSHAL; +import org.omg.CORBA.NO_PERMISSION; +import org.omg.CORBA.OBJECT_NOT_EXIST; +import org.omg.CORBA.OMGVMCID; +import org.omg.CORBA.ORB; +import org.omg.CORBA.SystemException; +import org.omg.CORBA.TCKind; +import org.omg.CORBA.TRANSACTION_REQUIRED; +import org.omg.CORBA.TRANSACTION_ROLLEDBACK; +import org.omg.CORBA.TypeCode; +import org.omg.CORBA.UNKNOWN; +import org.omg.CORBA.portable.InputStream; +import org.omg.CORBA.portable.OutputStream; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.net.MalformedURLException; +import java.rmi.AccessException; +import java.rmi.MarshalException; +import java.rmi.NoSuchObjectException; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.ServerError; +import java.rmi.ServerException; +import java.rmi.UnexpectedException; +import java.rmi.server.RMIClassLoader; +import java.util.Hashtable; + +import javax.rmi.CORBA.Stub; +import javax.rmi.CORBA.Tie; +import javax.rmi.CORBA.Util; +import javax.rmi.CORBA.UtilDelegate; +import javax.rmi.CORBA.ValueHandler; +import javax.transaction.InvalidTransactionException; +import javax.transaction.TransactionRequiredException; +import javax.transaction.TransactionRolledbackException; + +/** + * The implementation of UtilDelegate. + * + * @author Wu Gansha (gansha.wu@intel.com) (stub) + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) (implementation) + */ +public class UtilDelegateImpl + extends RmiUtilities + implements UtilDelegate +{ + /** + * The instance of the value handler, requested once. + */ + static ValueHandler m_ValueHandler; + + /** + * The global map of all ties to they records. + */ + static Hashtable m_Ties = new Hashtable(); + + /** + * The global map of all targets to they records. + */ + static Hashtable m_Targets = new Hashtable(); + + /** + * The standard package for that the exception names are omitted. + */ + static final String m_StandardPackage = "org.omg.CORBA."; + + /** + * Make a deep copy of the object. + */ + public Object copyObject(Object obj, ORB orb) + throws RemoteException + { + // Strings are immutable, can be shared. + if (obj instanceof String) + return obj; + else if (obj == null) + return null; + else if (obj instanceof String[] || obj instanceof String[][] + || obj instanceof String[][][]) + { + // String arrays can be just cloned. + return ((Object[]) obj).clone(); + } + else if (obj instanceof Serializable) + { + try + { + ByteArrayOutputStream a = new ByteArrayOutputStream(); + ObjectOutputStream ou = new ObjectOutputStream(a); + ou.writeObject(obj); + ou.close(); + ObjectInputStream input = new ObjectInputStream( + new ByteArrayInputStream(a.toByteArray())); + return input.readObject(); + } + catch (Exception ex) + { + RemoteException rex = new RemoteException("Cannot copy " + obj); + throw rex; + } + } + else + return obj; + } + + /** + * Make a deep copy of the object array. + */ + public Object[] copyObjects(Object[] obj, ORB orb) + throws RemoteException + { + return (Object[]) copyObject(obj, orb); + } + + public ValueHandler createValueHandler() + { + if (m_ValueHandler == null) + m_ValueHandler = (ValueHandler) DelegateFactory.getInstance(DelegateFactory.VALUEHANDLER); + return m_ValueHandler; + } + + /** + * Returns the codebase of the given class. + */ + public String getCodebase(Class clz) + { + return RMIClassLoader.getClassAnnotation(clz); + } + + /** + * Get the Tie that handles invocations on the given target. If the target/Tie + * pair has not been previously registered using {@link #registerTarget}, + * this method tries to locate a tie class by the name pattern. If this + * succeeds, the tie-target pair is also registered. + * + * @return the Tie. + */ + public Tie getTie(Remote target) + { + synchronized (m_Targets) + { + Tie tie; + TieTargetRecord r = ((TieTargetRecord) m_Targets.get(target)); + if (r == null) + { + if (target instanceof Stub) + { + tie = StubDelegateImpl.getTieFromStub(target); + registerTarget(tie, target); + } + else + { + // Treat this as implementation. + String tieClassName = getTieClassName(target.getClass().getName()); + try + { + Class tieClass = Util.loadClass(tieClassName, null, + target.getClass().getClassLoader()); + tie = (Tie) tieClass.newInstance(); + } + catch (Exception e) + { + MARSHAL m = new MARSHAL("Unable to instantiate " + + tieClassName); + m.minor = Minor.TargetConversion; + m.initCause(e); + throw m; + } + tie.setTarget(target); + registerTarget(tie, target); + } + } + else + tie = r.tie; + return tie; + } + } + + /** + * Get the Stub class name for the name, representing the given interface. + */ + private String getTieClassName(String interf) + { + String stubClassName; + int p = interf.lastIndexOf('.'); + + if (p < 0) + // The interface is defined in the default package. + stubClassName = "_" + interf + "_Tie"; + else + stubClassName = interf.substring(0, p + 1) + "_" + + interf.substring(p + 1) + "_Tie"; + return stubClassName; + } + + /** + * Register the Tie-target pair. As the Tie is a Servant, it can potentially + * be connected to several objects and hence may be registered with several + * targets. + */ + public void registerTarget(Tie tie, Remote target) + { + synchronized (m_Ties) + { + synchronized (m_Targets) + { + TieTargetRecord r = (TieTargetRecord) m_Ties.get(tie); + if (r == null) + { + // First registration for this Tie. + r = new TieTargetRecord(tie); + m_Ties.put(tie, r); + } + if (target != null) + { + r.add(target); + m_Targets.put(target, r); + } + } + } + } + + /** + * Deactivate the associated Tie, if it is found and is not connected to other + * registered targets. Independing from the POA policies, the transparent + * reactivation will not be possible. + */ + public void unexportObject(Remote target) + throws NoSuchObjectException + { + synchronized (m_Ties) + { + synchronized (m_Targets) + { + TieTargetRecord r = ((TieTargetRecord) m_Targets.get(target)); + if (r != null) + { + if (target instanceof org.omg.CORBA.Object) + r.tie.orb().disconnect((org.omg.CORBA.Object) target); + + if (r.unused()) + { + m_Targets.remove(target); + m_Ties.remove(r.tie); + r.tie.deactivate(); + + if (r.tie.orb() instanceof ORB_1_4) + { + // Standard case, when more deep cleanup is possible. + // Independing from the POA policies, the object will + // not be activable transparently. + ORB_1_4 orb = (ORB_1_4) r.tie.orb(); + + if (target instanceof org.omg.CORBA.Object) + { + AOM.Obj record = orb.rootPOA.findObject((org.omg.CORBA.Object) target); + + if (record != null && record.servant == r.tie + && record.poa instanceof gnuPOA) + { + ((gnuPOA) record.poa).aom.remove(record.key); + record.deactivated = true; + record.servant = null; + } + } + } + } + } + } + } + } + + /** + * Checks if the given stub is local. + * + * @param stub a stub to check. + * @return true if the stub is local, false otherwise. + */ + public boolean isLocal(Stub stub) + throws RemoteException + { + try + { + return stub._is_local(); + } + catch (SystemException e) + { + RemoteException rex = new RemoteException(); + rex.initCause(e); + throw rex; + } + } + + /** + * Load the class. The method uses class loaders from the call stact first. If + * this fails, the further behaviour depends on the System Property + * "java.rmi.server.useCodebaseOnly" with default value "false". + * + *
        + *
      • Try the current thread context class loader first.
      • + *
      • If remoteCodebase is non-null and useCodebaseOnly is "false" then call + * java.rmi.server.RMIClassLoader.loadClass (remoteCodebase, className)
      • + *
      • If remoteCodebase is null or useCodebaseOnly is true then call + * java.rmi.server.RMIClassLoader.loadClass(className)
      • + *
      • If a class is still not successfully loaded and the loader != null + * then try Class.forName(className, false, loader).
      • + *
      + * + * @param className the name of the class. + * @param remoteCodebase the codebase. + * @param loader the class loader. + * @return the loaded class. + * + * @throws ClassNotFoundException of the class cannot be loaded. + */ + public Class loadClass(String className, String remoteCodebase, + ClassLoader loader) + throws ClassNotFoundException + { + if (loader == null) + loader = VMStackWalker.firstNonNullClassLoader(); + + String p_useCodebaseOnly = System.getProperty("java.rmi.server.useCodebaseOnly"); + + boolean useCodebaseOnly = p_useCodebaseOnly != null + && p_useCodebaseOnly.trim().equalsIgnoreCase("true"); + + if (useCodebaseOnly) + remoteCodebase = null; + + try + { + return RMIClassLoader.loadClass(remoteCodebase, className, loader); + } + catch (MalformedURLException x) + { + throw new ClassNotFoundException(className, x); + } + } + + /** + * Converts CORBA {@link SystemException} into RMI {@link RemoteException}. + * The exception is converted as defined in the following table: + *

      + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
      CORBA ExceptionRMI Exception
      {@link COMM_FAILURE}{@link MarshalException}
      {@link INV_OBJREF}{@link NoSuchObjectException}
      {@link NO_PERMISSION}{@link AccessException}
      {@link MARSHAL}{@link MarshalException}
      {@link BAD_PARAM} (all other cases){@link MarshalException}
      {@link OBJECT_NOT_EXIST}{@link NoSuchObjectException}
      {@link TRANSACTION_REQUIRED}{@link TransactionRequiredException}
      {@link TRANSACTION_ROLLEDBACK}{@link TransactionRolledbackException}
      {@link INVALID_TRANSACTION}{@link InvalidTransactionException}
      Any other {@link SystemException}{@link RemoteException}
      + *

      + *

      + * The exception detailed message always consists of + *

        + *
      1. the string "CORBA "
      2. + *
      3. the CORBA name of the system exception
      4. + *
      5. single space
      6. + *
      7. the hexadecimal value of the system exception's minor code, preceeded + * by 0x (higher bits contain {@link OMGVMCID}).
      8. + *
      9. single space
      10. + *
      11. the {@link CompletionStatus} of the exception: "Yes", "No" or "Maybe".
      12. + *
      + *

      + * For instance, if the Internet connection was refused: + *

      + *

      + *

      +   * CORBA COMM_FAILURE 0x535500C9 No
      +   * 

      + *

      + * The original CORBA exception is set as the cause of the RemoteException + * being created. + *

      + */ + public RemoteException mapSystemException(SystemException ex) + { + RemoteException rex; + + String status; + + switch (ex.completed.value()) + { + case CompletionStatus._COMPLETED_MAYBE: + status = "Maybe"; + break; + + case CompletionStatus._COMPLETED_NO: + status = "No"; + break; + + case CompletionStatus._COMPLETED_YES: + status = "Yes"; + break; + + default: + status = "Unexpected completion status " + ex.completed.value(); + } + + String name = ex.getClass().getName(); + + if (name.startsWith(m_StandardPackage)) + name = name.substring(m_StandardPackage.length()); + + String message = "CORBA " + name + " 0x" + Integer.toHexString(ex.minor) + + " " + status; + + if (ex instanceof COMM_FAILURE) + rex = new MarshalException(message, ex); + else if (ex instanceof INV_OBJREF) + { + rex = new NoSuchObjectException(message); + rex.detail = ex; + } + else if (ex instanceof NO_PERMISSION) + rex = new AccessException(message, ex); + else if (ex instanceof MARSHAL) + rex = new MarshalException(message, ex); + else if (ex instanceof BAD_PARAM) + rex = new MarshalException(message, ex); + else if (ex instanceof OBJECT_NOT_EXIST) + { + rex = new NoSuchObjectException(message); + rex.detail = ex; + } + else if (ex instanceof TRANSACTION_REQUIRED) + { + rex = new TransactionRequiredException(message); + rex.detail = ex; + } + else if (ex instanceof TRANSACTION_ROLLEDBACK) + { + rex = new TransactionRolledbackException(message); + rex.detail = ex; + } + else if (ex instanceof INVALID_TRANSACTION) + { + rex = new InvalidTransactionException(message); + rex.detail = ex; + } + else if (ex instanceof UNKNOWN) + rex = wrapException(ex.getCause()); + else + rex = new RemoteException(message, ex); + + return rex; + } + + /** + * Converts the exception that was thrown by the implementation method on a + * server side into RemoteException that can be transferred and re-thrown on a + * client side. The method converts exceptions as defined in the following + * table: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
      Exception to map (or subclass)Maps into
      {@link Error}{@link ServerError}
      {@link RemoteException}{@link ServerException}
      {@link SystemException}wrapException({@link #mapSystemException})
      {@link RuntimeException}rethrows
      Any other exception{@link UnexpectedException}
      + * + * @param ex an exception that was thrown on a server side implementation. + * + * @return the corresponding RemoteException unless it is a RuntimeException. + * + * @throws RuntimeException the passed exception if it is an instance of + * RuntimeException. + * + * @specnote It is the same behavior, as in Suns implementations 1.4.0-1.5.0. + */ + public RemoteException wrapException(Throwable ex) + throws RuntimeException + { + if (ex instanceof RuntimeException) + throw (RuntimeException) ex; + else if (ex instanceof Error) + return new ServerError(ex.getMessage(), (Error) ex); + else if (ex instanceof RemoteException) + return new ServerException(ex.getMessage(), (Exception) ex); + else if (ex instanceof SystemException) + return wrapException(mapSystemException((SystemException) ex)); + else + return new UnexpectedException("Unexpected", (Exception) ex); + } + + /** + * Write abstract interface to the CORBA output stream. The write format is + * matching CORBA abstract interface. Remotes and CORBA objects are written as + * objects, other classes are supposed to be value types and are written as + * such. {@link Remote}s are processed as defined in + * {@link #writeRemoteObject}. The written data contains discriminator, + * defining, that was written. Another method that writes the same content is + * {@link org.omg.CORBA_2_3.portable.OutputStream#write_abstract_interface(java.lang.Object)}. + * + * @param output a stream to write to, must be + * {@link org.omg.CORBA_2_3.portable.OutputStream}. + * + * @param object an object to write, must be CORBA object, Remote + */ + public void writeAbstractObject(OutputStream output, Object object) + { + ((org.omg.CORBA_2_3.portable.OutputStream) output).write_abstract_interface(object); + } + + /** + * Write the passed java object to the output stream in the form of the CORBA + * {@link Any}. This includes creating an writing the object {@link TypeCode} + * first. Such Any can be later read by a non-RMI-IIOP CORBA implementation + * and manipulated, for instance, by means, provided in + * {@link org.omg.DynamicAny.DynAny}. Depending from the passed value, this + * method writes CORBA object, value type or value box. For value types Null + * is written with the abstract interface, its typecode having repository id + * "IDL:omg.org/CORBA/AbstractBase:1.0" and the empty string name. + * + * @param output the object to write. + * @param object the java object that must be written in the form of the CORBA + * {@link Any}. + */ + public void writeAny(OutputStream output, Object object) + { + Any any = output.orb().create_any(); + if (object == null) + { + GeneralTypeCode t = new GeneralTypeCode(TCKind.tk_abstract_interface); + t.setId("IDL:omg.org/CORBA/AbstractBase:1.0"); + t.setName(""); + any.type(t); + output.write_any(any); + return; + } + else if (object instanceof org.omg.CORBA.Object + && !(object instanceof Remote)) + { + // Write as value type. + boolean inserted = ObjectCreator.insertWithHelper(any, object); + if (inserted) + { + output.write_any(any); + return; + } + } + + if (object instanceof org.omg.CORBA.Object) + writeAnyAsRemote(output, object); + else if (object instanceof Serializable) + { + any.insert_Value((Serializable) object); + output.write_any(any); + } + else + { + MARSHAL m = new MARSHAL(object.getClass().getName() + + " must be CORBA Object, Remote or Serializable"); + m.minor = Minor.NonSerializable; + throw m; + } + } + + /** + * Write Any as for remote object. + */ + void writeAnyAsRemote(OutputStream output, Object object) + { + GeneralTypeCode t = new GeneralTypeCode(TCKind.tk_objref); + t.setId(m_ValueHandler.getRMIRepositoryID(object.getClass())); + t.setName(object.getClass().getName()); + + // Writing Any (typecode, followed by value). + output.write_TypeCode(t); + writeRemoteObject(output, object); + } + + /** + * Get the class name excluding the package name. + */ + String getName(String n) + { + int p = n.lastIndexOf('.'); + if (p < 0) + return n; + else + return n.substring(p + 1); + } + + /** + * Read Any from the input stream. + */ + public Object readAny(InputStream input) + { + return input.read_any(); + } + + /** + * Write the passed parameter to the output stream as CORBA object. If the + * parameter is an instance of Remote and not an instance of Stub, the method + * instantiates a suitable Tie, connects the parameter to this Tie and then + * connects that Tie to the ORB that is requested from the output stream. Then + * the object reference is written to the stream, making remote invocations + * possible. This method is used in write_value(..) method group in + * {@link org.omg.CORBA_2_3.portable.OutputStream} and also may be called + * directly from generated Stubs and Ties. + * + * @param output a stream to write to, must be + * org.omg.CORBA_2_3.portable.OutputStream + * @param object an object to write. + */ + public void writeRemoteObject(OutputStream an_output, Object object) + { + org.omg.CORBA_2_3.portable.OutputStream output = (org.omg.CORBA_2_3.portable.OutputStream) an_output; + if (object == null) + an_output.write_Object(null); + else if (isTieRequired(object)) + { + // Find the interface that is implemented by the object and extends + // Remote. + Class fc = getExportedInterface(object); + exportTie(output, object, fc); + } + else if (object instanceof org.omg.CORBA.Object) + { + ensureOrbRunning(output); + an_output.write_Object((org.omg.CORBA.Object) object); + } + else if (object != null && object instanceof Serializable) + writeFields(an_output, (Serializable) object); + } + +} diff --git a/libjava/classpath/gnu/javax/rmi/CORBA/ValueHandlerDelegateImpl.java b/libjava/classpath/gnu/javax/rmi/CORBA/ValueHandlerDelegateImpl.java new file mode 100644 index 000000000..33fff16e5 --- /dev/null +++ b/libjava/classpath/gnu/javax/rmi/CORBA/ValueHandlerDelegateImpl.java @@ -0,0 +1,163 @@ +/* ValueHandlerDelegateImpl.java -- + 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.rmi.CORBA; + +import gnu.CORBA.CDR.gnuRuntime; + +import org.omg.CORBA.BAD_PARAM; +import org.omg.CORBA.CustomMarshal; +import org.omg.CORBA.portable.OutputStream; +import org.omg.CORBA.portable.Streamable; +import org.omg.SendingContext.RunTime; + +import java.io.Externalizable; +import java.io.ObjectStreamClass; +import java.io.Serializable; +import java.rmi.Remote; + +import javax.rmi.CORBA.ValueHandler; +import javax.rmi.CORBA.ValueHandlerMultiFormat; + +/** + * Implementation of the ValueHandler. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) (implementation) + */ +public class ValueHandlerDelegateImpl + extends RmiUtilities + implements ValueHandler, ValueHandlerMultiFormat +{ + /** + * Return the maximal supported stream format version. We currently + * support the version 1. + * + * TODO Support the version 2. + */ + public byte getMaximumStreamFormatVersion() + { + return 1; + } + + /** + * Write value using the given stream format version. + */ + public void writeValue(OutputStream output, Serializable value, byte version) + { + if (version!=1) + throw new BAD_PARAM("Unsupported stream format version "+version); + else + writeValue(output, value); + } + + /** + * This implementation associates RunTime with stream rather than with the + * value handler and this method is not used in the implementation. It is + * implemented just for the sake of compatibility. + */ + public RunTime getRunTimeCodeBase() + { + return new gnuRuntime(null, null); + } + + /** + * Checks if an instance of this class can write its fields itself. + */ + public boolean isCustomMarshaled(Class clz) + { + return CustomMarshal.class.isAssignableFrom(clz) + || Streamable.class.isAssignableFrom(clz); + } + + /** + * No replacement, returns the passed parameter. + */ + public Serializable writeReplace(Serializable value) + { + return value; + } + + /** + * Compute the repository id in the RMI hashed format. + */ + public String getRMIRepositoryID(final Class cx) + { + long hash = 0; + Class of = cx.isArray() ? cx.getComponentType() : null; + + if (cx.equals(String[].class)) + return RMI_STRING_ARRAY_ID; + else if (cx.equals(String.class)) + return RMI_STRING_ID; + else if (cx.equals(Class.class)) + return RMI_CLASS_ID; + else if (Remote.class.isAssignableFrom(cx) + || !Serializable.class.isAssignableFrom(cx) + || cx.isInterface() + || (cx.isArray() && (!Serializable.class.isAssignableFrom(of) + || of.isPrimitive() || Remote.class.isAssignableFrom(of))) + + ) + // Some classes that have zero hash code and serial no version id + // included. + return "RMI:" + cx.getName() + ":" + toHex(hash); + else if (cx.isArray()) + // Arrays have the same hashcode and uid as they components. + return "RMI:" + cx.getName() + ":" + toHex(getHashCode(of)) + ":" + + toHex(getSid(of)); + else + { + if (Externalizable.class.isAssignableFrom(cx)) + hash = 1; + else + hash = getHashCode(cx); + + return "RMI:" + cx.getName() + ":" + toHex(hash) + ":" + + toHex(getSid(cx)); + } + } + + /** + * Get the class serial version UID. + */ + long getSid(Class cx) + { + ObjectStreamClass osc = ObjectStreamClass.lookup(cx); + return osc.getSerialVersionUID(); + } +} diff --git a/libjava/classpath/gnu/javax/security/auth/Password.java b/libjava/classpath/gnu/javax/security/auth/Password.java new file mode 100644 index 000000000..8fb07ee6b --- /dev/null +++ b/libjava/classpath/gnu/javax/security/auth/Password.java @@ -0,0 +1,283 @@ +/* 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; + +/** + * 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] = 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/libjava/classpath/gnu/javax/security/auth/callback/AWTCallbackHandler.java b/libjava/classpath/gnu/javax/security/auth/callback/AWTCallbackHandler.java new file mode 100644 index 000000000..f241157ee --- /dev/null +++ b/libjava/classpath/gnu/javax/security/auth/callback/AWTCallbackHandler.java @@ -0,0 +1,454 @@ +/* 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 gnu.java.lang.CPStringBuilder; + +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++) + { + CPStringBuilder lang = + new CPStringBuilder(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/libjava/classpath/gnu/javax/security/auth/callback/AbstractCallbackHandler.java b/libjava/classpath/gnu/javax/security/auth/callback/AbstractCallbackHandler.java new file mode 100644 index 000000000..31a7f5aca --- /dev/null +++ b/libjava/classpath/gnu/javax/security/auth/callback/AbstractCallbackHandler.java @@ -0,0 +1,295 @@ +/* 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; + } + + /** + * Create an instance of CallbackHandler of the designated + * type from the first Security Provider which offers it. + * + * @param type the type of callback handler to create. + * @return a newly created instance of ClassbackHandler. + * @throws NoSuchAlgorithmException if no security provider is found to offer + * an implementation of CallbackHandler of the + * designated type. + */ + public static CallbackHandler getInstance(String type) + throws NoSuchAlgorithmException + { + Provider[] p = Security.getProviders(); + NoSuchAlgorithmException lastException = null; + for (int i = 0; i < p.length; i++) + try + { + return getInstance(type, p[i]); + } + catch (NoSuchAlgorithmException x) + { + lastException = x; + } + if (lastException != null) + throw lastException; + throw new NoSuchAlgorithmException(type); + } + + /** + * Create an instance of CallbackHandler of the designated + * type from the named security provider. + * + * @param type the type of callback handler to create. + * @param provider a named security provider to use. + * @return a newly created instance of ClassbackHandler. + * @throws NoSuchAlgorithmException if no security provider is found to offer + * an implementation of CallbackHandler of the + * designated type. + * @throws IllegalArgumentException if either type or + * provider is null, or if + * type is an empty string. + */ + public static CallbackHandler getInstance(String type, String provider) + throws NoSuchAlgorithmException, NoSuchProviderException + { + if (provider == null) + throw new IllegalArgumentException("provider MUST NOT be null"); + Provider p = Security.getProvider(provider); + if (p == null) + throw new NoSuchProviderException(provider); + return getInstance(type, p); + } + + /** + * Create an instance of CallbackHandler of the designated + * type from the designated security provider. + * + * @param type the type of callback handler to create. + * @param provider a security provider to use. + * @return a newly created instance of ClassbackHandler. + * @throws NoSuchAlgorithmException if no security provider is found to offer + * an implementation of CallbackHandler of the + * designated type. + * @throws IllegalArgumentException if either type or + * provider is null, or if + * type is an empty string. + */ + public static CallbackHandler getInstance(String type, Provider provider) + throws NoSuchAlgorithmException + { + StringBuilder sb = new StringBuilder("CallbackHandler of type [") + .append(type).append("] from provider[") + .append(provider).append("] could not be created"); + Throwable cause; + try + { + return (CallbackHandler) Engine.getInstance(SERVICE, type, provider); + } + catch (InvocationTargetException x) + { + cause = x.getCause(); + if (cause instanceof NoSuchAlgorithmException) + throw (NoSuchAlgorithmException) cause; + if (cause == null) + cause = x; + } + catch (ClassCastException x) + { + cause = x; + } + NoSuchAlgorithmException x = new NoSuchAlgorithmException(sb.toString()); + x.initCause(cause); + throw x; + } + + 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/libjava/classpath/gnu/javax/security/auth/callback/CertificateCallback.java b/libjava/classpath/gnu/javax/security/auth/callback/CertificateCallback.java new file mode 100644 index 000000000..74885ed21 --- /dev/null +++ b/libjava/classpath/gnu/javax/security/auth/callback/CertificateCallback.java @@ -0,0 +1,64 @@ +/* CertificateCallback.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.security.cert.Certificate; + +import javax.security.auth.callback.ConfirmationCallback; + +/** + * A {@link javax.security.auth.callback.Callback} for confirming whether or + * not a certificate may be used. This works similarly to + * {@link ConfirmationCallback}, but additionally contains the certificate + * being verified. Thus, handlers may present the certificate to the user, when + * handling this callback. + * + * @author Casey Marshall (csm@gnu.org) + */ +public class CertificateCallback extends ConfirmationCallback +{ + static final long serialVersionUID = 8343869651419225634L; + public final Certificate certificate; + + public CertificateCallback(Certificate cert, String prompt) + { + super(prompt, ERROR, YES_NO_OPTION, NO); + this.certificate = cert; + } +} diff --git a/libjava/classpath/gnu/javax/security/auth/callback/ConsoleCallbackHandler.java b/libjava/classpath/gnu/javax/security/auth/callback/ConsoleCallbackHandler.java new file mode 100644 index 000000000..4c24ab808 --- /dev/null +++ b/libjava/classpath/gnu/javax/security/auth/callback/ConsoleCallbackHandler.java @@ -0,0 +1,299 @@ +/* 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(Integer.valueOf(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.print(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 }; + int defaultOption = c.getDefaultOption(); + if (defaultOption > -1 && defaultOption < choices.length) + { + out.print("["); + out.print(choices[defaultOption]); + out.print("] "); + } + 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.print(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/libjava/classpath/gnu/javax/security/auth/callback/DefaultCallbackHandler.java b/libjava/classpath/gnu/javax/security/auth/callback/DefaultCallbackHandler.java new file mode 100644 index 000000000..df0360b2e --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/security/auth/callback/GnuCallbacks.java b/libjava/classpath/gnu/javax/security/auth/callback/GnuCallbacks.java new file mode 100644 index 000000000..9fd72f926 --- /dev/null +++ b/libjava/classpath/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/libjava/classpath/gnu/javax/security/auth/callback/SwingCallbackHandler.java b/libjava/classpath/gnu/javax/security/auth/callback/SwingCallbackHandler.java new file mode 100644 index 000000000..c9d5b3eb5 --- /dev/null +++ b/libjava/classpath/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 (); + } +} diff --git a/libjava/classpath/gnu/javax/security/auth/login/ConfigFileParser.java b/libjava/classpath/gnu/javax/security/auth/login/ConfigFileParser.java new file mode 100644 index 000000000..5c4c4261f --- /dev/null +++ b/libjava/classpath/gnu/javax/security/auth/login/ConfigFileParser.java @@ -0,0 +1,346 @@ +/* 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 gnu.java.security.Configuration; + +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 java.util.logging.Logger; + +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 +{ + private static final Logger log = Logger.getLogger(ConfigFileParser.class.getName()); + private ConfigFileTokenizer cft; + private Map map = new HashMap(); + + // default 0-arguments constructor + + /** + * 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; + if (Configuration.DEBUG) + log.fine("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); + if (Configuration.DEBUG) + log.fine("MODULE_CLASS = " + clazz); + + if (cft.nextToken() != ConfigFileTokenizer.TT_WORD) + abort("Was expecting FLAG but found none"); + + String flag = cft.sval; + if (Configuration.DEBUG) + log.fine("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; + if (Configuration.DEBUG) + log.fine("PARAM_NAME = " + paramName); + if (cft.nextToken() != '=') + abort("Missing '=' after PARAM_NAME"); + + c = cft.nextToken(); + if (c != '"' && c != '\'') + { + if (Configuration.DEBUG) + log.fine("Was expecting a quoted string but got no quote character." + + " Assume unquoted string"); + } + paramValue = expandParamValue(cft.sval); + if (Configuration.DEBUG) + log.fine("PARAM_VALUE = " + paramValue); + options.put(paramName, paramValue); + + c = cft.nextToken(); + } + AppConfigurationEntry ace = new AppConfigurationEntry(clazz, f, options); + if (Configuration.DEBUG) + log.fine("LOGIN_MODULE_ENTRY = " + ace); + listOfACEs.add(ace); + return true; + } + + private void abort(String m) throws IOException + { + if (Configuration.DEBUG) + { + log.fine(m); + log.fine("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(t.charAt(0))) + abort("Class name [" + cn + + "] contains an invalid sub-package identifier: " + t); + + // 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) + { + if (Configuration.DEBUG) + log.fine("Found a ${ prefix with no } suffix. Ignore"); + break; + } + + String sysPropName = s.substring(i + 2, j); + if (Configuration.DEBUG) + log.fine("Found a reference to System property " + sysPropName); + String sysPropValue = System.getProperty(sysPropName); + if (Configuration.DEBUG) + log.fine("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) + { + if (Configuration.DEBUG) + log.fine("Exception (ignored) while expanding " + s + ": " + x); + } + + return result; + } +} diff --git a/libjava/classpath/gnu/javax/security/auth/login/ConfigFileTokenizer.java b/libjava/classpath/gnu/javax/security/auth/login/ConfigFileTokenizer.java new file mode 100644 index 000000000..fc35bf772 --- /dev/null +++ b/libjava/classpath/gnu/javax/security/auth/login/ConfigFileTokenizer.java @@ -0,0 +1,246 @@ +/* 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 gnu.java.lang.CPStringBuilder; + +import gnu.java.security.Configuration; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.Reader; +import java.util.logging.Logger; + +/** + * 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.StreamTokenizer} 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 +{ + private static final Logger log = Logger.getLogger(ConfigFileParser.class.getName()); + /** 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 CPStringBuilder 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 CPStringBuilder(); + 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 + { + if (Configuration.DEBUG) + { + log.fine(m); + log.fine("sb = " + sb); + log.fine("sbNdx = " + sbNdx); + } + throw new IOException(m); + } +} diff --git a/libjava/classpath/gnu/javax/security/auth/login/GnuConfiguration.java b/libjava/classpath/gnu/javax/security/auth/login/GnuConfiguration.java new file mode 100644 index 000000000..20d8f3afd --- /dev/null +++ b/libjava/classpath/gnu/javax/security/auth/login/GnuConfiguration.java @@ -0,0 +1,466 @@ +/* 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 java.util.logging.Logger; + +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 +{ + private static final Logger log = Logger.getLogger(GnuConfiguration.class.getName()); + /** + * 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; + + if (gnu.java.security.Configuration.DEBUG) + log.fine(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 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()) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("Using login configuration defined by Security property(ies)"); + } + else if (processSystemProperty()) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("Using login configuration defined by System property"); + } + else if (processUserHome()) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("Using login configuration defined in ${user.home}"); + } + else + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("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) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("java.security.auth.login.config.url." + counter + + " = " + s); + parseConfig(getInputStreamFromURL(s)); + result = true; + } + } + catch (Throwable t) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("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) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("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) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("java.security.auth.login.config = " + s); + parseConfig(getInputStreamFromURL(s)); + result = true; + } + } + } + catch (Throwable t) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("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) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("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) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("Exception (ignored) 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) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("User home path is not set or is empty"); + return null; + } + uh = uh.trim(); + File result = new File(uh); + if (! result.exists()) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("User home '" + uh + "' does not exist"); + return null; + } + if (! result.isDirectory()) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("User home '" + uh + "' is not a directory"); + return null; + } + if (! result.canRead()) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("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()) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("File '" + fileName + "' does not exist in user's home"); + return null; + } + if (! result.isFile()) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("File '" + fileName + "' in user's home is not a file"); + return null; + } + if (! result.canRead()) + { + if (gnu.java.security.Configuration.DEBUG) + log.fine("File '" + fileName + "' in user's home is not readable"); + return null; + } + return result; + } +} diff --git a/libjava/classpath/gnu/javax/sound/AudioSecurityManager.java b/libjava/classpath/gnu/javax/sound/AudioSecurityManager.java new file mode 100644 index 000000000..1daea2db5 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/AudioSecurityManager.java @@ -0,0 +1,112 @@ +/* AudioSecurityManager.java -- Manages Security requests for Sound classes. + + Copyright (C) 2007 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.sound; + +import javax.sound.sampled.AudioPermission; + +/** + * This class handles security requests for classes in the Sound API. + * + * A class that needs to check against a particular permission type may use this + * class to query the SecurityManager. + * + * For example, to check for a read permission, a class can simply pass the + * Permission.READ constant to + * {@link #checkPermissions(gnu.javax.sound.AudioSecurityManager.Permission))}, + * like the following code demonstrates: + * + *
      + * AudioSecurityManager.checkPermissions(Permission.PLAY);
      + * 
      + * + * If there is need to query for all the defined permissions type, the constant + * Permission.ALL can be used. In alternative, the + * {@link #checkPermissions()} is presented as a shorthand. + * + * @author Mario Torre + */ +public class AudioSecurityManager +{ + /** + * Defines a common set of permission allowed by the specification. + */ + public static enum Permission + { + PLAY, RECORD, ALL + } + + /** + * Shorthand to checkPermissions(Permission.ALL). + */ + public static final void checkPermissions() + { + checkPermissions(Permission.ALL); + } + + /** + * Query the SecurityManager agains the given + * Permission. + * + * @param permission + */ + public static final void checkPermissions(Permission permission) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + { + String perm = null; + switch (permission) + { + case PLAY: + perm = "play"; + break; + + case RECORD: + perm = "record"; + break; + + case ALL: default: + perm = "*"; + break; + } + + sm.checkPermission(new AudioPermission(perm)); + } + } +} diff --git a/libjava/classpath/gnu/javax/sound/midi/alsa/AlsaInputPortDevice.java b/libjava/classpath/gnu/javax/sound/midi/alsa/AlsaInputPortDevice.java new file mode 100644 index 000000000..d37a8fd6b --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/midi/alsa/AlsaInputPortDevice.java @@ -0,0 +1,130 @@ +/* AlsaInputPortDevice.java -- ALSA MIDI In Port + 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.sound.midi.alsa; + +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Receiver; +import javax.sound.midi.Transmitter; +import gnu.javax.sound.midi.alsa.AlsaMidiDeviceProvider.AlsaPortInfo; + +/** + * ALSA MIDI In Port. + * + * @author Anthony Green (green@redhat.com) + * + */ +public class AlsaInputPortDevice extends AlsaPortDevice +{ + + AlsaInputPortDevice (AlsaPortInfo info) + { + super(info); + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#open() + */ + public void open() throws MidiUnavailableException + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#close() + */ + public void close() + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#isOpen() + */ + public boolean isOpen() + { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#getMicrosecondPosition() + */ + public long getMicrosecondPosition() + { + // TODO Auto-generated method stub + return 0; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#getMaxReceivers() + */ + public int getMaxReceivers() + { + // TODO Auto-generated method stub + return 0; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#getMaxTransmitters() + */ + public int getMaxTransmitters() + { + // TODO Auto-generated method stub + return 1; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#getReceiver() + */ + public Receiver getReceiver() throws MidiUnavailableException + { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#getTransmitter() + */ + public Transmitter getTransmitter() throws MidiUnavailableException + { + return new AlsaTransmitter(); + } +} diff --git a/libjava/classpath/gnu/javax/sound/midi/alsa/AlsaMidiDeviceProvider.java b/libjava/classpath/gnu/javax/sound/midi/alsa/AlsaMidiDeviceProvider.java new file mode 100644 index 000000000..33181b6d5 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/midi/alsa/AlsaMidiDeviceProvider.java @@ -0,0 +1,216 @@ +/* AlsaMidiDeviceProvider.java -- The ALSA MIDI Device Provider + 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.sound.midi.alsa; + +import gnu.classpath.Configuration; + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiDevice.Info; +import javax.sound.midi.spi.MidiDeviceProvider; + +/** + * Provide ALSA MIDI devices. + * + * @author Anthony Green (green@redhat.com) + * + */ +public class AlsaMidiDeviceProvider extends MidiDeviceProvider +{ + /** + * Abstract base for ALSA specific MIDI device info. + * + * @author Anthony Green (green@redhat.com) + * + */ + private static abstract class AlsaInfo extends Info + { + /** + * Create an ALSA specific MIDI device info object. + * + * @param name the device name + * @param description the device description + */ + public AlsaInfo(String name, String description) + { + super(name, "Alsa", description, "0.0"); + } + + abstract MidiDevice getDevice (); + } + + /** + * ALSA MIDI Port. + * + * @author Anthony Green (green@redhat.com) + * + */ + public static abstract class AlsaPortInfo extends AlsaInfo + { + long client; + long port; + + /** + * Create ALSA MIDI In Port. + * + * @param name the device name + * @param description the device description + * @param client the client ID + * @param port the port ID + */ + public AlsaPortInfo(String name, String description, long client, long port) + { + super(name, description); + this.client = client; + this.port = port; + } + } + + /** + * ALSA Sequencer specific info. + * + * @author Anthony Green (green@redhat.com) + * + */ + private static class AlsaSequencerInfo extends AlsaInfo + { + public AlsaSequencerInfo(String name, String description) + { + super(name, description); + } + + MidiDevice getDevice() + { + return AlsaMidiSequencerDevice.getInstance(); + } + } + + /** + * ALSA MIDI In Port. + * + * @author Anthony Green (green@redhat.com) + * + */ + private static class AlsaInputPortInfo extends AlsaPortInfo + { + public AlsaInputPortInfo(String name, String description, long client, long port) + { + super(name, description, client, port); + } + + MidiDevice getDevice() + { + return new AlsaInputPortDevice(this); + } + } + + /** + * ALSA MIDI Out Port. + * + * @author Anthony Green (green@redhat.com) + * + */ + private static class AlsaOutputPortInfo extends AlsaPortInfo + { + public AlsaOutputPortInfo(String name, String description, long client, long port) + { + super(name, description, client, port); + } + + MidiDevice getDevice() + { + return new AlsaOutputPortDevice(this); + } + } + + private static AlsaInfo[] infos; + + private static native AlsaInfo[] getInputDeviceInfo_(); + private static native AlsaInfo[] getOutputDeviceInfo_(); + + /** + * Initialize the ALSA system + */ + private static native void init_(); + + static + { + if (Configuration.INIT_LOAD_LIBRARY) + { + System.loadLibrary("gjsmalsa"); + } + + init_(); + + AlsaInfo inputs[] = getInputDeviceInfo_(); + AlsaInfo outputs[] = getOutputDeviceInfo_(); + + infos = new AlsaInfo[inputs.length + outputs.length + 1]; + infos[0] = new AlsaSequencerInfo ("/dev/snd/seq", "ALSA Sequencer"); + System.arraycopy(inputs, 0, infos, 1, inputs.length); + System.arraycopy(outputs, 0, infos, 1 + inputs.length, outputs.length); + } + + public AlsaMidiDeviceProvider() + { + // Nothing. + } + + /* (non-Javadoc) + * @see javax.sound.midi.spi.MidiDeviceProvider#getDeviceInfo() + */ + public Info[] getDeviceInfo() + { + return infos; + } + + /* (non-Javadoc) + * @see javax.sound.midi.spi.MidiDeviceProvider#getDevice(javax.sound.midi.MidiDevice.Info) + */ + public MidiDevice getDevice(Info info) + { + for (int i = 0; i < infos.length; i++) + { + if (info.equals(infos[i])) + { + return infos[i].getDevice(); + } + } + throw new IllegalArgumentException("Don't recognize MIDI device " + info); + } +} diff --git a/libjava/classpath/gnu/javax/sound/midi/alsa/AlsaMidiSequencerDevice.java b/libjava/classpath/gnu/javax/sound/midi/alsa/AlsaMidiSequencerDevice.java new file mode 100644 index 000000000..3603bb5a7 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/midi/alsa/AlsaMidiSequencerDevice.java @@ -0,0 +1,515 @@ +/* AlsaMidiSequencerDevice.java -- The ALSA MIDI sequencer device + 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.sound.midi.alsa; + +import java.io.IOException; +import java.io.InputStream; + +import javax.sound.midi.ControllerEventListener; +import javax.sound.midi.InvalidMidiDataException; +import javax.sound.midi.MetaEventListener; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Receiver; +import javax.sound.midi.Sequence; +import javax.sound.midi.Sequencer; +import javax.sound.midi.Track; +import javax.sound.midi.Transmitter; + +/** + * The ALSA MIDI sequencer device. This is a singleton device. + * + * @author green@redhat.com + * + */ +public class AlsaMidiSequencerDevice implements Sequencer +{ + // The singleton instance. + public final static AlsaMidiSequencerDevice instance = new AlsaMidiSequencerDevice(); + + // A pointer to a native chunk of memory + private long nativeState; + + // The sequence to process + private Sequence sequence; + + /** + * A private constructor. There should only be one instance of this + * device. + */ + private AlsaMidiSequencerDevice() + { + super(); + } + + /** + * Return the sequencer singleton. + * + * @return the sequencer singleton + */ + public static AlsaMidiSequencerDevice getInstance() + { + return instance; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#setSequence(javax.sound.midi.Sequence) + */ + public void setSequence(Sequence seq) throws InvalidMidiDataException + { + sequence = seq; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#setSequence(java.io.InputStream) + */ + public void setSequence(InputStream istream) throws IOException, + InvalidMidiDataException + { + // TODO Auto-generated method stub + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#getSequence() + */ + public Sequence getSequence() + { + return sequence; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#start() + */ + public void start() + { + // TODO Auto-generated method stub + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#stop() + */ + public void stop() + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#isRunning() + */ + public boolean isRunning() + { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#startRecording() + */ + public void startRecording() + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#stopRecording() + */ + public void stopRecording() + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#isRecording() + */ + public boolean isRecording() + { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#recordEnable(javax.sound.midi.Track, int) + */ + public void recordEnable(Track track, int channel) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#recordDisable(javax.sound.midi.Track) + */ + public void recordDisable(Track track) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#getTempoInBPM() + */ + public float getTempoInBPM() + { + // TODO Auto-generated method stub + return 0; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#setTempoInBPM(float) + */ + public void setTempoInBPM(float bpm) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#getTempoInMPQ() + */ + public float getTempoInMPQ() + { + // TODO Auto-generated method stub + return 0; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#setTempoInMPQ(float) + */ + public void setTempoInMPQ(float mpq) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#setTempoFactor(float) + */ + public void setTempoFactor(float factor) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#getTempoFactor() + */ + public float getTempoFactor() + { + // TODO Auto-generated method stub + return 0; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#getTickLength() + */ + public long getTickLength() + { + // TODO Auto-generated method stub + return 0; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#getTickPosition() + */ + public long getTickPosition() + { + // TODO Auto-generated method stub + return 0; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#setTickPosition(long) + */ + public void setTickPosition(long tick) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#getMicrosecondLength() + */ + public long getMicrosecondLength() + { + // TODO Auto-generated method stub + return 0; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#getMicrosecondPosition() + */ + public long getMicrosecondPosition() + { + // TODO Auto-generated method stub + return 0; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#setMicrosecondPosition(long) + */ + public void setMicrosecondPosition(long microsecond) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#setMasterSyncMode(javax.sound.midi.Sequencer.SyncMode) + */ + public void setMasterSyncMode(SyncMode sync) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#getMasterSyncMode() + */ + public SyncMode getMasterSyncMode() + { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#getMasterSyncModes() + */ + public SyncMode[] getMasterSyncModes() + { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#setSlaveSyncMode(javax.sound.midi.Sequencer.SyncMode) + */ + public void setSlaveSyncMode(SyncMode sync) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#getSlaveSyncMode() + */ + public SyncMode getSlaveSyncMode() + { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#getSlaveSyncModes() + */ + public SyncMode[] getSlaveSyncModes() + { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#setTrackMute(int, boolean) + */ + public void setTrackMute(int track, boolean mute) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#getTrackMute(int) + */ + public boolean getTrackMute(int track) + { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#setTrackSolo(int, boolean) + */ + public void setTrackSolo(int track, boolean solo) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#getTrackSolo(int) + */ + public boolean getTrackSolo(int track) + { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#addMetaEventListener(javax.sound.midi.MetaEventListener) + */ + public boolean addMetaEventListener(MetaEventListener listener) + { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#removeMetaEventListener(javax.sound.midi.MetaEventListener) + */ + public void removeMetaEventListener(MetaEventListener listener) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#addControllerEventListener(javax.sound.midi.ControllerEventListener, int[]) + */ + public int[] addControllerEventListener(ControllerEventListener listener, + int[] controllers) + { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Sequencer#removeControllerEventListener(javax.sound.midi.ControllerEventListener, int[]) + */ + public int[] removeControllerEventListener(ControllerEventListener listener, + int[] controllers) + { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#getDeviceInfo() + */ + public Info getDeviceInfo() + { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#open() + */ + public void open() throws MidiUnavailableException + { + synchronized(this) + { + // Check to see if we're open already. + if (nativeState != 0) + return; + + nativeState = open_(); + } + } + + /** + * Allocate the native state object, and open the sequencer. + * + * @return a long representation of a pointer to the nativeState. + */ + private native long open_(); + + /** + * Close the sequencer and free the native state object. + */ + private native void close_(long nativeState); + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#close() + */ + public void close() + { + synchronized(this) + { + close_(nativeState); + nativeState = 0; + } + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#isOpen() + */ + public boolean isOpen() + { + synchronized(this) + { + return (nativeState != 0); + } + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#getMaxReceivers() + */ + public int getMaxReceivers() + { + return -1; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#getMaxTransmitters() + */ + public int getMaxTransmitters() + { + return -1; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#getReceiver() + */ + public Receiver getReceiver() throws MidiUnavailableException + { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#getTransmitter() + */ + public Transmitter getTransmitter() throws MidiUnavailableException + { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/libjava/classpath/gnu/javax/sound/midi/alsa/AlsaOutputPortDevice.java b/libjava/classpath/gnu/javax/sound/midi/alsa/AlsaOutputPortDevice.java new file mode 100644 index 000000000..9140d59ad --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/midi/alsa/AlsaOutputPortDevice.java @@ -0,0 +1,131 @@ +/* AlsaOutputPortDevice.java -- ALSA MIDI Output Port Device + 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.sound.midi.alsa; + +import gnu.javax.sound.midi.alsa.AlsaMidiDeviceProvider.AlsaPortInfo; + +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Receiver; +import javax.sound.midi.Transmitter; + +/** + * ALSA MIDI Out Device + * + * @author Anthony Green (green@redhat.com) + * + */ +public class AlsaOutputPortDevice extends AlsaPortDevice +{ + AlsaOutputPortDevice (AlsaPortInfo info) + { + super(info); + } + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#open() + */ + public void open() throws MidiUnavailableException + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#close() + */ + public void close() + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#isOpen() + */ + public boolean isOpen() + { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#getMicrosecondPosition() + */ + public long getMicrosecondPosition() + { + // TODO Auto-generated method stub + return 0; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#getMaxReceivers() + */ + public int getMaxReceivers() + { + // TODO Auto-generated method stub + return 1; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#getMaxTransmitters() + */ + public int getMaxTransmitters() + { + // TODO Auto-generated method stub + return 0; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#getReceiver() + */ + public Receiver getReceiver() throws MidiUnavailableException + { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#getTransmitter() + */ + public Transmitter getTransmitter() throws MidiUnavailableException + { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/libjava/classpath/gnu/javax/sound/midi/alsa/AlsaPortDevice.java b/libjava/classpath/gnu/javax/sound/midi/alsa/AlsaPortDevice.java new file mode 100644 index 000000000..f55941ba5 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/midi/alsa/AlsaPortDevice.java @@ -0,0 +1,150 @@ +/* AlsaPortDevice.java -- ALSA MIDI Port Devices + 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.sound.midi.alsa; + +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiMessage; +import javax.sound.midi.Receiver; +import javax.sound.midi.Transmitter; + +import gnu.javax.sound.midi.alsa.AlsaMidiDeviceProvider.AlsaPortInfo; + +/** + * ALSA Port Device + * + * @author Anthony Green (green@redhat.com) + * + */ +public abstract class AlsaPortDevice implements MidiDevice +{ + /** + * The ALSA Receiver class. + * + * @author Anthony Green (green@redhat.com) + * + */ + public class AlsaReceiver implements Receiver + { + /* (non-Javadoc) + * @see javax.sound.midi.Receiver#send(javax.sound.midi.MidiMessage, long) + */ + public void send(MidiMessage message, long timeStamp) + throws IllegalStateException + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Receiver#close() + */ + public void close() + { + // TODO Auto-generated method stub + + } + } + + AlsaMidiDeviceProvider.AlsaPortInfo info; + + public AlsaPortDevice (AlsaPortInfo info) + { + this.info = info; + } + + public Info getDeviceInfo() + { + return info; + } + + native void run_receiver_thread_ (long client, long port, Receiver receiver); + + /** + * The ALSA Transmitter class. + * + * @author Anthony Green (green@redhat.com) + * + */ + protected class AlsaTransmitter implements Transmitter, Runnable + { + private Receiver receiver; + + public void run() + { + run_receiver_thread_ (info.client, info.port, receiver); + } + + /* (non-Javadoc) + * @see javax.sound.midi.Transmitter#setReceiver(javax.sound.midi.Receiver) + */ + public void setReceiver(Receiver receiver) + { + synchronized (this) + { + this.receiver = receiver; + } + + // Create the processing thread + new Thread(this).start(); + } + + /* (non-Javadoc) + * @see javax.sound.midi.Transmitter#getReceiver() + */ + public Receiver getReceiver() + { + synchronized (this) + { + return receiver; + } + } + + /* (non-Javadoc) + * @see javax.sound.midi.Transmitter#close() + */ + public void close() + { + synchronized (this) + { + receiver.close(); + receiver = null; + } + } + } +} diff --git a/libjava/classpath/gnu/javax/sound/midi/dssi/DSSIMidiDeviceProvider.java b/libjava/classpath/gnu/javax/sound/midi/dssi/DSSIMidiDeviceProvider.java new file mode 100644 index 000000000..605c6dfb7 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/midi/dssi/DSSIMidiDeviceProvider.java @@ -0,0 +1,171 @@ +/* DSSIMidiDeviceProvider.java -- DSSI Device Provider + 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.sound.midi.dssi; + +import java.util.ArrayList; +import java.util.List; +import java.io.File; +import java.io.FilenameFilter; + +import gnu.classpath.Configuration; +import javax.sound.midi.MidiDevice; +import javax.sound.midi.MidiDevice.Info; +import javax.sound.midi.spi.MidiDeviceProvider; + +/** + * A DSSI MIDI device provider. + * + * DSSI (pronounced "dizzy") is an API for audio plugins, with particular + * application for software synthesis plugins with native user interfaces. + * + * Read about DSSI at http://dssi.sourceforge.net + * + * @author Anthony Green (green@redhat.com) + * + */ +public class DSSIMidiDeviceProvider extends MidiDeviceProvider +{ + /** + * The MidiDevice.Info specialized for DSSI synthesizers. + * + * @author Anthony Green (green@redhat.com) + * + */ + private static class DSSIInfo extends Info + { + String soname; + long index; + + public DSSIInfo(String name, String vendor, String description, + String version, String soname, long index) + { + super(name, vendor, description, version); + this.soname = soname; + this.index = index; + } + } + + static native long dlopen_(String soname); + static native void dlclose_(long sohandle); + static native long getDSSIHandle_(long sohandle, long index); + static native String getDSSIName_(long handle); + static native String getDSSICopyright_(long handle); + static native String getDSSIVendor_(long handle); + static native String getDSSILabel_(long handle); + + private static List examineLibrary(String soname) + { + List list = new ArrayList(); + long index = 0; + long handle; + + long sohandle = dlopen_(soname); + if (sohandle == 0) + return list; + do + { + handle = getDSSIHandle_(sohandle, index); + if (handle == 0) + break; + String name = getDSSILabel_(handle); + String copyright = getDSSICopyright_(handle); + String label = getDSSIName_(handle); + String vendor = getDSSIVendor_(handle); + list.add(new DSSIInfo(name, vendor, label, + "DSSI-1", soname, index)); + index++; + } while (true); + + // Close the library and free memory + dlclose_(sohandle); + + return list; + } + + private static DSSIInfo[] infos; + + static + { + if (Configuration.INIT_LOAD_LIBRARY) + System.loadLibrary("gjsmdssi"); + + File dssidir = new File("/usr/lib/dssi/"); + String sofiles[] = dssidir.list(new FilenameFilter() + { + public boolean accept(File dir, String n) + { + return n.endsWith(".so"); + } + }); + List ilist = new ArrayList(); + for (int i = 0; i < sofiles.length; i++) + ilist.addAll(examineLibrary(new File(dssidir, sofiles[i]).getAbsolutePath())); + infos = (DSSIInfo[]) ilist.toArray(new DSSIInfo[ilist.size()]); + } + + public DSSIMidiDeviceProvider() + { + // Empty. + } + + /* Return the Info array. + * @see javax.sound.midi.spi.MidiDeviceProvider#getDeviceInfo() + */ + public Info[] getDeviceInfo() + { + return infos; + } + + /* Get a MIDI Device for info. + * @see javax.sound.midi.spi.MidiDeviceProvider#getDevice(javax.sound.midi.MidiDevice.Info) + */ + public MidiDevice getDevice(Info info) + { + for (int i = 0; i < infos.length; i++) + { + if (info.equals(infos[i])) + { + return new DSSISynthesizer(infos[i], + infos[i].soname, + infos[i].index); + } + } + throw new IllegalArgumentException("Don't recognize MIDI device " + info); + } +} diff --git a/libjava/classpath/gnu/javax/sound/midi/dssi/DSSISynthesizer.java b/libjava/classpath/gnu/javax/sound/midi/dssi/DSSISynthesizer.java new file mode 100644 index 000000000..9472ee4ad --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/midi/dssi/DSSISynthesizer.java @@ -0,0 +1,742 @@ +/* DSSISynthesizer.java -- DSSI Synthesizer Provider + 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.sound.midi.dssi; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import javax.sound.midi.Instrument; +import javax.sound.midi.MidiChannel; +import javax.sound.midi.MidiMessage; +import javax.sound.midi.MidiUnavailableException; +import javax.sound.midi.Patch; +import javax.sound.midi.Receiver; +import javax.sound.midi.ShortMessage; +import javax.sound.midi.Soundbank; +import javax.sound.midi.SoundbankResource; +import javax.sound.midi.Synthesizer; +import javax.sound.midi.Transmitter; +import javax.sound.midi.VoiceStatus; + +/** + * DSSI soft-synth support. + * + * All DSSI soft-synths are expected to be installed in /usr/lib/dssi. + * + * @author Anthony Green (green@redhat.com) + * + */ +public class DSSISynthesizer implements Synthesizer +{ + /** + * The DSSI Instrument class. + * + * @author Anthony Green (green@redhat.com) + * + */ + class DSSIInstrument extends Instrument + { + DSSIInstrument (Soundbank soundbank, Patch patch, String name) + { + super (soundbank, patch, name, null); + } + + /* @see javax.sound.midi.SoundbankResource#getData() + */ + public Object getData() + { + return null; + } + + } + +/** + * DSSISoundbank holds all instruments. + * + * @author Anthony Green (green@redhat.com) + * + */ + class DSSISoundbank implements Soundbank + { + private String name; + private String description; + private List instruments = new ArrayList(); + private List resources = new ArrayList(); + private String vendor; + private String version; + + public DSSISoundbank(String name, String description, String vendor, String version) + { + this.name = name; + this.description = description; + this.vendor = vendor; + this.version = version; + } + + void add(Instrument instrument) + { + instruments.add(instrument); + } + + /* @see javax.sound.midi.Soundbank#getName() + */ + public String getName() + { + return name; + } + + /* @see javax.sound.midi.Soundbank#getVersion() + */ + public String getVersion() + { + return version; + } + + /* @see javax.sound.midi.Soundbank#getVendor() + */ + public String getVendor() + { + return vendor; + } + + /* @see javax.sound.midi.Soundbank#getDescription() + */ + public String getDescription() + { + return description; + } + + /* @see javax.sound.midi.Soundbank#getResources() + */ + public SoundbankResource[] getResources() + { + return (SoundbankResource[]) + resources.toArray(new SoundbankResource[resources.size()]); + } + + /* @see javax.sound.midi.Soundbank#getInstruments() + */ + public Instrument[] getInstruments() + { + return (Instrument[]) + instruments.toArray(new Instrument[instruments.size()]); + } + + /* @see javax.sound.midi.Soundbank#getInstrument(javax.sound.midi.Patch) + */ + public Instrument getInstrument(Patch patch) + { + Iterator itr = instruments.iterator(); + + while (itr.hasNext()) + { + Instrument i = (Instrument) itr.next(); + if (i.getPatch().equals(patch)) + return i; + } + + return null; + } + } + +/** + * The Receiver class receives all MIDI messages from a connected + * Transmitter. + * + * @author Anthony Green (green@redhat.com) + * + */ + class DSSIReceiver implements Receiver + { + /* (non-Javadoc) + * @see javax.sound.midi.Receiver#send(javax.sound.midi.MidiMessage, long) + */ + public void send(MidiMessage message, long timeStamp) + throws IllegalStateException + { + if (message instanceof ShortMessage) + { + ShortMessage smessage = (ShortMessage) message; + + switch (message.getStatus()) + { + case ShortMessage.NOTE_ON: + int velocity = smessage.getData2(); + if (velocity > 0) + channels[smessage.getChannel()].noteOn(smessage.getData1(), + smessage.getData2()); + else + channels[smessage.getChannel()].noteOff(smessage.getData1()); + break; + case ShortMessage.CONTROL_CHANGE: + channels[smessage.getChannel()].controlChange(smessage.getData1(), + smessage.getData2()); + break; + default: + System.out.println ("Unhandled message: " + message.getStatus()); + break; + } + } + } + + /* (non-Javadoc) + * @see javax.sound.midi.Receiver#close() + */ + public void close() + { + // TODO Auto-generated method stub + } + + } + + static native void noteOn_(long handle, int channel, int noteNumber, int velocity); + static native void noteOff_(long handle, int channel, int noteNumber, int velocity); + static native void setPolyPressure_(long handle, int channel, int noteNumber, int pressure); + static native int getPolyPressure_(long handle, int channel, int noteNumber); + static native void controlChange_(long handle, int channel, int control, int value); + static native void open_(long handle); + static native void close_(long handle); + static native String getProgramName_(long handle, int index); + static native int getProgramBank_(long handle, int index); + static native int getProgramProgram_(long handle, int index); + static native void selectProgram_(long handle, int bank, int program); + + /** + * @author Anthony Green (green@redhat.com) + * + */ + public class DSSIMidiChannel implements MidiChannel + { + int channel = 0; + + /** + * Default contructor. + */ + public DSSIMidiChannel(int channel) + { + super(); + this.channel = channel; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#noteOn(int, int) + */ + public void noteOn(int noteNumber, int velocity) + { + noteOn_(sohandle, channel, noteNumber, velocity); + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#noteOff(int, int) + */ + public void noteOff(int noteNumber, int velocity) + { + noteOff_(sohandle, channel, noteNumber, velocity); + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#noteOff(int) + */ + public void noteOff(int noteNumber) + { + noteOff_(sohandle, channel, noteNumber, -1); + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#setPolyPressure(int, int) + */ + public void setPolyPressure(int noteNumber, int pressure) + { + setPolyPressure_(sohandle, channel, noteNumber, pressure); + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#getPolyPressure(int) + */ + public int getPolyPressure(int noteNumber) + { + return getPolyPressure_(sohandle, channel, noteNumber); + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#setChannelPressure(int) + */ + public void setChannelPressure(int pressure) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#getChannelPressure() + */ + public int getChannelPressure() + { + // TODO Auto-generated method stub + return 0; + } + + /* @see javax.sound.midi.MidiChannel#controlChange(int, int) */ + public void controlChange(int controller, int value) + { + controlChange_(sohandle, channel, controller, value); + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#getController(int) + */ + public int getController(int controller) + { + // TODO Auto-generated method stub + return 0; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#programChange(int) + */ + public void programChange(int program) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#programChange(int, int) + */ + public void programChange(int bank, int program) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#getProgram() + */ + public int getProgram() + { + // TODO Auto-generated method stub + return 0; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#setPitchBend(int) + */ + public void setPitchBend(int bend) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#getPitchBend() + */ + public int getPitchBend() + { + // TODO Auto-generated method stub + return 0; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#resetAllControllers() + */ + public void resetAllControllers() + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#allNotesOff() + */ + public void allNotesOff() + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#allSoundOff() + */ + public void allSoundOff() + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#localControl(boolean) + */ + public boolean localControl(boolean on) + { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#setMono(boolean) + */ + public void setMono(boolean on) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#getMono() + */ + public boolean getMono() + { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#setOmni(boolean) + */ + public void setOmni(boolean on) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#getOmni() + */ + public boolean getOmni() + { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#setMute(boolean) + */ + public void setMute(boolean mute) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#getMute() + */ + public boolean getMute() + { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#setSolo(boolean) + */ + public void setSolo(boolean solo) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiChannel#getSolo() + */ + public boolean getSolo() + { + // TODO Auto-generated method stub + return false; + } + + } + + long sohandle; + long handle; + private Info info; + + MidiChannel channels[] = new MidiChannel[16]; + + // The list of known soundbanks, and the default one. + List soundbanks = new ArrayList(); + DSSISoundbank defaultSoundbank; + + /** + * Create a DSSI Synthesizer. + * + * @param info the DSSIInfo for this soft-synth + * @param soname the name of the .so file for this DSSI synth + * @param index the DSSI index for this soft-synth + */ + public DSSISynthesizer(Info info, String soname, long index) + { + super(); + this.info = info; + sohandle = DSSIMidiDeviceProvider.dlopen_(soname); + handle = DSSIMidiDeviceProvider.getDSSIHandle_(sohandle, index); + channels[0] = new DSSIMidiChannel(0); + defaultSoundbank = new DSSISoundbank("name", "description", + "vendor", "version"); + soundbanks.add(defaultSoundbank); + + int i = 0; + String name; + do + { + name = getProgramName_(sohandle, i); + if (name != null) + { + defaultSoundbank. + add(new DSSIInstrument(defaultSoundbank, + new Patch(getProgramBank_(sohandle, i), + getProgramProgram_(sohandle, i)), + name)); + i++; + } + } while (name != null); + } + + /* (non-Javadoc) + * @see javax.sound.midi.Synthesizer#getMaxPolyphony() + */ + public int getMaxPolyphony() + { + // TODO Auto-generated method stub + return 0; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Synthesizer#getLatency() + */ + public long getLatency() + { + // DSSI and LADSPA provide no way to determine the latency. + // Let's just return 0 for now. + return 0; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Synthesizer#getChannels() + */ + public MidiChannel[] getChannels() + { + return channels; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Synthesizer#getVoiceStatus() + */ + public VoiceStatus[] getVoiceStatus() + { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Synthesizer#isSoundbankSupported(javax.sound.midi.Soundbank) + */ + public boolean isSoundbankSupported(Soundbank soundbank) + { + // TODO Auto-generated method stub + return false; + } + + /* @see javax.sound.midi.Synthesizer#loadInstrument(javax.sound.midi.Instrument) + */ + public boolean loadInstrument(Instrument instrument) + { + // FIXME: perhaps this isn't quite right. It can probably + // be in any soundbank. + if (instrument.getSoundbank() != defaultSoundbank) + throw new IllegalArgumentException ("Synthesizer doesn't support this instrument's soundbank"); + + Patch patch = instrument.getPatch(); + selectProgram_(sohandle, patch.getBank(), patch.getProgram()); + return true; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Synthesizer#unloadInstrument(javax.sound.midi.Instrument) + */ + public void unloadInstrument(Instrument instrument) + { + // TODO Auto-generated method stub + + } + + /* (non-Javadoc) + * @see javax.sound.midi.Synthesizer#remapInstrument(javax.sound.midi.Instrument, javax.sound.midi.Instrument) + */ + public boolean remapInstrument(Instrument from, Instrument to) + { + // TODO Auto-generated method stub + return false; + } + + /* @see javax.sound.midi.Synthesizer#getDefaultSoundbank() + */ + public Soundbank getDefaultSoundbank() + { + return defaultSoundbank; + } + + /* @see javax.sound.midi.Synthesizer#getAvailableInstruments() + */ + public Instrument[] getAvailableInstruments() + { + List instruments = new ArrayList(); + Iterator itr = soundbanks.iterator(); + while (itr.hasNext()) + { + Soundbank sb = (Soundbank) itr.next(); + Instrument ins[] = sb.getInstruments(); + for (int i = 0; i < ins.length; i++) + instruments.add(ins[i]); + } + return (Instrument[]) + instruments.toArray(new Instrument[instruments.size()]); + } + + /* (non-Javadoc) + * @see javax.sound.midi.Synthesizer#getLoadedInstruments() + */ + public Instrument[] getLoadedInstruments() + { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Synthesizer#loadAllInstruments(javax.sound.midi.Soundbank) + */ + public boolean loadAllInstruments(Soundbank soundbank) + { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Synthesizer#unloadAllInstruments(javax.sound.midi.Soundbank) + */ + public void unloadAllInstruments(Soundbank soundbank) + { + // TODO Auto-generated method stub + } + + /* (non-Javadoc) + * @see javax.sound.midi.Synthesizer#loadInstruments(javax.sound.midi.Soundbank, javax.sound.midi.Patch[]) + */ + public boolean loadInstruments(Soundbank soundbank, Patch[] patchList) + { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see javax.sound.midi.Synthesizer#unloadInstruments(javax.sound.midi.Soundbank, javax.sound.midi.Patch[]) + */ + public void unloadInstruments(Soundbank soundbank, Patch[] patchList) + { + // TODO Auto-generated method stub + + } + + /* @see javax.sound.midi.MidiDevice#getDeviceInfo() + */ + public Info getDeviceInfo() + { + return info; + } + + /* @see javax.sound.midi.MidiDevice#open() + */ + public void open() throws MidiUnavailableException + { + open_(sohandle); + } + + /* @see javax.sound.midi.MidiDevice#close() + */ + public void close() + { + close_(sohandle); + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#isOpen() + */ + public boolean isOpen() + { + // TODO Auto-generated method stub + return false; + } + + /* (non-Javadoc) + * @see javax.sound.midi.MidiDevice#getMicrosecondPosition() + */ + public long getMicrosecondPosition() + { + // TODO Auto-generated method stub + return 0; + } + + /* @see javax.sound.midi.MidiDevice#getMaxReceivers() + */ + public int getMaxReceivers() + { + return 1; + } + + /* @see javax.sound.midi.MidiDevice#getMaxTransmitters() + */ + public int getMaxTransmitters() + { + return 0; + } + + /* @see javax.sound.midi.MidiDevice#getReceiver() + */ + public Receiver getReceiver() throws MidiUnavailableException + { + return new DSSIReceiver(); + } + + /* @see javax.sound.midi.MidiDevice#getTransmitter() + */ + public Transmitter getTransmitter() throws MidiUnavailableException + { + return null; + } +} diff --git a/libjava/classpath/gnu/javax/sound/midi/file/ExtendedMidiFileFormat.java b/libjava/classpath/gnu/javax/sound/midi/file/ExtendedMidiFileFormat.java new file mode 100644 index 000000000..4b065f3dc --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/midi/file/ExtendedMidiFileFormat.java @@ -0,0 +1,77 @@ +/* ExtendedMidiFileFormat.java -- extended with track count info. + 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.sound.midi.file; + +/** + * ExtendedMidiFileFormat is a package private class that simply + * adds the number of MIDI tracks for the MidiFileFormat class. + * + * @author Anthony Green (green@redhat.com) + */ +class ExtendedMidiFileFormat + extends javax.sound.midi.MidiFileFormat +{ + private int ntracks; + + /** + * Get the number of tracks for this MIDI file. + * + * @return the number of tracks for this MIDI file + */ + public int getNumberTracks() + { + return ntracks; + } + + /** + * Create an ExtendedMidiFileFormat object from the given parameters. + * + * @param type the MIDI file type (0, 1, or 2) + * @param divisionType the MIDI file division type + * @param resolution the MIDI file timing resolution + * @param bytes the MIDI file size in bytes + * @param microseconds the MIDI file length in microseconds + * @param ntracks the number of tracks + */ + public ExtendedMidiFileFormat(int type, float divisionType, int resolution, + int bytes, long microseconds, int ntracks) + { + super(type, divisionType, resolution, bytes, microseconds); + this.ntracks = ntracks; + } +} diff --git a/libjava/classpath/gnu/javax/sound/midi/file/MidiDataInputStream.java b/libjava/classpath/gnu/javax/sound/midi/file/MidiDataInputStream.java new file mode 100644 index 000000000..d91970b9f --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/midi/file/MidiDataInputStream.java @@ -0,0 +1,83 @@ +/* MidiDataInputStream.java -- adds variable length MIDI ints + 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.sound.midi.file; + +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * MidiDataInputStream is simply a DataInputStream with the addition + * of special variable length int reading as defined by the MIDI spec. + * + * @author Anthony Green (green@redhat.com) + */ +public class MidiDataInputStream + extends DataInputStream +{ + /** + * Create a MidiDataInputStream. + */ + public MidiDataInputStream(InputStream is) + { + super(is); + } + + /** + * Read an int encoded in the MIDI-style variable length + * encoding format. + * + * @return an int + */ + public int readVariableLengthInt() + throws IOException + { + int c, value = readByte(); + + if ((value & 0x80) != 0) + { + value &= 0x7F; + do + { + value = (value << 7) + ((c = readByte()) & 0x7F); + } while ((c & 0x80) != 0); + } + + return value; + } +} diff --git a/libjava/classpath/gnu/javax/sound/midi/file/MidiDataOutputStream.java b/libjava/classpath/gnu/javax/sound/midi/file/MidiDataOutputStream.java new file mode 100644 index 000000000..79c66e8a2 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/midi/file/MidiDataOutputStream.java @@ -0,0 +1,114 @@ +/* MidiDataOutputStream.java -- adds variable length MIDI ints + 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.sound.midi.file; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * MidiDataOutputStream is simply a DataOutputStream with the addition + * of special variable length int writing as defined by the MIDI spec. + * + * @author Anthony Green (green@redhat.com) + */ +public class MidiDataOutputStream + extends DataOutputStream +{ + /** + * Create a MidiDataOutputStream. + */ + public MidiDataOutputStream(OutputStream os) + { + super(os); + } + + /** + * Return the length of a variable length encoded int without + * writing it out. + * + * @return the length of the encoding + */ + public int variableLengthIntLength (int value) + { + int length = 0; + int buffer = value & 0x7F; + + while ((value >>= 7) != 0) + { + buffer <<= 8; + buffer |= ((value & 0x7F) | 0x80); + } + + while (true) + { + length++; + if ((buffer & 0x80) != 0) + buffer >>>= 8; + else + break; + } + + return length; + } + + /** + * Write an int encoded in the MIDI-style variable length + * encoding format. + */ + public synchronized void writeVariableLengthInt (int value) + throws IOException + { + int buffer = value & 0x7F; + + while ((value >>= 7) != 0) + { + buffer <<= 8; + buffer |= ((value & 0x7F) | 0x80); + } + + while (true) + { + writeByte(buffer & 0xff); + if ((buffer & 0x80) != 0) + buffer >>>= 8; + else + break; + } + } +} diff --git a/libjava/classpath/gnu/javax/sound/midi/file/MidiFileReader.java b/libjava/classpath/gnu/javax/sound/midi/file/MidiFileReader.java new file mode 100644 index 000000000..fb2a472fa --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/midi/file/MidiFileReader.java @@ -0,0 +1,378 @@ +/* MidiFileReader.java -- Read MIDI files. + 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.sound.midi.file; + +import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + +import javax.sound.midi.InvalidMidiDataException; +import javax.sound.midi.MetaMessage; +import javax.sound.midi.MidiEvent; +import javax.sound.midi.MidiFileFormat; +import javax.sound.midi.MidiMessage; +import javax.sound.midi.Sequence; +import javax.sound.midi.ShortMessage; +import javax.sound.midi.SysexMessage; +import javax.sound.midi.Track; + +/** + * A MIDI file reader. + * + * This code reads MIDI file types 0 and 1. + * + * There are many decent documents on the web describing the MIDI file + * format. I didn't bother looking for the official document. If it + * exists, I'm not even sure if it is freely available. We should + * update this comment if we find out anything helpful here. + * + * @author Anthony Green (green@redhat.com) + * + */ +public class MidiFileReader extends javax.sound.midi.spi.MidiFileReader +{ + /* Get the MidiFileFormat for the given input stream. + * @see javax.sound.midi.spi.MidiFileReader#getMidiFileFormat(java.io.InputStream) + */ + public MidiFileFormat getMidiFileFormat(InputStream in) + throws InvalidMidiDataException, IOException + { + DataInputStream din; + if (in instanceof DataInputStream) + din = (DataInputStream) in; + else + din = new DataInputStream(in); + + int type, ntracks, division, resolution, bytes; + float divisionType; + + if (din.readInt() != 0x4d546864) // "MThd" + throw new InvalidMidiDataException("Invalid MIDI chunk header."); + + bytes = din.readInt(); + if (bytes < 6) + throw new + InvalidMidiDataException("Invalid MIDI chunk header length: " + bytes); + + type = din.readShort(); + if (type < 0 || type > 2) + throw new + InvalidMidiDataException("Invalid MIDI file type value: " + type); + + ntracks = din.readShort(); + if (ntracks <= 0) + throw new + InvalidMidiDataException("Invalid number of MIDI tracks: " + ntracks); + + division = din.readShort(); + if ((division & 0x8000) != 0) + { + division = -((division >>> 8) & 0xFF); + switch (division) + { + case 24: + divisionType = Sequence.SMPTE_24; + break; + + case 25: + divisionType = Sequence.SMPTE_25; + break; + + case 29: + divisionType = Sequence.SMPTE_30DROP; + break; + + case 30: + divisionType = Sequence.SMPTE_30; + break; + + default: + throw new + InvalidMidiDataException("Invalid MIDI frame division type: " + + division); + } + resolution = division & 0xff; + } + else + { + divisionType = Sequence.PPQ; + resolution = division & 0x7fff; + } + + // If we haven't read every byte in the header now, just skip the rest. + din.skip(bytes - 6); + + return new ExtendedMidiFileFormat(type, divisionType, resolution, + MidiFileFormat.UNKNOWN_LENGTH, + MidiFileFormat.UNKNOWN_LENGTH, ntracks); + } + + /* Get the MidiFileFormat from the given URL. + * @see javax.sound.midi.spi.MidiFileReader#getMidiFileFormat(java.net.URL) + */ + public MidiFileFormat getMidiFileFormat(URL url) + throws InvalidMidiDataException, IOException + { + InputStream is = url.openStream(); + try + { + return getMidiFileFormat(is); + } + finally + { + is.close(); + } + } + + /* Get the MidiFileFormat from the given file. + * @see javax.sound.midi.spi.MidiFileReader#getMidiFileFormat(java.io.File) + */ + public MidiFileFormat getMidiFileFormat(File file) + throws InvalidMidiDataException, IOException + { + InputStream is = new FileInputStream(file); + try + { + return getMidiFileFormat(is); + } + finally + { + is.close(); + } + } + + /* Get the MIDI Sequence found in this input stream. + * @see javax.sound.midi.spi.MidiFileReader#getSequence(java.io.InputStream) + */ + public Sequence getSequence(InputStream is) throws InvalidMidiDataException, + IOException + { + MidiDataInputStream din = new MidiDataInputStream(is); + ExtendedMidiFileFormat mff = (ExtendedMidiFileFormat) getMidiFileFormat(din); + + Sequence seq = new Sequence(mff.getDivisionType(), mff.getResolution()); + + int ntracks = mff.getNumberTracks(); + + while (ntracks-- > 0) + { + Track track = seq.createTrack(); + int Mtrk = din.readInt(); + if (Mtrk != 0x4d54726b) + throw new InvalidMidiDataException("Invalid MIDI track header."); + int length = din.readInt(); + + int runningStatus = -1; + int click = 0; + + // Set this to true when we've hit an End of Track meta event. + boolean done = false; + + // Read all events. + while (! done) + { + MidiMessage mm; + int dtime = din.readVariableLengthInt(); + click += dtime; + + int sbyte = din.readUnsignedByte(); + + if (sbyte < 0xf0) + { + ShortMessage sm; + switch (sbyte & 0xf0) + { + case ShortMessage.NOTE_OFF: + case ShortMessage.NOTE_ON: + case ShortMessage.POLY_PRESSURE: + case ShortMessage.CONTROL_CHANGE: + case ShortMessage.PITCH_BEND: + case ShortMessage.SONG_POSITION_POINTER: + sm = new ShortMessage(); + sm.setMessage(sbyte, din.readByte(), din.readByte()); + runningStatus = sbyte; + break; + + case ShortMessage.PROGRAM_CHANGE: + case ShortMessage.CHANNEL_PRESSURE: + case ShortMessage.SONG_SELECT: + case 0xF5: // FIXME: unofficial bus select. Not in spec?? + sm = new ShortMessage(); + sm.setMessage(sbyte, din.readByte(), 0); + runningStatus = sbyte; + break; + + case ShortMessage.TUNE_REQUEST: + case ShortMessage.END_OF_EXCLUSIVE: + case ShortMessage.TIMING_CLOCK: + case ShortMessage.START: + case ShortMessage.CONTINUE: + case ShortMessage.STOP: + case ShortMessage.ACTIVE_SENSING: + case ShortMessage.SYSTEM_RESET: + sm = new ShortMessage(); + sm.setMessage(sbyte, 0, 0); + runningStatus = sbyte; + break; + + default: + if (runningStatus != - 1) + { + switch (runningStatus & 0xf0) + { + case ShortMessage.NOTE_OFF: + case ShortMessage.NOTE_ON: + case ShortMessage.POLY_PRESSURE: + case ShortMessage.CONTROL_CHANGE: + case ShortMessage.PITCH_BEND: + case ShortMessage.SONG_POSITION_POINTER: + sm = new ShortMessage(); + sm.setMessage(runningStatus, sbyte, din.readByte()); + break; + + case ShortMessage.PROGRAM_CHANGE: + case ShortMessage.CHANNEL_PRESSURE: + case ShortMessage.SONG_SELECT: + case 0xF5: // FIXME: unofficial bus select. Not in + // spec?? + sm = new ShortMessage(); + sm.setMessage(runningStatus, sbyte, 0); + continue; + + case ShortMessage.TUNE_REQUEST: + case ShortMessage.END_OF_EXCLUSIVE: + case ShortMessage.TIMING_CLOCK: + case ShortMessage.START: + case ShortMessage.CONTINUE: + case ShortMessage.STOP: + case ShortMessage.ACTIVE_SENSING: + case ShortMessage.SYSTEM_RESET: + sm = new ShortMessage(); + sm.setMessage(runningStatus, 0, 0); + continue; + + default: + throw new + InvalidMidiDataException("Invalid Short MIDI Event: " + + sbyte); + } + } + else + throw new + InvalidMidiDataException("Invalid Short MIDI Event: " + + sbyte); + } + mm = sm; + } + else if (sbyte == 0xf0 || sbyte == 0xf7) + { + // System Exclusive event + int slen = din.readVariableLengthInt(); + byte sysex[] = new byte[slen]; + din.readFully(sysex); + SysexMessage sm = new SysexMessage(); + sm.setMessage(sbyte, sysex, slen); + mm = sm; + runningStatus = - 1; + } + else if (sbyte == 0xff) + { + // Meta Message + byte mtype = din.readByte(); + int mlen = din.readVariableLengthInt(); + byte meta[] = new byte[mlen]; + din.readFully(meta); + MetaMessage metam = new MetaMessage(); + metam.setMessage(mtype, meta, mlen); + mm = metam; + + if (mtype == 0x2f) // End of Track + done = true; + + runningStatus = - 1; + } + else + { + throw new InvalidMidiDataException("Invalid status byte: " + + sbyte); + } + + track.add(new MidiEvent(mm, click)); + } + } + + return seq; + } + + /* Get the MIDI Sequence found at the given URL. + * @see javax.sound.midi.spi.MidiFileReader#getSequence(java.net.URL) + */ + public Sequence getSequence(URL url) throws InvalidMidiDataException, + IOException + { + InputStream is = url.openStream(); + try + { + return getSequence(is); + } + finally + { + is.close(); + } + } + + /* Get the MIDI Sequence found in the given file. + * @see javax.sound.midi.spi.MidiFileReader#getSequence(java.io.File) + */ + public Sequence getSequence(File file) throws InvalidMidiDataException, + IOException + { + InputStream is = new FileInputStream(file); + try + { + return getSequence(is); + } + finally + { + is.close(); + } + } +} diff --git a/libjava/classpath/gnu/javax/sound/midi/file/MidiFileWriter.java b/libjava/classpath/gnu/javax/sound/midi/file/MidiFileWriter.java new file mode 100644 index 000000000..5170fc1e7 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/midi/file/MidiFileWriter.java @@ -0,0 +1,197 @@ +/* MidiFileWriter.java -- Write MIDI files. + 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.sound.midi.file; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import javax.sound.midi.MetaMessage; +import javax.sound.midi.MidiEvent; +import javax.sound.midi.Sequence; +import javax.sound.midi.Track; + +/** + * A MIDI file writer. + * + * This code writes MIDI file types 0 and 1. + * + * There are many decent documents on the web describing the MIDI file + * format. I didn't bother looking for the official document. If it + * exists, I'm not even sure if it is freely available. We should + * update this comment if we find out anything helpful here. + * + * @author Anthony Green (green@redhat.com) + * + */ +public class MidiFileWriter + extends javax.sound.midi.spi.MidiFileWriter +{ + /* Return an array indicating which midi file types are supported. + * @see javax.sound.midi.spi.MidiFileWriter#getMidiFileTypes() + */ + public int[] getMidiFileTypes() + { + return new int[]{0, 1}; + } + + /* Return an array indicating which midi file types are supported + * for a given Sequence. + * @see javax.sound.midi.spi.MidiFileWriter#getMidiFileTypes(javax.sound.midi.Sequence) + */ + public int[] getMidiFileTypes(Sequence sequence) + { + if (sequence.getTracks().length == 1) + return new int[]{0}; + else + return new int[]{1}; + } + + /* Write a sequence to an output stream in standard midi format. + * @see javax.sound.midi.spi.MidiFileWriter#write(javax.sound.midi.Sequence, int, java.io.OutputStream) + */ + public int write(Sequence in, int fileType, OutputStream out) + throws IOException + { + MidiDataOutputStream dos = new MidiDataOutputStream (out); + Track[] tracks = in.getTracks(); + dos.writeInt(0x4d546864); // MThd + dos.writeInt(6); + dos.writeShort(fileType); + dos.writeShort(tracks.length); + float divisionType = in.getDivisionType(); + int resolution = in.getResolution(); + // FIXME: division computation is incomplete. + int division = 0; + if (divisionType == Sequence.PPQ) + division = resolution & 0x7fff; + dos.writeShort(division); + int length = 14; + for (int i = 0; i < tracks.length; i++) + length += writeTrack(tracks[i], dos); + return length; + } + + /** + * Compute the length of a track as it will be written to the + * output stream. + * + * @param track the track to measure + * @param dos a MidiDataOutputStream used for helper method + * @return the length of the track + */ + private int computeTrackLength(Track track, MidiDataOutputStream dos) + { + int count = 0, length = 0, i = 0, eventCount = track.size(); + long ptick = 0; + while (i < eventCount) + { + MidiEvent me = track.get(i); + long tick = me.getTick(); + length += dos.variableLengthIntLength((int) (tick - ptick)); + ptick = tick; + length += me.getMessage().getLength(); + i++; + } + return length; + } + + /** + * Write a track to an output stream. + * + * @param track the track to write + * @param dos a MidiDataOutputStream to write to + * @return the number of bytes written + */ + private int writeTrack(Track track, MidiDataOutputStream dos) + throws IOException + { + int i = 0, elength = track.size(), trackLength; + MidiEvent pme = null; + dos.writeInt(0x4d54726b); // "MTrk" + trackLength = computeTrackLength(track, dos); + dos.writeInt(trackLength); + while (i < elength) + { + MidiEvent me = track.get(i); + int dtime = 0; + if (pme != null) + dtime = (int) (me.getTick() - pme.getTick()); + dos.writeVariableLengthInt(dtime); + // FIXME: use running status byte + byte msg[] = me.getMessage().getMessage(); + dos.write(msg); + pme = me; + i++; + } + + // We're done if the last event was an End of Track meta message. + if (pme != null && (pme.getMessage() instanceof MetaMessage)) + { + MetaMessage mm = (MetaMessage) pme.getMessage(); + if (mm.getType() == 0x2f) // End of Track message + return trackLength + 8; + } + + // Write End of Track meta message + dos.writeVariableLengthInt(0); // Delta time of 0 + dos.writeByte(0xff); // Meta Message + dos.writeByte(0x2f); // End of Track message + dos.writeVariableLengthInt(0); // Length of 0 + + return trackLength + 8 + 4; + } + + /* Write a Sequence to a file. + * @see javax.sound.midi.spi.MidiFileWriter#write(javax.sound.midi.Sequence, int, java.io.File) + */ + public int write(Sequence in, int fileType, File out) throws IOException + { + OutputStream os = new FileOutputStream(out); + try + { + return write(in, fileType, os); + } + finally + { + os.close(); + } + } + +} diff --git a/libjava/classpath/gnu/javax/sound/sampled/AU/AUReader.java b/libjava/classpath/gnu/javax/sound/sampled/AU/AUReader.java new file mode 100644 index 000000000..fe0df6eb1 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/sampled/AU/AUReader.java @@ -0,0 +1,210 @@ +/* AUReader.java -- Read AU files. + 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.sound.sampled.AU; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.UnsupportedAudioFileException; +import javax.sound.sampled.spi.AudioFileReader; +import java.io.File; +import java.io.IOException; +import java.io.BufferedInputStream; +import java.io.InputStream; +import java.io.FileInputStream; +import java.net.URL; +import java.nio.ByteBuffer; + +public class AUReader extends AudioFileReader +{ + private static class AUHeader + { + // Magic number identifying the file. '.snd' + private static final int MAGIC = 0x2e736e64; + + public static final int SIZE = 24; // size of the header + + // Encoding types + public static final int ULAW = 1; // 8-bit u-law + public static final int PCM8 = 2; // 8-bit PCM + public static final int PCM16 = 3; // 16-bit PCM + public static final int PCM24 = 4; // 24-bit PCM + public static final int PCM32 = 5; // 32-bit PCM + public static final int IEEE32 = 6; // 32-bit IEEE f.p. + public static final int IEEE64 = 7; // 64-bit IEEE f.p. + public static final int G721 = 23; + public static final int G722 = 24; + public static final int G723 = 25; + public static final int G723_5BIT = 26; + public static final int ALAW = 27; // 8-bit a-law + + // Header data. + public int headerSize; + public int fileSize; // this value may not be set. + public int encoding; + public int sampleRate; + public int channels; + public int sampleSizeInBits; + + public AUHeader(InputStream stream) + throws IOException, UnsupportedAudioFileException + { + byte[] hdr = new byte[24]; + stream.read( hdr ); + ByteBuffer buf = ByteBuffer.wrap(hdr); + + if( buf.getInt() != MAGIC ) + throw new UnsupportedAudioFileException("Not an AU format audio file."); + headerSize = buf.getInt(); + fileSize = buf.getInt(); + encoding = buf.getInt(); + sampleRate = buf.getInt(); + channels = buf.getInt(); + + switch(encoding) + { + case ULAW: + case PCM8: + case ALAW: + sampleSizeInBits = 8; + break; + case PCM16: + sampleSizeInBits = 16; + break; + case PCM24: + sampleSizeInBits = 24; + break; + case PCM32: + sampleSizeInBits = 32; + break; + default: // other types exist but are not supported. Yet. + throw new UnsupportedAudioFileException("Unsupported encoding."); + } + } + + public AudioFormat getAudioFormat() + { + AudioFormat.Encoding encType = AudioFormat.Encoding.PCM_SIGNED; + if(encoding == 1) + encType = AudioFormat.Encoding.ULAW; + if(encoding == 27) + encType = AudioFormat.Encoding.ALAW; + + return new AudioFormat(encType, + (float)sampleRate, + sampleSizeInBits, + channels, + (sampleSizeInBits >> 3) * channels, + (float)sampleRate, + true); + } + + public AudioFileFormat getAudioFileFormat() + { + return new AudioFileFormat(new AUFormatType(), + getAudioFormat(), + AudioSystem.NOT_SPECIFIED); + } + } + + public static class AUFormatType extends AudioFileFormat.Type + { + public AUFormatType() + { + super("AU", ".au"); + } + } + + public AudioFileFormat getAudioFileFormat(File file) + throws IOException, UnsupportedAudioFileException + { + return getAudioFileFormat(new FileInputStream(file)); + } + + public AudioFileFormat getAudioFileFormat(InputStream stream) + throws IOException, UnsupportedAudioFileException + { + if(!stream.markSupported()) + throw new IOException("Stream must support marking."); + + stream.mark(25); + AUHeader header = new AUHeader(stream); + stream.reset(); + + return header.getAudioFileFormat(); + } + + public AudioFileFormat getAudioFileFormat(URL url) + throws IOException, UnsupportedAudioFileException + { + return getAudioFileFormat(new BufferedInputStream(url.openStream())); + } + + public AudioInputStream getAudioInputStream(File file) + throws IOException, UnsupportedAudioFileException + { + InputStream stream = new FileInputStream(file); + long length = file.length(); + + AUHeader header = new AUHeader( stream ); + if( header.headerSize > AUHeader.SIZE ) + stream.skip(header.headerSize - AUHeader.SIZE); + + length -= header.headerSize; + + return new AudioInputStream(stream, header.getAudioFormat(), length); + } + + public AudioInputStream getAudioInputStream(InputStream stream) + throws IOException, UnsupportedAudioFileException + { + AUHeader header = new AUHeader( stream ); + if( header.headerSize > AUHeader.SIZE ) + stream.skip(header.headerSize - AUHeader.SIZE); + + return new AudioInputStream(stream, header.getAudioFormat(), + AudioSystem.NOT_SPECIFIED); + } + + public AudioInputStream getAudioInputStream(URL url) + throws IOException, UnsupportedAudioFileException + { + return getAudioInputStream(new BufferedInputStream(url.openStream())); + } +} diff --git a/libjava/classpath/gnu/javax/sound/sampled/WAV/WAVReader.java b/libjava/classpath/gnu/javax/sound/sampled/WAV/WAVReader.java new file mode 100644 index 000000000..5cd6efe5e --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/sampled/WAV/WAVReader.java @@ -0,0 +1,236 @@ +/* WAVReader.java -- Read WAV files. + 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.sound.sampled.WAV; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.DataInputStream; +import java.io.FileInputStream; +import java.net.URL; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.UnsupportedAudioFileException; +import javax.sound.sampled.spi.AudioFileReader; + +/** + * A WAV file reader. + * + * This code reads WAV files. + * + * There are many decent documents on the web describing the WAV file + * format. I didn't bother looking for the official document. If it + * exists, I'm not even sure if it is freely available. We should + * update this comment if we find out anything helpful here. I used + * http://www.sonicspot.com/guide/wavefiles.html + * + * @author Anthony Green (green@redhat.com) + * + */ +public class WAVReader extends AudioFileReader +{ + private static long readUnsignedIntLE (DataInputStream is) + throws IOException + { + byte[] buf = new byte[4]; + is.readFully(buf); + return (buf[0] & 0xFF + | ((buf[1] & 0xFF) << 8) + | ((buf[2] & 0xFF) << 16) + | ((buf[3] & 0xFF) << 24)); + } + + private static short readUnsignedShortLE (DataInputStream is) + throws IOException + { + byte[] buf = new byte[2]; + is.readFully(buf); + return (short) (buf[0] & 0xFF + | ((buf[1] & 0xFF) << 8)); + } + + /* Get an AudioFileFormat from the given File. + * @see javax.sound.sampled.spi.AudioFileReader#getAudioFileFormat(java.io.File) + */ + public AudioFileFormat getAudioFileFormat(File file) + throws UnsupportedAudioFileException, IOException + { + InputStream is = new FileInputStream(file); + try + { + return getAudioFileFormat(is); + } + finally + { + is.close(); + } + } + + /* Get an AudioFileFormat from the given InputStream. + * @see javax.sound.sampled.spi.AudioFileReader#getAudioFileFormat(java.io.InputStream) + */ + public AudioFileFormat getAudioFileFormat(InputStream in) + throws UnsupportedAudioFileException, IOException + { + DataInputStream din; + + if (in instanceof DataInputStream) + din = (DataInputStream) in; + else + din = new DataInputStream(in); + + if (din.readInt() != 0x52494646) // "RIFF" + throw new UnsupportedAudioFileException("Invalid WAV chunk header."); + + // Read the length of this RIFF thing. + readUnsignedIntLE(din); + + if (din.readInt() != 0x57415645) // "WAVE" + throw new UnsupportedAudioFileException("Invalid WAV chunk header."); + + boolean foundFmt = false; + boolean foundData = false; + + short compressionCode = 0, numberChannels = 0, blockAlign = 0, bitsPerSample = 0; + long sampleRate = 0, bytesPerSecond = 0; + long chunkLength = 0; + + while (! foundData) + { + int chunkId = din.readInt(); + chunkLength = readUnsignedIntLE(din); + switch (chunkId) + { + case 0x666D7420: // "fmt " + foundFmt = true; + compressionCode = readUnsignedShortLE(din); + numberChannels = readUnsignedShortLE(din); + sampleRate = readUnsignedIntLE(din); + bytesPerSecond = readUnsignedIntLE(din); + blockAlign = readUnsignedShortLE(din); + bitsPerSample = readUnsignedShortLE(din); + din.skip(chunkLength - 16); + break; + case 0x66616374: // "fact" + // FIXME: hold compression format dependent data. + din.skip(chunkLength); + break; + case 0x64617461: // "data" + if (! foundFmt) + throw new UnsupportedAudioFileException("This implementation requires WAV fmt chunks precede data chunks."); + foundData = true; + break; + default: + // Unrecognized chunk. Skip it. + din.skip(chunkLength); + } + } + + AudioFormat.Encoding encoding; + + switch (compressionCode) + { + case 1: // PCM/uncompressed + if (bitsPerSample <= 8) + encoding = AudioFormat.Encoding.PCM_UNSIGNED; + else + encoding = AudioFormat.Encoding.PCM_SIGNED; + break; + + default: + throw new UnsupportedAudioFileException("Unrecognized WAV compression code: 0x" + + Integer.toHexString(compressionCode)); + } + + return new AudioFileFormat (AudioFileFormat.Type.WAVE, + new AudioFormat(encoding, + (float) sampleRate, + bitsPerSample, + numberChannels, + ((bitsPerSample + 7) / 8) * numberChannels, + (float) bytesPerSecond, false), + (int) chunkLength); + } + + /* Get an AudioFileFormat from the given URL. + * @see javax.sound.sampled.spi.AudioFileReader#getAudioFileFormat(java.net.URL) + */ + public AudioFileFormat getAudioFileFormat(URL url) + throws UnsupportedAudioFileException, IOException + { + InputStream is = url.openStream(); + try + { + return getAudioFileFormat(is); + } + finally + { + is.close(); + } + } + + /* Get an AudioInputStream from the given File. + * @see javax.sound.sampled.spi.AudioFileReader#getAudioInputStream(java.io.File) + */ + public AudioInputStream getAudioInputStream(File file) + throws UnsupportedAudioFileException, IOException + { + return getAudioInputStream(new FileInputStream(file)); + } + + /* Get an AudioInputStream from the given InputStream. + * @see javax.sound.sampled.spi.AudioFileReader#getAudioInputStream(java.io.InputStream) + */ + public AudioInputStream getAudioInputStream(InputStream stream) + throws UnsupportedAudioFileException, IOException + { + AudioFileFormat aff = getAudioFileFormat(stream); + return new AudioInputStream(stream, aff.getFormat(), (long) aff.getFrameLength()); + } + + /* Get an AudioInputStream from the given URL. + * @see javax.sound.sampled.spi.AudioFileReader#getAudioInputStream(java.net.URL) + */ + public AudioInputStream getAudioInputStream(URL url) + throws UnsupportedAudioFileException, IOException + { + return getAudioInputStream(url.openStream()); + } +} diff --git a/libjava/classpath/gnu/javax/sound/sampled/gstreamer/GStreamerMixer.java b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/GStreamerMixer.java new file mode 100644 index 000000000..1910ea655 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/GStreamerMixer.java @@ -0,0 +1,248 @@ +/* GStreamerMixer.java -- Mixer implementation. + Copyright (C) 2007 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.sound.sampled.gstreamer; + +import gnu.javax.sound.sampled.gstreamer.lines.GstSourceDataLine; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.Control; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.Line; +import javax.sound.sampled.LineListener; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.Mixer; +import javax.sound.sampled.SourceDataLine; +import javax.sound.sampled.Control.Type; + +/** + * @author Mario Torre + */ +public class GStreamerMixer + implements Mixer +{ + public static class GstInfo extends Info + { + /* Mixer Properties */ + + /** Name */ + private static final String name = "Classpath GStreamer Sound Audio Engine"; + + /** Vendor */ + private static final String vendor = "GNU Classpath"; + + /** Description */ + private static final String desc = "GStreamer-based software mixer"; + + /** Version */ + private static final String vers = "0.0.1"; + + protected GstInfo() + { + super(name, vendor, desc, vers); + } + } + + public static final String GST_BACKEND = GstInfo.name; + public static final String GST_DECODER = "decoder"; + public static final String GST_TYPE_NAME = "type"; + public static final String GST_FILE_EXTENSION = "ext"; + + /** Mixer Info */ + private static final Mixer.Info INFO = new GStreamerMixer.GstInfo(); + + public Line getLine(Line.Info info) + throws LineUnavailableException + { + // get all the lines formats supported by this mixer and + // and see if there is one matching the given line + // if the format comes from the gstreamer backend + // gstreamer will be able to deal with it + Class clazz = info.getLineClass(); + DataLine.Info _info = (DataLine.Info) info; + + if (clazz == SourceDataLine.class) + { + for (AudioFormat format : _info.getFormats()) + { + // see if we are a gstreamer child :) + if (format.properties().containsKey(GST_BACKEND)); + { + // we got it + return new GstSourceDataLine(format); + } + } + } + + // TODO: we also support basic PCM + + throw new LineUnavailableException("Cannot open a line"); + } + + public int getMaxLines(Line.Info info) + { + // TODO + return 1; + } + + public Info getMixerInfo() + { + return INFO; + } + + public javax.sound.sampled.Line.Info[] getSourceLineInfo() + { + // TODO Auto-generated method stub + return null; + } + + public Line.Info[] getSourceLineInfo(Line.Info info) + { + // TODO Auto-generated method stub + return null; + } + + public Line[] getSourceLines() + { + // TODO Auto-generated method stub + return null; + } + + public javax.sound.sampled.Line.Info[] getTargetLineInfo() + { + // TODO Auto-generated method stub + return null; + } + + public Line.Info[] getTargetLineInfo(Line.Info info) + { + // TODO Auto-generated method stub + return null; + } + + public Line[] getTargetLines() + { + // TODO Auto-generated method stub + return null; + } + + public boolean isLineSupported(Line.Info info) + { + // We support any kind of mixer that comes + // from our gstreamer backend. + // In addition, we support PCM based audio streams for + // direct playback. + if (info instanceof DataLine.Info) + { + DataLine.Info _dinfo = (DataLine.Info) info; + _dinfo.getFormats(); + } + + return true; + } + + public boolean isSynchronizationSupported(Line[] lines, boolean sync) + { + // TODO Auto-generated method stub + return false; + } + + public void synchronize(Line[] lines, boolean sync) + { + // TODO Auto-generated method stub + + } + + public void unsynchronize(Line[] lines) + { + // TODO Auto-generated method stub + + } + + public void addLineListener(LineListener listener) + { + // TODO Auto-generated method stub + + } + + public void close() + { + // TODO Auto-generated method stub + + } + + public Control getControl(Type what) + { + // TODO Auto-generated method stub + return null; + } + + public Control[] getControls() + { + // TODO Auto-generated method stub + return null; + } + + public javax.sound.sampled.Line.Info getLineInfo() + { + // TODO Auto-generated method stub + return null; + } + + public boolean isControlSupported(Type what) + { + // TODO Auto-generated method stub + return false; + } + + public boolean isOpen() + { + // TODO Auto-generated method stub + return false; + } + + public void open() throws LineUnavailableException + { + // TODO Auto-generated method stub + + } + + public void removeLineListener(LineListener listener) + { + // TODO Auto-generated method stub + } +} diff --git a/libjava/classpath/gnu/javax/sound/sampled/gstreamer/GStreamerMixerProvider.java b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/GStreamerMixerProvider.java new file mode 100644 index 000000000..6a0d7faa7 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/GStreamerMixerProvider.java @@ -0,0 +1,71 @@ +/*GStreamerMixerProvider -- GNU Classpath GStreamer Mixer provider. + Copyright (C) 2007 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.sound.sampled.gstreamer; + +import javax.sound.sampled.Mixer; +import javax.sound.sampled.Mixer.Info; +import javax.sound.sampled.spi.MixerProvider; + +/** + * Concrete provider class for GStreamerMixer. + * + * @author Mario Torre + */ +public class GStreamerMixerProvider + extends MixerProvider +{ + private static final GStreamerMixer mixer = new GStreamerMixer(); + + @Override + public Mixer getMixer(Info info) + { + if (info.equals(mixer.getMixerInfo())) + return mixer; + + throw new + IllegalArgumentException("This provider cannot handle a mixer or type: " + + info.getName()); + } + + @Override + public Info[] getMixerInfo() + { + Info[] info = { mixer.getMixerInfo() }; + return info; + } +} diff --git a/libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReader.java b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReader.java new file mode 100644 index 000000000..26fb12b09 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReader.java @@ -0,0 +1,185 @@ +/*GstAudioFileReader -- GNU Classpath GStreamer AudioFileReader. + Copyright (C) 2007 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.sound.sampled.gstreamer.io; + +import gnu.java.lang.CPStringBuilder; + +import gnu.javax.sound.sampled.gstreamer.GStreamerMixer; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import javax.sound.sampled.AudioFileFormat; +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.UnsupportedAudioFileException; +import javax.sound.sampled.spi.AudioFileReader; + +/** + * An implementation of a general AudioFileReader. Uses GStreamer to + * parse and retrieve informations about the file passed as input. + * + * @author Mario Torre + */ +public class GstAudioFileReader + extends AudioFileReader +{ + @Override + public AudioFileFormat getAudioFileFormat(File file) + throws UnsupportedAudioFileException, IOException + { + CPStringBuilder name = new CPStringBuilder(file.getName()); + String _name = name.substring(name.lastIndexOf(".") + 1); + + return getAudioFileFormat( + new BufferedInputStream(new FileInputStream(file)), _name); + } + + @Override + public AudioFileFormat getAudioFileFormat(InputStream is) + throws UnsupportedAudioFileException, IOException + { + return getAudioFileFormat(is, null); + } + + private AudioFileFormat getAudioFileFormat(InputStream is, String extension) + throws UnsupportedAudioFileException + { + AudioFormat format = null; + try + { + format = GstAudioFileReaderNativePeer.getAudioFormat(is); + } + catch (Exception e) + { + UnsupportedAudioFileException ex = + new UnsupportedAudioFileException("Unsupported encoding."); + + ex.initCause(ex.getCause()); + throw ex; + } + + if (format == null) + throw new UnsupportedAudioFileException("Unsupported encoding."); + + String name = format.getProperty(GStreamerMixer.GST_DECODER).toString(); + + if (extension == null) + { + extension = + format.getProperty(GStreamerMixer.GST_FILE_EXTENSION).toString(); + } + + AudioFileFormat.Type type = + new AudioFileFormat.Type(name, extension); + + // TODO: we should calculate this in some way. We don't need it, but + // application may want to use this data. + return new AudioFileFormat(type, format, AudioSystem.NOT_SPECIFIED); + } + + @Override + public AudioFileFormat getAudioFileFormat(URL url) + throws UnsupportedAudioFileException, IOException + { + return getAudioFileFormat(new BufferedInputStream(url.openStream())); + } + + @Override + public AudioInputStream getAudioInputStream(File file) + throws UnsupportedAudioFileException, IOException + { + InputStream stream = new FileInputStream(file); + long length = file.length(); + + AudioFormat format = null; + + try + { + format = GstAudioFileReaderNativePeer.getAudioFormat(file); + } + catch (Exception e) + { + UnsupportedAudioFileException ex = + new UnsupportedAudioFileException("Unsupported encoding."); + + ex.initCause(ex.getCause()); + throw ex; + } + + // get the header size + if (format == null) + throw new UnsupportedAudioFileException("Unsupported encoding."); + + return new AudioInputStream(stream, format, length); + } + + @Override + public AudioInputStream getAudioInputStream(InputStream is) + throws UnsupportedAudioFileException, IOException + { + AudioFormat format = null; + + try + { + format = GstAudioFileReaderNativePeer.getAudioFormat(is); + } + catch (Exception e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + // get the header size + if (format == null) + throw new UnsupportedAudioFileException("Unsupported encoding."); + + return new AudioInputStream(is, format, AudioSystem.NOT_SPECIFIED); + } + + @Override + public AudioInputStream getAudioInputStream(URL url) + throws UnsupportedAudioFileException, IOException + { + return getAudioInputStream(new BufferedInputStream(url.openStream())); + } +} diff --git a/libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReaderNativePeer.java b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReaderNativePeer.java new file mode 100644 index 000000000..6345d7654 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReaderNativePeer.java @@ -0,0 +1,284 @@ +/*GstAudioFileReaderNativePeer -- GNU Classpath GStreamer AudioFileReader + native peer class. + Copyright (C) 2007 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.sound.sampled.gstreamer.io; + +import gnu.classpath.Pointer; +import gnu.javax.sound.sampled.gstreamer.GStreamerMixer; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.AudioSystem; +import javax.sound.sampled.AudioFormat.Encoding; + +/** + * GStreamer native peer for GstAudioFileReader. + * + * @author Mario Torre + */ +final class GstAudioFileReaderNativePeer +{ + private static final String GST_ENCODING = "GStreamer Generic Audio Reader"; + + private static class GstHeader + { + /* + * NOTE: these properties are accessed by the native code, be careful + * if you change them. + * Not all the fields are necessarily set. + * + */ + public String file = null; + + public String suffix = null; + + public String name = null; + + public String mimetype = null; + + public String endianness = null; + + public String channels = null; + + public String rate = null; + + public String width = null; + + public String depth = null; + + public String isSigned = null; + + public String layer = null; + + public String bitrate = null; + + public String framed = null; + + public String type = null; + } + + public static AudioFormat getAudioFormat(File file) throws Exception + { + GstHeader header = new GstHeader(); + header.file = file.getAbsolutePath(); + + if (!gstreamer_get_audio_format_file(header)) + return null; + + return getAudioFormat(header); + } + + public static AudioFormat getAudioFormat(InputStream is) throws Exception + { + return getAudioFormat(is, new GstHeader()); + } + + public static AudioFormat getAudioFormat(URL url) throws Exception + { + GstHeader header = new GstHeader(); + header.file = url.toExternalForm(); + + return getAudioFormat(url.openStream(), header); + } + + private static AudioFormat getAudioFormat(InputStream is, GstHeader header) + throws Exception + { + BufferedInputStream stream = new BufferedInputStream(is); + if(!stream.markSupported()) + throw new IOException("Stream must support marking."); + + stream.mark(0); + + if (!gstreamer_get_audio_format_stream(header, new GstInputStream(stream). + getNativeClass())) + return null; + + return getAudioFormat(header); + } + + private static Encoding getEncoding(GstHeader header) + { + StringBuilder buffer = new StringBuilder(); + + if (header.name == null) + { + buffer.append(GST_ENCODING); + if (header.mimetype != null) + { + buffer.append(" "); + buffer.append(header.mimetype); + } + + header.name = buffer.toString(); + } + else + { + // strip the "decoder" word from the name, if any + // this is a bit ugly, the alternative would be to still output the + // full name of the decoder/demuxer + String lowerCase = header.name.toLowerCase(); + int index = lowerCase.indexOf("decoder"); + if (index == -1) + { + index = lowerCase.indexOf("demuxer"); + } + + if (index == -1) + index = lowerCase.length(); + + buffer.append(header.name.substring(0, index)); + + } + + return new Encoding(buffer.toString().trim()); + } + + private static AudioFormat getAudioFormat(GstHeader header) + throws Exception + { + int na = AudioSystem.NOT_SPECIFIED; + + /* we use mimetype as an header, but this could have some side effects */ + Encoding encoding = getEncoding(header); + + float sampleRate = ((header.rate != null) ? + new Float(header.rate).floatValue() : na); + + int sampleSizeInBits = ((header.depth != null) ? + new Integer(header.depth).intValue() : na); + + int channels = ((header.channels != null) ? + new Integer(header.channels).intValue() : na); + + boolean bigEndian = false; + if (header.endianness != null) + { + if (header.endianness.compareTo("4321") == 0) + bigEndian = true; + } + + String ext = null; + + int frameSize = na; + float frameRate = na; + String lowerCase = header.name.toLowerCase(); + + // FIXME: frameRate = sampleRate in these cases under all the tests so far + // but I'm not sure if this is always correct... + if (lowerCase.contains("law") || lowerCase.contains("au")) + { + frameSize = (sampleSizeInBits >> 3) * channels; + frameRate = sampleRate; + ext = "au"; + } + else if (lowerCase.contains("wav")) + { + frameSize = ((sampleSizeInBits + 7) / 8) * channels; + frameRate = sampleRate; + ext = "wav"; + } + else if (lowerCase.contains("iff")) + { + frameSize = (sampleSizeInBits * channels) / 8; + frameRate = sampleRate; + ext = "aiff"; + } + + // write all the additional properties we got to identify + // the gstreamer plugin actually used to deal with this stream + Map properties = new HashMap(); + properties.put(GStreamerMixer.GST_BACKEND, true); + properties.put(GStreamerMixer.GST_DECODER, header.name); + properties.put(GStreamerMixer.GST_TYPE_NAME, encoding.toString()); + if (ext != null) + properties.put(GStreamerMixer.GST_FILE_EXTENSION, ext); + + /* now we put in some of the additional properties if we have them */ + if (header.type != null) properties.put("type", header.type); + if (header.framed != null) properties.put("framed", header.framed); + if (header.bitrate != null) properties.put("bitrate", header.bitrate); + if (header.isSigned != null) properties.put("isSigned", header.isSigned); + if (header.depth != null) properties.put("depth", header.depth); + if (header.mimetype != null) properties.put("mimetype", header.mimetype); + + AudioFormat format = new AudioFormat(encoding, + sampleRate, + sampleSizeInBits, + channels, + frameSize, + frameRate, + bigEndian, + properties); + return format; + } + + /* ***** native methods ***** */ + + /** + * Retrieve header information about the stream being played. + */ + native static final + protected boolean gstreamer_get_audio_format_stream(GstHeader info, + Pointer pointer); + + /** + * Retrieve header information about the file being played. + */ + native static final + protected boolean gstreamer_get_audio_format_file(GstHeader info); + + /** + * Initialize the native peer and enables the object cache. + * It is meant to be used by the static initializer. + */ + native private static final void init_id_cache(); + + static + { + System.loadLibrary("gstreamerpeer"); //$NON-NLS-1$ + init_id_cache(); + } +} diff --git a/libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileWriter.java b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileWriter.java new file mode 100644 index 000000000..9b395dca2 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileWriter.java @@ -0,0 +1,80 @@ +/*GstAudioFileWriter -- GNU Classpath GStreamer AudioFileReader. + Copyright (C) 2007 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.sound.sampled.gstreamer.io; + +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; + +import javax.sound.sampled.AudioInputStream; +import javax.sound.sampled.AudioFileFormat.Type; +import javax.sound.sampled.spi.AudioFileWriter; + +public class GstAudioFileWriter + extends AudioFileWriter +{ + @Override + public Type[] getAudioFileTypes() + { + // TODO Auto-generated method stub + return null; + } + + @Override + public Type[] getAudioFileTypes(AudioInputStream ais) + { + // TODO Auto-generated method stub + return null; + } + + @Override + public int write(AudioInputStream ais, Type type, File out) + throws IOException + { + // TODO Auto-generated method stub + return 0; + } + + @Override + public int write(AudioInputStream ais, Type type, OutputStream os) + throws IOException + { + // TODO Auto-generated method stub + return 0; + } + +} diff --git a/libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstInputStream.java b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstInputStream.java new file mode 100644 index 000000000..56bddcaad --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstInputStream.java @@ -0,0 +1,119 @@ +/* GstInputStream.java -- Trampoline class for an InputStream, mean to be used + by native code. + Copyright (C) 2007 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.sound.sampled.gstreamer.io; + +import gnu.classpath.Pointer; + +import java.io.IOException; +import java.io.InputStream; + +/** + * Encapsulates the functionality of an InputStream Object. + * + * This class is only meant to be used by the native code, to allow reading + * of the given InputStream as part of a the GStreamer InputStream Source + * Plugin. + * + * Note: this class will be not garbage collected as the + * native code contains strong references to internal fields. + * The native layer provides a method that can be called by the C code to + * free the resources and to let the garbage collected to handle this class + * when not needed anymore. + * + * @author Mario Torre + */ +public class GstInputStream +{ + /** The real InputStream on which to perform reading operations. */ + private InputStream istream; + + /** + * Initialized in the native code, don't change without changes + * in the native layer. + */ + private Pointer gstInputStream = null; + + public GstInputStream(InputStream istream) + { + this.istream = istream; + init_instance(); + } + + public int read(byte[] buf, int off, int len) throws IOException + { + return this.istream.read(buf, off, len); + } + + public int available() throws IOException + { + return this.istream.available(); + } + + /** + * Return a reference to the GstInputStream native class as a Pointer object. + * This method is intended as an helper accessor and the returned pointer + * needs to be casted and used in the native code only. + * + * @return Pointer to the native GstInputStream class. + */ + public Pointer getNativeClass() + { + return this.gstInputStream; + } + + /* native methods */ + + /** + * Initialize the native peer and enables the object cache. + * It is meant to be used by the class constructor. + */ + native private final void init_instance(); + + /** + * Initialize the native peer and enables the object cache. + * It is meant to be used by the static initializer. + */ + native private static final void init_id_cache(); + + static + { + System.loadLibrary("gstreamerpeer"); //$NON-NLS-1$ + init_id_cache(); + } +} diff --git a/libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstDataLine.java b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstDataLine.java new file mode 100644 index 000000000..4e8cb1bb2 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstDataLine.java @@ -0,0 +1,151 @@ +/* GstDataLine.java -- Abstract DataLine. + Copyright (C) 2007 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.sound.sampled.gstreamer.lines; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.Control; +import javax.sound.sampled.DataLine; +import javax.sound.sampled.LineListener; +import javax.sound.sampled.Control.Type; + +public abstract class GstDataLine + implements DataLine +{ + public static final int DEFAULT_BUFFER_SIZE = 1024; + + /** Represents if this Line is opened or not. */ + protected Boolean open = false; + + private AudioFormat format = null; + private int bufferSize = 0; + + public GstDataLine(AudioFormat format) + { + this.format = format; + this.bufferSize = DEFAULT_BUFFER_SIZE; + } + + public GstDataLine(AudioFormat format, int bufferSize) + { + this.format = format; + this.bufferSize = bufferSize; + } + + public int getBufferSize() + { + return this.bufferSize; + } + + public AudioFormat getFormat() + { + return this.format; + } + + public float getLevel() + { + // TODO Auto-generated method stub + return 0; + } + + public void addLineListener(LineListener listener) + { + // TODO Auto-generated method stub + + } + + public Control getControl(Type what) + { + // TODO Auto-generated method stub + return null; + } + + public Control[] getControls() + { + // TODO Auto-generated method stub + return null; + } + + public javax.sound.sampled.Line.Info getLineInfo() + { + // TODO Auto-generated method stub + return null; + } + + public boolean isControlSupported(Type what) + { + return false; + } + + public boolean isOpen() + { + // TODO Auto-generated method stub + return false; + } + + public void removeLineListener(LineListener listener) + { + // TODO Auto-generated method stub + + } + + /* protected methods for subclasses */ + + /** + * @param open the open to set + */ + protected void setOpen(Boolean open) + { + this.open = open; + } + + /** + * @param bufferSize the bufferSize to set + */ + protected void setBufferSize(int bufferSize) + { + this.bufferSize = bufferSize; + } + + /** + * @param format the format to set + */ + protected void setFormat(AudioFormat format) + { + this.format = format; + } +} diff --git a/libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstNativeDataLine.java b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstNativeDataLine.java new file mode 100644 index 000000000..896f0cb85 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstNativeDataLine.java @@ -0,0 +1,77 @@ +/* GstNativeDataLine.java -- SourceDataLine implementation. + Copyright (C) 2007 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.sound.sampled.gstreamer.lines; + +import gnu.classpath.Pointer; + +import javax.sound.sampled.LineUnavailableException; + +public class GstNativeDataLine +{ + public static final GstPipeline createSourcePipeline(int bufferSize) + throws LineUnavailableException + { + GstPipeline pipeline = new GstPipeline(bufferSize); + + pipeline.createForWrite(); + + if (!setup_sink_pipeline(pipeline.getNativeClass())) + throw new LineUnavailableException("Line unavailable"); + + return pipeline; + } + + /* native methods */ + + /** + * Initialize the native peer and enables the object cache. + * It is meant to be used by the static initializer. + */ + native static final private void init_id_cache(); + + /** + * Setup a new GStreamer Pipeline + */ + native static final private boolean setup_sink_pipeline(Pointer pipeline); + + static + { + System.loadLibrary("gstreamerpeer"); //$NON-NLS-1$ + init_id_cache(); + } +} diff --git a/libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstPipeline.java b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstPipeline.java new file mode 100644 index 000000000..9280e9f15 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstPipeline.java @@ -0,0 +1,415 @@ +/* GstPipeline.java -- Represents a Gstreamer Pipeline. + Copyright (C) 2007 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.sound.sampled.gstreamer.lines; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.prefs.Preferences; + +import javax.sound.sampled.LineUnavailableException; + +import gnu.classpath.Pointer; + +/** + * This class represent a GStreamer pipeline and is resposible to handle the + * flow of data to and from the GStreamer native backend. + * + * @author Mario Torre + */ +public class GstPipeline +{ + /* + * Implementation note: + * This class is at first a bit confusing as it serves as a gateway + * to a real filesystem named pipe. + * The pipelines is shared by the gstreamer backend and by the java code. + * If the operation we are performing is to play a given stream of bytes, + * we need to open the java side of the pipeline for writing, which is done + * in the prepareWrite method. At the same time, the native side of the code + * need to open the pipeline in read mode, to get access to the data, + * and hence, act as a source element. This is why you will see terms + * like "read" or "source" in methods that are used to write in the pipeline, + * in other words, each the native operation is the opposite of the java + * side operation. + * Opening the pipe to record audio data from the sound card works the same + * except that all the operation are inverted. + */ + + // These enums are used in the native code also, changes here must reflect + // changes in the native code. + public static enum State + { + PLAY, PAUSE, STOP, CLOSE + } + + private static final int READ = 0; + private static final int WRITE = 1; + private static final int QUEUED = 1; + + private static final String CAPACITY_KEY = "Capacity"; + + private static final Object [] lock = new Object[0]; + + /* + * Preference subsystem. We use this to store some system specific settings. + */ + protected Preferences prefs = + Preferences.userNodeForPackage(GstPipeline.class).node("GStreamer"); + + // used by the native code, stores the size of the named pipeline + // created by the operating system. + private long capacity = -1; + + /** Represents the playing state of this Line. */ + private State state = State.STOP; + + /** The name of the named pipe. */ + // Will be setup and filled in the native code. See the native library + // for details. + private String name = null; + + /** This is the named pipe that will be read by the gstreamer backend. */ + private FileOutputStream output = null; + + /** + * Defines if we are getting data from a sink pipe + * or writing to a source pipe. + */ + private boolean source = true; + + /** Indicate that we are ready to process audio data to/from the pipe. */ + private boolean ready = false; + + /** + * This is the native GStreamer Pipeline. + */ + // This field is used by the native code, so any change to it must be + // followed by similar changes in the native peer. + private Pointer pipeline = null; + + /** + * Creates a new GstPipeline with a capacity of + * {@link GstDataLine#DEFAULT_BUFFER_SIZE}. + * + * @see GstDataLine#DEFAULT_BUFFER_SIZE + */ + public GstPipeline() + { + this(GstDataLine.DEFAULT_BUFFER_SIZE); + } + + /** + * Creates a new GstPipeline with a capacity of bufferSize. + * @see GstDataLine#DEFAULT_BUFFER_SIZE + */ + public GstPipeline(int bufferSize) + { + // see if we need to detect the size of the named pipe or we can use + // an already computet default for this system. + // Note that this is very different from the bufferSize parameter, + // see below. + capacity = prefs.getLong(CAPACITY_KEY, -1); + if (capacity == -1) + { + synchronized (lock) + { + capacity = detect_pipe_size(); + } + + prefs.putLong(CAPACITY_KEY, capacity); + } + + // FIXME: bufferSize actually not used nor needed by the backend. + // Applications that expects a buffer of different size will be a + // bit disappointed by that.. + init_instance(); + + // need to remove the named pipe in case of abnormal termination + Runtime.getRuntime().addShutdownHook(new CleanPipeline()); + } + + /** + * Creates a source pipeline. A source pipeline is a pipe you send data for + * processing using the write method. + */ + public void createForWrite() throws LineUnavailableException + { + // create the named pipe + if (!create_named_pipe(this.pipeline)) + throw new LineUnavailableException("Unable to create filesystem pipe"); + + open_native_pipe(this.pipeline, READ); + prepareWrite(); + + this.source = true; + } + + /** + * @return the state + */ + public State getState() + { + return this.state; + } + + /** + * Closes this pipeline. + * Short hand for #setState(State.STOP). + */ + public void close() + { + setState(State.STOP); + } + + /** + * @param state the state to set + */ + public void setState(final State state) + { + int _state = -1; + switch (state) + { + case PLAY: + _state = 0; + break; + + case PAUSE: + _state = 1; + break; + + case STOP: case CLOSE: + _state = 2; + closePipe(); + break; + } + + if (set_state(pipeline, _state)) + GstPipeline.this.state = state; + } + + /** + * Return a reference to the GstPipeline native class as a Pointer object. + * This method is intended as an helper accessor and the returned pointer + * needs to be casted and used in the native code only. + * + * @return Pointer to the native GstPipeline class. + */ + public Pointer getNativeClass() + { + return this.pipeline; + } + + /** + * Write length bytes from the given buffer into this pipeline, + * starting at offset. + * This method block if the pipeline can't accept more data. + * + * @param buffer + * @param offset + * @param length + * @return + */ + public int write(byte[] buffer, int offset, int length) + { + if (this.state == State.STOP) + return -1; + else if (this.state == State.PAUSE) + return 0; + else if (!ready) + return -1; + + try + { + if (output != null) + { + output.write(buffer, offset, length); + return length; + } + return 0; + } + catch (Exception e) + { + /* nothing to do */ + } + + return -1; + } + + public int read(byte[] buffer, int offset, int length) + { + return 0; + } + + public int available() + { + if (this.source) + return available(this.pipeline, READ); + else + return available(this.pipeline, WRITE); + } + + /** + * Wait for remaining data to be enqueued in the pipeline. + */ + public void drain() + { + if (this.state == State.STOP) + return; + + try + { + // wait untill there is anymore data in the pipe + while (available(this.pipeline, QUEUED) > 0) + Thread.sleep(3000); + + // plus a bit to allow data to be processed + Thread.sleep(1000); + } + catch (InterruptedException e) + { + /* nothing to do*/ + } + } + + /** + * Flush all the data currently waiting to be processed. + */ + public void flush() + { + try + { + if (source) + this.output.flush(); + } + catch (IOException e) + { + /* nothing */ + } + } + + private void closePipe() + { + try + { + GstPipeline.this.flush(); + if (source) + GstPipeline.this.output.close(); + } + catch (IOException e) + { + /* nothing to do */ + } + } + + private void prepareWrite() + { + try + { + // if this is not completed for some reason, we will catch + // in the write method. As this call can block, we assume we will + // succeed and that the dataline can get data. + GstPipeline.this.ready = true; + GstPipeline.this.output = new FileOutputStream(name); + } + catch (Exception e) + { + GstPipeline.this.ready = false; + } + } + + /* ***** native ***** */ + + /** + * Initialize the native peer and enables the object cache. + * It is meant to be used by the static initializer. + */ + native private static final void init_id_cache(); + + /** + * Set the playing state of this pipeline. + */ + native private static final boolean set_state(Pointer pipeline, int state); + + /** + * Get the number of bytes currently available for reading or writing + * from the pipeline. + */ + native private static final int available(Pointer pipeline, int mode); + + /** + * Open the native pipeline with the given mode. + */ + native private static final void open_native_pipe(Pointer jpipeline, + int mode); + + /** + * Close the native pipeline. + */ + native private static final void close_native_pipe(Pointer jpipeline); + + /** + * Initialize the native peer and enables the object cache. + * It is meant to be used by the class constructor. + */ + native private final void init_instance(); + + /** + * Crates the named pipe used to pass data between the application code + * and gstreamer. + */ + native private final boolean create_named_pipe(Pointer jpipeline); + + /** + * Detect and return the size of the filesystem named pipe. + */ + native private final long detect_pipe_size(); + + private class CleanPipeline extends Thread + { + public void run() + { + GstPipeline.close_native_pipe(GstPipeline.this.pipeline); + } + } + + static + { + System.loadLibrary("gstreamerpeer"); //$NON-NLS-1$ + init_id_cache(); + } +} diff --git a/libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstSourceDataLine.java b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstSourceDataLine.java new file mode 100644 index 000000000..2bc2de454 --- /dev/null +++ b/libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstSourceDataLine.java @@ -0,0 +1,153 @@ +/* GstSourceDataLine.java -- SourceDataLine implementation. + Copyright (C) 2007 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.sound.sampled.gstreamer.lines; + +import gnu.javax.sound.AudioSecurityManager; +import gnu.javax.sound.sampled.gstreamer.lines.GstPipeline.State; + +import javax.sound.sampled.AudioFormat; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.SourceDataLine; + +import static gnu.javax.sound.AudioSecurityManager.Permission; + +public class GstSourceDataLine + extends GstDataLine implements SourceDataLine +{ + private GstPipeline pipeline = null; + private boolean open = false; + + public GstSourceDataLine(AudioFormat format) + { + super(format); + } + + public void open() throws LineUnavailableException + { + AudioSecurityManager.checkPermissions(Permission.PLAY); + + if (open) + throw new IllegalStateException("Line already opened"); + + // create the pipeline + pipeline = GstNativeDataLine.createSourcePipeline(getBufferSize()); + + this.open = true; + } + + public void open(AudioFormat fmt) throws LineUnavailableException + { + AudioSecurityManager.checkPermissions(Permission.PLAY); + + setFormat(fmt); + this.open(); + } + + public void open(AudioFormat fmt, int size) throws LineUnavailableException + { + AudioSecurityManager.checkPermissions(Permission.PLAY); + + setBufferSize(size); + this.open(fmt); + } + + public int write(byte[] buf, int offset, int length) + { + return this.pipeline.write(buf, offset, length); + } + + public int available() + { + return this.pipeline.available(); + } + + public void drain() + { + this.pipeline.drain(); + } + + public void flush() + { + this.pipeline.flush(); + } + + public int getFramePosition() + { + System.out.println("getFramePosition -: IMPLEMENT ME!!"); + return 0; + } + + public long getLongFramePosition() + { + System.out.println("getLongFramePosition -: IMPLEMENT ME!!"); + return 0; + } + + public long getMicrosecondPosition() + { + System.out.println("getMicrosecondPosition -: IMPLEMENT ME!!"); + return 0; + } + + public boolean isActive() + { + State state = pipeline.getState(); + return (state == State.PLAY || state == State.PAUSE); + } + + public void start() + { + pipeline.setState(State.PLAY); + } + + public void stop() + { + pipeline.setState(State.PAUSE); + } + + public void close() + { + pipeline.close(); + this.open = false; + } + + public boolean isRunning() + { + return (pipeline.getState() == State.PLAY); + } +} diff --git a/libjava/classpath/gnu/javax/swing/plaf/gnu/GNULookAndFeel.java b/libjava/classpath/gnu/javax/swing/plaf/gnu/GNULookAndFeel.java new file mode 100644 index 000000000..75ba45506 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/plaf/gnu/GNULookAndFeel.java @@ -0,0 +1,266 @@ +/* GNULookAndFeel.java -- An example of using the javax.swing UI. + Copyright (C) 2005 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.javax.swing.plaf.gnu; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; + +import javax.swing.Icon; +import javax.swing.ImageIcon; +import javax.swing.JCheckBox; +import javax.swing.JRadioButton; +import javax.swing.UIDefaults; +import javax.swing.plaf.ColorUIResource; +import javax.swing.plaf.IconUIResource; +import javax.swing.plaf.basic.BasicLookAndFeel; + +public class GNULookAndFeel extends BasicLookAndFeel +{ + + static Color blueGray = new Color(0xdc, 0xda, 0xd5); + + public boolean isNativeLookAndFeel() { return true; } + public boolean isSupportedLookAndFeel() { return true; } + public String getDescription() { return "GNU Look and Feel"; } + public String getID() { return "GNULookAndFeel"; } + public String getName() { return "GNU"; } + + static UIDefaults LAF_defaults; + + private final static String iconspath = "/gnu/javax/swing/plaf/gtk/icons/"; + + public UIDefaults getDefaults() + { + if (LAF_defaults == null) + { + LAF_defaults = super.getDefaults(); + Object[] myDefaults = new Object[] { + "Button.background", new ColorUIResource(blueGray), + "CheckBox.background", new ColorUIResource(blueGray), + "CheckBoxMenuItem.background", new ColorUIResource(blueGray), + "ToolBar.background", new ColorUIResource(blueGray), + "Panel.background", new ColorUIResource(blueGray), + "Slider.background", new ColorUIResource(blueGray), + "OptionPane.background", new ColorUIResource(blueGray), + "ProgressBar.background", new ColorUIResource(blueGray), + "TabbedPane.background", new ColorUIResource(blueGray), + "Label.background", new ColorUIResource(blueGray), + "Menu.background", new ColorUIResource(blueGray), + "MenuBar.background", new ColorUIResource(blueGray), + "MenuItem.background", new ColorUIResource(blueGray), + "ScrollBar.background", new ColorUIResource(blueGray), + "CheckBox.icon", new CheckBoxIcon(), + "RadioButton.icon", new RadioButtonIcon(), + "Tree.hash", new ColorUIResource(Color.black), + + "Tree.closedIcon", + new IconUIResource(new ImageIcon + (getClass().getResource + (iconspath + "TreeClosed.png"))), + "Tree.leafIcon", + new IconUIResource(new ImageIcon + (getClass().getResource + (iconspath + "TreeLeaf.png"))), + "Tree.openIcon", + new IconUIResource(new ImageIcon + (getClass().getResource + (iconspath + "TreeOpen.png"))), + }; + LAF_defaults.putDefaults(myDefaults); + } + return LAF_defaults; + } + + /** + * The icon used for CheckBoxes in the BasicLookAndFeel. This is an empty + * icon with a size of 13x13 pixels. + */ + static class CheckBoxIcon + implements Icon + { + /** + * Returns the height of the icon. The BasicLookAndFeel CheckBox icon + * has a height of 13 pixels. + * + * @return the height of the icon + */ + public int getIconHeight() + { + return 13; + } + + /** + * Returns the width of the icon. The BasicLookAndFeel CheckBox icon + * has a width of 13 pixels. + * + * @return the height of the icon + */ + public int getIconWidth() + { + return 13; + } + + /** + * Paints the icon. The BasicLookAndFeel CheckBox icon is empty and does + * not need to be painted. + * + * @param c the component to be painted + * @param g the Graphics context to be painted with + * @param x the x position of the icon + * @param y the y position of the icon + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + Color save = g.getColor(); + g.setColor(c.getForeground()); + g.drawRect(x, y, getIconWidth(), getIconHeight()); + + JCheckBox item = (JCheckBox) c; + if (item.isSelected()) + { + g.drawLine(3 + x, 5 + y, 3 + x, 9 + y); + g.drawLine(4 + x, 5 + y, 4 + x, 9 + y); + g.drawLine(5 + x, 7 + y, 9 + x, 3 + y); + g.drawLine(5 + x, 8 + y, 9 + x, 4 + y); + } + + g.setColor(save); + } + } + + /** + * The icon used for RadioButtons in the GNULookAndFeel. This is an empty + * icon with a size of 13x13 pixels. + */ + static class RadioButtonIcon + implements Icon + { + /** + * Returns the height of the icon. The GNULookAndFeel RadioButton icon + * has a height of 13 pixels. + * + * @return the height of the icon + */ + public int getIconHeight() + { + return 13; + } + + /** + * Returns the width of the icon. The GNULookAndFeel RadioButton icon + * has a width of 13 pixels. + * + * @return the height of the icon + */ + public int getIconWidth() + { + return 13; + } + + /** + * Paints the icon. The GNULookAndFeel RadioButton icon is empty and does + * not need to be painted. + * + * @param c the component to be painted + * @param g the Graphics context to be painted with + * @param x the x position of the icon + * @param y the y position of the icon + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + Color savedColor = g.getColor(); + JRadioButton b = (JRadioButton) c; + + // draw outer circle + if (b.isEnabled()) + g.setColor(Color.GRAY); + else + g.setColor(Color.GRAY); + g.drawLine(x + 2, y + 1, x + 3, y + 1); + g.drawLine(x + 4, y, x + 7, y); + g.drawLine(x + 8, y + 1, x + 9, y + 1); + g.drawLine(x + 10, y + 2, x + 10, y + 3); + g.drawLine(x + 11, y + 4, x + 11, y + 7); + g.drawLine(x + 10, y + 8, x + 10, y + 9); + g.drawLine(x + 8, y + 10, x + 9, y + 10); + g.drawLine(x + 4, y + 11, x + 7, y + 11); + g.drawLine(x + 2, y + 10, x + 3, y + 10); + g.drawLine(x + 1, y + 9, x + 1, y + 8); + g.drawLine(x, y + 7, x, y + 4); + g.drawLine(x + 1, y + 2, x + 1, y + 3); + + if (b.getModel().isArmed()) + { + g.setColor(Color.GRAY); + g.drawLine(x + 4, y + 1, x + 7, y + 1); + g.drawLine(x + 4, y + 10, x + 7, y + 10); + g.drawLine(x + 1, y + 4, x + 1, y + 7); + g.drawLine(x + 10, y + 4, x + 10, y + 7); + g.fillRect(x + 2, y + 2, 8, 8); + } + else + { + // only draw inner highlight if not filled + if (b.isEnabled()) + { + g.setColor(Color.WHITE); + + g.drawLine(x + 2, y + 8, x + 2, y + 9); + g.drawLine(x + 1, y + 4, x + 1, y + 7); + g.drawLine(x + 2, y + 2, x + 2, y + 3); + g.drawLine(x + 3, y + 2, x + 3, y + 2); + g.drawLine(x + 4, y + 1, x + 7, y + 1); + g.drawLine(x + 8, y + 2, x + 9, y + 2); + } + } + + // draw outer highlight + if (b.isEnabled()) + { + g.setColor(Color.WHITE); + + // outer + g.drawLine(x + 10, y + 1, x + 10, y + 1); + g.drawLine(x + 11, y + 2, x + 11, y + 3); + g.drawLine(x + 12, y + 4, x + 12, y + 7); + g.drawLine(x + 11, y + 8, x + 11, y + 9); + g.drawLine(x + 10, y + 10, x + 10, y + 10); + g.drawLine(x + 8, y + 11, x + 9, y + 11); + g.drawLine(x + 4, y + 12, x + 7, y + 12); + g.drawLine(x + 2, y + 11, x + 3, y + 11); + } + + if (b.isSelected()) + { + if (b.isEnabled()) + g.setColor(Color.BLACK); + else + g.setColor(Color.GRAY); + g.drawLine(x + 4, y + 3, x + 7, y + 3); + g.fillRect(x + 3, y + 4, 6, 4); + g.drawLine(x + 4, y + 8, x + 7, y + 8); + } + g.setColor(savedColor); + } + } +} diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Error.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Error.png new file mode 100644 index 000000000..9d6f12278 Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Error.png differ diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Inform.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Inform.png new file mode 100644 index 000000000..89931d54d Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Inform.png differ diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/JavaCup.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/JavaCup.png new file mode 100644 index 000000000..d2cff6258 Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/JavaCup.png differ diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/JavaCupLarge.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/JavaCupLarge.png new file mode 100644 index 000000000..6a4f7923a Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/JavaCupLarge.png differ diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Question.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Question.png new file mode 100644 index 000000000..89931d54d Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Question.png differ diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/README b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/README new file mode 100644 index 000000000..755f31820 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/README @@ -0,0 +1,20 @@ +Images required by Basic Look and Feel + +Information based on images from Swing 1.1.1b2 +JavaCup.gif - a picture of the steaming cup of Java - 16x16 - 3 colors + +TreeOpen.gif - a picture of an open file folder - 16x13 - 8 colors +TreeClosed.gif - a picture of a closed file folder - 16x13 - 7 colors +TreeLeaf.gif - a picture of a small circle with points in four + directions - 16x13 - 2 colors + +Information on images used by Gtk Look and Feel, really need to work the +number of colors down I think. + +JavaCup.gif - a picture of Classpath's mascot - 16x16 - 58 colors + +TreeOpen.gif - taken from Gnome File Manager - 16x12 - 34 colors +TreeClosed.gif - taken from Gnome File Manager 14x12 - 28 colors +TreeLeaf.gif - a blank gif - 16x12 - 1 color + +Error.gif - think this will be needed later (taken from gnome) diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeClosed.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeClosed.png new file mode 100644 index 000000000..e2edbf78e Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeClosed.png differ diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeLeaf-normal.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeLeaf-normal.png new file mode 100644 index 000000000..fb8dbc982 Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeLeaf-normal.png differ diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeLeaf.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeLeaf.png new file mode 100644 index 000000000..cdf058fe6 Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeLeaf.png differ diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeOpen.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeOpen.png new file mode 100644 index 000000000..fba82587a Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeOpen.png differ diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Warn.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Warn.png new file mode 100644 index 000000000..9d6f12278 Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Warn.png differ diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/file-folders.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/file-folders.png new file mode 100644 index 000000000..e1a03d0c9 Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/file-folders.png differ diff --git a/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/slider.png b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/slider.png new file mode 100644 index 000000000..ac429b158 Binary files /dev/null and b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/slider.png differ diff --git a/libjava/classpath/gnu/javax/swing/plaf/metal/CustomizableTheme.java b/libjava/classpath/gnu/javax/swing/plaf/metal/CustomizableTheme.java new file mode 100644 index 000000000..7dbf6e12a --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/plaf/metal/CustomizableTheme.java @@ -0,0 +1,218 @@ +/* CustomizableTheme.java -- A customizable metal theme + 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.swing.plaf.metal; + +import java.awt.Color; + +import javax.swing.plaf.ColorUIResource; +import javax.swing.plaf.metal.DefaultMetalTheme; + +/** + * A Metal theme that can be customized by setting the primary and secondary + * colors. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class CustomizableTheme + extends DefaultMetalTheme + implements Cloneable +{ + + /** + * The primary1 color. + */ + private ColorUIResource primary1; + + /** + * The primary2 color. + */ + private ColorUIResource primary2; + + /** + * The primary3 color. + */ + private ColorUIResource primary3; + + /** + * The secondary1 color. + */ + private ColorUIResource secondary1; + + /** + * The secondary2 color. + */ + private ColorUIResource secondary2; + + /** + * The secondary3 color. + */ + private ColorUIResource secondary3; + + /** + * Sets the primary1 color of the theme. + * + * @param c the primary1 color to set + */ + public void setPrimary1(Color c) + { + primary1 = new ColorUIResource(c); + } + + /** + * Returns the primary1 color of this theme. + * + * @return the primary1 color of this theme + */ + public ColorUIResource getPrimary1() + { + return primary1 == null ? super.getPrimary1() : primary1; + } + + + /** + * Sets the primary2 color of the theme. + * + * @param c the primary2 color to set + */ + public void setPrimary2(Color c) + { + primary2 = new ColorUIResource(c); + } + + /** + * Returns the primary2 color of this theme. + * + * @return the primary2 color of this theme + */ + public ColorUIResource getPrimary2() + { + return primary2 == null ? super.getPrimary2() : primary2; + } + + /** + * Sets the primary3 color of the theme. + * + * @param c the primary3 color to set + */ + public void setPrimary3(Color c) + { + primary3 = new ColorUIResource(c); + } + + /** + * Returns the primary3 color of this theme. + * + * @return the primary3 color of this theme + */ + public ColorUIResource getPrimary3() + { + return primary3 == null ? super.getPrimary3() : primary3; + } + + /** + * Sets the secondary1 color of the theme. + * + * @param c the secondary1 color to set + */ + public void setSecondary1(Color c) + { + secondary1 = new ColorUIResource(c); + } + + /** + * Returns the secondary1 color of this theme. + * + * @return the secondary1 color of this theme + */ + public ColorUIResource getSecondary1() + { + return secondary1 == null ? super.getSecondary1() : secondary1; + } + + /** + * Sets the secondary2 color of the theme. + * + * @param c the secondary2 color to set + */ + public void setSecondary2(Color c) + { + secondary2 = new ColorUIResource(c); + } + + /** + * Returns the secondary2 color of this theme. + * + * @return the secondary2 color of this theme + */ + public ColorUIResource getSecondary2() + { + return secondary2 == null ? super.getSecondary2() : secondary2; + } + + /** + * Sets the secondary3 color of the theme. + * + * @param c the secondary3 color to set + */ + public void setSecondary3(Color c) + { + secondary3 = new ColorUIResource(c); + } + + /** + * Returns the secondary3 color of this theme. + * + * @return the secondary3 color of this theme + */ + public ColorUIResource getSecondary3() + { + return secondary3 == null ? super.getSecondary3() : secondary3; + } + + /** + * Returns a clone of this theme. + * + * @return a clone of this theme + */ + public Object clone() + throws CloneNotSupportedException + { + return super.clone(); + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/CharacterAttributeTranslator.java b/libjava/classpath/gnu/javax/swing/text/html/CharacterAttributeTranslator.java new file mode 100644 index 000000000..d4e58eb5d --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/CharacterAttributeTranslator.java @@ -0,0 +1,192 @@ +/* CharacterAttributeTranslator.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.javax.swing.text.html; + +import java.awt.Color; +import java.util.HashMap; +import java.util.StringTokenizer; + +import javax.swing.text.MutableAttributeSet; +import javax.swing.text.StyleConstants; +import javax.swing.text.html.HTML.Attribute; +import javax.swing.text.html.HTML.Tag; + +/** + * This is a small utility class to translate HTML character attributes to + * Swing StyleConstants + */ +public class CharacterAttributeTranslator +{ + /** + * Maps color name to its hex encoding. + */ + private static final HashMap colorMap = new HashMap(); + static + { + colorMap.put("aqua" , "#00FFFF"); + colorMap.put("blue" , "#0000FF"); + colorMap.put("black", "#000000"); + colorMap.put("fuchsia" , "#FF00FF"); + colorMap.put("gray" , "#808080"); + colorMap.put("green" , "#008000"); + colorMap.put("lime" , "#00FF00"); + colorMap.put("maroon" , "#800000"); + colorMap.put("navy" , "#000080"); + colorMap.put("olive" , "#808000"); + colorMap.put("purple" , "#800080"); + colorMap.put("red" , "#FF0000"); + colorMap.put("silver" , "#C0C0C0"); + colorMap.put("teal" , "#008080"); + colorMap.put("white" , "#FFFFFF"); + colorMap.put("yellow" , "#FFFF00"); + } + + /** + * Convert the color string represenation into java.awt.Color. The valid + * values are like "aqua" , "#00FFFF" or "rgb(1,6,44)". + * + * @param colorName the color to convert. + * @return the matching java.awt.color + */ + public static Color getColor(String colorName) + { + colorName = colorName.toLowerCase(); + try + { + if (colorName.startsWith("rgb")) + { + // rgb(red, green, blue) notation. + StringTokenizer st = new StringTokenizer(colorName, " ,()"); + String representation = st.nextToken(); + + // Return null if the representation is not supported. + if (! representation.equals("rgb")) + return null; + int red = Integer.parseInt(st.nextToken()); + int green = Integer.parseInt(st.nextToken()); + int blue = Integer.parseInt(st.nextToken()); + + return new Color(red, green, blue); + } + else + { + String s2 = (String) colorMap.get(colorName); + if (s2 == null) + s2 = colorName; + return Color.decode(s2); + } + } + catch (Exception nex) + { + // Can be either number format exception or illegal argument + // exception. + return null; + } + } + + /** + * Translate the HTML character attribute to the Swing style constant. + * + * @param charAttr the character attributes of the html tag + * @param t the html tag itself + * @param a the attribute set where the translated attributes will be stored + * + * @return true if some attributes were translated, false otherwise. + */ + public static boolean translateTag(MutableAttributeSet charAttr, + Tag t, MutableAttributeSet a) + { + if(t == Tag.FONT) + { + Object color = a.getAttribute(Attribute.COLOR); + if(color != null) + { + Color c = getColor(color.toString()); + if( c == null ) + return false; + charAttr.addAttribute(StyleConstants.Foreground, c); + return true; + } + + if(a.getAttribute(Attribute.SIZE) != null) + { + // FIXME + // charAttr.addAttribute(StyleConstants.FontSize, + // new java.lang.Integer(72)); + return true; + } + } + + if( t == Tag.B ) + { + charAttr.addAttribute(StyleConstants.Bold, Boolean.TRUE); + return true; + } + + if( t == Tag.I ) + { + charAttr.addAttribute(StyleConstants.Italic, Boolean.TRUE); + return true; + } + + if( t == Tag.U ) + { + charAttr.addAttribute(StyleConstants.Underline, Boolean.TRUE); + return true; + } + + if( t == Tag.STRIKE ) + { + charAttr.addAttribute(StyleConstants.StrikeThrough, Boolean.TRUE); + return true; + } + + if( t == Tag.SUP ) + { + charAttr.addAttribute(StyleConstants.Superscript, Boolean.TRUE); + return true; + } + + if( t == Tag.SUB ) + { + charAttr.addAttribute(StyleConstants.Subscript, Boolean.TRUE); + return true; + } + return false; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/CombinedAttributes.java b/libjava/classpath/gnu/javax/swing/text/html/CombinedAttributes.java new file mode 100644 index 000000000..c3fe66816 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/CombinedAttributes.java @@ -0,0 +1,213 @@ +/* CombinedAttributes.java -- A two combined sets of attributes + 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.swing.text.html; + +import java.io.Serializable; +import java.util.Enumeration; + +import javax.swing.text.AttributeSet; +import javax.swing.text.SimpleAttributeSet; + +/** + * Contains the two combined attribute sets what are searched subsequently. + * This is used to combine style sheet attributes with the HTML view attributes. + * The parent cannot be used as the view may have its own attribute hierarchy. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class CombinedAttributes implements AttributeSet, Serializable +{ + /** + * Returns the elements from both enumerations. + */ + class CombinedEnumeration implements Enumeration + { + /** + * Create a combined enumeration that enumerates over two enumerations. + * + * @param first the first enumeration to enumerate + * @param second the second enumeration to enumerate + */ + CombinedEnumeration(Enumeration first, Enumeration second) + { + a = first; + b = second; + } + + /** + * The first enumeration (elements returned first) + */ + final Enumeration a; + + /** + * The second enumeration (elements returned later) + */ + final Enumeration b; + + /** @inheritDoc */ + public boolean hasMoreElements() + { + return a.hasMoreElements() || b.hasMoreElements(); + } + + /** @inheritDoc */ + public Object nextElement() + { + return a.hasMoreElements() ? a.nextElement():b.nextElement(); + } + } + + + /** + * The first attribute set. + */ + final AttributeSet a; + + /** + * The second attribute set. + */ + final AttributeSet b; + + /** + * Create the CombinedAttributes what search in the two sets. If any of the + * two passed sets is null, another set is returned. Otherwise, the combined + * attribute set is returned. + * + * @param primary the first set (searched first) + * @param secondary the second set (searched later). + */ + public static AttributeSet combine(AttributeSet primary, + AttributeSet secondary) + { + if (primary == null) + return secondary; + else if (secondary == null) + return primary; + else + return new CombinedAttributes(primary, secondary); + } + + /** + * Create the CombinedAttributes what search in the two sets. + * + * @param primary the first set (searched first) + * @param secondary the second set (searched later). + */ + private CombinedAttributes(AttributeSet primary, AttributeSet secondary) + { + a = primary; + b = secondary; + } + + /** @inheritDoc */ + public boolean containsAttribute(Object name, Object value) + { + return a.containsAttribute(name, value) || b.containsAttribute(name, value); + } + + /** @inheritDoc */ + public boolean containsAttributes(AttributeSet attributes) + { + Enumeration names = attributes.getAttributeNames(); + Object name; + while (names.hasMoreElements()) + { + name = names.nextElement(); + if (!containsAttribute(name, attributes.getAttribute(name))) + return false; + } + return true; + } + + /** @inheritDoc */ + public AttributeSet copyAttributes() + { + SimpleAttributeSet copy = new SimpleAttributeSet(); + copy.addAttributes(a); + copy.addAttributes(b); + return copy; + } + + /** @inheritDoc */ + public Object getAttribute(Object key) + { + Object value = a.getAttribute(key); + if (value == null) + value = b.getAttribute(key); + + return value; + } + + /** @inheritDoc */ + public int getAttributeCount() + { + return a.getAttributeCount()+b.getAttributeCount(); + } + + /** @inheritDoc */ + public Enumeration getAttributeNames() + { + return new CombinedEnumeration(a.getAttributeNames(), b.getAttributeNames()); + } + + /** + * There is no one. + * + * @return null, always. + */ + public AttributeSet getResolveParent() + { + return null; + } + + /** @inheritDoc */ + public boolean isDefined(Object attrName) + { + return a.isDefined(attrName) || b.isDefined(attrName); + } + + /** @inheritDoc */ + public boolean isEqual(AttributeSet attr) + { + if (attr.getAttributeCount() == getAttributeCount()) + return containsAttributes(attr); + else + return false; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/ImageViewIconFactory.java b/libjava/classpath/gnu/javax/swing/text/html/ImageViewIconFactory.java new file mode 100644 index 000000000..ef3a1c6d1 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/ImageViewIconFactory.java @@ -0,0 +1,282 @@ +package gnu.javax.swing.text.html; + + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics; +import java.io.Serializable; + +import javax.swing.Icon; +import javax.swing.plaf.metal.MetalLookAndFeel; + +/** + * Creates icons for ImageView. The icons reflect the basic ideas of the Sun's + * icons as they would be described in the text (sheet of paper with image and + * broken sheet of paper with image). They are not pixel to pixel identical and + * contain elements from the metal icon factory. + * + * @author Audrius Meskauskas (audriusa@bioinformatics.org) + */ +public class ImageViewIconFactory +{ + private static Icon noImageIcon; + + private static Icon loadingImageIcon; + + /** + * This icon reflects the general concept (broken sheet of paper with + * image), but is currently not pixel to pixel identical with the Sun's + * implementation. + */ + public static class NoImageIcon implements Icon, Serializable + { + /** + * Creates a new icon. + */ + public NoImageIcon() + { + // Nothing to do here. + } + + /** + * Returns the width of the icon, in pixels. + * + * @return The width of the icon. + */ + public int getIconWidth() + { + return 38; + } + + /** + * Returns the height of the icon, in pixels. + * + * @return The height of the icon. + */ + public int getIconHeight() + { + return 38; + } + + /** + * Paints the icon using colors from the {@link MetalLookAndFeel}. + * + * @param c + * the component (ignored). + * @param g + * the graphics device. + * @param x + * the x-coordinate for the top-left of the icon. + * @param y + * the y-coordinate for the top-left of the icon. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + // frame + Color savedColor = g.getColor(); + + g.setColor(MetalLookAndFeel.getBlack()); + + g.drawLine(x, y, x + 19, y); + + g.drawLine(x, y + 1, x, y + 5); + g.drawLine(x, y + 13, x, y + 25); + + g.drawLine(x, y + 25, x + 22, y + 25); + + g.drawLine(x + 22, y + 25, x + 22, y + 21); + g.drawLine(x + 22, y + 13, x + 22, y + 6); + + g.drawLine(x + 22, y + 6, x + 19, y); + + g.drawLine(x + 17, y + 2, x + 21, y + 6); + + g.drawLine(x + 18, y + 1, x + 19, y + 1); + + g.setColor(MetalLookAndFeel.getControlShadow()); + + g.drawLine(x + 1, y + 1, x + 17, y + 1); + + g.drawLine(x + 1, y + 1, x + 1, y + 5); + g.drawLine(x + 1, y + 13, x + 1, y + 24); + + g.drawLine(x + 1, y + 24, x + 21, y + 24); + + g.drawLine(x + 21, y + 24, x + 21, y + 21); + g.drawLine(x + 21, y + 13, x + 21, y + 7); + + g.drawLine(x + 18, y + 2, x + 20, y + 4); + + // Breaking line + + // Shadow + g.drawLine(x + 1, y + 6, x + 20, y + 13); + g.drawLine(x + 1, y + 13, x + 20, y + 20); + + // Edge + g.setColor(MetalLookAndFeel.getBlack()); + g.drawLine(x, y + 6, x + 21, y + 14); + g.drawLine(x, y + 12, x + 21, y + 20); + + // Picture + + y += 1; + x += 3; + + g.setColor(MetalLookAndFeel.getBlack()); + + // roof + g.drawLine(x + 4, y + 5, x + 8, y + 1); + g.drawLine(x + 8, y + 1, x + 15, y + 8); + + // chimney + g.drawLine(x + 11, y + 2, x + 11, y + 4); + g.drawLine(x + 12, y + 2, x + 12, y + 5); + + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + + // roof paint + int xx = x + 8; + for (int i = 0; i < 4; i++) + g.drawLine(xx - i, y + 2 + i, xx + i, y + 2 + i); + g.fillRect(x + 4, y + 6, 9, 2); + + // base of house + g.drawLine(x + 3, y + 14, x + 3, y + 18); + g.drawLine(x + 3, y + 18, x + 13, y + 18); + + g.setColor(savedColor); + } + } + + /** + * This icon reflects the general concept (sheet of paper with image), but is + * currently not pixel to pixel identical with the Sun's implementation. + */ + public static class LoadingImageIcon implements Icon, Serializable + { + + /** + * Creates a new icon. + */ + public LoadingImageIcon() + { + // Nothing to do here. + } + + /** + * Returns the width of the icon, in pixels. + * + * @return The width of the icon. + */ + public int getIconWidth() + { + return 38; + } + + /** + * Returns the height of the icon, in pixels. + * + * @return The height of the icon. + */ + public int getIconHeight() + { + return 38; + } + + /** + * Paints the icon using colors from the {@link MetalLookAndFeel}. + * + * @param c + * the component (ignored). + * @param g + * the graphics device. + * @param x + * the x-coordinate for the top-left of the icon. + * @param y + * the y-coordinate for the top-left of the icon. + */ + public void paintIcon(Component c, Graphics g, int x, int y) + { + // frame + Color savedColor = g.getColor(); + + g.setColor(Color.black); + g.drawLine(x, y, x + 19, y); + g.drawLine(x, y + 1, x, y + 25); + g.drawLine(x, y + 25, x + 22, y + 25); + g.drawLine(x + 22, y + 25, x + 22, y + 6); + g.drawLine(x + 22, y + 6, x + 19, y); + + g.drawLine(x + 17, y + 2, x + 21, y + 6); + g.drawLine(x + 18, y + 1, x + 19, y + 1); + + g.setColor(new Color(204, 204, 255)); + + g.drawLine(x + 1, y + 1, x + 17, y + 1); + g.drawLine(x + 1, y + 1, x + 1, y + 24); + g.drawLine(x + 1, y + 24, x + 21, y + 24); + g.drawLine(x + 21, y + 24, x + 21, y + 7); + g.drawLine(x + 18, y + 2, x + 20, y + 4); + + // Picture (house) + + y += 3; + x += 3; + + g.setColor(MetalLookAndFeel.getBlack()); + + // roof + g.drawLine(x + 1, y + 8, x + 8, y + 1); + g.drawLine(x + 8, y + 1, x + 15, y + 8); + + // base of house + g.drawLine(x + 3, y + 6, x + 3, y + 15); + g.drawLine(x + 3, y + 15, x + 13, y + 15); + g.drawLine(x + 13, y + 6, x + 13, y + 15); + + // door frame + g.drawLine(x + 6, y + 9, x + 6, y + 15); + g.drawLine(x + 6, y + 9, x + 10, y + 9); + g.drawLine(x + 10, y + 9, x + 10, y + 15); + + // chimney + g.drawLine(x + 11, y + 2, x + 11, y + 4); + g.drawLine(x + 12, y + 2, x + 12, y + 5); + + g.setColor(MetalLookAndFeel.getControlDarkShadow()); + + // roof paint + int xx = x + 8; + for (int i = 0; i < 4; i++) + g.drawLine(xx - i, y + 2 + i, xx + i, y + 2 + i); + g.fillRect(x + 4, y + 6, 9, 2); + + // door knob + g.drawLine(x + 9, y + 12, x + 9, y + 12); + + // house paint + g.setColor(MetalLookAndFeel.getPrimaryControl()); + g.drawLine(x + 4, y + 8, x + 12, y + 8); + g.fillRect(x + 4, y + 9, 2, 6); + g.fillRect(x + 11, y + 9, 2, 6); + + g.setColor(savedColor); + } + } + + public static Icon getNoImageIcon() + { + if (noImageIcon == null) + noImageIcon = new NoImageIcon(); + return noImageIcon; + } + + public static Icon getLoadingImageIcon() + { + if (loadingImageIcon == null) + loadingImageIcon = new LoadingImageIcon(); + return loadingImageIcon; + } + +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/BorderStyle.java b/libjava/classpath/gnu/javax/swing/text/html/css/BorderStyle.java new file mode 100644 index 000000000..3ccd38491 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/BorderStyle.java @@ -0,0 +1,64 @@ +/* BorderStyle.java -- Utility for dealing with border styles + 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.swing.text.html.css; + +/** + * Utility class for handling border styles. + */ +public class BorderStyle +{ + + /** + * Determines if a given value makes up a valid border style value. + * + * @param value the value to check + * + * @return true when this is a valid border style, + * false otherwise + */ + public static boolean isValidStyle(String value) + { + return value.equals("none") || value.equals("hidden") + || value.equals("dotted") || value.equals("dashed") + || value.equals("solid") || value.equals("double") + || value.equals("groove") || value.equals("ridge") + || value.equals("inset") || value.equals("outset"); + + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/BorderWidth.java b/libjava/classpath/gnu/javax/swing/text/html/css/BorderWidth.java new file mode 100644 index 000000000..ae64c2110 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/BorderWidth.java @@ -0,0 +1,78 @@ +/* BorderWidth.java -- A CSS metric for border widths + 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.swing.text.html.css; + +/** + * A special CSS metric for border widths. It basically understands everything + * as Length, and in addition to that provides a mapping for the border-width's + * thin, medium and think values. + */ +public class BorderWidth + extends Length +{ + + /** + * Creates a new BorderWidth instance. + * + * @param val the CSS value to be interpreted + */ + public BorderWidth(String val) + { + super(val); + if (val.equals("thin")) + floatValue = 1.F; + else if (val.equals("medium")) + floatValue = 2.F; + else if (val.equals("thick")) + floatValue = 3.F; + } + + /** + * Checks if the specified value makes up a valid border-width value. + * + * @param value the value to check + * + * @return true if the value is a valid border-width + */ + public static boolean isValid(String value) + { + return value.equals("thin") || value.equals("medium") + || value.equals("thick") || Length.isValid(value); + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/CSSColor.java b/libjava/classpath/gnu/javax/swing/text/html/css/CSSColor.java new file mode 100644 index 000000000..ea4b94ae0 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/CSSColor.java @@ -0,0 +1,170 @@ +/* CSSColor.java -- Converts CSS color values + 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.swing.text.html.css; + +import java.awt.Color; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Set; + +/** + * Converts CSS color values into AWT Color values. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class CSSColor +{ + + private static final HashMap COLOR_MAP; + static + { + COLOR_MAP = new HashMap(); + COLOR_MAP.put("maroon", "#800000"); + COLOR_MAP.put("red", "#ff0000"); + COLOR_MAP.put("orange", "#ffa500"); + COLOR_MAP.put("yellow", "#ffff00"); + COLOR_MAP.put("olive", "#808000"); + COLOR_MAP.put("purple", "#800080"); + COLOR_MAP.put("fuchsia", "#ff00ff"); + COLOR_MAP.put("white", "#ffffff"); + COLOR_MAP.put("lime", "#00ff00"); + COLOR_MAP.put("green", "#008000"); + COLOR_MAP.put("navy", "#000080"); + COLOR_MAP.put("blue", "#0000ff"); + COLOR_MAP.put("aqua", "#00ffff"); + COLOR_MAP.put("teal", "#008080"); + COLOR_MAP.put("black", "#000000"); + COLOR_MAP.put("silver", "#c0c0c0"); + COLOR_MAP.put("gray", "#808080"); + } + + /** + * The CSS value. + */ + private String value; + + /** + * The converted color. + */ + private Color color; + + /** + * Creates a new instance. + * + * @param val the CSS value + */ + public CSSColor(String val) + { + value = val; + color = convertValue(value); + } + + /** + * Converts a CSS color value to an AWT color. + * + * @param value the CSS color value + * + * @return the converted color value + */ + public static Color convertValue(String value) + { + Color color; + String val1 = value.toLowerCase(); + if (val1.charAt(0) != '#') + val1 = (String) COLOR_MAP.get(val1); + if (val1 != null) + { + String hexVal = val1.substring(1).trim(); + try + { + int rgb = Integer.parseInt(hexVal, 16); + color = new Color(rgb); + } + catch (NumberFormatException ex) + { + color = Color.BLACK; + } + } + else + color = null; + return color; + } + + /** + * Returns the converted color. + * + * @return the converted color + */ + public Color getValue() + { + return color; + } + + public String toString() + { + return value; + } + + /** + * Returns true if the specified value is a valid color value, + * false otherwise. + * + * @param val the value to check + * + * @return true if the specified value is a valid color value, + * false otherwise + */ + public static boolean isValidColor(String val) + { + boolean ret = false; + if (val.charAt(0) == '#') + ret = true; + else + { + Set colors = COLOR_MAP.keySet(); + for (Iterator i = colors.iterator(); i.hasNext() && ret == false;) + { + String color = (String) i.next(); + if (color.equalsIgnoreCase(val)) + ret = true; + } + } + return ret; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/CSSLexicalException.java b/libjava/classpath/gnu/javax/swing/text/html/css/CSSLexicalException.java new file mode 100644 index 000000000..13968e4d2 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/CSSLexicalException.java @@ -0,0 +1,60 @@ +/* CSSLexicalException.java -- Indicates a failure in the lexical analyser + 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.swing.text.html.css; + +import java.io.IOException; + +/** + * Indicates a failure in the lexical analyser of the CSS parser. + */ +public class CSSLexicalException + extends IOException +{ + + public CSSLexicalException() + { + super(); + } + + public CSSLexicalException(String message) + { + super(message); + } + +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/CSSParser.java b/libjava/classpath/gnu/javax/swing/text/html/css/CSSParser.java new file mode 100644 index 000000000..4be315e37 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/CSSParser.java @@ -0,0 +1,503 @@ +/* CSSParser.java -- A parser for CSS stylesheets + 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.swing.text.html.css; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.StringTokenizer; + +/** + * A parser for CSS stylesheets. + * + * This parser is based on the simple CSS grammar describe in + * + * http://www.w3.org/TR/CSS21/syndata.html . + * + * @author Roman Kennke (kennke@aicas.com) + */ +// TODO: Maybe use more restrictive grammar: +// http://www.w3.org/TR/CSS21/grammar.html#q1 +public class CSSParser +{ + + /** + * The scanner used to read the input streams into more usable tokens. + */ + private CSSScanner scanner; + + /** + * The parser callback. + */ + private CSSParserCallback callback; + + /** + * One lookahead token. + */ + private int lookahead; + + /** + * The parse error. + */ + private String error; + + /** + * Creates a new CSSParser that parses the specified input. + * + * @param in the source to parse + */ + public CSSParser(Reader in, CSSParserCallback cb) + { + scanner = new CSSScanner(in); + callback = cb; + lookahead = -1; + } + + /** + * Parses the input source specified in the constructor. + * + * @throws IOException if an IO or parse error occurs + */ + public void parse() + throws IOException + { + boolean success = parseStylesheet(); + if (! success) + { + throw new CSSParserException(error); + } + } + + /** + * Parses a stylesheet. + * + * @return true if the stylesheet could be parsed successfully, + * false otherwise + * + * @throws IOException if an IO or parse error occurs + */ + private boolean parseStylesheet() + throws IOException + { + int token = peekToken(); + while (token != CSSScanner.EOF && (token == CSSScanner.CDC + || token == CSSScanner.CDO || token == CSSScanner.S + || parseStatement())) + { + if (token == CSSScanner.CDC || token == CSSScanner.CDO + || token == CSSScanner.S) + readToken(); + token = peekToken(); + } + // Last token must be EOF for valid stylesheets, I'd think. + return token == CSSScanner.EOF; + } + + /** + * Parses a CSS statement. + * @return true if the stylesheet could be parsed successfully, + * false otherwise + * + * @throws IOException if an IO or parse error occurs + */ + private boolean parseStatement() + throws IOException + { + return parseRuleset() || parseAtRule(); + } + + /** + * Parses a CSS rule set. + * + * @return true if the ruleset could be parsed successfully, + * false otherwise + * + * @throws IOException if an IO or parse error occurs + */ + private boolean parseRuleset() + throws IOException + { + StringBuilder selector = new StringBuilder(); + parseSelector(selector); + StringTokenizer selSplitter = + new StringTokenizer(selector.toString(), ","); + Selector[] sels = new Selector[selSplitter.countTokens()]; + for (int i = 0; selSplitter.hasMoreTokens(); i++) + { + String sel = selSplitter.nextToken().trim(); + sels[i] = new Selector(sel); + } + callback.startStatement(sels); + // Read any number of whitespace. + int token; + do + { + token = readToken(); + } while (token == CSSScanner.S); + boolean ret = true; + + if (token == CSSScanner.CURLY_LEFT) + { + // Read any number of whitespace. + do + { + token = readToken(); + } while (token == CSSScanner.S); + lookahead = token; + + // Maybe read declaration. + boolean decl = parseDeclaration(); + token = peekToken(); + while (token == CSSScanner.SEMICOLON) + { + readToken(); // Read the semicolon. + // Read any number of whitespace. + do + { + token = readToken(); + } while (token == CSSScanner.S); + lookahead = token; + + // Maybe read declaration. + parseDeclaration(); + token = peekToken(); + } + if (token != CSSScanner.CURLY_RIGHT) + { + error = "Expected right curly brace"; + ret = false; + } + else + { + readToken(); + // Read any number of whitespace. + do + { + token = readToken(); + } while (token == CSSScanner.S); + lookahead = token; + callback.endStatement(); + } + } + else + { + ret = false; + error = "Expected left curly brace"; + } + return ret; + } + + /** + * Parses a CSS declaration. + * + * @return true if the ruleset could be parsed successfully, + * false otherwise + * + * @throws IOException if an IO or parse error occurs + */ + private boolean parseDeclaration() + throws IOException + { + // Maybe fetch one DELIM. + int token = readToken(); + if (token == CSSScanner.DELIM) + token = readToken(); + + boolean ret = true; + + // Parse property + String property = null; + if (token == CSSScanner.IDENT) + { + property = new String(scanner.parseBuffer, 0, scanner.tokenEnd); + // Read any number of whitespace. + do + { + token = readToken(); + } while (token == CSSScanner.S); + + // Read ':'. + if (token == CSSScanner.DELIM && scanner.parseBuffer[0] == ':') + { + // Read any number of whitespace. + do + { + token = readToken(); + } while (token == CSSScanner.S); + lookahead = token; + + StringBuilder value = new StringBuilder(); + if (parseValue(value)) + { + callback.declaration(property, value.toString().trim()); + } + else + { + ret = false; + error = "Error while reading the property value"; + } + } + else + { + ret = false; + error = "Expected colon to separate property and value"; + } + + } + else + { + lookahead = token; + ret = false; + error = "Expected IDENT token for property"; + } + return ret; + } + + /** + * Parses a property value. + * + * @param s the string builder to read the value into + * + * @return true if the ruleset could be parsed successfully, + * false otherwise + * + * @throws IOException if an IO or parse error occurs + */ + private boolean parseValue(StringBuilder s) + throws IOException + { + // FIXME: Handle block and ATKEYWORD. + boolean success = parseAny(s); + while (parseAny(s)) + ; + + return success; + } + + /** + * Parses a selector. + * + * @param sel the string buffer to put the selector into + * + * @return true if the ruleset could be parsed successfully, + * false otherwise + * + * @throws IOException if an IO or parse error occurs + */ + private boolean parseSelector(StringBuilder sel) + throws IOException + { + // At least one any needs to be parsed. + boolean ret = parseAny(sel); + if (ret) + { + while (parseAny(sel)) + ; + } + return ret; + } + + /** + * Parses the any rule. If s is not null, then the contents of the + * tokens is appended verbatim. + * + * @param s the string builder to append to + * + * @return true if the ruleset could be parsed successfully, + * false otherwise + * + * @throws IOException if an IO or parse error occurs + */ + private boolean parseAny(StringBuilder s) + throws IOException + { + int token = peekToken(); + boolean ret = false; + if (token == CSSScanner.IDENT || token == CSSScanner.NUMBER + || token == CSSScanner.PERCENTAGE || token == CSSScanner.DIMENSION + || token == CSSScanner.STRING || token == CSSScanner.DELIM + || token == CSSScanner.URI || token == CSSScanner.HASH + || token == CSSScanner.UNICODE_RANGE || token == CSSScanner.INCLUDES + || token == CSSScanner.DASHMATCH) + { + if (s != null) + s.append(scanner.parseBuffer, 0, scanner.tokenEnd); + readToken(); + ret = true; + } + else if (token == CSSScanner.FUNCTION) + System.err.println("Implement parseAny for FUNCTION"); + else if (token == CSSScanner.PAREN_LEFT) + System.err.println("Implement parseAny for ("); + else if (token == CSSScanner.BRACE_LEFT) + System.err.println("Implement parseAny for ["); + + // Parse any following whitespace too. + token = peekToken(); + while (token == CSSScanner.S) + { + if (s != null) + s.append(scanner.parseBuffer, 0, scanner.tokenEnd); + readToken(); + token = peekToken(); + } + return ret; + } + + /** + * Parses a CSS at-rule. + * + * @return true if the at-rule could be parsed successfully, + * false otherwise + * + * @throws IOException if an IO or parse error occurs + */ + private boolean parseAtRule() + throws IOException + { + // FIXME: Implement. + return false; + } + + /** + * Reads the next token, and skips the comments. + * + * @return the next non-comment token + */ + private int readToken() + throws IOException + { + int token; + if (lookahead == -1) + { + do + { + token = scanner.nextToken(); + } while (token == CSSScanner.COMMENT); + } + else + { + token = lookahead; + lookahead = -1; + } + return token; + } + + /** + * Returns the next token to be read, without really reading it. The next + * call to readToken() will return the same token again. + * + * @return the next token to be read, without really reading it + */ + private int peekToken() + throws IOException + { + int token; + if (lookahead == -1) + { + do + { + token = scanner.nextToken(); + } while (token == CSSScanner.COMMENT); + lookahead = token; + } + else + token = lookahead; + return token; + } + + /** + * For testing, we read in the default.css in javax/swing/text/html + * + * @param args + */ + public static void main(String[] args) + { + try + { + InputStream in; + if (args.length > 0) + { + File file = new File(args[0]); + in = new FileInputStream(file); + } + else + { + String name = "/javax/swing/text/html/default.css"; + in = CSSScanner.class.getResourceAsStream(name); + } + BufferedInputStream bin = new BufferedInputStream(in); + InputStreamReader r = new InputStreamReader(bin); + CSSParserCallback cb = new CSSParserCallback() + { + public void startStatement(Selector[] selector) + { + System.out.print("startStatement: "); + for (int i = 0; i < selector.length; i++) + { + System.out.print(selector[i]); + if (i < selector.length - 1) + System.out.print(','); + else + System.out.println(); + } + } + public void endStatement() + { + System.out.println("endStatement"); + } + public void declaration(String property, String value) + { + System.out.println("declaration: " + property + ", " + value); + } + }; + CSSParser p = new CSSParser(r, cb); + p.parse(); + } + catch (IOException ex) + { + ex.printStackTrace(); + } + } + +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/CSSParserCallback.java b/libjava/classpath/gnu/javax/swing/text/html/css/CSSParserCallback.java new file mode 100644 index 000000000..f49ffa232 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/CSSParserCallback.java @@ -0,0 +1,81 @@ +/* CSSParserCallback.java -- Callback for parsing CSS + 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.swing.text.html.css; + +/** + * Defines the callback that is used by the CSSParser to notify the + * backend of the parsing process. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public interface CSSParserCallback +{ + + /** + * Signals the beginning of a statement. + * + * A CSS statement is build up like follows: + *
      +   *  {
      +   *   ... declarations...
      +   * }
      +   * 
      + * + * After startStatement(), the callback will receive zero to n callbacks + * to declaration, followed by an endStatement() call. + * + * @param selector the selector of the statement. + */ + void startStatement(Selector[] selector); + + /** + * Signals the end of a statement. + */ + void endStatement(); + + /** + * Signals the parsing of one declaration, which defines a mapping + * from a property to a value. + * + * @param property the property + * @param value the value + */ + void declaration(String property, String value); + +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/CSSParserException.java b/libjava/classpath/gnu/javax/swing/text/html/css/CSSParserException.java new file mode 100644 index 000000000..2328d5398 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/CSSParserException.java @@ -0,0 +1,62 @@ +/* CSSParserException.java -- The CSS parser exception + 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.swing.text.html.css; + +import java.io.IOException; + +/** + * This exception is raised when the CSS parser hits a syntax error. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class CSSParserException + extends IOException +{ + + /** + * Creates a new CSSParserException. + * + * @param message the exception message + */ + public CSSParserException(String message) + { + super(message); + } + +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/CSSScanner.java b/libjava/classpath/gnu/javax/swing/text/html/css/CSSScanner.java new file mode 100644 index 000000000..37d544641 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/CSSScanner.java @@ -0,0 +1,718 @@ +/* CSSScanner.java -- A parser for CSS stylesheets + 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.swing.text.html.css; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; + +/** + * A tokenizer for CSS stylesheets. This is based on the scanner definition + * from: + * + * http://www.w3.org/TR/CSS21/syndata.html#tokenization + * + * @author Roman Kennke (kennke@aicas.com) + */ +// TODO: Maybe implement more restrictive scanner: +// http://www.w3.org/TR/CSS21/grammar.html#q2 +class CSSScanner +{ + + // The tokens. This list is taken from: + // http://www.w3.org/TR/CSS21/syndata.html#tokenization + static final int IDENT = 1; + static final int ATKEYWORD = 2; + static final int STRING = 3; + static final int INVALID = 4; + static final int HASH = 5; + static final int NUMBER = 6; + static final int PERCENTAGE = 7; + static final int DIMENSION = 8; + static final int URI = 9; + static final int UNICODE_RANGE = 10; + static final int CDO = 11; + static final int CDC = 12; + static final int SEMICOLON = 13; + static final int CURLY_LEFT = 14; + static final int CURLY_RIGHT = 15; + static final int PAREN_LEFT = 16; + static final int PAREN_RIGHT = 17; + static final int BRACE_LEFT = 16; + static final int BRACE_RIGHT = 17; + static final int S = 18; + static final int COMMENT = 19; + static final int FUNCTION = 20; + static final int INCLUDES = 21; + static final int DASHMATCH = 22; + static final int DELIM = 23; + + // Additional tokens defined for convenience. + static final int EOF = -1; + + /** + * The input source. + */ + private Reader in; + + /** + * The parse buffer. + */ + char[] parseBuffer; + + /** + * The end index in the parseBuffer of the current token. + */ + int tokenEnd; + + /** + * The lookahead 'buffer'. + */ + private int[] lookahead; + + CSSScanner(Reader r) + { + lookahead = new int[2]; + lookahead[0] = -1; + lookahead[1] = -1; + parseBuffer = new char[2048]; + in = r; + } + + /** + * Fetches the next token. The actual character data is in the parseBuffer + * afterwards with the tokenStart at index 0 and the tokenEnd field + * pointing to the end of the token. + * + * @return the next token + */ + int nextToken() + throws IOException + { + tokenEnd = 0; + int token = -1; + int next = read(); + if (next != -1) + { + switch (next) + { + case ';': + parseBuffer[0] = (char) next; + tokenEnd = 1; + token = SEMICOLON; + break; + case '{': + parseBuffer[0] = (char) next; + tokenEnd = 1; + token = CURLY_LEFT; + break; + case '}': + parseBuffer[0] = (char) next; + tokenEnd = 1; + token = CURLY_RIGHT; + break; + case '(': + parseBuffer[0] = (char) next; + tokenEnd = 1; + token = PAREN_LEFT; + break; + case ')': + parseBuffer[0] = (char) next; + tokenEnd = 1; + token = PAREN_RIGHT; + break; + case '[': + parseBuffer[0] = (char) next; + tokenEnd = 1; + token = BRACE_LEFT; + break; + case ']': + parseBuffer[0] = (char) next; + tokenEnd = 1; + token = BRACE_RIGHT; + break; + case '@': + parseBuffer[0] = (char) next; + tokenEnd = 1; + readIdent(); + token = ATKEYWORD; + break; + case '#': + parseBuffer[0] = (char) next; + tokenEnd = 1; + readName(); + token = HASH; + break; + case '\'': + case '"': + lookahead[0] = next; + readString(); + token = STRING; + break; + case ' ': + case '\t': + case '\r': + case '\n': + case '\f': + lookahead[0] = next; + readWhitespace(); + token = S; + break; + // FIXME: Detecting an URI involves several characters lookahead. +// case 'u': +// lookahead[0] = ch; +// readURI(); +// token = URI; +// break; + case '<': + parseBuffer[0] = (char) next; + parseBuffer[1] = (char) read(); + parseBuffer[2] = (char) read(); + parseBuffer[3] = (char) read(); + if (parseBuffer[1] == '!' && parseBuffer[2] == '-' + && parseBuffer[3] == '-') + { + token = CDO; + tokenEnd = 4; + } + else + throw new CSSLexicalException("expected CDO token"); + break; + case '/': + lookahead[0] = next; + readComment(); + token = COMMENT; + break; + case '~': + parseBuffer[0] = (char) next; + parseBuffer[1] = (char) read(); + if (parseBuffer[1] == '=') + token = INCLUDES; + else + throw new CSSLexicalException("expected INCLUDES token"); + break; + case '|': + parseBuffer[0] = (char) next; + parseBuffer[1] = (char) read(); + if (parseBuffer[1] == '=') + token = DASHMATCH; + else + throw new CSSLexicalException("expected DASHMATCH token"); + break; + case '-': + int ch2 = read(); + if (ch2 == '-') + { + int ch3 = read(); + if (ch3 == '>') + { + parseBuffer[0] = (char) next; + parseBuffer[1] = (char) ch2; + parseBuffer[2] = (char) ch3; + tokenEnd = 3; + token = CDC; + } + else + throw new CSSLexicalException("expected CDC token"); + } + else + { + lookahead[0] = next; + lookahead[1] = ch2; + readIdent(); + int ch3 = read(); + if (ch3 == -1 || ch3 != '(') + { + lookahead[0] = ch3; + token = IDENT; + } + else + { + parseBuffer[tokenEnd] = (char) ch3; + tokenEnd++; + token = FUNCTION; + } + } + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + lookahead[0] = next; + readNum(); + int ch3 = read(); + if (ch3 == '%') + { + parseBuffer[tokenEnd] = (char) ch3; + tokenEnd++; + token = PERCENTAGE; + } + else if (ch3 == -1 || (! (ch3 == '_' + || (ch3 >= 'a' && ch3 <= 'z') + || (ch3 >= 'A' && ch3 <= 'Z') + || ch3 == '\\' || ch3 > 177))) + { + lookahead[0] = ch3; + token = NUMBER; + } + else + { + lookahead[0] = ch3; + readIdent(); + token = DIMENSION; + } + break; + default: + // Handle IDENT that don't begin with '-'. + if (next == '_' || (next >= 'a' && next <= 'z') + || (next >= 'A' && next <= 'Z') || next == '\\' || next > 177) + { + lookahead[0] = next; + readIdent(); + int ch4 = read(); + if (ch4 == -1 || ch4 != '(') + { + lookahead[0] = ch4; + token = IDENT; + } + else + { + parseBuffer[tokenEnd] = (char) ch4; + tokenEnd++; + token = FUNCTION; + } + } + else + { + parseBuffer[0] = (char) next; + tokenEnd = 1; + token = DELIM; + } + break; + } + } + return token; + } + + String currentTokenString() + { + return new String(parseBuffer, 0, tokenEnd); + } + + /** + * Reads one character from the input stream or from the lookahead + * buffer, if it contains one character. + * + * @return the next character + * + * @throws IOException if problems occur on the input source + */ + private int read() + throws IOException + { + int ret; + if (lookahead[0] != -1) + { + ret = lookahead[0]; + lookahead[0] = -1; + } + else if (lookahead[1] != -1) + { + ret = lookahead[1]; + lookahead[1] = -1; + } + else + { + ret = in.read(); + } + return ret; + } + + /** + * Reads and identifier. + * + * @throws IOException if something goes wrong in the input source or if + * the lexical analyser fails to read an identifier + */ + private void readIdent() + throws IOException + { + int ch1 = read(); + // Read possibly leading '-'. + if (ch1 == '-') + { + parseBuffer[tokenEnd] = (char) ch1; + tokenEnd++; + ch1 = read(); + } + // What follows must be '_' or a-z or A-Z or nonascii (>177) or an + // escape. + if (ch1 == '_' || (ch1 >= 'a' && ch1 <= 'z') + || (ch1 >= 'A' && ch1 <= 'Z') || ch1 > 177) + { + parseBuffer[tokenEnd] = (char) ch1; + tokenEnd++; + } + else if (ch1 == '\\') + { + // Try to read an escape. + lookahead[0] = ch1; + readEscape(); + } + else + throw new CSSLexicalException("First character of identifier incorrect"); + + // Read any number of [_a-zA-Z0-9-] chars. + int ch = read(); + while (ch != -1 && (ch == '_' || ch == '-' || (ch >= 'a' && ch <= 'z') + || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9'))) + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + ch = read(); + } + + // Push back last read character since it doesn't belong to the IDENT. + lookahead[0] = ch; + } + + /** + * Reads an escape. + * + * @throws IOException if something goes wrong in the input source or if + * the lexical analyser fails to read an escape + */ + private void readEscape() + throws IOException + { + int ch = read(); + if (ch != -1 && ch == '\\') + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + ch = read(); + if ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f')) + { + // Read unicode escape. + // Zero to five 0-9a-f chars can follow. + int hexcount = 0; + ch = read(); + while (((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f')) + && hexcount < 5) + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + hexcount++; + ch = read(); + } + // Now we can have a \r\n or any whitespace character following. + if (ch == '\r') + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + ch = read(); + if (ch == '\n') + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + } + else + { + lookahead[0] = ch; + } + } + else if (ch == ' ' || ch == '\n' || ch == '\f' || ch == '\t') + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + } + else + { + lookahead[0] = ch; + } + } + else if (ch != '\n' && ch != '\r' && ch != '\f') + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + } + else + throw new CSSLexicalException("Can't read escape"); + } + else + throw new CSSLexicalException("Escape must start with '\\'"); + + } + + private void readName() + throws IOException + { + // Read first name character. + int ch = read(); + if (ch != -1 && (ch == '_' || ch == '-' || (ch >= 'a' && ch <= 'z') + || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9'))) + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + } + else + throw new CSSLexicalException("Invalid name"); + + // Read any number (at least one) of [_a-zA-Z0-9-] chars. + ch = read(); + while (ch != -1 && (ch == '_' || ch == '-' || (ch >= 'a' && ch <= 'z') + || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9'))) + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + ch = read(); + } + + // Push back last read character since it doesn't belong to the IDENT. + lookahead[0] = ch; + } + + /** + * Reads in a string. + * + * @throws IOException + */ + private void readString() + throws IOException + { + int ch1 = read(); + if (ch1 != -1 && (ch1 == '\'' || ch1 == '\"')) + { + parseBuffer[tokenEnd] = (char) ch1; + tokenEnd++; + + // Read any number of chars until we hit another chc1 char. + // Reject newlines, except if prefixed with \. + int ch = read(); + while (ch != -1 && ch != ch1) + { + // Every non-newline and non-\ char should be ok. + if (ch != '\n' && ch != '\r' && ch != '\f' && ch != '\\') + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + } + // Ok when followed by newline or as part of escape. + else if (ch == '\\') + { + int ch2 = read(); + if (ch2 == '\n' || ch2 == '\r') + { + parseBuffer[tokenEnd] = (char) ch; + parseBuffer[tokenEnd + 1] = (char) ch2; + tokenEnd += 2; + } + else + { + // Try to parse an escape. + lookahead[0] = ch; + lookahead[1] = ch2; + readEscape(); + } + } + else + throw new CSSLexicalException("Invalid string"); + + ch = read(); + } + if (ch != -1) + { + // Push the final char on the buffer. + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + } + else + throw new CSSLexicalException("Unterminated string"); + } + else + throw new CSSLexicalException("Invalid string"); + } + + /** + * Reads a chunk of whitespace. + * + * @throws IOException + */ + private void readWhitespace() + throws IOException + { + int ch = read(); + while (ch != -1 && (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' + || ch == '\f')) + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + ch = read(); + } + // Push back last character read. + lookahead[0] = ch; + + } + + private void readURI() + throws IOException + { + // FIXME: Implement. + } + + /** + * Reads a comment block. + * + * @throws IOException + */ + private void readComment() + throws IOException + { + // First we need a / and a * + int ch = read(); + if (ch != -1 && ch == '/') + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + ch = read(); + if (ch != -1 && ch == '*') + { + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + ch = read(); + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + boolean finished = false; + int lastChar = ch; + ch = read(); + while (! finished && ch != -1) + { + if (lastChar == '*' && ch == '/') + finished = true; + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + lastChar = ch; + ch = read(); + } + } + } + if (ch == -1) + throw new CSSLexicalException("Unterminated comment"); + + // Push back last character read. + lookahead[0] = ch; + } + + /** + * Reads a number. + * + * @throws IOException + */ + private void readNum() + throws IOException + { + boolean hadDot = false; + // First char must be number or . + int ch = read(); + if (ch != -1 && ((ch >= '0' && ch <= '9') || ch == '.')) + { + if (ch == '.') + hadDot = true; + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + // Now read in any number of digits afterwards, and maybe one dot, + // if we hadn't one already. + ch = read(); + while (ch != -1 && ((ch >= '0' && ch <= '9') + || (ch == '.' && ! hadDot))) + { + if (ch == '.') + hadDot = true; + parseBuffer[tokenEnd] = (char) ch; + tokenEnd++; + ch = read(); + } + } + else + throw new CSSLexicalException("Invalid number"); + + // Check if we haven't accidentally finished with a dot. + if (parseBuffer[tokenEnd - 1] == '.') + throw new CSSLexicalException("Invalid number"); + + // Push back last character read. + lookahead[0] = ch; + } + + /** + * For testing, we read in the default.css in javax/swing/text/html + * + * @param args + */ + public static void main(String[] args) + { + try + { + String name = "/javax/swing/text/html/default.css"; + InputStream in = CSSScanner.class.getResourceAsStream(name); + BufferedInputStream bin = new BufferedInputStream(in); + InputStreamReader r = new InputStreamReader(bin); + CSSScanner s = new CSSScanner(r); + int token; + do + { + token = s.nextToken(); + System.out.println("token: " + token + ": " + + s.currentTokenString()); + } while (token != -1); + } + catch (IOException ex) + { + ex.printStackTrace(); + } + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/FontSize.java b/libjava/classpath/gnu/javax/swing/text/html/css/FontSize.java new file mode 100644 index 000000000..203eadc40 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/FontSize.java @@ -0,0 +1,273 @@ +/* FontSize.java -- Converts CSS font size values into real values + 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.swing.text.html.css; + +/** + * Converts CSS font-size values into real (point) values. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class FontSize +{ + + /** + * The CSS value. + */ + private String value; + + /** + * The actual font size. + */ + private int size; + + /** + * The index of one of the standard sizes that this font size maps to. + * This is -1 if this fontsize doesn't map to one of the standard sizes. + * + * @see #SCALE + */ + private int sizeIndex; + + /** + * True when this font size is relative. + */ + private boolean isRelative; + + /** + * The default size for 'medium' absolute size. The other absolute sizes + * are calculated from this. + */ + public static final int DEFAULT_FONT_SIZE = 12; + + /** + * The scaling factors relative to the medium size. Medium is at index 2. + */ + private static final double[] SCALE = {0.8, 0.9, 1.0, 1.2, 1.4, 1.6, 1.8 }; + + /** + * Creates a new FontSize for the specified value. + * + * @param val the value to convert + */ + public FontSize(String val) + { + value = val; + sizeIndex = -1; + isRelative = false; + size = mapValue(); + } + + /** + * Returns the font size value. + * + * @return the font size value + */ + public int getValue(int p) + { + if (isRelative) + mapRelative(p); + return size; + } + + public int getValue() + { + assert ! isRelative; + return size; + } + + /** + * Returns the converted real value in point. + * + * @return the converted real value in point + */ + private int mapValue() + { + int intVal; + if (value.contains("pt")) + intVal = mapPoints(); + else if (value.contains("px")) + intVal = mapPixels(); + else if (value.contains("em") || value.contains("%") + || value.contains("larger") || value.contains("smaller")) + { + intVal = -1; + isRelative = true; + } + else + intVal = mapAbsolute(); + return intVal; + } + + /** + * Maps point values ('XXXpt'). + * + * @return the real font size + */ + private int mapPoints() + { + int end = value.indexOf("pt"); + String number = value.substring(0, end); + int intVal = (int) Double.parseDouble(number); + return intVal; + } + + /** + * Maps pixel values ('XXXpx'). + * + * @return the real font size + */ + private int mapPixels() + { + int end = value.indexOf("px"); + if (end == -1) + end = value.length(); + String number = value.substring(0, end); + try + { + int intVal = (int) Double.parseDouble(number); + return intVal; + } + catch (NumberFormatException ex) + { + return DEFAULT_FONT_SIZE; + } + } + + private int mapPercent(int par) + { + int end = value.indexOf("%"); + if (end == -1) + end = value.length(); + String number = value.substring(0, end); + try + { + int intVal = (int) Double.parseDouble(number); + return intVal * par / 100; + } + catch (NumberFormatException ex) + { + System.err.println("couldn't map value: '" + value + "'"); + return DEFAULT_FONT_SIZE; + } + } + + private int mapEM(int par) + { + int end = value.indexOf("em"); + if (end == -1) + end = value.length(); + String number = value.substring(0, end); + try + { + float factor = Float.parseFloat(number); + // FIXME: Should be relative to the parent element's size. + return (int) (factor * par); + } + catch (NumberFormatException ex) + { + return DEFAULT_FONT_SIZE; + } + } + + private int mapSmaller(int par) + { + return (int) (par * 0.9); + } + + private int mapLarger(int par) + { + return (int) (par * 0.9); + } + + /** + * Maps absolute font-size values. + * + * @return the real value + */ + private int mapAbsolute() + { + int index; + if (value.equals("xx-small") || value.equals("x-small")) + index = 0; + else if (value.equals("small")) + index = 1; + else if (value.equals("medium")) + index = 2; + else if (value.equals("large")) + index = 3; + else if (value.equals("x-large")) + index = 4; + else if (value.equals("xx-large")) + index = 5; + else + index = 2; + double scale = SCALE[index]; + // FIXME: Scale the real medium size of the document, rather than the + // constant here. + int intVal = (int) (scale * DEFAULT_FONT_SIZE); + sizeIndex = index; + return intVal; + } + + /** + * Returns the string representation. + */ + public String toString() + { + return value; + } + + private int mapRelative(int par) + { + if (value.indexOf('%') != -1) + size = mapPercent(par); + else if (value.indexOf("em") != -1) + size = mapEM(par); + else if (value.indexOf("larger") != -1) + size = mapLarger(par); + else if (value.indexOf("smaller") != -1) + size = mapSmaller(par); + return size; + } + + public boolean isRelative() + { + return isRelative; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/FontStyle.java b/libjava/classpath/gnu/javax/swing/text/html/css/FontStyle.java new file mode 100644 index 000000000..e52893193 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/FontStyle.java @@ -0,0 +1,80 @@ +/* FontStyle.java -- Converts font-size CSS values + 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.swing.text.html.css; + +import java.awt.Font; + +/** + * Converts font-size CSS values to a form to be used by {@link java.awt.Font}. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class FontStyle +{ + + /** + * The real value. + */ + private String value; + + /** + * Creates a new instance. + * + * @param val the CSS value + */ + public FontStyle(String val) + { + value = val; + } + + /** + * Returns the converted value. + * + * @return the converted value + */ + public int getValue() + { + int intVal; + if (value.equals("italic") || value.equals("oblique")) + intVal = Font.ITALIC; + else + intVal = Font.PLAIN; + return intVal; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/FontWeight.java b/libjava/classpath/gnu/javax/swing/text/html/css/FontWeight.java new file mode 100644 index 000000000..d338c6f55 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/FontWeight.java @@ -0,0 +1,84 @@ +/* FontWeight.java -- Converts font-weight values + 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.swing.text.html.css; + +import java.awt.Font; + +/** + * Converts font-weight CSS values to the constants defined for + * {@link java.awt.Font} + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class FontWeight +{ + + /** + * The value to convert. + */ + private String value; + + /** + * Creates a new instance. + * + * @param val the value to convert + */ + public FontWeight(String val) + { + value = val; + } + + /** + * Returns the converted value. + * + * @return the converted value + */ + public int getValue() + { + int intVal; + if (value.equals("normal")) + intVal = Font.PLAIN; + else if (value.equals("bold")) + intVal = Font.BOLD; + else + // FIXME: Implement finer-grained weights. + intVal = Font.PLAIN; + return intVal; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/Length.java b/libjava/classpath/gnu/javax/swing/text/html/css/Length.java new file mode 100644 index 000000000..06fa36e3d --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/Length.java @@ -0,0 +1,283 @@ +/* Length.java -- Converts CSS length values + 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.swing.text.html.css; + +/** + * Converts CSS length values to usable length values. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class Length +{ + + /** + * The original value. + */ + private String value; + + /** + * The converted value. + */ + protected float floatValue; + + /** + * Indicates when the value is a percentage value. + */ + private boolean isPercentage; + + /** + * Indicates a length value that is relative to the font size (em). + */ + private boolean isFontEMRelative; + + /** + * Indicates a length value that is relative to the font size (ex). + */ + private boolean isFontEXRelative; + + /** + * The EM base size. + */ + private float emBase; + + /** + * The EX base size. + */ + private float exBase; + + /** + * Creates a new length converter instance. + * + * @param val the CSS value + */ + public Length(String val) + { + isFontEMRelative = false; + isFontEXRelative = false; + isPercentage = false; + value = val; + int i = value.indexOf("px"); + int percent = value.indexOf("%"); + int em = value.indexOf("em"); + int ex = value.indexOf("ex"); + try + { + floatValue = 0.0F; + if (i != -1) + { + String sub = value.substring(0, i); + floatValue = Float.parseFloat(sub); + } + else if (percent != -1) + { + isPercentage = true; + String sub = value.substring(0, percent); + floatValue = Float.parseFloat(sub) / 100; + } + else if (em != -1) + { + isFontEMRelative = true; + String sub = value.substring(0, em); + floatValue = Float.parseFloat(sub); + } + else if (ex != -1) + { + isFontEXRelative = true; + String sub = value.substring(0, ex); + floatValue = Float.parseFloat(sub); + } + else + { + floatValue = Float.parseFloat(value); + } + } + catch (NumberFormatException exc) + { + // Don't let such small problems interrupt CSS parsing. + System.err.println("couldn't parse: " + val); + } + } + + /** + * Returns the value converted to pixels. + * + * @return the value converted to pixels + */ + public float getValue() + { + return floatValue; + } + + /** + * Returns the absolute span for the case when this length value is + * a relative value. + * + * @param base the base span + * + * @return the absolute span + */ + public float getValue(float base) + { + float span = floatValue; + if (isPercentage) + span *= base; + else if (isFontEMRelative) + span *= emBase; + else if (isFontEXRelative) + span *= exBase; + return span; + } + + /** + * Sets the font relative EM base. + * + * @param base the font relative EM base + */ + public void setEMBase(float base) + { + emBase = base; + } + + /** + * Sets the font relative EX base. + * + * @param base the font relative EX base + */ + public void setEXBase(float base) + { + exBase = base; + } + + /** + * Sets the font relative base values. + * + * @param emBase the EM base + * @param exBase the EX base + */ + public void setFontBases(float emBase, float exBase) + { + setEMBase(emBase); + setEXBase(exBase); + } + + /** + * Returns true when this length value is an em font relative value. In + * order to get correct results, you need the exBase property set up + * correctly. + * + * @return true when this length value is an ex font relative value + */ + public boolean isFontEMRelative() + { + return isFontEMRelative; + } + + /** + * Returns true when this length value is an ex font relative value. In + * order to get correct results, you need the emBase property set up + * correctly. + * + * @return true when this length value is an ex font relative value + */ + public boolean isFontEXRelative() + { + return isFontEXRelative; + } + + /** + * Returns true when the length value is a percentage + * value, false otherwise. + * + * @return true when the length value is a percentage + * value, false otherwise + */ + public boolean isPercentage() + { + return isPercentage; + } + + /** + * Checks if the specified value makes up a valid length value. + * + * @param value the value to check + * + * @return true if the value is a valid length + */ + public static boolean isValid(String value) + { + boolean isValid = true; + int px = value.indexOf("px"); + int em = value.indexOf("em"); + int ex = value.indexOf("ex"); + int pc = value.indexOf('%'); + try + { + if (px != -1) + { + Integer.parseInt(value.substring(0, px)); + } + else if (em != -1) + { + Integer.parseInt(value.substring(0, em)); + } + else if (ex != -1) + { + Integer.parseInt(value.substring(0, ex)); + } + else if (pc != -1) + { + Integer.parseInt(value.substring(0, ex)); + } + else + { + Integer.parseInt(value); + } + } + catch (NumberFormatException nfe) + { + isValid = false; + } + return isValid; + } + + public String toString() + { + return value; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/css/Selector.java b/libjava/classpath/gnu/javax/swing/text/html/css/Selector.java new file mode 100644 index 000000000..97e582194 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/css/Selector.java @@ -0,0 +1,245 @@ +/* Selector.java -- A CSS selector + 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.swing.text.html.css; + +import gnu.java.lang.CPStringBuilder; + +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +/** + * A CSS selector. This provides methods to interpret a selector and + * query matches with an actual HTML element tree. + */ +public class Selector +{ + + /** + * The actual selector. The selector tokens are stored backwards, that + * is the last token first. This makes matching easier. + */ + private String[] selector; + + private String[] elements; + private String[] ids; + private String[] classes; + + /** + * The specificity of the selector. + */ + private int specificity; + + /** + * An implicit selector has true here. This is the case for CSS rules that + * are attached to HTML elements directly via style="". + */ + private boolean implicit; + + /** + * Creates a new Selector instance for the specified selector string. + * + * @param sel the selector + */ + public Selector(String sel) + { + StringTokenizer selectorTokens = new StringTokenizer(sel, " "); + selector = new String[selectorTokens.countTokens()]; + for (int i = selector.length - 1; selectorTokens.hasMoreTokens(); i--) + { + selector[i] = selectorTokens.nextToken(); + } + calculateSpecificity(); + } + + /** + * Determines if this selector matches the element path specified in the + * arguments. The arguments hold the element names as well as class + * and id attibutes of the HTML element to be queried. The first item + * in the array is the deepest element and the last on the highest up (for + * instance, the html tag). + * + * @param tags + * + * @return true when this selector matches the element path, + * false otherwise + */ + public boolean matches(String[] tags, List> attributes) + { + // TODO: This implements class, id and descendent matching. These are + // the most commonly used selector matchers in CSS together with HTML. + // However, the CSS spec defines a couple of more sophisticated matches + // which should be implemented. + // http://www.w3.org/TR/CSS21/selector.html + + // All parts of the selector must match at some point. + boolean match = false; + int numTags = tags.length; + int numSel = selector.length; + if (numSel <= numTags) + { + match = true; + int tagIndex = 0; + for (int j = 0; j < numSel && match; j++) + { + boolean tagMatch = false; + for (; tagIndex < numTags && tagMatch == false; tagIndex++) + { + Object pathClass = attributes.get(tagIndex).get("class"); + // Try pseudo class too. + Object pseudoClass = attributes.get(tagIndex).get("_pseudo"); + Object dynClass = attributes.get(tagIndex).get("_dynamic"); + Object pathId = attributes.get(tagIndex).get("id"); + String tag = elements[j]; + String clazz = classes[j]; + String id = ids[j]; + tagMatch = tag.equals("") || tag.equals("*") + || tag.equals(tags[tagIndex]); + tagMatch = tagMatch && (clazz.equals("*") + || clazz.equals(dynClass) + || clazz.equals(pseudoClass) + || clazz.equals(pathClass)); + tagMatch = tagMatch && (id.equals("*") + || id.equals(pathId)); + // For the last element in the selector we must not look + // further. + if (j == 0) + break; + } + // If we don't come out here with a matching tag, then we're + // not matching at all. + match = tagMatch; + } + } + return match; + } + + /** + * Returns the specificity of the selector. This is calculated according + * to: + * http://www.w3.org/TR/CSS21/cascade.html#specificity + * + * @return the specificity of the selector + */ + public int getSpecificity() + { + return specificity; + } + + /** + * Returns a string representation of the selector. This tries to reconstruct + * the original selector as closely as possible. + * + * @return a string representation of the selector + */ + public String toString() + { + CPStringBuilder b = new CPStringBuilder(); + for (int i = selector.length - 1; i >= 0; i--) + { + b.append(selector[i]); + if (i > 0) + b.append(' '); + } + return b.toString(); + } + + /** + * Calculates the specificity of the selector. This is calculated according + * to: + * http://www.w3.org/TR/CSS21/cascade.html#specificity + */ + private void calculateSpecificity() + { + int a = implicit ? 1 : 0; + int b = 0; + int c = 0; + int d = 0; + int numSel = selector.length; + elements = new String[numSel]; + ids = new String[numSel]; + classes = new String[numSel]; + for (int i = 0; i < numSel; i++) + { + String sel = selector[i]; + int clazzIndex = sel.indexOf('.'); + // Try pseudo class too. + if (clazzIndex == -1) + clazzIndex = sel.indexOf(':'); + int idIndex = sel.indexOf('#'); + String clazz; + if (clazzIndex == -1) + { + clazz = "*"; + clazzIndex = sel.length(); + } + else + { + c++; + clazz = sel.substring(clazzIndex + 1, + idIndex > 0 ? Math.min(idIndex, sel.length()) + : sel.length()); + } + String id; + if (idIndex == -1) + { + id = "*"; + idIndex = sel.length(); + } + else + { + b++; + id = sel.substring(idIndex + 1, + clazzIndex > 0 ? Math.min(clazzIndex, sel.length()) + : sel.length()); + } + String tag = sel.substring(0, + Math.min(Math.min(clazzIndex, idIndex), + sel.length())); + if (! tag.equals("") && ! tag.equals("*")) + d++; + + elements[i] = tag; + ids[i] = id; + classes[i] = clazz; + } + // An order of 20 should be enough for everybody. + specificity = a * 20 ^ 3 + b * 20 ^ 2 + c * 20 + d; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/package.html b/libjava/classpath/gnu/javax/swing/text/html/package.html new file mode 100644 index 000000000..c7e774428 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/package.html @@ -0,0 +1,50 @@ + + + + +GNU Classpath - javax.swing.text.html + + +

      Provides supporting classes for web browsers, + web robots, web page content analysers, web editors and + other applications applications working with Hypertext + Markup Language (HTML). +

      + + + diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/GnuParserDelegator.java b/libjava/classpath/gnu/javax/swing/text/html/parser/GnuParserDelegator.java new file mode 100644 index 000000000..9f3666d3a --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/GnuParserDelegator.java @@ -0,0 +1,179 @@ +/* GnuParserDelegator.java -- The parser delegator which uses Swing DTD + 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.swing.text.html.parser; + +import java.io.IOException; +import java.io.Reader; +import java.io.Serializable; + +import javax.swing.text.BadLocationException; +import javax.swing.text.SimpleAttributeSet; +import javax.swing.text.html.HTMLEditorKit; +import javax.swing.text.html.HTMLEditorKit.ParserCallback; +import javax.swing.text.html.parser.DTD; +import javax.swing.text.html.parser.ParserDelegator; +import javax.swing.text.html.parser.TagElement; + +/** + * This parser delegator uses the different DTD ({@link HTML_401Swing}). + * It is derived from the ParserDelegator for the compatibility reasons. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class GnuParserDelegator extends ParserDelegator implements Serializable +{ + class gnuParser + extends gnu.javax.swing.text.html.parser.support.Parser + { + private static final long serialVersionUID = 1; + + gnuParser(DTD d) + { + super(d); + } + + protected final void handleComment(char[] comment) + { + callBack.handleComment(comment, hTag.where.startPosition); + } + + protected final void handleEmptyTag(TagElement tag) + throws javax.swing.text.ChangedCharSetException + { + callBack.handleSimpleTag(tag.getHTMLTag(), getAttributes(), + hTag.where.startPosition + ); + } + + protected final void handleEndTag(TagElement tag) + { + callBack.handleEndTag(tag.getHTMLTag(), hTag.where.startPosition); + } + + protected final void handleError(int line, String message) + { + callBack.handleError(message, hTag.where.startPosition); + } + + protected final void handleStartTag(TagElement tag) + { + SimpleAttributeSet attributes = gnu.getAttributes(); + + if (tag.fictional()) + attributes.addAttribute(ParserCallback.IMPLIED, Boolean.TRUE); + + callBack.handleStartTag(tag.getHTMLTag(), attributes, + hTag.where.startPosition + ); + } + + protected final void handleText(char[] text) + { + callBack.handleText(text, hTag.where.startPosition); + } + + DTD getDTD() + { + // Accessing the inherited gnu.javax.swing.text.html.parser.support.Parser + // field. super. is a workaround, required to support JDK1.3's javac. + return super.dtd; + } + } + + /** + * Use serialVersionUID for interoperability. + */ + private static final long serialVersionUID = -1276686502624777206L; + + private DTD theDtd; + + /** + * The callback. + * This is package-private to avoid an accessor method. + */ + HTMLEditorKit.ParserCallback callBack; + + /** + * The reference to the working class of HTML parser that is + * actually used to parse the document. + * This is package-private to avoid an accessor method. + */ + gnuParser gnu; + + /** + * Create the parser that uses the given DTD to parse the document. + * + * @param theDtd the DTD + */ + public GnuParserDelegator(DTD theDtd) + { + this.theDtd = theDtd; + gnu = new gnuParser(theDtd); + } + + /** + * Parses the HTML document, calling methods of the provided callback. This + * method must be multithread - safe. + * + * @param reader The reader to read the HTML document from + * @param a_callback The callback that is notifyed about the presence of HTML + * elements in the document. + * @param ignoreCharSet If thrue, any charset changes during parsing are + * ignored. + * @throws java.io.IOException + */ + public void parse(Reader reader, + HTMLEditorKit.ParserCallback a_callback, + boolean ignoreCharSet) throws IOException + { + callBack = a_callback; + gnu.parse(reader); + + callBack.handleEndOfLineString(gnu.getEndOfLineSequence()); + try + { + callBack.flush(); + } + catch (BadLocationException ex) + { + // Convert this into the supported type of exception. + throw new IOException(ex.getMessage()); + } + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/HTML_401F.java b/libjava/classpath/gnu/javax/swing/text/html/parser/HTML_401F.java new file mode 100644 index 000000000..d4b061465 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/HTML_401F.java @@ -0,0 +1,3801 @@ +/* HTML_401F.java -- HTML 4.01 FRAMESET DTD java conception. + 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.swing.text.html.parser; + +import gnu.javax.swing.text.html.parser.models.PCDATAonly_model; +import gnu.javax.swing.text.html.parser.models.TableRowContentModel; +import gnu.javax.swing.text.html.parser.models.noTagModel; + +import java.io.IOException; +import java.io.Serializable; + +import javax.swing.text.html.parser.*; +import javax.swing.text.html.parser.ContentModel; +import javax.swing.text.html.parser.DTDConstants; + +/** + * This class represents the java implementation of the HTML 4.01 + * ( -//W3C//DTD HTML 4.01 Frameset//EN ) Frameset version. The + * Frameset version includes as recommended, as obsoleted features and + * also the frameset support. This the default DTD to parse HTML + * documents in this implementation, containing 315 pre-defined general + * entities and 92 elements. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class HTML_401F + extends gnuDTD + implements DTDConstants, Serializable +{ + private static final long serialVersionUID = 1; + + /** + * The standard name of this DTD, + * '-//W3C//DTD HTML 4.01 Frameset//EN' + */ + public static final String DTD_NAME = "-//W3C//DTD HTML 4.01 Frameset//EN"; + + /** + * The integer representing length in pixels. + */ + static final int PIXELS = NUMBER; + + static final String[] NONE = new String[0]; + + /* Define the HTML tags. */ + static final String PCDATA = "#pcdata"; + static final String A = "a"; + static final String ABBR = "abbr"; + static final String ACRONYM = "acronym"; + static final String ADDRESS = "address"; + static final String APPLET = "applet"; + static final String AREA = "area"; + static final String B = "b"; + static final String BASE = "base"; + static final String BASEFONT = "basefont"; + static final String BDO = "bdo"; + static final String BIG = "big"; + static final String BLOCKQUOTE = "blockquote"; + static final String BODY = "body"; + static final String BR = "br"; + static final String BUTTON = "button"; + static final String CAPTION = "caption"; + static final String CENTER = "center"; + static final String CITE = "cite"; + static final String CODE = "code"; + static final String COL = "col"; + static final String COLGROUP = "colgroup"; + static final String DEFAULTS = "default"; + static final String DD = "dd"; + static final String DEL = "del"; + static final String DFN = "dfn"; + static final String DIR = "dir"; + static final String DIV = "div"; + static final String DL = "dl"; + static final String DT = "dt"; + static final String EM = "em"; + static final String FIELDSET = "fieldset"; + static final String FONT = "font"; + static final String FORM = "form"; + static final String FRAME = "frame"; + static final String FRAMESET = "frameset"; + static final String H1 = "h1"; + static final String H2 = "h2"; + static final String H3 = "h3"; + static final String H4 = "h4"; + static final String H5 = "h5"; + static final String H6 = "h6"; + static final String HEAD = "head"; + static final String HR = "hr"; + static final String HTML = "html"; + static final String I = "i"; + static final String IFRAME = "iframe"; + static final String IMG = "img"; + static final String INPUT = "input"; + static final String INS = "ins"; + static final String ISINDEX = "isindex"; + static final String KBD = "kbd"; + static final String LABEL = "label"; + static final String LEGEND = "legend"; + static final String LI = "li"; + static final String LINK = "link"; + static final String MAP = "map"; + static final String MENU = "menu"; + static final String META = "meta"; + static final String NOFRAMES = "noframes"; + static final String NOSCRIPT = "noscript"; + static final String NONES = "none"; + static final String sNAME = "name"; + static final String OBJECT = "object"; + static final String OL = "ol"; + static final String OPTGROUP = "optgroup"; + static final String OPTION = "option"; + static final String P = "p"; + static final String PARAM = "param"; + static final String PRE = "pre"; + static final String Q = "q"; + static final String S = "s"; + static final String SAMP = "samp"; + static final String SCRIPT = "script"; + static final String SELECT = "select"; + static final String SMALL = "small"; + static final String SPAN = "span"; + static final String STRIKE = "strike"; + static final String STRONG = "strong"; + static final String STYLE = "style"; + static final String SUB = "sub"; + static final String SUP = "sup"; + static final String TABLE = "table"; + static final String TBODY = "tbody"; + static final String TD = "td"; + static final String TEXTAREA = "textarea"; + static final String TFOOT = "tfoot"; + static final String TH = "th"; + static final String THEAD = "thead"; + static final String TITLE = "title"; + static final String TR = "tr"; + static final String TT = "tt"; + static final String U = "u"; + static final String UL = "ul"; + static final String VAR = "var"; + + /* Define the attribute constants. */ + static final String C_0 = "0"; + static final String C_1 = "1"; + static final String CHECKBOX = "checkbox"; + static final String DATA = "data"; + static final String FILE = "file"; + static final String GET = "get"; + static final String HIDDEN = "hidden"; + static final String IMAGE = "image"; + static final String PASSWORD = "password"; + static final String POST = "post"; + static final String RADIO = "radio"; + static final String REF = "ref"; + static final String RESET = "reset"; + static final String SUBMIT = "submit"; + static final String TEXT = "text"; + static final String ABOVE = "above"; + static final String ACCEPT = "accept"; + static final String ACCEPTCHARSET = "accept-charset"; + static final String ACCESSKEY = "accesskey"; + static final String ACTION = "action"; + static final String ALIGN = "align"; + static final String ALINK = "alink"; + static final String ALL = "all"; + static final String ALT = "alt"; + static final String APPLICATION_X_WWW_FORM_URLENCODED + = "application/x-www-form-urlencoded"; + static final String ARCHIVE = "archive"; + static final String AUTO = "auto"; + static final String AXIS = "axis"; + static final String BACKGROUND = "background"; + static final String BASELINE = "baseline"; + static final String BELOW = "below"; + static final String BGCOLOR = "bgcolor"; + static final String BORDER = "border"; + static final String BOTTOM = "bottom"; + static final String BOX = "box"; + static final String CELLPADDING = "cellpadding"; + static final String CELLSPACING = "cellspacing"; + static final String CHAR = "char"; + static final String CHAROFF = "charoff"; + static final String CHARSET = "charset"; + static final String CHECKED = "checked"; + static final String CIRCLE = "circle"; + static final String CLASS = "class"; + static final String CLASSID = "classid"; + static final String CLEAR = "clear"; + static final String CODEBASE = "codebase"; + static final String CODETYPE = "codetype"; + static final String COLOR = "color"; + static final String COLS = "cols"; + static final String COLSPAN = "colspan"; + static final String COMPACT = "compact"; + static final String CONTENT = "content"; + static final String COORDS = "coords"; + static final String DATAPAGESIZE = "datapagesize"; + static final String DATETIME = "datetime"; + static final String DECLARE = "declare"; + static final String DEFER = "defer"; + static final String DISABLED = "disabled"; + static final String DISC = "disc"; + static final String ENCTYPE = "enctype"; + static final String EVENT = "event"; + static final String FACE = "face"; + static final String FOR = "for"; + static final String FRAMEBORDER = "frameborder"; + static final String GROUPS = "groups"; + static final String HEADERS = "headers"; + static final String HEIGHT = "height"; + static final String HREF = "href"; + static final String HREFLANG = "hreflang"; + static final String HSIDES = "hsides"; + static final String HSPACE = "hspace"; + static final String HTTPEQUIV = "http-equiv"; + static final String sID = "id"; + static final String ISMAP = "ismap"; + static final String JUSTIFY = "justify"; + static final String LANG = "lang"; + static final String LANGUAGE = "language"; + static final String LEFT = "left"; + static final String LHS = "lhs"; + static final String LONGDESC = "longdesc"; + static final String LTR = "ltr"; + static final String MARGINHEIGHT = "marginheight"; + static final String MARGINWIDTH = "marginwidth"; + static final String MAXLENGTH = "maxlength"; + static final String MEDIA = "media"; + static final String METHOD = "method"; + static final String MIDDLE = "middle"; + static final String MULTIPLE = "multiple"; + static final String NO = "no"; + static final String NOHREF = "nohref"; + static final String NORESIZE = "noresize"; + static final String NOSHADE = "noshade"; + static final String NOWRAP = "nowrap"; + static final String ONBLUR = "onblur"; + static final String ONCHANGE = "onchange"; + static final String ONCLICK = "onclick"; + static final String ONDBLCLICK = "ondblclick"; + static final String ONFOCUS = "onfocus"; + static final String ONKEYDOWN = "onkeydown"; + static final String ONKEYPRESS = "onkeypress"; + static final String ONKEYUP = "onkeyup"; + static final String ONLOAD = "onload"; + static final String ONMOUSEDOWN = "onmousedown"; + static final String ONMOUSEMOVE = "onmousemove"; + static final String ONMOUSEOUT = "onmouseout"; + static final String ONMOUSEOVER = "onmouseover"; + static final String ONMOUSEUP = "onmouseup"; + static final String ONRESET = "onreset"; + static final String ONSELECT = "onselect"; + static final String ONSUBMIT = "onsubmit"; + static final String ONUNLOAD = "onunload"; + static final String POLY = "poly"; + static final String PROFILE = "profile"; + static final String PROMPT = "prompt"; + static final String READONLY = "readonly"; + static final String RECT = "rect"; + static final String REL = "rel"; + static final String REV = "rev"; + static final String RHS = "rhs"; + static final String RIGHT = "right"; + static final String ROW = "row"; + static final String ROWGROUP = "rowgroup"; + static final String ROWS = "rows"; + static final String ROWSPAN = "rowspan"; + static final String RTL = "rtl"; + static final String RULES = "rules"; + static final String SCHEME = "scheme"; + static final String SCOPE = "scope"; + static final String SCROLLING = "scrolling"; + static final String SELECTED = "selected"; + static final String SHAPE = "shape"; + static final String SIZE = "size"; + static final String SQUARE = "square"; + static final String SRC = "src"; + static final String STANDBY = "standby"; + static final String START = "start"; + static final String SUMMARY = "summary"; + static final String TABINDEX = "tabindex"; + static final String TARGET = "target"; + static final String TOP = "top"; + static final String TYPE = "type"; + static final String USEMAP = "usemap"; + static final String VALIGN = "valign"; + static final String VALUE = "value"; + static final String VALUETYPE = "valuetype"; + static final String VERSION = "version"; + static final String VLINK = "vlink"; + static final String VOID = "void"; + static final String VSIDES = "vsides"; + static final String VSPACE = "vspace"; + static final String WIDTH = "width"; + static final String YES = "yes"; + + static final String[] BLOCK = + new String[] { + ADDRESS, BLOCKQUOTE, CENTER, DIR, + DIV, DL, FIELDSET, FORM, + H1, H2, H3, H4, H5, H6, + HR, ISINDEX, MENU, NOFRAMES, NOSCRIPT, + OL, P, PRE, TABLE, UL + }; + + /** + * Creates this DTD, filling in the entities and attributes data + * as defined in -//W3C//DTD HTML 4.01 Frameset//EN. + */ + protected HTML_401F() + { + super(DTD_NAME); + defineEntities(); + defineElements(); + } + + /** + * Either takes the document (by name) from DTD table, or + * creates a new instance and registers it in the tabe. + * The document is registerd under name "-//W3C//DTD HTML 4.01 Frameset//EN". + * @return The new or existing DTD for parsing HTML 4.01 Frameset. + */ + public static DTD getInstance() + { + try + { + DTD dtd = getDTD(DTD_NAME); + if (dtd == null || dtd.getClass().equals(DTD.class)) + { + dtd = new HTML_401F(); + putDTDHash(DTD_NAME, dtd); + } + return dtd; + } + catch (IOException ex) + { + throw new Error("This should never happen. Report the bug.", ex); + } + } + + /** + * Define all elements of this DTD. + */ + protected void defineElements() + { + /* Define the elements. This used to be one huge method, which + unfortunately took too long to compile and consumed + too much memory while compiling it. While it can serve as + a good stress test for gcj, it is better to split it up + to save time and memory used during GCC bootstrap. */ + defineElements1(); + defineElements2(); + defineElements3(); + defineElements4(); + defineElements5(); + defineElements6(); + } + + /** + * Define first sixth of elements of this DTD. + */ + private void defineElements1() + { + /* Define the elements. */ + defElement(PCDATA, 0, false, false, null, NONE, NONE, + new AttributeList[ 0 ]); + + defElement(A, 0, false, false, null, + new String[] { + A + } + , + new String[] { + PCDATA, ABBR, ACRONYM, APPLET, + B, BASEFONT, BDO, BIG, BR, + BUTTON, CITE, CODE, DFN, EM, + FONT, I, IFRAME, IMG, INPUT, + KBD, LABEL, MAP, OBJECT, Q, + S, SAMP, SCRIPT, SELECT, SMALL, + SPAN, STRIKE, STRONG, SUB, SUP, + TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(CHARSET, null, null, 0, IMPLIED), + attr(TYPE, null, null, 0, IMPLIED), + attr(sNAME, null, null, 0, IMPLIED), + attr(HREF, null, null, 0, IMPLIED), + attr(HREFLANG, null, null, 0, IMPLIED), + attr(TARGET, null, null, 0, IMPLIED), + attr(REL, null, null, 0, IMPLIED), + attr(REV, null, null, 0, IMPLIED), + attr(ACCESSKEY, null, null, 0, IMPLIED), + attr(SHAPE, RECT, new String[] { RECT, CIRCLE, POLY, DEFAULTS }, + 0, DEFAULT), + attr(COORDS, null, null, 0, IMPLIED), + attr(TABINDEX, null, null, NUMBER, IMPLIED), + attr(ONFOCUS, null, null, 0, IMPLIED), + attr(ONBLUR, null, null, 0, IMPLIED) + } + ); + defElement(ABBR, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(ACRONYM, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(ADDRESS, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + P + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(APPLET, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL, PARAM + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(CODEBASE, null, null, 0, IMPLIED), + attr(ARCHIVE, null, null, 0, IMPLIED), + attr(CODE, null, null, 0, IMPLIED), + attr(OBJECT, null, null, 0, IMPLIED), + attr(ALT, null, null, 0, IMPLIED), + attr(sNAME, null, null, 0, IMPLIED), + attr(WIDTH, null, null, 0, REQUIRED), + attr(HEIGHT, null, null, 0, REQUIRED), + attr(ALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, LEFT, RIGHT }, + 0, IMPLIED), + attr(HSPACE, null, null, 0, IMPLIED), + attr(VSPACE, null, null, 0, IMPLIED) + } + ); + defElement(AREA, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(SHAPE, RECT, new String[] { RECT, CIRCLE, POLY, DEFAULTS }, + 0, DEFAULT), + attr(COORDS, null, null, 0, IMPLIED), + attr(HREF, null, null, 0, IMPLIED), + attr(TARGET, null, null, 0, IMPLIED), + attr(NOHREF, null, new String[] { NOHREF }, 0, IMPLIED), + attr(ALT, null, null, 0, REQUIRED), + attr(TABINDEX, null, null, NUMBER, IMPLIED), + attr(ACCESSKEY, null, null, 0, IMPLIED), + attr(ONFOCUS, null, null, 0, IMPLIED), + attr(ONBLUR, null, null, 0, IMPLIED) + } + ); + defElement(B, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(BASE, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(HREF, null, null, 0, IMPLIED), + attr(TARGET, null, null, 0, IMPLIED) + } + ); + defElement(BASEFONT, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(SIZE, null, null, 0, REQUIRED), + attr(COLOR, null, null, 0, IMPLIED), + attr(FACE, null, null, 0, IMPLIED) + } + ); + defElement(BDO, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, REQUIRED) + } + ); + defElement(BIG, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(BLOCKQUOTE, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(CITE, null, null, 0, IMPLIED) + } + ); + defElement(BODY, 0, true, true, null, + NONE + , + getBodyElements() + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ONLOAD, null, null, 0, IMPLIED), + attr(ONUNLOAD, null, null, 0, IMPLIED), + attr(BACKGROUND, null, null, 0, IMPLIED), + attr(BGCOLOR, null, null, 0, IMPLIED), + attr(TEXT, null, null, 0, IMPLIED), + attr(LINK, null, null, 0, IMPLIED), + attr(VLINK, null, null, 0, IMPLIED), + attr(ALINK, null, null, 0, IMPLIED) + } + ); + defElement(BR, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(CLEAR, "NONE", new String[] { LEFT, ALL, RIGHT, NONES }, + 0, DEFAULT) + } + ); + defElement(BUTTON, 0, false, false, null, + new String[] { + A, BUTTON, IFRAME, INPUT, + LABEL, SELECT, TEXTAREA, FIELDSET, FORM, + ISINDEX + } + , + new String[] { + PCDATA, ABBR, ACRONYM, APPLET, + B, BASEFONT, BDO, BIG, BR, + CITE, CODE, DFN, EM, FONT, + I, IMG, KBD, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SMALL, + SPAN, STRIKE, STRONG, SUB, SUP, + TT, U, VAR, ADDRESS, BLOCKQUOTE, + CENTER, DIR, DIV, DL, H1, + H2, H3, H4, H5, H6, + HR, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(sNAME, null, null, 0, IMPLIED), + attr(VALUE, null, null, 0, IMPLIED), + attr(TYPE, SUBMIT, new String[] { BUTTON, SUBMIT, RESET }, 0, DEFAULT), + attr(DISABLED, null, new String[] { DISABLED }, 0, IMPLIED), + attr(TABINDEX, null, null, NUMBER, IMPLIED), + attr(ACCESSKEY, null, null, 0, IMPLIED), + attr(ONFOCUS, null, null, 0, IMPLIED), + attr(ONBLUR, null, null, 0, IMPLIED) + } + ); + defElement(CAPTION, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { TOP, BOTTOM, LEFT, RIGHT }, + 0, IMPLIED) + } + ); + + } + + /** + * Define second sixth of elements of this DTD. + */ + private void defineElements2() + { + /* Define the elements. */ + defElement(CENTER, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(CITE, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(CODE, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(COL, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(SPAN, C_1, null, NUMBER, DEFAULT), + attr(WIDTH, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY, CHAR }, + 0, IMPLIED), + attr(CHAR, null, null, 0, IMPLIED), + attr(CHAROFF, null, null, 0, IMPLIED), + attr(VALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, BASELINE }, + 0, IMPLIED) + } + ); + defElement(COLGROUP, 0, false, true, null, + NONE + , + new String[] { + COL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(SPAN, C_1, null, NUMBER, DEFAULT), + attr(WIDTH, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY, CHAR }, + 0, IMPLIED), + attr(CHAR, null, null, 0, IMPLIED), + attr(CHAROFF, null, null, 0, IMPLIED), + attr(VALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, BASELINE }, + 0, IMPLIED) + } + ); + defElement(DD, 0, false, true, new ContentModel(0, + new noTagModel( new String[] { DD, DT } ), null ), + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(DEL, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(CITE, null, null, 0, IMPLIED), + attr(DATETIME, null, null, 0, IMPLIED) + } + ); + defElement(DFN, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(DIR, 0, false, false, createListModel(), + new String[] { + ADDRESS, BLOCKQUOTE, CENTER, DIR, + DIV, DL, FIELDSET, FORM, H1, + H2, H3, H4, H5, H6, + HR, ISINDEX, MENU, NOFRAMES, NOSCRIPT, + OL, P, PRE, TABLE, UL + } + , + new String[] { + LI, UL, OL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(COMPACT, null, new String[] { COMPACT }, 0, IMPLIED) + } + ); + defElement(DIV, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY }, + 0, IMPLIED) + } + ); + defElement(DL, 0, false, false, createDefListModel(), + NONE + , + new String[] { + DD, DT + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(COMPACT, null, new String[] { COMPACT }, 0, IMPLIED) + } + ); + defElement(DT, 0, false, true, + new ContentModel(0, + new noTagModel( new String[] { DT, DD } ), null), + BLOCK + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(EM, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(FIELDSET, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL, LEGEND + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + + } + + /** + * Define third sixth of elements of this DTD. + */ + private void defineElements3() + { + /* Define the elements. */ + defElement(FONT, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(SIZE, null, null, 0, IMPLIED), + attr(COLOR, null, null, 0, IMPLIED), + attr(FACE, null, null, 0, IMPLIED) + } + ); + defElement(FORM, 0, false, false, null, + new String[] { + FORM + } + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, H1, H2, H3, + H4, H5, H6, HR, ISINDEX, + MENU, NOFRAMES, NOSCRIPT, OL, P, + PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ACTION, null, null, 0, REQUIRED), + attr(METHOD, GET, new String[] { GET, POST }, 0, DEFAULT), + attr(ENCTYPE, APPLICATION_X_WWW_FORM_URLENCODED, null, 0, DEFAULT), + attr(ACCEPT, null, null, 0, IMPLIED), + attr(sNAME, null, null, 0, IMPLIED), + attr(ONSUBMIT, null, null, 0, IMPLIED), + attr(ONRESET, null, null, 0, IMPLIED), + attr(TARGET, null, null, 0, IMPLIED), + attr(ACCEPTCHARSET, null, null, 0, IMPLIED) + } + ); + defElement(FRAME, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LONGDESC, null, null, 0, IMPLIED), + attr(sNAME, null, null, 0, IMPLIED), + attr(SRC, null, null, 0, IMPLIED), + attr(FRAMEBORDER, C_1, new String[] { C_1, C_0 }, 0, DEFAULT), + attr(MARGINWIDTH, null, null, PIXELS, IMPLIED), + attr(MARGINHEIGHT, null, null, PIXELS, IMPLIED), + attr(NORESIZE, null, new String[] { NORESIZE }, 0, IMPLIED), + attr(SCROLLING, AUTO, new String[] { YES, NO, AUTO }, 0, DEFAULT) + } + ); + defElement(FRAMESET, 0, false, false, null, + NONE + , + new String[] { + NOFRAMES, FRAME, FRAMESET + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(ROWS, null, null, 0, IMPLIED), + attr(COLS, null, null, 0, IMPLIED), + attr(ONLOAD, null, null, 0, IMPLIED), + attr(ONUNLOAD, null, null, 0, IMPLIED) + } + ); + defElement(H1, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY }, + 0, IMPLIED) + } + ); + defElement(H2, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY }, + 0, IMPLIED) + } + ); + defElement(H3, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY }, + 0, IMPLIED) + } + ); + defElement(H4, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY }, + 0, IMPLIED) + } + ); + defElement(H5, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY }, + 0, IMPLIED) + } + ); + defElement(H6, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY }, + 0, IMPLIED) + } + ); + defElement(HEAD, 0, true, true, null, + new String[] { + BODY + } + , + new String[] { + TITLE, ISINDEX, BASE, + SCRIPT, STYLE, META, LINK, OBJECT + } + , + new AttributeList[] { + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(PROFILE, null, null, 0, IMPLIED) + } + ); + + defElement(HR, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT }, 0, IMPLIED), + attr(NOSHADE, null, new String[] { NOSHADE }, 0, IMPLIED), + attr(SIZE, null, null, 0, IMPLIED), + attr(WIDTH, null, null, 0, IMPLIED) + } + ); + defElement(HTML, 0, true, true, createHtmlContentModel(), + NONE + , + new String[] { + HEAD, BODY + } + , + new AttributeList[] { + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(VERSION, DTD_NAME, null, 0, FIXED) + } + ); + defElement(I, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(IFRAME, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LONGDESC, null, null, 0, IMPLIED), + attr(sNAME, null, null, 0, IMPLIED), + attr(SRC, null, null, 0, IMPLIED), + attr(FRAMEBORDER, C_1, new String[] { C_1, C_0 }, 0, DEFAULT), + attr(MARGINWIDTH, null, null, PIXELS, IMPLIED), + attr(MARGINHEIGHT, null, null, PIXELS, IMPLIED), + attr(SCROLLING, AUTO, new String[] { YES, NO, AUTO }, 0, DEFAULT), + attr(ALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, LEFT, RIGHT }, + 0, IMPLIED), + attr(HEIGHT, null, null, 0, IMPLIED), + attr(WIDTH, null, null, 0, IMPLIED) + } + ); + defElement(IMG, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(SRC, null, null, 0, REQUIRED), + attr(ALT, null, null, 0, REQUIRED), + attr(LONGDESC, null, null, 0, IMPLIED), + attr(sNAME, null, null, 0, IMPLIED), + attr(HEIGHT, null, null, 0, IMPLIED), + attr(WIDTH, null, null, 0, IMPLIED), + attr(USEMAP, null, null, 0, IMPLIED), + attr(ISMAP, null, new String[] { ISMAP }, 0, IMPLIED), + attr(ALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, LEFT, RIGHT }, + 0, IMPLIED), + attr(BORDER, null, null, PIXELS, IMPLIED), + attr(HSPACE, null, null, 0, IMPLIED), + attr(VSPACE, null, null, 0, IMPLIED) + } + ); + + } + + /** + * Define fourth sixth of elements of this DTD. + */ + private void defineElements4() + { + /* Define the elements. */ + defElement(INPUT, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(TYPE, TEXT, new String[] { TEXT, PASSWORD, CHECKBOX, RADIO, + SUBMIT, RESET, FILE, HIDDEN, IMAGE, BUTTON }, 0, DEFAULT), + attr(sNAME, null, null, 0, IMPLIED), + attr(VALUE, null, null, 0, IMPLIED), + attr(CHECKED, null, new String[] { CHECKED }, 0, IMPLIED), + attr(DISABLED, null, new String[] { DISABLED }, 0, IMPLIED), + attr(READONLY, null, new String[] { READONLY }, 0, IMPLIED), + attr(SIZE, null, null, 0, IMPLIED), + attr(MAXLENGTH, null, null, 0, IMPLIED), + attr(SRC, null, null, 0, IMPLIED), + attr(ALT, null, null, 0, IMPLIED), + attr(USEMAP, null, null, 0, IMPLIED), + attr(ISMAP, null, new String[] { ISMAP }, 0, IMPLIED), + attr(TABINDEX, null, null, NUMBER, IMPLIED), + attr(ACCESSKEY, null, null, 0, IMPLIED), + attr(ONFOCUS, null, null, 0, IMPLIED), + attr(ONBLUR, null, null, 0, IMPLIED), + attr(ONSELECT, null, null, 0, IMPLIED), + attr(ONCHANGE, null, null, 0, IMPLIED), + attr(ACCEPT, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, LEFT, RIGHT }, + 0, IMPLIED) + } + ); + defElement(INS, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(CITE, null, null, 0, IMPLIED), + attr(DATETIME, null, null, 0, IMPLIED) + } + ); + defElement(ISINDEX, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(PROMPT, null, null, 0, IMPLIED) + } + ); + defElement(KBD, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(LABEL, 0, false, false, null, + new String[] { + LABEL + } + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, MAP, OBJECT, Q, + S, SAMP, SCRIPT, SELECT, SMALL, + SPAN, STRIKE, STRONG, SUB, SUP, + TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(FOR, null, null, 0, IMPLIED), + attr(ACCESSKEY, null, null, 0, IMPLIED), + attr(ONFOCUS, null, null, 0, IMPLIED), + attr(ONBLUR, null, null, 0, IMPLIED) + } + ); + defElement(LEGEND, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ACCESSKEY, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { TOP, BOTTOM, LEFT, RIGHT }, + 0, IMPLIED) + } + ); + // LI has a special content model that will be resolved into + // by transformer. + defElement(LI, 0, false, true, + new ContentModel(0, + new noTagModel(LI), null), + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(TYPE, null, null, 0, IMPLIED), + attr(VALUE, null, null, NUMBER, IMPLIED) + } + ); + defElement(LINK, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(CHARSET, null, null, 0, IMPLIED), + attr(HREF, null, null, 0, IMPLIED), + attr(HREFLANG, null, null, 0, IMPLIED), + attr(TYPE, null, null, 0, IMPLIED), + attr(REL, null, null, 0, IMPLIED), + attr(REV, null, null, 0, IMPLIED), + attr(MEDIA, null, null, 0, IMPLIED), + attr(TARGET, null, null, 0, IMPLIED) + } + ); + defElement(MAP, 0, false, false, null, + NONE + , + new String[] { + ADDRESS, BLOCKQUOTE, CENTER, DIR, + DIV, DL, FIELDSET, FORM, H1, + H2, H3, H4, H5, H6, + HR, ISINDEX, MENU, NOFRAMES, NOSCRIPT, + OL, P, PRE, TABLE, UL, + AREA + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(sNAME, null, null, 0, REQUIRED) + } + ); + defElement(MENU, 0, false, false, createListModel(), + new String[] { + ADDRESS, BLOCKQUOTE, CENTER, DIR, + DIV, DL, FIELDSET, FORM, H1, + H2, H3, H4, H5, H6, + HR, ISINDEX, MENU, NOFRAMES, NOSCRIPT, + OL, P, PRE, TABLE, UL + } + , + new String[] { + LI, UL, OL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(COMPACT, null, new String[] { COMPACT }, 0, IMPLIED) + } + ); + defElement(META, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(HTTPEQUIV, null, null, 0, IMPLIED), + attr(sNAME, null, null, NAME, IMPLIED), + attr(CONTENT, null, null, 0, REQUIRED), + attr(SCHEME, null, null, 0, IMPLIED) + } + ); + defElement(NOFRAMES, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(NOSCRIPT, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(OBJECT, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL, PARAM + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(DECLARE, null, new String[] { DECLARE }, 0, IMPLIED), + attr(CLASSID, null, null, 0, IMPLIED), + attr(CODEBASE, null, null, 0, IMPLIED), + attr(DATA, null, null, 0, IMPLIED), + attr(TYPE, null, null, 0, IMPLIED), + attr(CODETYPE, null, null, 0, IMPLIED), + attr(ARCHIVE, null, null, 0, IMPLIED), + attr(STANDBY, null, null, 0, IMPLIED), + attr(HEIGHT, null, null, 0, IMPLIED), + attr(WIDTH, null, null, 0, IMPLIED), + attr(USEMAP, null, null, 0, IMPLIED), + attr(sNAME, null, null, 0, IMPLIED), + attr(TABINDEX, null, null, NUMBER, IMPLIED), + attr(ALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, LEFT, RIGHT }, + 0, IMPLIED), + attr(BORDER, null, null, PIXELS, IMPLIED), + attr(HSPACE, null, null, 0, IMPLIED), + attr(VSPACE, null, null, 0, IMPLIED) + } + ); + + } + + /** + * Define fifth sixth of elements of this DTD. + */ + private void defineElements5() + { + /* Define the elements. */ + defElement(OL, 0, false, false, createListModel(), + NONE + , + new String[] { + // See note on the createListModel method + LI, UL, OL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(TYPE, null, null, 0, IMPLIED), + attr(COMPACT, null, new String[] { COMPACT }, 0, IMPLIED), + attr(START, null, null, 0, IMPLIED) + } + ); + defElement(OPTGROUP, 0, false, false, null, + NONE + , + new String[] { + OPTION + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(DISABLED, null, new String[] { DISABLED }, 0, IMPLIED), + attr(LABEL, null, null, 0, REQUIRED) + } + ); + defElement(OPTION, 0, false, true, new ContentModel(0, + new PCDATAonly_model(), null), + NONE, + new String[] { + PCDATA + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(SELECTED, null, new String[] { SELECTED }, 0, IMPLIED), + attr(DISABLED, null, new String[] { DISABLED }, 0, IMPLIED), + attr(LABEL, null, null, 0, IMPLIED), + attr(VALUE, null, null, 0, IMPLIED) + } + ); + + // Headers in the paragraph are not allowed. + defElement(P, 0, false, true, new ContentModel( 0, + new noTagModel(new String[] { P, H1, H2, H3, H4, H5, H6 }), null), + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY }, + 0, IMPLIED) + } + ); + defElement(PARAM, EMPTY, false, true, null, + NONE + , + NONE + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(sNAME, null, null, 0, REQUIRED), + attr(VALUE, null, null, 0, IMPLIED), + attr(VALUETYPE, DATA, new String[] { DATA, REF, OBJECT }, 0, DEFAULT), + attr(TYPE, null, null, 0, IMPLIED) + } + ); + defElement(PRE, 0, false, false, null, + new String[] { + APPLET, BASEFONT, BIG, FONT, + IMG, OBJECT, SMALL, SUB, SUP + } + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + B, BDO, BR, BUTTON, CITE, + CODE, DFN, EM, I, IFRAME, + INPUT, KBD, LABEL, MAP, Q, + S, SAMP, SCRIPT, SELECT, SPAN, + STRIKE, STRONG, TEXTAREA, TT, U, + VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(WIDTH, null, null, NUMBER, IMPLIED) + } + ); + defElement(Q, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(CITE, null, null, 0, IMPLIED) + } + ); + defElement(S, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(SAMP, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(SCRIPT, CDATA, false, false, null, + NONE + , + NONE + , + new AttributeList[] { + attr(CHARSET, null, null, 0, IMPLIED), + attr(TYPE, null, null, 0, REQUIRED), + attr(LANGUAGE, null, null, 0, IMPLIED), + attr(SRC, null, null, 0, IMPLIED), + attr(DEFER, null, new String[] { DEFER }, 0, IMPLIED), + attr(EVENT, null, null, 0, IMPLIED), + attr(FOR, null, null, 0, IMPLIED) + } + ); + defElement(SELECT, 0, false, false, null, + NONE + , + new String[] { + OPTGROUP, OPTION + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(sNAME, null, null, 0, IMPLIED), + attr(SIZE, null, null, NUMBER, IMPLIED), + attr(MULTIPLE, null, new String[] { MULTIPLE }, 0, IMPLIED), + attr(DISABLED, null, new String[] { DISABLED }, 0, IMPLIED), + attr(TABINDEX, null, null, NUMBER, IMPLIED), + attr(ONFOCUS, null, null, 0, IMPLIED), + attr(ONBLUR, null, null, 0, IMPLIED), + attr(ONCHANGE, null, null, 0, IMPLIED) + } + ); + defElement(SMALL, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(SPAN, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(STRIKE, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(STRONG, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(STYLE, CDATA, false, false, null, + NONE + , + NONE + , + new AttributeList[] { + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(TYPE, null, null, 0, REQUIRED), + attr(MEDIA, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED) + } + ); + defElement(SUB, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + + } + + /** + * Define last sixth of elements of this DTD. + */ + private void defineElements6() + { + /* Define the elements. */ + defElement(SUP, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(TABLE, 0, false, false, createTableContentModel(), + NONE + , + new String[] { + CAPTION, COL, COLGROUP, TBODY, + TFOOT, THEAD + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(SUMMARY, null, null, 0, IMPLIED), + attr(WIDTH, null, null, 0, IMPLIED), + attr(BORDER, null, null, PIXELS, IMPLIED), + attr(FRAME, null, new String[] { VOID, ABOVE, BELOW, HSIDES, LHS, RHS, + VSIDES, BOX, BORDER }, 0, IMPLIED), + attr(RULES, null, new String[] { NONES, GROUPS, ROWS, COLS, ALL }, + 0, IMPLIED), + attr(CELLSPACING, null, null, 0, IMPLIED), + attr(CELLPADDING, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT }, 0, IMPLIED), + attr(BGCOLOR, null, null, 0, IMPLIED), + attr(DATAPAGESIZE, null, null, 0, IMPLIED) + } + ); + defElement(TBODY, 0, true, true, model(TR,'+'), + NONE + , + new String[] { + TR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY, CHAR }, + 0, IMPLIED), + attr(CHAR, null, null, 0, IMPLIED), + attr(CHAROFF, null, null, 0, IMPLIED), + attr(VALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, BASELINE }, + 0, IMPLIED) + } + ); + + defElement(TD, 0, false, true, + new ContentModel(0, + new noTagModel(new String[] {"TD", "TH", "TR" } ), null), + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ABBR, null, null, 0, IMPLIED), + attr(AXIS, null, null, 0, IMPLIED), + attr(HEADERS, null, null, 0, IMPLIED), + attr(SCOPE, null, new String[] { ROW, COL, ROWGROUP, COLGROUP }, + 0, IMPLIED), + attr(ROWSPAN, C_1, null, NUMBER, DEFAULT), + attr(COLSPAN, C_1, null, NUMBER, DEFAULT), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY, CHAR }, + 0, IMPLIED), + attr(CHAR, null, null, 0, IMPLIED), + attr(CHAROFF, null, null, 0, IMPLIED), + attr(VALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, BASELINE }, + 0, IMPLIED), + attr(NOWRAP, null, new String[] { NOWRAP }, 0, IMPLIED), + attr(BGCOLOR, null, null, 0, IMPLIED), + attr(WIDTH, null, null, 0, IMPLIED), + attr(HEIGHT, null, null, 0, IMPLIED) + } + ); + defElement(TEXTAREA, 0, false, false, null, + NONE + , + new String[] { + PCDATA + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(sNAME, null, null, 0, IMPLIED), + attr(ROWS, null, null, NUMBER, REQUIRED), + attr(COLS, null, null, NUMBER, REQUIRED), + attr(DISABLED, null, new String[] { DISABLED }, 0, IMPLIED), + attr(READONLY, null, new String[] { READONLY }, 0, IMPLIED), + attr(TABINDEX, null, null, NUMBER, IMPLIED), + attr(ACCESSKEY, null, null, 0, IMPLIED), + attr(ONFOCUS, null, null, 0, IMPLIED), + attr(ONBLUR, null, null, 0, IMPLIED), + attr(ONSELECT, null, null, 0, IMPLIED), + attr(ONCHANGE, null, null, 0, IMPLIED) + } + ); + defElement(TFOOT, 0, false, true, model(TR,'+'), + NONE + , + new String[] { + TR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY, CHAR }, + 0, IMPLIED), + attr(CHAR, null, null, 0, IMPLIED), + attr(CHAROFF, null, null, 0, IMPLIED), + attr(VALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, BASELINE }, + 0, IMPLIED) + } + ); + defElement(TH, 0, false, true, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DIR, DIV, + DL, FIELDSET, FORM, H1, H2, + H3, H4, H5, H6, HR, + ISINDEX, MENU, NOFRAMES, NOSCRIPT, OL, + P, PRE, TABLE, UL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ABBR, null, null, 0, IMPLIED), + attr(AXIS, null, null, 0, IMPLIED), + attr(HEADERS, null, null, 0, IMPLIED), + attr(SCOPE, null, new String[] { ROW, COL, ROWGROUP, COLGROUP }, + 0, IMPLIED), + attr(ROWSPAN, C_1, null, NUMBER, DEFAULT), + attr(COLSPAN, C_1, null, NUMBER, DEFAULT), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY, CHAR }, + 0, IMPLIED), + attr(CHAR, null, null, 0, IMPLIED), + attr(CHAROFF, null, null, 0, IMPLIED), + attr(VALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, BASELINE }, + 0, IMPLIED), + attr(NOWRAP, null, new String[] { NOWRAP }, 0, IMPLIED), + attr(BGCOLOR, null, null, 0, IMPLIED), + attr(WIDTH, null, null, 0, IMPLIED), + attr(HEIGHT, null, null, 0, IMPLIED) + } + ); + defElement(THEAD, 0, false, true, model(TR,'+'), + NONE + , + new String[] { + TR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY, CHAR }, + 0, IMPLIED), + attr(CHAR, null, null, 0, IMPLIED), + attr(CHAROFF, null, null, 0, IMPLIED), + attr(VALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, BASELINE }, + 0, IMPLIED) + } + ); + defElement(TITLE, 0, false, false, null, + new String[] { + OBJECT, SCRIPT, LINK, META, + STYLE + } + , + new String[] { + PCDATA + } + , + new AttributeList[] { + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED) + } + ); + defElement(TR, 0, false, true, + new ContentModel(0, new TableRowContentModel(this), null), + NONE + , + new String[] { + TD, TH + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(ALIGN, null, new String[] { LEFT, CENTER, RIGHT, JUSTIFY, CHAR }, + 0, IMPLIED), + attr(CHAR, null, null, 0, IMPLIED), + attr(CHAROFF, null, null, 0, IMPLIED), + attr(VALIGN, null, new String[] { TOP, MIDDLE, BOTTOM, BASELINE }, + 0, IMPLIED), + attr(BGCOLOR, null, null, 0, IMPLIED) + } + ); + defElement(TT, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(U, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + defElement(UL, 0, false, false, createListModel(), + NONE + , + new String[] { + // See note on the createListModel method + LI, UL, OL + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED), + attr(TYPE, null, new String[] { DISC, SQUARE, CIRCLE }, 0, IMPLIED), + attr(COMPACT, null, new String[] { COMPACT }, 0, IMPLIED) + } + ); + defElement(VAR, 0, false, false, null, + NONE + , + new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR + } + , + new AttributeList[] { + attr(sID, null, null, ID, IMPLIED), + attr(CLASS, null, null, 0, IMPLIED), + attr(STYLE, null, null, 0, IMPLIED), + attr(TITLE, null, null, 0, IMPLIED), + attr(LANG, null, null, 0, IMPLIED), + attr(DIR, null, new String[] { LTR, RTL }, 0, IMPLIED), + attr(ONCLICK, null, null, 0, IMPLIED), + attr(ONDBLCLICK, null, null, 0, IMPLIED), + attr(ONMOUSEDOWN, null, null, 0, IMPLIED), + attr(ONMOUSEUP, null, null, 0, IMPLIED), + attr(ONMOUSEOVER, null, null, 0, IMPLIED), + attr(ONMOUSEMOVE, null, null, 0, IMPLIED), + attr(ONMOUSEOUT, null, null, 0, IMPLIED), + attr(ONKEYPRESS, null, null, 0, IMPLIED), + attr(ONKEYDOWN, null, null, 0, IMPLIED), + attr(ONKEYUP, null, null, 0, IMPLIED) + } + ); + + } + + /** + * Define all entities in this DTD. + */ + protected void defineEntities() + { + /* Define general entities */ + defineEntity("AElig", 198); + defineEntity("Aacute", 193); + defineEntity("Acirc", 194); + defineEntity("Agrave", 192); + defineEntity("Alpha", 913); + defineEntity("Aring", 197); + defineEntity("Atilde", 195); + defineEntity("Auml", 196); + defineEntity("Beta", 914); + defineEntity("Ccedil", 199); + defineEntity("Chi", 935); + defineEntity("Dagger", 8225); + defineEntity("Delta", 916); + defineEntity("ETH", 208); + defineEntity("Eacute", 201); + defineEntity("Ecirc", 202); + defineEntity("Egrave", 200); + defineEntity("Epsilon", 917); + defineEntity("Eta", 919); + defineEntity("Euml", 203); + defineEntity("Gamma", 915); + defineEntity("Iacute", 205); + defineEntity("Icirc", 206); + defineEntity("Igrave", 204); + defineEntity("Iota", 921); + defineEntity("Iuml", 207); + defineEntity("Kappa", 922); + defineEntity("Lambda", 923); + defineEntity("Mu", 924); + defineEntity("Ntilde", 209); + defineEntity("Nu", 925); + defineEntity("OElig", 338); + defineEntity("Oacute", 211); + defineEntity("Ocirc", 212); + defineEntity("Ograve", 210); + defineEntity("Omega", 937); + defineEntity("Omicron", 927); + defineEntity("Oslash", 216); + defineEntity("Otilde", 213); + defineEntity("Ouml", 214); + defineEntity("Phi", 934); + defineEntity("Pi", 928); + defineEntity("Prime", 8243); + defineEntity("Psi", 936); + defineEntity("Rho", 929); + defineEntity("Scaron", 352); + defineEntity("Sigma", 931); + defineEntity("THORN", 222); + defineEntity("Tau", 932); + defineEntity("Theta", 920); + defineEntity("Uacute", 218); + defineEntity("Ucirc", 219); + defineEntity("Ugrave", 217); + defineEntity("Upsilon", 933); + defineEntity("Uuml", 220); + defineEntity("Xi", 926); + defineEntity("Yacute", 221); + defineEntity("Yuml", 376); + defineEntity("Zeta", 918); + defineEntity("aacute", 225); + defineEntity("acirc", 226); + defineEntity("acute", 180); + defineEntity("aelig", 230); + defineEntity("agrave", 224); + defineEntity("alefsym", 8501); + defineEntity("alpha", 945); + defineEntity("amp", 38); + defineEntity("and", 8743); + defineEntity("ang", 8736); + defineEntity("aring", 229); + defineEntity("asymp", 8776); + defineEntity("atilde", 227); + defineEntity("auml", 228); + defineEntity("bdquo", 8222); + defineEntity("beta", 946); + defineEntity("brvbar", 166); + defineEntity("bull", 8226); + defineEntity("cap", 8745); + defineEntity("ccedil", 231); + defineEntity("cedil", 184); + defineEntity("cent", 162); + defineEntity("chi", 967); + defineEntity("circ", 710); + defineEntity("clubs", 9827); + defineEntity("cong", 8773); + defineEntity("copy", 169); + defineEntity("crarr", 8629); + defineEntity("cup", 8746); + defineEntity("curren", 164); + defineEntity("dArr", 8659); + defineEntity("dagger", 8224); + defineEntity("darr", 8595); + defineEntity("deg", 176); + defineEntity("delta", 948); + defineEntity("diams", 9830); + defineEntity("divide", 247); + defineEntity("eacute", 233); + defineEntity("ecirc", 234); + defineEntity("egrave", 232); + defineEntity("empty", 8709); + defineEntity("emsp", 8195); + defineEntity("ensp", 8194); + defineEntity("epsilon", 949); + defineEntity("equiv", 8801); + defineEntity("eta", 951); + defineEntity("eth", 240); + defineEntity("euml", 235); + defineEntity("euro", 8364); + defineEntity("exist", 8707); + defineEntity("fnof", 402); + defineEntity("forall", 8704); + defineEntity("frac12", 189); + defineEntity("frac14", 188); + defineEntity("frac34", 190); + defineEntity("frasl", 8260); + defineEntity("gamma", 947); + defineEntity("ge", 8805); + defineEntity("gt", 62); + defineEntity("hArr", 8660); + defineEntity("harr", 8596); + defineEntity("hearts", 9829); + defineEntity("hellip", 8230); + defineEntity("iacute", 237); + defineEntity("icirc", 238); + defineEntity("iexcl", 161); + defineEntity("igrave", 236); + defineEntity("image", 8465); + defineEntity("infin", 8734); + defineEntity("int", 8747); + defineEntity("iota", 953); + defineEntity("iquest", 191); + defineEntity("isin", 8712); + defineEntity("iuml", 239); + defineEntity("kappa", 954); + defineEntity("lArr", 8656); + defineEntity("lambda", 955); + defineEntity("lang", 9001); + defineEntity("laquo", 171); + defineEntity("larr", 8592); + defineEntity("lceil", 8968); + defineEntity("ldquo", 8220); + defineEntity("le", 8804); + defineEntity("lfloor", 8970); + defineEntity("lowast", 8727); + defineEntity("loz", 9674); + defineEntity("lrm", 8206); + defineEntity("lsaquo", 8249); + defineEntity("lsquo", 8216); + defineEntity("lt", 60); + defineEntity("macr", 175); + defineEntity("mdash", 8212); + defineEntity("micro", 181); + defineEntity("middot", 183); + defineEntity("minus", 8722); + defineEntity("mu", 956); + defineEntity("nabla", 8711); + defineEntity("nbsp", 160); + defineEntity("ndash", 8211); + defineEntity("ne", 8800); + defineEntity("ni", 8715); + defineEntity("not", 172); + defineEntity("notin", 8713); + defineEntity("nsub", 8836); + defineEntity("ntilde", 241); + defineEntity("nu", 957); + defineEntity("oacute", 243); + defineEntity("ocirc", 244); + defineEntity("oelig", 339); + defineEntity("ograve", 242); + defineEntity("oline", 8254); + defineEntity("omega", 969); + defineEntity("omicron", 959); + defineEntity("oplus", 8853); + defineEntity("or", 8744); + defineEntity("ordf", 170); + defineEntity("ordm", 186); + defineEntity("oslash", 248); + defineEntity("otilde", 245); + defineEntity("otimes", 8855); + defineEntity("ouml", 246); + defineEntity("para", 182); + defineEntity("part", 8706); + defineEntity("permil", 8240); + defineEntity("perp", 8869); + defineEntity("phi", 966); + defineEntity("pi", 960); + defineEntity("piv", 982); + defineEntity("plusmn", 177); + defineEntity("pound", 163); + defineEntity("prime", 8242); + defineEntity("prod", 8719); + defineEntity("prop", 8733); + defineEntity("psi", 968); + defineEntity("quot", 34); + defineEntity("rArr", 8658); + defineEntity("radic", 8730); + defineEntity("rang", 9002); + defineEntity("raquo", 187); + defineEntity("rarr", 8594); + defineEntity("rceil", 8969); + defineEntity("rdquo", 8221); + defineEntity("real", 8476); + defineEntity("reg", 174); + defineEntity("rfloor", 8971); + defineEntity("rho", 961); + defineEntity("rlm", 8207); + defineEntity("rsaquo", 8250); + defineEntity("rsquo", 8217); + defineEntity("sbquo", 8218); + defineEntity("scaron", 353); + defineEntity("sdot", 8901); + defineEntity("sect", 167); + defineEntity("shy", 173); + defineEntity("sigma", 963); + defineEntity("sigmaf", 962); + defineEntity("sim", 8764); + defineEntity("spades", 9824); + defineEntity("sub", 8834); + defineEntity("sube", 8838); + defineEntity("sum", 8721); + defineEntity("sup", 8835); + defineEntity("sup1", 185); + defineEntity("sup2", 178); + defineEntity("sup3", 179); + defineEntity("supe", 8839); + defineEntity("szlig", 223); + defineEntity("tau", 964); + defineEntity("there4", 8756); + defineEntity("theta", 952); + defineEntity("thetasym", 977); + defineEntity("thinsp", 8201); + defineEntity("thorn", 254); + defineEntity("tilde", 732); + defineEntity("times", 215); + defineEntity("trade", 8482); + defineEntity("uArr", 8657); + defineEntity("uacute", 250); + defineEntity("uarr", 8593); + defineEntity("ucirc", 251); + defineEntity("ugrave", 249); + defineEntity("uml", 168); + defineEntity("upsih", 978); + defineEntity("upsilon", 965); + defineEntity("uuml", 252); + defineEntity("weierp", 8472); + defineEntity("xi", 958); + defineEntity("yacute", 253); + defineEntity("yen", 165); + defineEntity("yuml", 255); + defineEntity("zeta", 950); + defineEntity("zwj", 8205); + defineEntity("zwnj", 8204); + } + + /** + * Crate a content model, consisting of the single + * element, specified by name. + */ + protected ContentModel model(String element) + { + return new ContentModel(getElement(element)); + } + + /** + * Crate a chain from the two content models, + * the last containing the given element and + * the specified unary operation. + */ + private ContentModel model(String element, int unary) + { + ContentModel ct = model(element); + ct.type = unary; + return new ContentModel(0, ct); + } + + /** + * Create the model HEAD, BODY + * @return the HTML content model of the whole document + */ + protected ContentModel createHtmlContentModel() + { + ContentModel head = model(HEAD); + ContentModel body = model(BODY); + head.next = body; + head.type = ','; + return head; + } + + /** + * Create the model + * ( CAPTION ? , ( COL * | COLGROUP * ) , THEAD ? , TFOOT ? , TBODY + ) + */ + protected ContentModel createTableContentModel() + { + ContentModel col_colgroup = new ContentModel + ('|', model(COL,'*'), model(COLGROUP,'*') ); + + col_colgroup = new ContentModel('*', col_colgroup); + col_colgroup = new ContentModel(',', col_colgroup); + + ContentModel caption = model(CAPTION,'?'); + ContentModel thead = model(THEAD, '?'); + ContentModel tfoot = model(TFOOT, '?'); + ContentModel tbody = model(TBODY, '+'); + + caption.next = col_colgroup; + col_colgroup.next = thead; + thead.next = tfoot; + tfoot.next = tbody; + + caption.type = col_colgroup.type = thead.type = tfoot.type = + tbody.type = ','; + + return caption; + } + + /** + * Creates a model for <DL> tag: + * DT+ | DL+ . + * @return + */ + protected ContentModel createDefListModel() + { + ContentModel dt = model(DT, '+'); + ContentModel dd = model(DD, '+'); + + dt.next = dd; + dt.type = dd.type = '|'; + return dt; + } + + /** + * This model is used for UL, OL, MENU and DIR. + * HTML 4.01 specifies LI only, but the nested + * list seems rendered correctly only if + * it is not enclosed into
    • -
    • of the + * parent list. + */ + protected ContentModel createListModel() + { + ContentModel li = model(LI, '+'); + ContentModel ul = model(UL, '+'); + ContentModel ol = model(OL, '+'); + + li.next = ul; + ul.next = ol; + li.type = ul.type = ol.type = '|'; + return li; + } + + /** + * Get elements that are allowed in the document body, at the zero level. + */ + protected String[] getBodyElements() + { + return new String[] { + PCDATA, A, ABBR, ACRONYM, + APPLET, B, BASEFONT, BDO, BIG, + BR, BUTTON, CITE, CODE, DFN, + EM, FONT, I, IFRAME, IMG, + INPUT, KBD, LABEL, MAP, OBJECT, + Q, S, SAMP, SCRIPT, SELECT, + SMALL, SPAN, STRIKE, STRONG, SUB, + SUP, TEXTAREA, TT, U, VAR, + ADDRESS, BLOCKQUOTE, CENTER, DEL, DIR, + DIV, DL, FIELDSET, FORM, H1, + H2, H3, H4, H5, H6, + HR, INS, ISINDEX, MENU, NOFRAMES, + NOSCRIPT, OL, P, PRE, TABLE, + UL + }; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/SmallHtmlAttributeSet.java b/libjava/classpath/gnu/javax/swing/text/html/parser/SmallHtmlAttributeSet.java new file mode 100644 index 000000000..8739ad453 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/SmallHtmlAttributeSet.java @@ -0,0 +1,261 @@ +/* SmallHtmlAttributeSet.java -- Small fixed HTML attribute set + 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.swing.text.html.parser; + +import java.io.Serializable; +import java.util.Enumeration; +import java.util.NoSuchElementException; + +import javax.swing.text.AttributeSet; +import javax.swing.text.html.HTML.Attribute; +import javax.swing.text.html.HTML.Tag; + +/** + * Small fixed HTML attribute set. The most of the HTML elements contain only + * several attributes. With four attributes, the number of operations in more + * complex algorithms is not larger than using the naive algorithm. + * + * Same as HtmlAttributeSet, this set allows both strings and non-string as + * keys. The strings are case insensitive, the non strings are compared with + * .equals. + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class SmallHtmlAttributeSet + implements AttributeSet, Cloneable, Serializable +{ + private static final long serialVersionUID = 1; + + /** + * The keys, stored in this attribute set. + */ + final Object[] keys; + + /** + * The values, stored in this attribute set. + */ + final Object[] values; + + /** + * The parent, used for resolving the values, not found in this set. + */ + final AttributeSet parent; + + /** + * Create a new small fixed attribute set that contains the unchangeable copy + * of the passed attribute set and inherits its parent. + * + * @param copyFrom the attribute set, containing the attribute values to copy. + */ + public SmallHtmlAttributeSet(AttributeSet copyFrom) + { + int n = copyFrom.getAttributeCount(); + + keys = new Object[n]; + values = new Object[n]; + parent = copyFrom.getResolveParent(); + + Enumeration en = copyFrom.getAttributeNames(); + Object key; + Object value; + + for (int i = 0; i < n; i++) + { + key = en.nextElement(); + keys[i] = key; + value = copyFrom.getAttribute(key); + values[i] = value; + } + } + + public boolean containsAttribute(Object name, Object value) + { + Object contains = getAttribute(name); + if (value == null) + return value == contains; + else + return value.equals(contains); + } + + public boolean containsAttributes(AttributeSet attributes) + { + if (attributes == this) + return true; + Object v; + for (int i = 0; i < keys.length; i++) + { + v = attributes.getAttribute(keys[i]); + if (v != values[i]) + { + if (values[i] == null) + return false; + else if (! values[i].equals(v)) + return false; + } + } + return true; + } + + /** + * THIS can be safely returned as the set is not mutable. + */ + public AttributeSet copyAttributes() + { + return this; + } + + /** + * Get the attribute value, matching this key. If not found in this set, the + * call is delegated to parent. + * + * @return the value, matching key (or null if none). + */ + public Object getAttribute(Object key) + { + // Null and HTML attributes or tags can be searched by direct comparison. + if (key == null || key instanceof Attribute || key instanceof Tag) + { + for (int i = 0; i < keys.length; i++) + { + if (keys[i] == key) + return values[i]; + } + } + + // Strings are case insensitive. Only string can be match the string. + else if (key instanceof String) + { + String ks = (String) key; + for (int i = 0; i < keys.length; i++) + { + if (keys[i] instanceof String) + if (ks.equalsIgnoreCase((String) keys[i])) + return values[i]; + } + } + + // Otherwise, defaults to .equals + else + { + for (int i = 0; i < keys.length; i++) + { + if (key.equals(keys[i])) + return values[i]; + } + } + + if (parent != null) + return parent.getAttribute(key); + else + return null; + } + + /** + * Get the number of the stored attributes. + */ + public int getAttributeCount() + { + return keys.length; + } + + /** + * Get enumeration, containing the attribute names. No guard agains the + * concurent modification is required as the set is not mutable. + */ + public Enumeration getAttributeNames() + { + return new Enumeration() + { + int p = 0; + + public boolean hasMoreElements() + { + return p < keys.length; + } + + public Object nextElement() + { + if (p < keys.length) + return keys[p++]; + else + throw new NoSuchElementException(); + } + }; + } + + /** + * Get the parent that this set uses to resolve the not found attributes. + */ + public AttributeSet getResolveParent() + { + return parent; + } + + /** + * Check if the given attribute is defined in this set (not in the parent). + */ + public boolean isDefined(Object attrName) + { + if (attrName instanceof String) + attrName = ((String) attrName).toLowerCase(); + + for (int i = 0; i < keys.length; i++) + { + if (attrName.equals(keys[i])) + return true; + } + return false; + } + + /** + * Check this set and another set for equality by content. + */ + public boolean isEqual(AttributeSet attr) + { + return keys.length == attr.getAttributeCount() && containsAttributes(attr); + } + + /** + * It is safe to return THIS on cloning, if one happens. + */ + protected Object clone() + { + return this; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/gnuDTD.java b/libjava/classpath/gnu/javax/swing/text/html/parser/gnuDTD.java new file mode 100644 index 000000000..5924e0fb9 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/gnuDTD.java @@ -0,0 +1,421 @@ +/* gnuDTD.java -- + 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.swing.text.html.parser; + +import java.io.PrintStream; +import java.io.Serializable; + +import java.util.BitSet; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.Vector; + +import javax.swing.text.html.parser.AttributeList; +import javax.swing.text.html.parser.ContentModel; +import javax.swing.text.html.parser.Element; +import javax.swing.text.html.parser.Entity; + +/** + *

      + * The class is derived from {@link gnu.javax.swing.text.html.parser.DTD } + * making structure creation methods public. This is required when + * creating the DTD by SGML parser that must have access to the structure. + * + * SGML DTD representation. Provides basis for describing a syntax of the + * HTML documents. The fields of this class are NOT initialized in + * constructor. You need to do this separately before passing this data + * structure to the parser constructor.

      + * + *

      This implementation also provides you the derived class + * gnu.javax.swing.text.html.parser.DTD.HTML_4_0_1, where + * all fields are initialized to the values, representing HTML 4.01 + * ("-//W3C//DTD HTML 4.01 Frameset//EN") DTD. You can use it if you do not care + * about the portability between different implementations of the core + * class libraries.

      + *

      Use {@link javax.swing.HTML.HTMLEditorKit.Parser#parse } + * for parsing in accordance with "-//W3C//DTD HTML 4.01 Frameset//EN" + * without specifying DTD separately.

      + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class gnuDTD + extends javax.swing.text.html.parser.DTD + implements javax.swing.text.html.parser.DTDConstants, Serializable +{ + /* The undocumented element types, used to specify types, not defined + in DTDConstants. */ + + /** + * The URI element type (not defined in DTDConstants). + */ + public static final int URI = 512; + + /** + * The Length element type + */ + public static final int Length = 513; + + /** + * The Char element type + */ + public static final int Char = 514; + + /** + * The Color element type + */ + public static final int Color = 515; + + /** + * Creates a new instance of gnuDTD. + * @param name the name of the DTD. + */ + public gnuDTD(String name) + { + super(name); + } + + /** + * Creates and returns new attribute (not an attribute list). + * @param name the name of this attribute + * @param type the type of this attribute (FIXED, IMPLIED or + * REQUIRED from DTDConstants). + * @param modifier the modifier of this attribute + * @param default_value the default value of this attribute or null if + * it is not specified. + * @param allowed_values the allowed values of this attribute. The multiple + * possible values in this parameter are supposed to be separated by + * '|', same as in SGML DTD <!ATTLIST tag. This parameter + * can be null if no list of allowed values is specified. + * @param atts the previous attribute of this element. This is + * placed to the field + * {@link javax.swing.text.html.parser.AttributeList#next }, + * creating a linked list. + * @return + */ + public AttributeList defAttributeList(String name, int type, int modifier, + String default_value, + String allowed_values, + AttributeList atts + ) + { + return super.defAttributeList(name, type, modifier, default_value, + allowed_values, atts + ); + } + + /** + * Define the attributes for the element with the given name. + * If the element is not exist, it is created. This method is + * needed if the element attributes are defined befor the + * element itself. + * @param forElement + * @param attributes + */ + public void defAttrsFor(String forElement, AttributeList attributes) + { + super.defineAttributes(forElement, attributes); + } + + /** + * Creates a new content model. + * @param type specifies the BNF operation for this content model. + * The valid operations are documented in the + * {@link javax.swing.text.html.parser.ContentModel#type }. + * @param content the content of this content model + * @param next if the content model is specified by BNF-like + * expression, contains the rest of this expression. + * @return The newly created content model. + */ + public ContentModel defContentModel(int type, Object content, + ContentModel next + ) + { + return super.defContentModel(type, content, next); + } + + /** + * Defines a new element and adds it to the element table. + * If the element alredy exists, + * overrides it settings with the specified values. + * @param name the name of the new element + * @param type the type of the element + * @param headless true if the element needs no starting tag + * @param tailless true if the element needs no closing tag + * @param content the element content. + * @param exclusions the elements that must be excluded from the + * content of this element, in all levels of the hierarchy. + * @param inclusions the elements that can be included as the + * content of this element. + * @param attributes the element attributes. + * @return the created or updated element. + */ + public Element defElement(String name, int type, boolean headless, + boolean tailless, ContentModel content, + String[] exclusions, String[] inclusions, + AttributeList attributes + ) + { + return super.defElement(name, type, headless, tailless, content, + exclusions, inclusions, attributes + ); + } + + /** + * Defines a new element and adds it to the element table. + * If the element alredy exists, + * overrides it settings with the specified values. + * @param name the name of the new element + * @param type the type of the element + * @param headless true if the element needs no starting tag + * @param tailless true if the element needs no closing tag + * @param content the element content. + * @param exclusions the elements that must be excluded from the + * content of this element, in all levels of the hierarchy. + * @param inclusions the elements that can be included as the + * content of this element. + * @param attributes the element attributes. + * @return the created or updated element. + */ + public Element defElement(String name, int type, boolean headless, + boolean tailless, ContentModel content, + Collection exclusions, Collection inclusions, + AttributeList attributes + ) + { + return super.defElement(name, type, headless, tailless, content, + toStringArray(exclusions), + toStringArray(inclusions), attributes + ); + } + + /** + * Defines a new element and adds it to the element table. + * If the element alredy exists, + * overrides it settings with the specified values. + * @param name the name of the new element + * @param type the type of the element + * @param headless true if the element needs no starting tag + * @param tailless true if the element needs no closing tag + * @param content the element content. + * @param exclusions the elements that must be excluded from the + * content of this element, in all levels of the hierarchy. + * @param inclusions the elements that can be included as the + * content of this element. + * @param attributes the element attributes (an array and not a + * linked list). The attributes are chained into the linked list + * inside this method. + * @return the created or updated element. + */ + public Element defElement(String name, int type, boolean headless, + boolean tailless, ContentModel content, + String[] exclusions, String[] inclusions, + AttributeList[] attributes + ) + { + AttributeList list; + + if (attributes == null || attributes.length == 0) + list = null; + else + { + if (attributes.length > 1) + for (int i = 1; i < attributes.length; i++) + { + attributes [ i - 1 ].next = attributes [ i ]; + } + list = attributes [ 0 ]; + } + + Element e = + super.defElement(name, type, headless, tailless, content, exclusions, + inclusions, list + ); + return e; + } + + /** + * Creates, adds into the internal table and returns the + * character entity like &lt; + * (means '<' ); + * This method inactivates the recursive refenrences to the same + * entity. + * @param name The entity name (without heading & and closing ;) + * @param type The entity type + * @param character The entity value (single character) + * @return The created entity + */ + public Entity defEntity(String name, int type, String data) + { + int r; + String eref = "%" + name + ";"; + do + { + r = data.indexOf(eref); + if (r > 0) + { + data = data.substring(0, r) + data.substring(r + 1); + } + } + while (r > 0); + + return super.defEntity(name, type, data); + } + + /** + * Summarises the document content into the given PrintStream. + */ + public void dump(PrintStream p) + { + Iterator iter = entityHash.entrySet().iterator(); + while (iter.hasNext()) + { + Map.Entry item = (Map.Entry) iter.next(); + Entity e = (Entity) item.getValue(); + if (e.isGeneral()) + p.println("Entity " + e.getName() + ": " + e.getString()); + } + + iter = elementHash.entrySet().iterator(); + while (iter.hasNext()) + { + Map.Entry item = (Map.Entry) iter.next(); + Element e = (Element) item.getValue(); + p.println("Element " + e.getName()); + + System.out.println(" includes:"); + dump(e.inclusions); + System.out.println(" excludes:"); + dump(e.exclusions); + System.out.println(" attributes:"); + + AttributeList atts = e.atts; + while (atts != null) + { + p.print(" " + atts.name + " = " + atts.value); + if (atts.values == null || atts.values.size() == 0) + p.println(); + else + { + Iterator viter = atts.values.iterator(); + System.out.print(" ( "); + while (viter.hasNext()) + { + System.out.print(viter.next()); + if (viter.hasNext()) + System.out.print(" | "); + } + System.out.println(" ) "); + } + atts = atts.next; + } + } + } + + /** + * Prints the content of the given attribute set to the System.out. + * @param b + */ + public void dump(BitSet b) + { + if (b != null) + { + for (int i = 0; i < b.size(); i++) + { + if (b.get(i)) + System.out.println(" " + elements.get(i)); + } + } + else + System.out.println(" NULL set"); + } + + /** + * Creates the attribute. + * @param name The attribute name. + * @param type The attribute type. + * @param modifier The attribute modifier. + * @param defaultValue Default value (or null) + * @param allowed_values Allowed values (or null) + * @return The newly created AttributeList. The next + * field is initialized to null. + */ + protected AttributeList attr(String name, String default_value, + String[] allowed_values, int type, int modifier + ) + { + Vector allowed = null; + + if (allowed_values != null) + { + allowed = new Vector(allowed_values.length); + for (int i = 0; i < allowed_values.length; i++) + { + allowed.add(allowed_values [ i ]); + } + } + + AttributeList attr = + new AttributeList(name, type, modifier, default_value, allowed, null); + + return attr; + } + + /** + * Define the general entity, holding a single character. + * @param name The entity name (for example, 'amp'). + * The defined entity is stored into the entity table. + * @param character The entity character (for example, '&'). + */ + protected void defineEntity(String name, int character) + { + super.defEntity(name, GENERAL, character); + } + + private String[] toStringArray(Collection c) + { + String[] s = new String[ c.size() ]; + Iterator iter = c.iterator(); + for (int i = 0; i < s.length; i++) + { + s [ i ] = iter.next().toString(); + } + return s; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/htmlAttributeSet.java b/libjava/classpath/gnu/javax/swing/text/html/parser/htmlAttributeSet.java new file mode 100644 index 000000000..7eb0f616e --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/htmlAttributeSet.java @@ -0,0 +1,183 @@ +/* htmlAttributeSet.java -- A set to store HTML attributes + 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.swing.text.html.parser; + +import java.util.Enumeration; + +import javax.swing.text.AttributeSet; +import javax.swing.text.SimpleAttributeSet; +import javax.swing.text.html.HTML; + +/** + * A set, adapted to store HTML attributes. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class htmlAttributeSet + extends SimpleAttributeSet +{ + public static final htmlAttributeSet EMPTY_HTML_ATTRIBUTE_SET = + new htmlAttributeSet(); + + AttributeSet parent; + + /** + * Looks in this set and, if not found, later looks in the parent set. Calls + * toString(), allowing to pass as HTML.Attribute, as String to this method. + * + * @param _key A key to search for a value. + * @return The value, if one is defined. + */ + public Object getAttribute(Object _key) + { + Object v = super.getAttribute(_key); + if (v != null || _key == null) + return v; + + Object key = _key.toString().toLowerCase(); + + v = super.getAttribute(key); + if (v != null) + return v; + + key = HTML.getAttributeKey((String) key); + v = super.getAttribute(key); + if (v != null) + return v; + + if (parent != null) + return parent.getAttribute(key); + else + return null; + } + + /** + * The name set must return HTML.Attribute and not a string, + * where applicable. + */ + public Enumeration getAttributeNames() + { + // Replace the string keys by HTML.attribute, where applicable + final Enumeration enumeration = super.getAttributeNames(); + + return new Enumeration() + { + public boolean hasMoreElements() + { + return enumeration.hasMoreElements(); + } + + public Object nextElement() + { + Object key = enumeration.nextElement(); + if (key instanceof String) + { + HTML.Attribute hKey = HTML.getAttributeKey((String) key); + if (hKey != null) + return hKey; + } + return key; + } + }; + } + + /** + * Set the parent set, containing the default values. + * + * @param a_parent + */ + public void setResolveParent(AttributeSet a_parent) + { + parent = a_parent; + } + + /** + * Get the parent set, containing the default values. + * + * @return the parent, used to resolve the attributes. + */ + public AttributeSet getResolveParent() + { + return parent; + } + + /** + * Add the attribute to this attribute set. + * + * @param key Attribute key (if string, it will be case insensitive) + * @param value Attribute value + */ + public void addAttribute(Object key, Object value) + { + if (key instanceof String) + super.addAttribute(((String) key).toLowerCase(), value); + else + super.addAttribute(key, value); + } + + /** + * Copy attributes. The returned copy does not longer contains the extended + * features, needed to participate in the HTML parsing. The returned set may + * not be mutable. + */ + public AttributeSet copyAttributes() + { + if (getAttributeCount() <= 8) + // For the small size, typical in HTML tags, the direct iteration is + // faster than more complex algorithms. + return new SmallHtmlAttributeSet(this); + else + return (AttributeSet) clone(); + } + + /** + * Returns a clone of the attribute set. + * + * @return A clone of the attribute set. + */ + public Object clone() + { + htmlAttributeSet set = new htmlAttributeSet(); + set.addAttributes(this); + AttributeSet parent = getResolveParent(); + if (parent != null) + set.setResolveParent(parent); + return set; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/htmlValidator.java b/libjava/classpath/gnu/javax/swing/text/html/parser/htmlValidator.java new file mode 100644 index 000000000..2b624cc3c --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/htmlValidator.java @@ -0,0 +1,622 @@ +/* tagStack.java -- The HTML tag stack. + 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.swing.text.html.parser; + +import gnu.java.lang.CPStringBuilder; + +import gnu.javax.swing.text.html.parser.models.node; +import gnu.javax.swing.text.html.parser.models.transformer; + +import java.util.BitSet; +import java.util.Enumeration; +import java.util.LinkedList; +import java.util.ListIterator; + +import javax.swing.text.SimpleAttributeSet; +import javax.swing.text.html.HTML; +import javax.swing.text.html.parser.*; + +/** + *

      The HTML content validator, is responsible for opening and + * closing elements with optional start/end tags, detecting + * the wrongly placed html tags and reporting errors. The working instance + * is the inner class inside the {@link javax.swing.text.html.parser.Parser } + *

      + *

      This class could potentially + * provide basis for automated closing and insertion of the html tags, + * correcting the found html errors. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public abstract class htmlValidator +{ + /** + * The tag reference, holding additional information that the tag + * has been forcibly closed. + */ + protected class hTag + { + protected final Element element; + protected final HTML.Tag tag; + protected final TagElement tgElement; + protected boolean forcibly_closed; + protected node validationTrace; + + protected hTag(TagElement an_element) + { + element = an_element.getElement(); + tag = an_element.getHTMLTag(); + tgElement = an_element; + + if (element.content != null) + validationTrace = transformer.transform(element.content, dtd); + } + + /** + * This is called when the tag must be forcibly closed because + * it would make the newly appearing tag invalid. + * The parser is not notified about such event (just the error + * is reported). For such tags, the closing message does not + * appear when later reaching the end of stream. The exception is + * the <head> tag: the parser is notified about its silent closing + * when <body> or other html content appears. + */ + protected void forciblyCloseDueContext() + { + forcibly_closed = true; + } + + /** + * This is called when the tag must be forcibly closed after + * reaching the end of stream. The parser is notified as if + * closing the tag explicitly. + */ + protected void forciblyCloseDueEndOfStream() + { + forcibly_closed = true; + handleSupposedEndTag(element); + } + } + + /** + * The DTD, providing information about the valid document structure. + */ + protected final DTD dtd; + + /** + * The stack, holding the current tag context. + */ + protected final LinkedList stack = new LinkedList(); + + /** + * Creates a new tag stack, using the given DTD. + * @param a_dtd A DTD, providing the information about the valid + * tag content. + */ + public htmlValidator(DTD a_dtd) + { + dtd = a_dtd; + } + + /** + * Close all opened tags (called at the end of parsing). + */ + public void closeAll() + { + hTag h; + while (!stack.isEmpty()) + { + h = (hTag) stack.getLast(); + if (!h.forcibly_closed && !h.element.omitEnd()) + s_error("Unclosed <" + h.tag + ">, closing at the end of stream"); + + handleSupposedEndTag(h.element); + + closeTag(h.tgElement); + } + } + + /** + * Remove the given tag from the stack or (if found) from the list + * of the forcibly closed tags. + */ + public boolean closeTag(TagElement tElement) + { + HTML.Tag tag = tElement.getHTMLTag(); + hTag x; + hTag close; + + if (!stack.isEmpty()) + { + ListIterator iter = stack.listIterator(stack.size()); + + while (iter.hasPrevious()) + { + x = (hTag) iter.previous(); + if (tag.equals(x.tag)) + { + if (x.forcibly_closed && !x.element.omitEnd()) + s_error("The tag <" + x.tag + + "> has already been forcibly closed" + ); + + + // If the tag has a content model defined, forcibly close all + // tags that were opened after the tag being currently closed. + closing: + if (x.element.content != null) + { + iter = stack.listIterator(stack.size()); + while (iter.hasPrevious()) + { + close = (hTag) iter.previous(); + if (close == x) + break closing; + handleSupposedEndTag(close.element); + iter.remove(); + } + } + + stack.remove(x); + return true; + } + } + } + s_error("Closing unopened <" + tag + ">"); + return false; + } + + /** + * Add the given HTML tag to the stack of the opened tags. Forcibly closes + * all tags in the stack that does not allow this tag in they content (error + * is reported). + * @param element + */ + public void openTag(TagElement tElement, htmlAttributeSet parameters) + { + // If this is a fictional call, the message from the parser + // has recursively returned - ignore. + if (tElement.fictional()) + return; + + validateParameters(tElement, parameters); + + // If the stack is empty, start from HTML + if (stack.isEmpty() && tElement.getHTMLTag() != HTML.Tag.HTML) + { + Element html = dtd.getElement(HTML.Tag.HTML.toString()); + openFictionalTag(html); + } + + Object v = tagIsValidForContext(tElement); + if (v != Boolean.TRUE) + { + // The tag is not valid for context, the content + // model suggest to open another tag. + if (v instanceof Element) + { + int n = 0; + while (v instanceof Element && (n++ < 100)) + { + Element fe = (Element) v; + + // notify the content model that we add the proposed tag + node ccm = getCurrentContentModel(); + if (ccm != null) + ccm.show(fe); + openFictionalTag(fe); + + Object vv = tagIsValidForContext(tElement); + if (vv instanceof Element) // One level of nesting is supported. + { + openFictionalTag((Element) vv); + + Object vx = tagIsValidForContext(tElement); + if (vx instanceof Element) + openFictionalTag((Element) vx); + } + else if (vv == Boolean.FALSE) + { + // The tag is still not valid for the current + // content after opening a fictional element. + if (fe.omitEnd()) + { + // close the previously opened fictional tag. + closeLast(); + vv = tagIsValidForContext(tElement); + if (vv instanceof Element) + + // another tag was suggested by the content model + openFictionalTag((Element) vv); + } + } + v = tagIsValidForContext(tElement); + } + } + else // If the current element has the optional end tag, close it. + { + if (!stack.isEmpty()) + { + closing: + do + { + hTag last = (hTag) stack.getLast(); + if (last.element.omitEnd()) + { + closeLast(); + v = tagIsValidForContext(tElement); + if (v instanceof Element) // another tag was suggested by the content model + { + openFictionalTag((Element) v); + break closing; + } + } + else + break closing; + } + while (v == Boolean.FALSE && !stack.isEmpty()); + } + } + } + + stack.add(new hTag(tElement)); + } + + /** + * Clear the stack. + */ + public void restart() + { + stack.clear(); + } + + /** + * Check if this tag is valid for the current context. Return Boolean.True if + * it is OK, Boolean.False if it is surely not OK or the Element that the + * content model recommends to insert making the situation ok. If Boolean.True + * is returned, the content model current position is moved forward. Otherwise + * this position remains the same. + * + * @param tElement + * @return + */ + public Object tagIsValidForContext(TagElement tElement) + { + // Check the current content model, if one is available. + node cv = getCurrentContentModel(); + + if (cv != null) + return cv.show(tElement.getElement()); + + // Check exclusions and inclusions. + ListIterator iter = stack.listIterator(stack.size()); + hTag t = null; + final int idx = tElement.getElement().index; + + // Check only known tags. + if (idx >= 0) + { + BitSet inclusions = new BitSet(); + while (iter.hasPrevious()) + { + t = (hTag) iter.previous(); + if (! t.forcibly_closed) + { + if (t.element.exclusions != null + && t.element.exclusions.get(idx)) + return Boolean.FALSE; + + if (t.element.inclusions != null) + inclusions.or(t.element.inclusions); + } + } + if (! inclusions.get(idx)) + { + // If we need to insert something, and cannot do this, but + // it is allowed to insert the paragraph here, insert the + // paragraph. + Element P = dtd.getElement(HTML_401F.P); + if (inclusions.get(P.index)) + return P; + else + return Boolean.FALSE; + } + } + return Boolean.TRUE; + } + + /** + * Validate tag without storing in into the tag stack. This is called + * for the empty tags and results the subsequent calls to the openTag + * and closeTag. + */ + public void validateTag(TagElement tElement, htmlAttributeSet parameters) + { + openTag(tElement, parameters); + closeTag(tElement); + } + + /** + * Check for mandatory elements, subsequent to the last tag: + * @param tElement The element that will be inserted next. + */ + protected void checkContentModel(TagElement tElement, boolean first) + { + if (stack.isEmpty()) + return; + + hTag last = (hTag) stack.getLast(); + if (last.validationTrace == null) + return; + + Object r = last.validationTrace.show(tElement.getElement()); + if (r == Boolean.FALSE) + s_error("The <" + last.element + "> does not match the content model " + + last.validationTrace + ); + else if (r instanceof Element) // The content model recommends insertion of this element + { + if (!first) + closeTag(last.tgElement); + handleSupposedStartTag((Element) r); + openTag(new TagElement((Element) r), null); + } + } + + /** + * The method is called when the tag must be closed because + * it does not allow the subsequent elements inside its context + * or the end of stream has been reached. The parser is only + * informed if the element being closed does not require the + * end tag (the "omitEnd" flag is set). + * The closing message must be passed to the parser mechanism + * before passing message about the opening the next tag. + * + * @param element The tag being fictionally (forcibly) closed. + */ + protected abstract void handleSupposedEndTag(Element element); + + /** + * The method is called when the validator decides to open the + * tag on its own initiative. This may happen if the content model + * includes the element with the optional (supposed) start tag. + * + * @param element The tag being opened. + */ + protected abstract void handleSupposedStartTag(Element element); + + /** + * Handles the error message. This method must be overridden to pass + * the message where required. + * @param msg The message text. + */ + protected abstract void s_error(String msg); + + /** + * Validate the parameters, report the error if the given parameter is + * not in the parameter set, valid for the given attribute. The information + * about the valid parameter set is taken from the Element, enclosed + * inside the tag. The method does not validate the default parameters. + * @param tag The tag + * @param parameters The parameters of this tag. + */ + protected void validateParameters(TagElement tag, htmlAttributeSet parameters) + { + if (parameters == null || + parameters == htmlAttributeSet.EMPTY_HTML_ATTRIBUTE_SET || + parameters == SimpleAttributeSet.EMPTY + ) + return; + + Enumeration enumeration = parameters.getAttributeNames(); + + while (enumeration.hasMoreElements()) + { + validateAttribute(tag, parameters, enumeration); + } + + // Check for missing required values. + AttributeList a = tag.getElement().getAttributes(); + + while (a != null) + { + if (a.getModifier() == DTDConstants.REQUIRED) + if (parameters.getAttribute(a.getName()) == null) + { + s_error("Missing required attribute '" + a.getName() + "' for <" + + tag.getHTMLTag() + ">" + ); + } + a = a.next; + } + } + + private node getCurrentContentModel() + { + if (!stack.isEmpty()) + { + hTag last = (hTag) stack.getLast(); + return last.validationTrace; + } + else + return null; + } + + private void closeLast() + { + handleSupposedEndTag(((hTag) stack.getLast()).element); + stack.removeLast(); + } + + private void openFictionalTag(Element e) + { + handleSupposedStartTag(e); + stack.add(new hTag(new TagElement(e, true))); + if (!e.omitStart()) + s_error("<" + e + "> is expected (supposing it)"); + } + + private void validateAttribute(TagElement tag, htmlAttributeSet parameters, + Enumeration enumeration + ) + { + Object foundAttribute; + AttributeList dtdAttribute; + foundAttribute = enumeration.nextElement(); + dtdAttribute = tag.getElement().getAttribute(foundAttribute.toString()); + if (dtdAttribute == null) + { + CPStringBuilder valid = + new CPStringBuilder("The tag <" + tag.getHTMLTag() + + "> cannot contain the attribute '" + foundAttribute + + "'. The valid attributes for this tag are: " + ); + + AttributeList a = tag.getElement().getAttributes(); + + while (a != null) + { + valid.append(a.name.toUpperCase()); + valid.append(' '); + a = a.next; + } + s_error(valid.toString()); + } + + else + { + String value = parameters.getAttribute(foundAttribute).toString(); + + if (dtdAttribute.type == DTDConstants.NUMBER) + validateNumberAttribute(tag, foundAttribute, value); + + if (dtdAttribute.type == DTDConstants.NAME || + dtdAttribute.type == DTDConstants.ID + ) + validateNameOrIdAttribute(tag, foundAttribute, value); + + if (dtdAttribute.values != null) + validateAttributeWithValueList(tag, foundAttribute, dtdAttribute, + value + ); + } + } + + private void validateAttributeWithValueList(TagElement tag, + Object foundAttribute, + AttributeList dtdAttribute, + String value + ) + { + if (!dtdAttribute.values.contains(value.toLowerCase()) && + !dtdAttribute.values.contains(value.toUpperCase()) + ) + { + CPStringBuilder valid; + if (dtdAttribute.values.size() == 1) + valid = + new CPStringBuilder("The attribute '" + foundAttribute + + "' of the tag <" + tag.getHTMLTag() + + "> cannot have the value '" + value + + "'. The only valid value is " + ); + else + valid = + new CPStringBuilder("The attribute '" + foundAttribute + + "' of the tag <" + tag.getHTMLTag() + + "> cannot have the value '" + value + "'. The " + + dtdAttribute.values.size() + + " valid values are: " + ); + + Enumeration vv = dtdAttribute.values.elements(); + while (vv.hasMoreElements()) + { + valid.append('"'); + valid.append(vv.nextElement()); + valid.append("\" "); + } + s_error(valid.toString()); + } + } + + private void validateNameOrIdAttribute(TagElement tag, Object foundAttribute, + String value + ) + { + boolean ok = true; + + if (!Character.isLetter(value.charAt(0))) + ok = false; + + char c; + for (int i = 0; i < value.length(); i++) + { + c = value.charAt(i); + if (!( + Character.isLetter(c) || Character.isDigit(c) || + "".indexOf(c) >= 0 + ) + ) + ok = false; + } + if (!ok) + s_error("The '" + foundAttribute + "' attribute of the tag <" + + tag.getHTMLTag() + "> must start from letter and consist of " + + "letters, digits, hypens, colons, underscores and periods. " + + "It cannot be '" + value + "'" + ); + } + + private void validateNumberAttribute(TagElement tag, Object foundAttribute, + String value + ) + { + try + { + Integer.parseInt(value); + } + catch (NumberFormatException ex) + { + s_error("The '" + foundAttribute + "' attribute of the tag <" + + tag.getHTMLTag() + "> must be a valid number and not '" + + value + "'" + ); + } + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/models/PCDATAonly_model.java b/libjava/classpath/gnu/javax/swing/text/html/parser/models/PCDATAonly_model.java new file mode 100644 index 000000000..5a19a1bc1 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/models/PCDATAonly_model.java @@ -0,0 +1,62 @@ +/* PCDATAonly_model.java -- + 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.swing.text.html.parser.models; + +import java.io.Serializable; + +/** + * The model, allowing only PCDATA in it (like for element OPTION). + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class PCDATAonly_model + extends node + implements Serializable +{ + private static final long serialVersionUID = 1; + + public PCDATAonly_model() + { + super((char) 0, (char) 0, null); + } + + public Object show(Object x) + { + return x.toString().equalsIgnoreCase("#pcdata") ? Boolean.TRUE : Boolean.FALSE; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/models/TableRowContentModel.java b/libjava/classpath/gnu/javax/swing/text/html/parser/models/TableRowContentModel.java new file mode 100644 index 000000000..14514d584 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/models/TableRowContentModel.java @@ -0,0 +1,77 @@ +/* TableRowContentModel.java -- + 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.swing.text.html.parser.models; + +import java.io.Serializable; + +import javax.swing.text.html.parser.DTD; +import javax.swing.text.html.parser.Element; + +/** + * Table row content model. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class TableRowContentModel + extends node + implements Serializable +{ + private static final long serialVersionUID = 1; + final Element TD; + + public TableRowContentModel(DTD dtd) + { + super((char) 0, (char) 0, null); + TD = dtd.getElement("TD"); + } + + public Object show(Object x) + { + // Always accept TD and TH + String s = x.toString(); + if (s.equalsIgnoreCase("TD") || s.equalsIgnoreCase("TH")) + return Boolean.TRUE; + + // Suggest closing in response to TR: + if (s.equalsIgnoreCase("TR")) + return Boolean.FALSE; + + // Recommend TD for other cases: + return TD; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/models/list.java b/libjava/classpath/gnu/javax/swing/text/html/parser/models/list.java new file mode 100644 index 000000000..1ff22f8cd --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/models/list.java @@ -0,0 +1,384 @@ +/* list.java -- + 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.swing.text.html.parser.models; + +import gnu.java.lang.CPStringBuilder; + +import java.io.Serializable; + +/** + * Part of the internal representation of the content model. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class list + extends node + implements Serializable +{ + private static final long serialVersionUID = 1; + + /** + * Setting to true means that the list nodes must always be connected + * by the same operation. This is far safer and clearer, but not + * required by default standard. + */ + public static boolean CLEAR; + + /** + * A list of nodes. + */ + public final node[] nodes; + + /** + * Creates a new model list that is a member of some enclosing list. + * @param binary_operator An operator with that this list is connected + * with other members of the enclosing list. + * @param unary_operator The unary operator for this list. + * @param a_nodes The nodes inside this list. + */ + public list(char binary_operator, char unary_operator, node[] a_nodes) + { + super(binary_operator, unary_operator, a_nodes); + nodes = a_nodes; + } + + /** + * Creates a new model list. Assigns the previous field. + * @param a_nodes The nodes for this list. + * @throws an error if the node elements are connected by the + * different operations. This is not supported, use grouping. + */ + public list(node[] a_nodes) + throws Error + { + this(',', (char) 0, a_nodes); + + int operation = nodes [ 0 ].binary; + + for (int i = 0; i < nodes.length; i++) + { + if (CLEAR && nodes [ i ].binary != operation) + throw new Error("List members can only be connected by " + + "the same operation, use grouping" + ); + + if (i > 0) + nodes [ i ].previous = nodes [ i - 1 ]; + } + } + + /** + * Returns true if all members in the list are closed. + */ + public boolean isClosed() + { + if (super.isClosed()) + return true; + for (int i = 0; i < nodes.length; i++) + { + if (!nodes [ i ].isClosed()) + return false; + } + return true; + } + + /** + * Find the token that could match as the next token in + * the token list. + * + * @return Such token object or null if none is found. + */ + public Object findFreeNode() + { + Object fn; + for (int j = 0; j < nodes.length; j++) + { + if (!nodes [ j ].isClosed()) + { + fn = nodes [ j ].findFreeNode(); + if (fn != null) + return fn; + } + } + return null; + } + + /** + * Tries to match this list agains the given token sequence. + * @param tokens the sequence of the tokens to match. + * @return true if the valid match is found. + */ + public boolean matches(Object[] tokens) + { + reset(); + + Object x; + boolean m; + boolean matched = false; + + for (int i = 0; i < tokens.length; i++) + { + matched = false; + x = tokens [ i ]; + + nodescan: + for (int j = 0; j < nodes.length; j++) + { + if (!nodes [ j ].isClosed()) + { + m = nodes [ j ].performMatch(x); + + if (m) + { + matched = true; + break nodescan; + } + } + } + if (!matched) + return false; + } + + boolean valid = true; + + for (int i = 0; i < nodes.length; i++) + { + if (!nodes [ i ].valid()) + valid = false; + } + + return valid; + } + + /** + * The list never closes, despite it is trated as closed + * if all members in the list are closed. + * @return false. + */ + public boolean mustClose() + { + return false; + } + + /** + * Perform a match operation for the single token + * against this list. + * @param token a token to match. + * @return true if the match is found. + */ + public boolean performMatch(Object token) + { + boolean ok = false; + Matching: + for (int i = 0; i < nodes.length; i++) + { + ok = nodes [ i ].performMatch(token); + + if (ok) + break Matching; + } + + if (ok) + matches(); + + return ok; + } + + /** + * Prepeares the list for the next matching operation. + */ + public void reset() + { + super.reset(); + for (int i = 0; i < nodes.length; i++) + nodes [ i ].reset(); + } + + /** + * Check if the provided token can match as a next token in the + * list. In the case of match, the list state changes, moving + * current position after the matched token. However if this method + * returns a suggested new token to insert before the provided one, + * the state of the list does not change. + * @return Boolean.TRUE if the match is found, + * Boolean.FALSE if the match is not possible and no token can be + * inserted to make the match valid. Otherwise, returns the + * token object that can be inserted before the last token in the + * list, probably (not for sure) making the match valid. + * If the object is an instance of Element or TagElement, + * it is first ensured that the object flag "omit start" is set. + */ + public Object show(Object x) + { + boolean m; + boolean matched = false; + + nodescan: + for (int j = 0; j < nodes.length; j++) + { + if (!nodes [ j ].isClosed()) + { + m = nodes [ j ].performMatch(x); + + if (m) + { + matched = true; + break nodescan; + } + else + { + // For comma operation, only first not closed + // node must be tested for a match. + // unless it allows matching zero times. + if (binary == ',' && + !(nodes [ j ].unary == '?' || nodes [ j ].unary == '*') + ) + break nodescan; + } + } + } + + if (!matched) + { + // Find and return that would be matched. + Object freeNode = findFreeNode(); + if (freeNode == null) + return Boolean.FALSE; + else + return freeNode; + } + + for (int i = 0; i < nodes.length; i++) + if (!nodes [ i ].validPreliminary()) + { + return Boolean.FALSE; + } + + return Boolean.TRUE; + } + + /** + * Returns a string representation of the list. + * @return String representation, similar to BNF expression. + */ + public String toString() + { + CPStringBuilder b = new CPStringBuilder(); + b.append(" ( "); + for (int i = 0; i < nodes.length; i++) + { + if (i > 0) + b.append(" " + (char) nodes [ i ].binary + " "); + b.append(nodes [ i ]); + } + + b.append(" )"); + if (unary != 0) + b.append((char) unary); + else + b.append(' '); + return b.toString(); + } + + /** + * Returns true if all memebers in the list are valid. + */ + public boolean valid() + { + for (int i = 0; i < nodes.length; i++) + { + if (!nodes [ i ].valid()) + return false; + } + return true; + } + + /** + * Returns true if all memebers in the list are either valid + * or unvisited. The unvisited members can become valid after + * more tokens will be shown. + */ + public boolean validPreliminary() + { + if (silenceAllowed()) + { + boolean everVisited = false; + for (int i = 0; i < nodes.length; i++) + { + if (nodes [ i ].visits > 0) + { + everVisited = true; + break; + } + } + if (!everVisited) + return true; + } + + for (int i = 0; i < nodes.length; i++) + { + if (!nodes [ i ].validPreliminary()) + return false; + } + return true; + } + + /** + * Closes all members in the list. + */ + protected void close() + { + super.close(); + for (int i = 0; i < nodes.length; i++) + { + nodes [ i ].close(); + } + } + + /** + * Compare given token with the token of this node. + * If the token represents a list, the call may be + * delegeted to the child subnodes. + * @param a_token A token to compare. + * @return True if the token matches the token of this node. + */ + protected boolean compare(Object a_token) + { + return performMatch(a_token); + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/models/noTagModel.java b/libjava/classpath/gnu/javax/swing/text/html/parser/models/noTagModel.java new file mode 100644 index 000000000..8aac14d8e --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/models/noTagModel.java @@ -0,0 +1,75 @@ +/* noTagModel.java -- + 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.swing.text.html.parser.models; + +import java.io.Serializable; + +/** + * Disallows a single given tag at the current content level only. + *

      @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)

      + */ +public class noTagModel + extends node + implements Serializable +{ + private static final long serialVersionUID = 1; + final String[] no; + + public noTagModel(String[] noTag) + { + super((char) 0, (char) 0, null); + no = noTag; + } + + public noTagModel(String noTag) + { + super((char) 0, (char) 0, null); + no = new String[] { noTag }; + } + + public Object show(Object x) + { + for (int i = 0; i < no.length; i++) + { + if (x.toString().equalsIgnoreCase(no [ i ])) + return Boolean.FALSE; + } + return Boolean.TRUE; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/models/node.java b/libjava/classpath/gnu/javax/swing/text/html/parser/models/node.java new file mode 100644 index 000000000..f45a13b3e --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/models/node.java @@ -0,0 +1,339 @@ +/* node.java -- + 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.swing.text.html.parser.models; + +import gnu.java.lang.CPStringBuilder; + +import java.io.Serializable; + +/** + * Part of the internal representation of the content model. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class node + implements Serializable +{ + private static final long serialVersionUID = 1; + + /** + * The token to match (can be instance of list). + */ + public Object token; + + /** + * True for the node that cannot be visited again. + */ + public boolean _closed; + + /** + * The binary operation for this node. + */ + public char binary; + + /** + * The unary opeation for this node. + */ + public char unary; + + /** + * The number of times the node already was visited. + */ + public int visits; + + /** + * The previous node in content model (used for closing nodes). + */ + public node previous; + + /** + * Creates a new node. + * @param binary_operator The operator, connecting all nodes in the list. + * The nodes, connected by the different operators, must be arranged into + * the different lists. + * @param unary_operator The unary operator for this node or zero if + * no such was specified. + * @param token The token to match. This can be either a string or + * the new instance of the list. + * @param a_previous The previous node in the list, null for the first + * node. This is used for propagating the closing operation for the + * comma delimited list. + */ + public node(char binary_operator, char unary_operator, Object a_token) + { + if (a_token != null) + if (a_token.getClass().equals(node.class)) + throw new Error("Creating node in node is redundant and ineffective."); + + binary = binary_operator; + unary = unary_operator; + token = a_token; + } + + /** + * Checks if this node is in the closed state. + * @return True if the node is closed. + */ + public boolean isClosed() + { + return _closed; + } + + /** + * Check if closing this node means closing the previous node. + */ + public boolean closePrevious() + { + return binary == ','; + } + + /** + * Return the token object if it could match as a next token in + * a token list of null if it could not. + * @return + */ + public Object findFreeNode() + { + boolean ok; + if (isClosed() || silenceAllowed()) + return null; + + // Try if the node would stay valid after a one more visit. + visits++; + ok = valid(); + visits--; + + if (ok) + { + if (token instanceof node) + return ((node) token).findFreeNode(); + else + return token; + } + else + return null; + } + + /** + * Check if the current situation is such that the node must be closed + * now. + */ + public boolean mustClose() + { + switch (unary) + { + case 0 : + return true; + + case '*' : + return false; + + case '+' : + return false; + + case '?' : + return visits <= 1; + + default : + throw new Error("Invalid unary operation " + unary + " ( '" + + (char) unary + "' )" + ); + } + } + + /** + * Do the match operation with the given token. This sets various + * flags. + * @param a_token The token to match. + * @return true if the the token matches node, false if it does not match + * or if the node is closed. + */ + public boolean performMatch(Object a_token) + { + if (isClosed()) + return false; + + boolean matches = compare(a_token); + if (matches) + matches(); + + return matches; + } + + /** + * Prepares the node for matching against a new list of tokens. + */ + public void reset() + { + _closed = false; + visits = 0; + } + + /** + * Check if the provided token can match this node. + * In the case of match, the node state changes, moving + * current position after the matched token. However if this method + * returns a suggested new token to insert before the provided one, + * the state of the list does not change. + * @return Boolean.TRUE if the match is found, + * Boolean.FALSE if the match is not possible and no token can be + * inserted to make the match valid. Otherwise, returns the + * token object that can be inserted before the last token in the + * list, probably (not for sure) making the match valid. + */ + public Object show(Object x) + { + if (compare(x)) + return performMatch(x) ? Boolean.TRUE : Boolean.FALSE; + + Object recommended = findFreeNode(); + return recommended != null ? recommended : Boolean.FALSE; + } + + /** + * Check if it would be a valid case if this node is visited zero times. + * Nodes with unary operator * or ? need not be matched to make a + * model valid. + */ + public boolean silenceAllowed() + { + return unary == '?' || unary == '*'; + } + + /** + * Returns a string representation of the list. + * @return String representation, similar to BNF expression. + */ + public String toString() + { + CPStringBuilder b = new CPStringBuilder(); + + b.append(token); + if (unary != 0) + b.append((char) unary); + else + b.append('\''); + + return b.toString(); + } + + /** + * Check if the node state is valid. + */ + public boolean valid() + { + switch (unary) + { + case 0 : + if (binary == '|') + return true; + else + return visits == 1; + + case '*' : + return true; + + case '+' : + return visits > 0; + + case '?' : + return visits <= 1; + + default : + throw new Error("Invalid unary operation " + unary + " ( '" + + (char) unary + "' )" + ); + } + } + + public boolean validPreliminary() + { + return visits == 0 || valid(); + } + + /** + * Closes this node and, if closePrevious() returs true, calls close() for + * the previous node. + */ + protected void close() + { + _closed = true; + if (previous != null && closePrevious()) + previous.close(); + } + + /** + * Compare the provided token object with the token object of this node. + */ + protected boolean compare(Object a_token) + { + if (token instanceof Object[]) + throw new Error("Invalid token object, probably the 'list' " + + "should be used. " + ); + + if (token instanceof node[]) + throw new Error("Do not use 'node' for the array of nodes, use 'list'. "); + + if (token instanceof node) + { + return ((node) token).performMatch(a_token); + } + + boolean rt = false; + + if (token == a_token) + rt = true; + if (token.equals(a_token)) + rt = true; + if (token.toString().equalsIgnoreCase(a_token.toString())) + rt = true; + + return rt; + } + + /** + * Fire the changes that must happen then the token matches this node. + */ + protected void matches() + { + visits++; + if (mustClose()) + close(); + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/models/package.html b/libjava/classpath/gnu/javax/swing/text/html/parser/models/package.html new file mode 100644 index 000000000..18e61aede --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/models/package.html @@ -0,0 +1,53 @@ + + + + +GNU Classpath - gnu.javax.swing.text.html.parser.models + + +

      This package contains classes for working with content models. In this implementation, the +standardized content model is pre-processed by transformer into an instance of +node. Node holds a single element of the content model with the optional unary operation. +The derived class list holds multiple nodes connected by the same binary operation. +As the members of this list can also be lists itself, these structures support +the most of required operations. Several cases when the model cannot be expressed using +BNF syntax are handled providing specialised classes that are also derived from node. +

      +@author Audrius Meskauskas, Lithuania + + diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/models/transformer.java b/libjava/classpath/gnu/javax/swing/text/html/parser/models/transformer.java new file mode 100644 index 000000000..22ae3c3fa --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/models/transformer.java @@ -0,0 +1,201 @@ +/* transformer.java -- Content model transforms. + 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.swing.text.html.parser.models; + +import java.io.Serializable; + +import javax.swing.text.html.parser.ContentModel; +import javax.swing.text.html.parser.DTD; + +/** + * Transforms the standard ContentModel tree into the internal representation, + * used in this implementation. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class transformer + implements Serializable +{ + private static final long serialVersionUID = 1; + + /** + * All binary operators. + */ + protected static String binary = "&|,"; + + /** + * All unary operators. + */ + protected static String unary = "+*?"; + + /** + * Measure length of the linked list of the content models. + * @param c The heading element of the linked list. + * @return the length of the list (0 for null 1 if c!=null and c.next==null, + * etc. + */ + public static int measureChainLength(ContentModel c) + { + if (c == null) + return 0; + else + return measureChainLength(c.next) + 1; + } + + /** + * Transform into internal representation without usind dtd. + * This should be used only for testing. + */ + public static node transform(ContentModel c) + { + return transform(c, null); + } + + /** + * Transform into internal representation. + * @param c a model to transform + * @return a transformed model + * @throws Error if the model structure contains errors. + */ + public static node transform(ContentModel c, DTD dtd) + { + // Handle the special cases first. + if (c.content instanceof node) + return (node) c.content; + + // Do the typical transform. + node n; + + /* Case with the single token */ + if (c.next == null) + { + n = optionalTransform(c, dtd); + } + else /* Case with the chain of the multiple tokens. */ + { + node[] l = new node[ measureChainLength(c) ]; + ContentModel m = c; + for (int i = 0; i < l.length; i++) + { + if (m.content instanceof ContentModel) + { + ContentModel nested = (ContentModel) m.content; + if (nested.next == null && + !(nested.content instanceof ContentModel) + ) + { + l [ i ] = + new node((char) m.type, (char) nested.type, nested.content); + } + else + { + l [ i ] = transform(nested, dtd); + } + } + else + l [ i ] = new node((char) 0, (char) 0, m.content); + addtype(l [ i ], (char) m.type); + m = m.next; + } + + if (isBinary(c.type)) + for (int i = 0; i < l.length; i++) + { + l [ i ].binary = (char) c.type; + } + + n = new list(l); + } + + addtype(n, (char) c.type); + + return n; + } + + /** + * True for binary operator + * @param c a character to test + * @return true for [ ,&| ], false otherwise. + */ + private static boolean isBinary(int c) + { + return binary.indexOf((char) c) >= 0; + } + + /** + * True for unary operator. + * @param c a character to test + * @return true for [ +?* ], false otherwise. + */ + private static boolean isUnary(int c) + { + return unary.indexOf((char) c) >= 0; + } + + /** + * Assign an operation type for the given node. + * @param n A node to set the operation to. + * @param type Either binary or unary operation, is assigned to the + * corresponding field of the node. + * @throws error if the operation type is not + * representing a valid unary or binary operation. + */ + private static void addtype(node n, char type) + { + if (isBinary(type)) + n.binary = type; + + else if (isUnary(type)) + n.unary = type; + + else if (type != 0) + throw new Error("Invalid operation '" + (char) type + "'"); + } + + private static node optionalTransform(ContentModel c, DTD dtd) + { + node n; + if (c.content instanceof ContentModel) + n = transform((ContentModel) c.content, dtd); + else + + /* A single token with the specified operation */ + n = new node((char) 0, (char) 0, c.content); + return n; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/package.html b/libjava/classpath/gnu/javax/swing/text/html/parser/package.html new file mode 100644 index 000000000..cd050f9c2 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/package.html @@ -0,0 +1,51 @@ + + + + +GNU Classpath - javax.swing.text.html.parser + + +

      Provides the error tolerant, DTD-driven HTML 4.01 parser. +The parser that is used in web robots, html content analysers, +web browsers, web editors and other related applications. +It should compativle with the older HTML versions, supporting +obsoleted HTML featues. This package also includes some +supporting classes.

      +@author Audrius Meskauskas, Lithuania + + diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/Parser.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/Parser.java new file mode 100644 index 000000000..cdefb75c8 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/Parser.java @@ -0,0 +1,1532 @@ +/* Parser.java -- HTML parser. + 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.swing.text.html.parser.support; + +import gnu.java.lang.CPStringBuilder; + +import gnu.javax.swing.text.html.parser.htmlAttributeSet; +import gnu.javax.swing.text.html.parser.htmlValidator; +import gnu.javax.swing.text.html.parser.support.low.Constants; +import gnu.javax.swing.text.html.parser.support.low.ParseException; +import gnu.javax.swing.text.html.parser.support.low.ReaderTokenizer; +import gnu.javax.swing.text.html.parser.support.low.Token; +import gnu.javax.swing.text.html.parser.support.low.node; +import gnu.javax.swing.text.html.parser.support.low.pattern; + +import java.io.IOException; +import java.io.Reader; + +import java.util.Comparator; +import java.util.Set; +import java.util.TreeSet; +import java.util.Vector; + +import javax.swing.text.ChangedCharSetException; +import javax.swing.text.SimpleAttributeSet; +import javax.swing.text.html.HTML; +import javax.swing.text.html.parser.AttributeList; +import javax.swing.text.html.parser.DTD; +import javax.swing.text.html.parser.DTDConstants; +import javax.swing.text.html.parser.Element; +import javax.swing.text.html.parser.Entity; +import javax.swing.text.html.parser.TagElement; + +/** + *

      A simple error-tolerant HTML parser that uses a DTD document + * to access data on the possible tokens, arguments and syntax.

      + *

      The parser reads an HTML content from a Reader and calls various + * notifying methods (which should be overridden in a subclass) + * when tags or data are encountered.

      + *

      Some HTML elements need no opening or closing tags. The + * task of this parser is to invoke the tag handling methods also when + * the tags are not explicitly specified and must be supposed using + * information, stored in the DTD. + * For example, parsing the document + *

      <table><tr><td>a<td>b<td>c</tr>
      + * will invoke exactly the handling methods exactly in the same order + * (and with the same parameters) as if parsing the document:
      + * <html><head></head><body><table>< + * tbody><tr><td>a</td><td>b + * </td><td>c</td></tr>< + * /tbody></table></body></html>

      + * (supposed tags are given in italics). The parser also supports + * obsolete elements of HTML syntax.

      + *

      + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class Parser + extends ReaderTokenizer + implements DTDConstants +{ + /** + * The current html tag. + */ + public Token hTag = new Token(); + + /** + * The document template description that will be used to parse the documents. + */ + protected DTD dtd; + + /** + * The value of this field determines whether or not the Parser will be + * strict in enforcing SGML compatibility. The default value is false, + * stating that the parser should do everything to parse and get at least + * some information even from the incorrectly written HTML input. + */ + protected boolean strict; + + /** + * This fields has positive values in preformatted tags. + */ + protected int preformatted = 0; + + /** + * The set of the document tags. This field is used for supporting + * markFirstTime(). + */ + private Set documentTags = + new TreeSet(new Comparator() + { + public int compare(Object a, Object b) + { + return ((String) a).compareToIgnoreCase((String) b); + } + } + ); + + /** + * The buffer to collect the incremental output like text or coment. + */ + private final StringBuffer buffer = new StringBuffer(); + + /** + * The buffer to store the document title. + */ + private final StringBuffer title = new StringBuffer(); + + /** + * The current token. + */ + private Token t; + + /** + * True means that the 'title' tag of this document has + * already been handled. + */ + private boolean titleHandled; + + /** + * True means that the 'title' tag is currently open and all + * text is also added to the title buffer. + */ + private boolean titleOpen; + + /** + * The attributes of the current HTML element. + * Package-private to avoid an accessor method. + */ + htmlAttributeSet attributes = + htmlAttributeSet.EMPTY_HTML_ATTRIBUTE_SET; + + /** + * The validator, controlling the forcible closing of the tags that + * (in accordance to dtd) are not allowed in the current context. + */ + private htmlValidator validator; + + /** + * Provides the default values for parameters in the case when these + * values are defined in the DTD. + */ + private parameterDefaulter defaulter; + + /** + * The text pre-processor for handling line ends and tabs. + */ + private textPreProcessor textProcessor = new textPreProcessor(); + + /** + * Creates a new Parser that uses the given + * {@link javax.swing.text.html.parser.DTD }. The only standard way + * to get an instance of DTD is to construct it manually, filling in + * all required fields. + * @param a_dtd The DTD to use. The parser behaviour after passing null + * as an argument is not documented and may vary between implementations. + */ + public Parser(DTD a_dtd) + { + if (a_dtd == null) + dtd = gnu.javax.swing.text.html.parser.HTML_401F.getInstance(); + else + dtd = a_dtd; + + defaulter = new parameterDefaulter(dtd); + + validator = + new htmlValidator(dtd) + { + /** + * Handles the error message. This method must be overridden to pass + * the message where required. + * @param msg The message text. + */ + protected void s_error(String msg) + { + error(msg); + } + + /** + * The method is called when the tag validator decides to close the + * tag on its own initiative. After reaching the end of stream, + * The tag validator closes all unclosed elements that are required + * to have the end (closing) tag. + * + * @param tElement The tag being fictionally (forcibly) closed. + */ + protected void handleSupposedEndTag(Element tElement) + { + // The tag is cloned as the original tElement is the + // element from the starting tag - may be accidently used + // somewhere else. + TagElement tag = makeTag(tElement, true); + _handleEndTag_remaining(tag); + } + + /** + * The method is called when the the tag validator decides to open + * the new tag on its own initiative. The tags, opened in this + * way, are HTML, HEAD and BODY. The attribute set is temporary + * assigned to the empty one, the previous value is + * restored before return. + * + * @param tElement The tag being fictionally (forcibly) closed. + */ + protected void handleSupposedStartTag(Element tElement) + { + TagElement tag = makeTag(tElement, true); + htmlAttributeSet were = attributes; + attributes = htmlAttributeSet.EMPTY_HTML_ATTRIBUTE_SET; + _handleStartTag(tag); + attributes = were; + } + }; + } + + /** + * Get the attributes of the current tag. + * @return The attribute set, representing the attributes of the current tag. + */ + public SimpleAttributeSet getAttributes() + { + return new SimpleAttributeSet(attributes); + } + + /** + * Invokes the error handler. The default method in this implementation + * delegates the call to handleError, also providing the current line. + */ + public void error(String msg) + { + error(msg, getTokenAhead()); + } + + public void error(String msg, Token atToken) + { + if (atToken != null) + handleError(atToken.where.beginLine, + msg + ": line " + atToken.where.beginLine + + ", absolute pos " + atToken.where.startPosition + ); + else + handleError(0, msg); + } + + /** + * Invokes the error handler. The default method in this implementation + * delegates the call to error (parm1+": '"+parm2+"'"). + */ + public void error(String msg, String invalid) + { + error(msg + ": '" + invalid + "'"); + } + + /** + * Invokes the error handler. The default method in this implementation + * delegates the call to error (parm1+" "+ parm2+" "+ parm3). + */ + public void error(String parm1, String parm2, String parm3) + { + error(parm1 + " " + parm2 + " " + parm3); + } + + /** + * Invokes the error handler. The default method in this implementation + * delegates the call to error (parm1+" "+ parm2+" "+ parm3+" "+ parm4). + */ + public void error(String parm1, String parm2, String parm3, String parm4) + { + error(parm1 + " " + parm2 + " " + parm3 + " " + parm4); + } + + public void flushAttributes() + { + } + + /** + * Parse the HTML text, calling various methods in response to the + * occurence of the corresponding HTML constructions. + * @param reader The reader to read the source HTML from. + * @throws IOException If the reader throws one. + */ + public synchronized void parse(Reader reader) + throws IOException + { + reset(reader); + restart(); + try + { + parseDocument(); + validator.closeAll(); + } + catch (ParseException ex) + { + if (ex != null) + { + error("Unable to continue parsing the document", ex.getMessage()); + + Throwable cause = ex.getCause(); + if (cause instanceof IOException) + throw (IOException) cause; + } + } + } + + /** + * Parses DTD markup declaration. Currently returns null without action. + * @return null. + * @throws IOException + */ + public String parseDTDMarkup() + throws IOException + { + return null; + } + + /** + * Parse SGML insertion ( <! ... > ). When the + * the SGML insertion is found, this method is called, passing + * SGML in the string buffer as a parameter. The default method + * returns false without action and can be overridden to + * implement user - defined SGML support. + *

      + * If you need more information about SGML insertions in HTML documents, + * the author suggests to read SGML tutorial on + * {@link http://www.w3.org/TR/WD-html40-970708/intro/sgmltut.html}. + * We also recommend Goldfarb C.F (1991) The SGML Handbook, + * Oxford University Press, 688 p, ISBN: 0198537379. + *

      + * @param strBuff + * @return true if this is a valid DTD markup declaration. + * @throws IOException + */ + public boolean parseMarkupDeclarations(StringBuffer strBuff) + throws IOException + { + return false; + } + + /** + * Get the first line of the last parsed token. + */ + protected int getCurrentLine() + { + return hTag.where.beginLine; + } + + /** + * Read parseable character data, add to buffer. + * @param clearBuffer If true, buffer if filled by CDATA section, + * otherwise the section is appended to the existing content of the + * buffer. + * + * @throws ParseException + */ + protected void CDATA(boolean clearBuffer) + throws ParseException + { + Token start = hTag = getTokenAhead(); + + if (clearBuffer) + buffer.setLength(0); + + // Handle expected EOF. + if (start.kind == EOF) + return; + + read: + while (true) + { + t = getTokenAhead(); + if (t.kind == EOF) + { + error("unexpected eof", t); + break read; + } + else if (t.kind == BEGIN) + break read; + else if (t.kind == Constants.ENTITY) + { + resolveAndAppendEntity(t); + getNextToken(); + } + else + { + append(t); + getNextToken(); + } + } + hTag = new Token(start, getTokenAhead(0)); + if (buffer.length() != 0) + _handleText(); + } + + /** + * Process Comment. This method skips till --> without + * taking SGML constructs into consideration. The supported SGML + * constructs are handled separately. + */ + protected void Comment() + throws ParseException + { + buffer.setLength(0); + + Token start = hTag = mustBe(BEGIN); + optional(WS); + mustBe(EXCLAMATION); + optional(WS); + mustBe(DOUBLE_DASH); + + Token t; + Token last; + + comment: + while (true) + { + t = getTokenAhead(); + if (t.kind == EOF) + { + handleEOFInComment(); + last = t; + break comment; + } + else if (COMMENT_END.matches(this)) + { + mustBe(DOUBLE_DASH); + optional(WS); + last = mustBe(END); + break comment; + } + else if (COMMENT_TRIPLEDASH_END.matches(this)) + { + mustBe(DOUBLE_DASH); + t = mustBe(NUMTOKEN); + if (t.getImage().equals("-")) + { + append(t); + last = mustBe(END); + break comment; + } + else + { + buffer.append("--"); + append(t); + t = getTokenAhead(); + } + } + else + /* The lllll-- can match as NUMTOKEN */ + if ((t.getImage().endsWith("--")) && + ( + getTokenAhead(1).kind == END || + (getTokenAhead(1).kind == WS && getTokenAhead(2).kind == END) + ) + ) + { + buffer.append(t.getImage().substring(0, t.getImage().length() - 2)); + + /* Skip the closing > that we have already checked. */ + last = mustBe(t.kind); + break comment; + } + else + append(t); + mustBe(t.kind); + } + hTag = new Token(start, last); + + // Consume any whitespace immediately following a comment. + optional(WS); + handleComment(); + } + + /** + * Read a script. The text, returned without any changes, + * is terminated only by the closing tag SCRIPT. + */ + protected void Script() + throws ParseException + { + Token name; + + Token start = hTag = mustBe(BEGIN); + optional(WS); + + name = mustBe(SCRIPT); + + optional(WS); + + restOfTag(false, name, start); + + buffer.setLength(0); + + while (!SCRIPT_CLOSE.matches(this)) + { + append(getNextToken()); + } + + consume(SCRIPT_CLOSE); + + _handleText(); + + endTag(false); + _handleEndTag(makeTagElement(name.getImage(), false)); + } + + /** + * Process SGML insertion that is not a comment. + */ + protected void Sgml() + throws ParseException + { + if (COMMENT_OPEN.matches(this)) + Comment(); + else // skip till ">" + { + Token start = hTag = mustBe(BEGIN); + optional(WS); + mustBe(EXCLAMATION); + + buffer.setLength(0); + read: + while (true) + { + t = getNextToken(); + if (t.kind == Constants.ENTITY) + { + resolveAndAppendEntity(t); + } + else if (t.kind == EOF) + { + error("unexpected eof", t); + break read; + } + else if (t.kind == END) + break read; + else + append(t); + } + + try + { + parseMarkupDeclarations(buffer); + } + catch (IOException ex) + { + error("Unable to parse SGML insertion: '" + buffer + "'", + new Token(start, t) + ); + } + } + // Consume any whitespace that follows the Sgml insertion. + optional(WS); + } + + /** + * Read a style definition. The text, returned without any changes, + * is terminated only by the closing tag STYLE. + */ + protected void Style() + throws ParseException + { + Token name; + + Token start = hTag = mustBe(BEGIN); + optional(WS); + + name = mustBe(STYLE); + + optional(WS); + + restOfTag(false, name, start); + + buffer.setLength(0); + + while (!STYLE_CLOSE.matches(this)) + { + append(getNextToken()); + } + + consume(STYLE_CLOSE); + + _handleText(); + + endTag(false); + _handleEndTag(makeTagElement(name.getImage(), false)); + } + + /** + * Read a html tag. + */ + protected void Tag() + throws ParseException + { + mark(true); + + boolean closing = false; + Token name; + Token start = hTag = mustBe(BEGIN); + + optional(WS); + name = getNextToken(); + optional(WS); + + if (name.kind == SLASH) + { + closing = true; + name = getNextToken(); + } + + restOfTag(closing, name, start); + } + + /** + * A hook, for operations, preceeding call to handleText. + * Handle text in a string buffer. + * In non - preformatted mode, all line breaks immediately following the + * start tag and immediately before an end tag is discarded, + * \r, \n and \t are replaced by spaces, multiple space are replaced + * by the single one and the result is moved into array, + * passing it to handleText(). + */ + protected void _handleText() + { + char[] text; + + if (preformatted > 0) + text = textProcessor.preprocessPreformatted(buffer); + else + text = textProcessor.preprocess(buffer); + + if (text != null && text.length > 0 + // According to the specs we need to discard whitespace immediately + // before a closing tag. + && (text.length > 1 || text[0] != ' ' || ! TAG_CLOSE.matches(this))) + { + TagElement pcdata = new TagElement(dtd.getElement("#pcdata")); + attributes = htmlAttributeSet.EMPTY_HTML_ATTRIBUTE_SET; + _handleEmptyTag(pcdata); + + handleText(text); + if (titleOpen) + title.append(text); + } + } + + /** + * Add the image of this token to the buffer. + * @param t A token to append. + */ + protected final void append(Token t) + { + if (t.kind != EOF) + t.appendTo(buffer); + } + + /** + * Consume pattern that must match. + * @param p A pattern to consume. + */ + protected final void consume(pattern p) + { + node n; + for (int i = 0; i < p.nodes.length; i++) + { + n = p.nodes [ i ]; + if (n.optional) + optional(n.kind); + else + mustBe(n.kind); + } + } + + /** + * The method is called when the HTML end (closing) tag is found or if + * the parser concludes that the one should be present in the + * current position. The method is called immediatly + * before calling the handleEndTag(). + * @param omitted True if the tag is no actually present in the document, + * but is supposed by the parser (like </html> at the end of the + * document). + */ + protected void endTag(boolean omitted) + { + } + + /** + * Handle HTML comment. The default method returns without action. + * @param comment + */ + protected void handleComment(char[] comment) + { + } + + /** + * This is additionally called in when the HTML content terminates + * without closing the HTML comment. This can only happen if the + * HTML document contains errors (for example, the closing --;gt is + * missing. + */ + protected void handleEOFInComment() + { + error("Unclosed comment"); + } + + /** + * Handle the tag with no content, like <br>. The method is + * called for the elements that, in accordance with the current DTD, + * has an empty content. + * @param tag The tag being handled. + * @throws javax.swing.text.ChangedCharSetException + */ + protected void handleEmptyTag(TagElement tag) + throws javax.swing.text.ChangedCharSetException + { + } + + /** + * The method is called when the HTML closing tag ((like </table>) + * is found or if the parser concludes that the one should be present + * in the current position. + * @param tag The tag + */ + protected void handleEndTag(TagElement tag) + { + } + + /* Handle error that has occured in the given line. */ + protected void handleError(int line, String message) + { + } + + /** + * The method is called when the HTML opening tag ((like <table>) + * is found or if the parser concludes that the one should be present + * in the current position. + * @param tag The tag + */ + protected void handleStartTag(TagElement tag) + { + } + + /** + * Handle the text section. + *

      For non-preformatted section, the parser replaces + * \t, \r and \n by spaces and then multiple spaces + * by a single space. Additionaly, all whitespace around + * tags is discarded. + *

      + *

      For pre-formatted text (inside TEXAREA and PRE), the parser preserves + * all tabs and spaces, but removes one bounding \r, \n or \r\n, + * if it is present. Additionally, it replaces each occurence of \r or \r\n + * by a single \n.

      + * + * @param text A section text. + */ + protected void handleText(char[] text) + { + } + + /** + * Handle HTML <title> tag. This method is invoked when + * both title starting and closing tags are already behind. + * The passed argument contains the concatenation of all + * title text sections. + * @param title The title text. + */ + protected void handleTitle(char[] title) + { + } + + /** + * Constructs the tag from the given element. In this implementation, + * this is defined, but never called. + * @return the tag + */ + protected TagElement makeTag(Element element) + { + return makeTag(element, false); + } + + /** + * Constructs the tag from the given element. + * @param the tag base {@link javax.swing.text.html.parser.Element} + * @param isSupposed true if the tag is not actually present in the + * html input, but the parser supposes that it should to occur in + * the current location. + * @return the tag + */ + protected TagElement makeTag(Element element, boolean isSupposed) + { + return new TagElement(element, isSupposed); + } + + /** + * This is called when the tag, representing the given element, + * occurs first time in the document. + * @param element + */ + protected void markFirstTime(Element element) + { + } + + /** + * Consume the token that was checked before and hence MUST be present. + * @param kind The kind of token to consume. + */ + protected Token mustBe(int kind) + { + if (getTokenAhead().kind == kind) + return getNextToken(); + else + { + String ei = ""; + if (kind < 1000) + ei = " ('" + (char) kind + "') "; + throw new AssertionError("The token of kind " + kind + ei + + " MUST be here," + ); + } + } + + /** + * Handle attribute without value. The default method uses + * the only allowed attribute value from DTD. + * If the attribute is unknown or allows several values, + * the HTML.NULL_ATTRIBUTE_VALUE is used. The attribute with + * this value is added to the attribute set. + * @param element The name of element. + * @param attribute The name of attribute without value. + */ + protected void noValueAttribute(String element, String attribute) + { + Object value = HTML.NULL_ATTRIBUTE_VALUE; + + Element e = dtd.elementHash.get(element.toLowerCase()); + if (e != null) + { + AttributeList attr = e.getAttribute(attribute); + if (attr != null) + { + Vector values = attr.values; + if (values != null && values.size() == 1) + value = values.get(0); + } + } + attributes.addAttribute(attribute, value); + } + + /** + * Consume the optional token, if present. + * @param kind The kind of token to consume. + */ + protected Token optional(int kind) + { + if (getTokenAhead().kind == kind) + return getNextToken(); + else + return null; + } + + /** Parse the html document. */ + protected void parseDocument() + throws ParseException + { + // Read up any initial whitespace. + optional(WS); + while (getTokenAhead().kind != EOF) + { + advanced = false; + if (TAG.matches(this)) + Tag(); + else if (COMMENT_OPEN.matches(this)) + Comment(); + else if (STYLE_OPEN.matches(this)) + Style(); + else if (SCRIPT_OPEN.matches(this)) + Script(); + else if (SGML.matches(this)) + Sgml(); + else + CDATA(true); + + // Surely HTML error, treat as a text. + if (!advanced) + { + Token wrong = getNextToken(); + error("unexpected '" + wrong.getImage() + "'", wrong); + buffer.setLength(0); + buffer.append(wrong.getImage()); + _handleText(); + } + } + } + + /** + * Read the element attributes, adding them into attribute set. + * @param element The element name (needed to access attribute + * information in dtd). + */ + protected void readAttributes(String element) + { + Token name; + Token value; + Token next; + String attrValue; + + attributes = new htmlAttributeSet(); + + optional(WS); + + attributeReading: + while (getTokenAhead().kind == NUMTOKEN) + { + name = getNextToken(); + optional(WS); + + next = getTokenAhead(); + if (next.kind == EQ) + { + mustBe(EQ); + optional(WS); + + next = getNextToken(); + + switch (next.kind) + { + case QUOT: + + // read "quoted" attribute. + buffer.setLength(0); + readTillTokenE(QUOT); + attrValue = buffer.toString(); + break; + + case AP: + + // read 'quoted' attribute. + buffer.setLength(0); + readTillTokenE(AP); + attrValue = buffer.toString(); + break; + + // read unquoted attribute. + case NUMTOKEN: + value = next; + optional(WS); + + // Check maybe the opening quote is missing. + next = getTokenAhead(); + if (bQUOTING.get(next.kind)) + { + hTag = next; + error("The value without opening quote is closed with '" + + next.getImage() + "'"); + attrValue = value.getImage(); + } + else if (next.kind == SLASH || next.kind == OTHER) + // The slash and other characters (like %) in this context is + // treated as the ordinary + // character, not as a token. The character may be part of + // the unquoted URL. + { + CPStringBuilder image = new CPStringBuilder(value.getImage()); + while (next.kind == NUMTOKEN || next.kind == SLASH + || next.kind == OTHER) + { + image.append(getNextToken().getImage()); + next = getTokenAhead(); + } + attrValue = image.toString(); + } + else + attrValue = value.getImage(); + break; + + case SLASH: + value = next; + optional(WS); + + // Check maybe the opening quote is missing. + next = getTokenAhead(); + if (bQUOTING.get(next.kind)) + { + hTag = next; + error("The value without opening quote is closed with '" + + next.getImage() + "'"); + attrValue = value.getImage(); + } + else if (next.kind == NUMTOKEN || next.kind == SLASH) + // The slash in this context is treated as the ordinary + // character, not as a token. The slash may be part of + // the unquoted URL. + { + CPStringBuilder image = new CPStringBuilder(value.getImage()); + while (next.kind == NUMTOKEN || next.kind == SLASH) + { + image.append(getNextToken().getImage()); + next = getTokenAhead(); + } + attrValue = image.toString(); + } + else + attrValue = value.getImage(); + break; + default: + break attributeReading; + } + attributes.addAttribute(name.getImage(), attrValue); + optional(WS); + } + else + // The '=' is missing: attribute without value. + { + noValueAttribute(element, name.getImage()); + } + } + } + + /** + * Return string, corresponding the given named entity. The name is passed + * with the preceeding &, but without the ending semicolon. + */ + protected String resolveNamedEntity(final String a_tag) + { + // Discard & + if (!a_tag.startsWith("&")) + throw new AssertionError("Named entity " + a_tag + + " must start witn '&'." + ); + + String tag = a_tag.substring(1); + + try + { + Entity entity = dtd.getEntity(tag); + if (entity != null) + return entity.getString(); + + entity = dtd.getEntity(tag.toLowerCase()); + + if (entity != null) + { + error("The name of this entity should be in lowercase", a_tag); + return entity.getString(); + } + } + catch (IndexOutOfBoundsException ibx) + { + /* The error will be reported. */ + } + + error("Unknown named entity", a_tag); + return a_tag; + } + + /** + * Return char, corresponding the given numeric entity. + * The name is passed with the preceeding &#, but without + * the ending semicolon. + */ + protected char resolveNumericEntity(final String a_tag) + { + // Discard &# + if (!a_tag.startsWith("&#")) + throw new AssertionError("Numeric entity " + a_tag + + " must start witn '&#'." + ); + + String tag = a_tag.substring(2); + + try + { + // Determine the encoding type: + char cx = tag.charAt(0); + if (cx == 'x' || cx == 'X') // Hexadecimal &#Xnnn; + + return (char) Integer.parseInt(tag.substring(1), 16); + + return (char) Integer.parseInt(tag); + } + + /* The error will be reported. */ + catch (NumberFormatException nex) + { + } + catch (IndexOutOfBoundsException ix) + { + } + + error("Invalid numeric entity", a_tag); + return '?'; + } + + /** + * Reset all fields into the intial default state, preparing the + * parset for parsing the next document. + */ + protected void restart() + { + documentTags.clear(); + titleHandled = false; + titleOpen = false; + buffer.setLength(0); + title.setLength(0); + validator.restart(); + } + + /** + * The method is called when the HTML opening tag ((like <table>) + * is found or if the parser concludes that the one should be present + * in the current position. The method is called immediately before + * calling the handleStartTag. + * @param tag The tag + */ + protected void startTag(TagElement tag) + throws ChangedCharSetException + { + } + + /** + * Handle a complete element, when the tag content is already present in the + * buffer and both starting and heading tags behind. This is called + * in the case when the tag text must not be parsed for the nested + * elements (elements STYLE and SCRIPT). + */ + private void _handleCompleteElement(TagElement tag) + { + _handleStartTag(tag); + + // Suppress inclusion of the SCRIPT ans STYLE texts into the title. + HTML.Tag h = tag.getHTMLTag(); + if (h == HTML.Tag.SCRIPT || h == HTML.Tag.STYLE) + { + boolean tmp = titleOpen; + titleOpen = false; + _handleText(); + titleOpen = tmp; + } + else + _handleText(); + + _handleEndTag(tag); + } + + /** + * A hooks for operations, preceeding call to handleEmptyTag(). + * Handle the tag with no content, like <br>. As no any + * nested tags are expected, the tag validator is not involved. + * @param tag The tag being handled. + */ + private void _handleEmptyTag(TagElement tag) + { + try + { + validator.validateTag(tag, attributes); + handleEmptyTag(tag); + HTML.Tag h = tag.getHTMLTag(); + // When a block tag is closed, consume whitespace that follows after + // it. + // For some unknown reason a FRAME tag is not treated as block element. + // However in this case it should be treated as such. + if (isBlock(h)) + optional(WS); + } + catch (ChangedCharSetException ex) + { + error("Changed charset exception:", ex.getMessage()); + } + } + + /** + * A hooks for operations, preceeding call to handleEndTag(). + * The method is called when the HTML closing tag + * is found. Calls handleTitle after closing the 'title' tag. + * @param tag The tag + */ + private void _handleEndTag(TagElement tag) + { + if (validator.closeTag(tag)) + _handleEndTag_remaining(tag); + } + + /** + * Actions that are also required if the closing action was + * initiated by the tag validator. + * Package-private to avoid an accessor method. + */ + void _handleEndTag_remaining(TagElement tag) + { + HTML.Tag h = tag.getHTMLTag(); + + handleEndTag(tag); + endTag(tag.fictional()); + + if (h.isPreformatted()) + preformatted--; + if (preformatted < 0) + preformatted = 0; + + // When a block tag is closed, consume whitespace that follows after + // it. + if (isBlock(h)) + optional(WS); + + if (h == HTML.Tag.TITLE) + { + titleOpen = false; + titleHandled = true; + + char[] a = new char[ title.length() ]; + title.getChars(0, a.length, a, 0); + handleTitle(a); + } + } + + /** + * A hooks for operations, preceeding call to handleStartTag(). + * The method is called when the HTML opening tag ((like <table>) + * is found. + * Package-private to avoid an accessor method. + * @param tag The tag + */ + void _handleStartTag(TagElement tag) + { + validator.openTag(tag, attributes); + startingTag(tag); + handleStartTag(tag); + + HTML.Tag h = tag.getHTMLTag(); + + if (isBlock(h)) + optional(WS); + + if (h.isPreformatted()) + preformatted++; + + if (h == HTML.Tag.TITLE) + { + if (titleHandled) + error("Repetetive tag"); + titleOpen = true; + titleHandled = false; + } + } + + /** + * Resume parsing after heavy errors in HTML tag structure. + * @throws ParseException + */ + private void forciblyCloseTheTag() + throws ParseException + { + int closeAt = 0; + buffer.setLength(0); + + ahead: + for (int i = 1; i < 100; i++) + { + t = getTokenAhead(i - 1); + if (t.kind == EOF || t.kind == BEGIN) + break ahead; + if (t.kind == END) + { + /* Closing '>' found. */ + closeAt = i; + break ahead; + } + } + if (closeAt > 0) + { + buffer.append("Ignoring '"); + for (int i = 1; i <= closeAt; i++) + { + t = getNextToken(); + append(t); + } + buffer.append('\''); + error(buffer.toString()); + } + } + + /** + * Handle comment in string buffer. You can avoid allocating a char + * array each time by processing your comment directly here. + */ + private void handleComment() + { + char[] a = new char[ buffer.length() ]; + buffer.getChars(0, a.length, a, 0); + handleComment(a); + } + + private TagElement makeTagElement(String name, boolean isSupposed) + { + Element e = dtd.elementHash.get(name.toLowerCase()); + if (e == null) + { + error("Unknown tag <" + name + ">"); + e = dtd.getElement(name); + e.name = name.toUpperCase(); + e.index = -1; + } + + if (!documentTags.contains(e.name)) + { + markFirstTime(e); + documentTags.add(e.name); + } + + return makeTag(e, isSupposed); + } + + /** + * Read till the given token, resolving entities. Consume the given + * token without adding it to buffer. + * @param till The token to read till + * @throws ParseException + */ + private void readTillTokenE(int till) + throws ParseException + { + buffer.setLength(0); + read: + while (true) + { + t = getNextToken(); + if (t.kind == Constants.ENTITY) + { + resolveAndAppendEntity(t); + } + else if (t.kind == EOF) + { + error("unexpected eof", t); + break read; + } + else if (t.kind == till) + break read; + else if (t.kind == WS) + { + // Processing whitespace in accordance with CDATA rules: + String s = t.getImage(); + char c; + for (int i = 0; i < s.length(); i++) + { + c = s.charAt(i); + if (c == '\r') + buffer.append(' '); // CR replaced by space + else if (c == '\n') + { /* LF ignored */ } + else if (c == '\t') + buffer.append(' '); // Tab replaced by space + else + buffer.append(c); + } + } + else + append(t); + } + } + + /** + * Resolve the entity and append it to the end of buffer. + * @param entity + */ + private void resolveAndAppendEntity(Token entity) + { + switch (entity.category) + { + case ENTITY_NAMED : + buffer.append(resolveNamedEntity(entity.getImage())); + break; + + case ENTITY_NUMERIC : + buffer.append(resolveNumericEntity(entity.getImage())); + break; + + default : + throw new AssertionError("Invalid entity category " + + entity.category + ); + } + } + + /** + * Handle the remaining of HTML tags. This is a common end for + * TAG, SCRIPT and STYLE. + * @param closing True for closing tags ( </TAG> ). + * @param name Name of element + * @param start Token where element has started + * @throws ParseException + */ + private void restOfTag(boolean closing, Token name, Token start) + throws ParseException + { + boolean end = false; + Token next; + + optional(WS); + + readAttributes(name.getImage()); + + optional(WS); + + next = getTokenAhead(); + if (next.kind == END) + { + mustBe(END); + end = true; + } + + hTag = new Token(start, next); + + if (!end) + { + // The tag body contains errors. If additionally the tag + // name is not valid, this construction is treated as text. + if (dtd.elementHash.get(name.getImage().toLowerCase()) == null && + backupMode + ) + { + error("Errors in tag body and unknown tag name. " + + "Treating the tag as a text." + ); + reset(); + + hTag = mustBe(BEGIN); + buffer.setLength(0); + buffer.append(hTag.getImage()); + CDATA(false); + return; + } + else + { + error("Forcibly closing invalid parameter list"); + forciblyCloseTheTag(); + } + } + + if (closing) + { + endTag(false); + _handleEndTag(makeTagElement(name.getImage(), false)); + } + else + { + TagElement te = makeTagElement(name.getImage(), false); + if (te.getElement().type == DTDConstants.EMPTY) + _handleEmptyTag(te); + else + { + // According to the specs we need to consume whitespace following + // immediately after a opening tag. + optional(WS); + _handleStartTag(te); + } + } + } + + /** + * This should fire additional actions in response to the + * ChangedCharSetException. The current implementation + * does nothing. + * @param tag + */ + private void startingTag(TagElement tag) + { + try + { + startTag(tag); + } + catch (ChangedCharSetException cax) + { + error("Invalid change of charset"); + } + } + + private void ws_error() + { + error("Whitespace here is not permitted"); + } + + /** + * Returns true when the specified tag should be considered a block tag + * wrt whitespace handling. We need this special handling, since there + * are a couple of tags that we must treat as block tags but which aren't + * officially block tags. + * + * @param tag the tag to check + * @return true when the specified tag should be considered a block tag + * wrt whitespace handling + */ + private boolean isBlock(HTML.Tag tag) + { + return tag.isBlock() || tag == HTML.Tag.STYLE || tag == HTML.Tag.FRAME; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/gnuStringIntMapper.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/gnuStringIntMapper.java new file mode 100644 index 000000000..9cdf810dd --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/gnuStringIntMapper.java @@ -0,0 +1,112 @@ +/* gnuStringIntMapper.java -- + 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.swing.text.html.parser.support; + +import java.util.HashMap; +import java.util.Map; +import java.util.TreeMap; + +/** + * A helper class, mapping between the strings and they unique integer + * identifiers. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public abstract class gnuStringIntMapper +{ + /** + * Maps argument integer values from DTDConstants into they string + * names. Initialized on demand. + */ + private Map is_Map; + + /** + * Maps argument string names into they integer values from DTDConstants. + * Initialized on demand. + */ + private Map si_Map; + + /** + * Get string from id or null if no such id is present in the mapper. + */ + public final String get(int id) + { + if (is_Map == null) + createTheMap(); + + return (String) is_Map.get(new Integer(id)); + } + + /** Get id from string or 0 if no such string is present in the mapper. */ + public final int get(String id) + { + if (si_Map == null) + createTheMap(); + + Integer i = (Integer) si_Map.get(id); + + return i != null ? i.intValue() : 0; + } + + /** + * Create the mapping table for this mapper by adding the required + * String/int pairs. The method is invoked + * only once for each instance, after the first invocation of the any + * form of the <code>get</code> method. Use <code>add</code> to + * create a map for a concrete instance. + */ + protected abstract void create(); + + /** + * Add an id/string pair to this mapper. This is called from + * the method <code>create</code> only. + */ + protected void add(String name, int id) + { + Integer i = new Integer(id); + si_Map.put(name, i); + is_Map.put(i, name); + } + + private void createTheMap() + { + is_Map = new HashMap(); + si_Map = new TreeMap(); + create(); + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Buffer.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Buffer.java new file mode 100644 index 000000000..a39330af8 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Buffer.java @@ -0,0 +1,238 @@ +/* Buffer.java -- + 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.swing.text.html.parser.support.low; + +/** + * A string buffer that additionally holds line and absolute postion + * information. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class Buffer +{ + public static int INITIAL_SIZE = 2048; + + /** + * True if the \n symbol has been seen. + */ + public boolean n_seen; + + /** + * True if the \r symbol has been seen. + */ + public boolean r_seen; + char[] chr = new char[ INITIAL_SIZE ]; + int[] line = new int[ INITIAL_SIZE ]; + int[] position = new int[ INITIAL_SIZE ]; + + /** + * Current line. + */ + int current_line = 0; + + /** + * Point to the next free position. + */ + int length; + + public Buffer() + { + } + + public Buffer(String content) + { + for (int i = 0; i < content.length(); i++) + { + append(content.charAt(i), i); + } + } + + /** + * Get the characters into array. + * @param srcBegin From, inclusive + * @param srcEnd To, exclusive. + * @param dst Into + * @param dstBegin Offset. + */ + public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) + { + System.arraycopy(chr, srcBegin, dst, dstBegin, (srcEnd - srcBegin)); + } + + /** + * Return the sequence, used to separate lines in the document. + * @return one of \n, \r or \r\n. + */ + public String getEndOfLineSequence() + { + if (r_seen && n_seen) + return "\r\n"; + else if (r_seen) + return "\r"; + else + + // This also is returned for single-line document. + return "\n"; + } + + /** + * Truncate. + * @param n The length to truncate till. + */ + public void setLength(int n) + { + length = n; + } + + /** + * Get location information for the given region. + * @param from Region start, inclusive. + * @param to Region end, exclusive. + * @return The location, covering the region. + */ + public Location getLocation(int from, int to) + { + Location l = new Location(); + l.beginLine = line [ from ]; + l.endLine = line [ to - 1 ]; + + l.startPosition = position [ from ]; + l.endPosition = position [ to - 1 ] + 1; + + return l; + } + + /** + * Add the character. + * @param c The character. + * @param pos The character position in the stream (the line number + * is handled internally in the buffer). + */ + public void append(char c, int pos) + { + if (length >= chr.length) + expand(); + chr [ length ] = c; + position [ length ] = pos; + + if (c == '\n') + { + if (!r_seen) + current_line++; + n_seen = true; + } + else if (c == '\r') + { + current_line++; + r_seen = true; + } + + line [ length ] = current_line; + + length++; + } + + /** + * Return char at the given positon. + */ + public char charAt(int i) + { + return chr [ i ]; + } + + /** + * Delete the range + * @param from Start position, inclusive. + * @param to End position, exclusive. + */ + public void delete(int from, int to) + { + int len = to - from; + if (len < 1) + throw new AssertionError("Deleting " + from + " till " + to); + + int tail = length - to; + + System.arraycopy(chr, to, chr, from, tail); + System.arraycopy(position, to, position, from, tail); + System.arraycopy(line, to, line, from, tail); + length = length - len; + } + + /** + * Double the buffer size. + */ + public void expand() + { + int nSize = 2 * chr.length; + + char[] nchr = new char[ nSize ]; + int[] nposition = new int[ nSize ]; + int[] nline = new int[ nSize ]; + + System.arraycopy(chr, 0, nchr, 0, chr.length); + System.arraycopy(position, 0, nposition, 0, position.length); + System.arraycopy(line, 0, nline, 0, line.length); + + chr = nchr; + position = nposition; + line = nline; + } + + /** + * Return length of the occupied part of the buffer. + */ + public int length() + { + return length; + } + + /** + * Prepare for parsing the new document. + */ + public void reset() + { + setLength(0); + r_seen = n_seen = false; + } + + public String toString() + { + return new String(chr, 0, length); + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Constants.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Constants.java new file mode 100644 index 000000000..5416582ad --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Constants.java @@ -0,0 +1,433 @@ +/* Constants.java -- + 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.swing.text.html.parser.support.low; + +import java.util.BitSet; + +/** + * The parser constants and operations, directly related to the parser + * constants. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class Constants +{ + /* Single character tokens are reflected into they ASCII codes. */ + + /** + * Start of HTML token. + */ + public static final int BEGIN = '<'; + + /** + * End of HTML token. + */ + public static final int END = '>'; + + /** + * Exclamation (indicates SGML or comment). + */ + public static final int EXCLAMATION = '!'; + + /** + * Slash (indicates closing tag). + */ + public static final int SLASH = '/'; + + /** + * Equals sign. + */ + public static final int EQ = '='; + + /** + * Quoting sign. + */ + public static final int AP = '\''; + + /** + * Quoting sign. + */ + public static final int QUOT = '"'; + + /* The numbers of other tokens start outside the ascii space. */ + /* String tokens */ + + /** + * Double dash (--) + */ + public static final int DOUBLE_DASH = 1000; + + /** + * The STYLE tag (needs special handling). + */ + public static final int STYLE = 1001; + + /** + * The SCRIPT tag (needs special handling). + */ + public static final int SCRIPT = 1002; + + /* Pattern tokens */ + + /** + * HTML whitespace. + */ + public static final int WS = 1003; + + /** + * Named or numeric entity, + */ + public static final int ENTITY = 1004; + + /** + * Sequence of valid name characters (can start from digit). + */ + public static final int NUMTOKEN = 1005; + + /* Complex tokens */ + + /** + * Comment opening sequence. + */ + public static final pattern COMMENT_OPEN = + new pattern(new node[] + { + new node(BEGIN), new node(WS, true), new node(EXCLAMATION), + new node(WS, true), new node(DOUBLE_DASH), + } + ); + + /** + * Comment closing sequence + */ + public static final pattern COMMENT_END = + new pattern(new node[] + { + new node(DOUBLE_DASH), new node(WS, true), new node(END) + } + ); + + /** + * Special case ---> (also is treated as end of comment). + */ + public static final pattern COMMENT_TRIPLEDASH_END = + new pattern(new node[] + { + new node(DOUBLE_DASH), new node(NUMTOKEN), new node(END) + } + ); + + /** + * STYLE element heading pattern. + */ + public static final pattern STYLE_OPEN = + new pattern(new node[] { new node(BEGIN), new node(WS, true), new node(STYLE) }); + + /** + * SCRIPT element heading pattern. + */ + public static final pattern SCRIPT_OPEN = + new pattern(new node[] { new node(BEGIN), new node(WS, true), new node(SCRIPT) }); + + /** + * SGML element heading pattern. + */ + public static final pattern SGML = + new pattern(new node[] + { + new node(BEGIN), new node(WS, true), new node(EXCLAMATION) + } + ); + + /** + * SCRIPT element closing pattern. + */ + public static final pattern SCRIPT_CLOSE = + new pattern(new node[] + { + new node(BEGIN), new node(WS, true), new node(SLASH), + new node(WS, true), new node(SCRIPT), new node(WS, true), + new node(END) + } + ); + + /** + * STYLE element closing pattern. + */ + public static final pattern STYLE_CLOSE = + new pattern(new node[] + { + new node(BEGIN), new node(WS, true), new node(SLASH), + new node(WS, true), new node(STYLE), new node(WS, true), + new node(END) + } + ); + + /** + * Ordinary HTML tag heading pattern. + */ + public static final pattern TAG = + new pattern(new node[] + { + new node(BEGIN), new node(WS, true), new node(SLASH, true), + new node(WS, true), new node(NUMTOKEN) + } + ); + + /** + * Ordinary HTML tag closing pattern. + */ + public static final pattern TAG_CLOSE = + new pattern(new node[] + { + new node(BEGIN), new node(WS, true), new node(SLASH), + new node(WS, true), new node(NUMTOKEN) + } + ); + + /* Special tokens */ + + /** + * All other tokens. + */ + public static final int OTHER = 1999; + + /** + * The UNICODE "end of text" control code + */ + static final char ETX = 3; + + /** + * End of file. + */ + public static final int EOF = ETX; + + /* Character categories */ + + /** + * All single char tokens. + */ + public static final BitSet bSINGLE_CHAR_TOKEN = new BitSet(); + + /** + * Non letters and non numbers, allowed in HTML names. + */ + public static final BitSet bSPECIAL = new BitSet(); + + /** + * All letters, used in HTML names. + */ + public static final BitSet bLETTER = new BitSet(); + + /** + * Digits. + */ + public static final BitSet bDIGIT = new BitSet(); + + /** + * Both line breaks. + */ + public static final BitSet bLINEBREAK = new BitSet(); + + /** + * All whitespace. + */ + public static final BitSet bWHITESPACE = new BitSet(); + + /** + * Both quoting characters. + */ + public static final BitSet bQUOTING = new BitSet(); + + /** + * Valid name characters. + */ + public static final BitSet bNAME = new BitSet(); + + /* Entity subcategories */ + + /** + * Named entity. + */ + public static final int ENTITY_NAMED = 1; + + /** + * Numeric entity. + */ + public static final int ENTITY_NUMERIC = 2; + + static + { + bQUOTING.set(AP); + bQUOTING.set(QUOT); + + bSINGLE_CHAR_TOKEN.set(BEGIN); + bSINGLE_CHAR_TOKEN.set(END); + bSINGLE_CHAR_TOKEN.set(EXCLAMATION); + bSINGLE_CHAR_TOKEN.set(SLASH); + bSINGLE_CHAR_TOKEN.set(EQ); + bSINGLE_CHAR_TOKEN.set(EOF); + + bSINGLE_CHAR_TOKEN.or(bQUOTING); + + bLINEBREAK.set('\r'); + bLINEBREAK.set('\n'); + + bWHITESPACE.set(' '); + bWHITESPACE.set('\t'); + bWHITESPACE.set(0xC); + bWHITESPACE.or(bLINEBREAK); + + for (char i = '0'; i <= '9'; i++) + { + bDIGIT.set(i); + } + + for (char i = 'a'; i <= 'z'; i++) + { + bLETTER.set(i); + } + + for (char i = 'A'; i <= 'Z'; i++) + { + bLETTER.set(i); + } + + bSPECIAL.set('-'); + bSPECIAL.set('_'); + bSPECIAL.set(':'); + bSPECIAL.set('.'); + + bNAME.or(bLETTER); + bNAME.or(bDIGIT); + bNAME.or(bSPECIAL); + } + + /** + * Verifies if one of the tokens matches the end of string + * buffer. The last character in the string buffer is the + * "future character", some tokens needs to verify it the + * token does not continue "towards the future". If the token + * matches, it matches till "pre-last" character in the buffer. + * @param b + * @return + */ + public Token endMatches(Buffer b) + { + if (b.length() < 2) + return null; + + int p = b.length() - 2; + + if (b.length() > 2 && b.charAt(p) == '-' && b.charAt(p - 1) == '-') + return new Token(DOUBLE_DASH, "--", b.getLocation(p - 1, p + 1)); + + char last = b.charAt(p); + + if (bSINGLE_CHAR_TOKEN.get(last)) + return new Token(last, last, b.getLocation(p, p + 1)); + + char future = b.charAt(p + 1); + + // Check for numtokens, script and style: + if (bNAME.get(last) && !bNAME.get(future)) + { + // Scan the history up: + int u = p - 1; + while (u >= 0 && bNAME.get(b.charAt(u))) + u--; + u++; + + char[] token = new char[ p - u + 1 ]; + + // Found a numtoken + b.getChars(u, p + 1, token, 0); + + // Verify for the built-in tokens: + String e = new String(token); + + // found the entity reference + if (u > 0 && b.charAt(u - 1) == '&') + { + // The subsequent semicolon may be the part of the token + // as well. The semicolon must be ignored. This must be + // handled elsewhere. + return new Token(ENTITY, ENTITY_NAMED, "&" + e, + b.getLocation(u - 1, p + 1) + ); + } + + // found the numeric entity reference + if (u > 1 && b.charAt(u - 1) == '#' && b.charAt(u - 2) == '&') + { + // The subsequent semicolon may be the part of the token + // as well. The semicolon must be ignored. This must be + // handled elsewhere. + return new Token(ENTITY, ENTITY_NUMERIC, "&#" + e, + b.getLocation(u - 2, p + 2) + ); + } + + Location le = b.getLocation(u, p + 1); + + if (e.equalsIgnoreCase("SCRIPT")) + return new Token(SCRIPT, e, le); + else if (e.equalsIgnoreCase("STYLE")) + return new Token(STYLE, e, le); + else + return new Token(NUMTOKEN, e, le); + } + + // Check for whitespace + if (bWHITESPACE.get(last) && !bWHITESPACE.get(future)) + { + // Scan the history up: + int u = p - 1; + while (u >= 0 && bWHITESPACE.get(b.charAt(u))) + u--; + u++; + + char[] token = new char[ p - u + 1 ]; + b.getChars(u, p + 1, token, 0); + + return new Token(WS, new String(token), b.getLocation(u, p + 1)); + } + + return null; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Location.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Location.java new file mode 100644 index 000000000..8a1cde1c8 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Location.java @@ -0,0 +1,83 @@ +/* Location.java -- + 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.swing.text.html.parser.support.low; + +/** + * Defines a region in the text: its bounding positions and the line number. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class Location +{ + /** + * The line number, where the token starts. + */ + public int beginLine; + + /** + * The line, where the token ends. + */ + public int endLine; + + /** + * The absolute token end position in the input stream, + * exclusive. + */ + public int endPosition; + + /** + * The absolute token start position in the input stream, + * inclusive. + */ + public int startPosition; + + public Location() + { + } + + /** + * Special case, used to mark EOF. + * @param p The total stream length. + */ + public Location(int p) + { + startPosition = p; + endPosition = p + 1; + beginLine = endLine = -1; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/ParseException.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/ParseException.java new file mode 100644 index 000000000..e71c0c1f6 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/ParseException.java @@ -0,0 +1,51 @@ +/* ParseException.java -- + 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.swing.text.html.parser.support.low; + +/** + * This can be thrown from various parsing methods. + */ +public class ParseException + extends RuntimeException +{ + public ParseException(String s, Throwable cause) + { + super(s, cause); + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Queue.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Queue.java new file mode 100644 index 000000000..31cf4bb4d --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Queue.java @@ -0,0 +1,142 @@ +/* Queue.java -- a token queue. + 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.swing.text.html.parser.support.low; + +import java.util.Arrays; + +/** + * A token queue. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class Queue +{ + Token[] m = new Token[ 64 ]; + int a = 0; + int b = 0; + + /** + * True for the empty queue. + */ + public boolean isEmpty() + { + return size() == 0; + } + + /** + * Add this trace to the end of the queue. + */ + public void add(Token u) + { + if (a < m.length) + { + m [ a ] = u; + a++; + } + else // The end of array has been reached. + { + if (b > 0) // If some elements were deleted from the start of the queue, shift. + { + int d = b; + System.arraycopy(m, b, m, 0, a - b); + b = b - d; + a = a - d; + m [ a ] = u; + a++; + } + else // Enlarge the queue, doubling the size. + { + int n = m.length * 2; + Token[] nm = new Token[ 2 * n ]; + System.arraycopy(m, 0, nm, 0, m.length); + Arrays.fill(m, null); + + nm [ a ] = u; + m = nm; + a++; + } + } + } + + /** + * Clear the queue. + */ + public void clear() + { + a = b = 0; + Arrays.fill(m, null); + } + + /** + * Read the value ahead. 0 is the value that will be returned with + * the following next. This method does not remove values from the + * queue. To test if there is enough tokens in the queue, size() must + * be checked before calling this method. + */ + public Token get(int ahead) + { + int p = b + ahead; + if (p < a) + return m [ p ]; + else + throw new ArrayIndexOutOfBoundsException("Not enough tokens"); + } + + /** + * Read the oldest value from the queue and remove this value from + * the queue. + */ + public Token next() + { + if (a == b) + throw new ArrayIndexOutOfBoundsException("queue empty"); + + Token r = m [ b ]; + m [ b ] = null; + b++; + return r; + } + + /** + * Size of the queue. + */ + public int size() + { + return a - b; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/ReaderTokenizer.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/ReaderTokenizer.java new file mode 100644 index 000000000..45ac181b3 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/ReaderTokenizer.java @@ -0,0 +1,373 @@ +/* ReaderTokenizer.java -- splits the input char sequence int tokens. + 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.swing.text.html.parser.support.low; + +import java.io.IOException; +import java.io.Reader; + +/** + * Reader splits the input char sequence into tokens. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class ReaderTokenizer + extends Constants +{ + /** + * This is set to true each time the getNextToken is called. + * Used in preventing loops when all patterns refuse to accept + * the invalid input. + */ + protected boolean advanced; + + /** + * If true, the returned tokens are also placed in the backup + * queue. + */ + protected boolean backupMode; + + /** + * The buffer to read document into. + */ + Buffer buffer = new Buffer(); + + /** + * The queue for supporting mark(). + */ + Queue backup = new Queue(); + + /** + * The queue of found tokens. + */ + Queue queue = new Queue(); + + /** + * The reader to read the document from. + */ + Reader reader; + + /** + * Array of char tokens + */ + char[] charTokens; + + /** + * Array of string tokens. + */ + String[] stringTokens; + + /** + * The current reader position. + */ + int readerPosition = -1; + + /** + * Creates a new ReaderTokenizer. The reset(...) method must be + * subsequently called to set the reader. + */ + public ReaderTokenizer() + { + } + + /** + * Return the sequence, used to separate lines in the document. + * @return one of \n, \r or \r\n. + */ + public String getEndOfLineSequence() + { + return buffer.getEndOfLineSequence(); + } + + /** + * Get the next token. + * @return + */ + public Token getNextToken() + { + Token rt; + advanced = true; + try + { + if (queue.isEmpty()) + read(1); + + if (!queue.isEmpty()) + rt = queue.next(); + else + rt = new Token(EOF, new Location(readerPosition)); + } + catch (IOException ex) + { + throw new ParseException("IO Exception", ex); + } + if (backupMode) + backup.add(rt); + return rt; + } + + /** + * Get a token, lying the given number of tokens + * ahead. getToken(0) will return the same token, + * what would be returned by getNextToken(). + * getToken(..) does change the current position + * in the input stream. If the end of stream is + * reached, the EOF token is always returned. + */ + public Token getTokenAhead(int ahead) + { + try + { + read(ahead - queue.size() + 1); + return queue.size() >= ahead ? queue.get(ahead) : eofToken(); + } + catch (IOException ex) + { + throw new ParseException("IO Exception", ex); + } + } + + /** + * Get a token, bein immediatley ahead. + * If the end of stream is + * reached, the EOF token is always returned. + * The method is equivalent calling getTokenAhead(0). + */ + public Token getTokenAhead() + { + try + { + if (queue.isEmpty()) + read(1); + if (!queue.isEmpty()) + return queue.get(0); + else + return eofToken(); + } + catch (IOException ex) + { + throw new ParseException("IO Exception", ex); + } + } + + /** + * Invokes the error handler. + */ + public void error(String msg, Token at) + { + System.out.println(msg); + } + + /** + * Turns the backup mode on or off. + * It is possible to return where the mark(true) was last called + * by calling reset(). + * @param mode True if it is required to save tokens, making + * returning to the current point possible. + */ + public void mark(boolean mode) + { + backup.clear(); + backupMode = mode; + } + + /** + * Prepare for new parsing from the given stream. + * @param a_reader A reader to parse from. + */ + public void reset(Reader a_reader) + { + reader = a_reader; + readerPosition = -1; + buffer.reset(); + queue.clear(); + } + + /** + * Reset the internal cursor to the position where the mark() + * was last time called. Switches the backup mode off. + */ + public void reset() + { + if (!backupMode) + throw new AssertionError("Call mark(true) before using reset()!"); + backupMode = false; + + // That is now in the queue, will be appended to the end of backup. + while (!queue.isEmpty()) + backup.add(queue.next()); + + Queue t = queue; + queue = backup; + backup = t; + backup.clear(); + } + + /** + * Read the given number of the tokens. Add the needed number of EOF + * tokens if there are no more data in the stream. + * @param numberOfTokens The number of additional tokens to read. + */ + void read(int numberOfTokens) + throws IOException + { + if (numberOfTokens <= 0) + return; + + for (int i = 0; i < numberOfTokens; i++) + readToken(); + } + + /** + * Read next token from the reader, add it to the queue + */ + void readToken() + throws IOException + { + Token t; + int ch; + + enlarging: + while (true) + { + t = tokenMatches(); + if (t != null) + break enlarging; + else + { + ch = reader.read(); + readerPosition++; + if (ch == ETX) + ch = ' '; + if (ch < 0) + { + if (buffer.length() == 0) + { + queue.add(eofToken()); + return; + } + else + { + if (buffer.charAt(buffer.length() - 1) != ETX) + buffer.append(ETX, readerPosition++); + else + { + // Discard terminating ETX + buffer.setLength(buffer.length() - 1); + if (buffer.length() > 0) + { + t = new Token(OTHER, buffer.toString(), + buffer.getLocation(0, buffer.length()) + ); + queue.add(t); + buffer.setLength(0); + } + return; + } + } + } + else + buffer.append((char) ch, readerPosition); + } + } + } + + /** + * Check if the end of buffer matches one of the tokens. If it does, + * return this token and remove the token sequence from the end of + * buffer. + * @return The matching token. + */ + Token tokenMatches() + { + Token rt = endMatches(buffer); + if (rt != null) // Remove the matched image + { + // Consume future character if it was an entity and the future + // character is semicolon. + if (rt.kind == ENTITY) + { + if (buffer.charAt(buffer.length() - 1) == ';') + buffer.setLength(buffer.length() - rt.getImage().length() - 1); + else + { + error("Missing closing semicolon for entity '" + rt.getImage() + + "'", rt + ); + consumeBuffer(rt); + } + } + else + { + consumeBuffer(rt); + } + } + + // If the buffer is not empty, some sequence does not match any tokens. + // Add it to the queue as "OTHER". + if (rt != null) + { + if (buffer.length() > 1) + { + String rest = buffer.toString(); + rest = rest.substring(0, rest.length() - 1); + + Token other = + new Token(OTHER, rest, buffer.getLocation(0, buffer.length)); + queue.add(other); + consumeBuffer(other); + } + queue.add(rt); + } + return rt; + } + + private void consumeBuffer(Token rt) + { + buffer.delete(buffer.length() - rt.getImage().length() - 1, + buffer.length() - 1 + ); + } + + /** + * Create EOF token. + */ + private Token eofToken() + { + return new Token(EOF, "#", new Location(readerPosition)); + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Token.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Token.java new file mode 100644 index 000000000..d91adf47a --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Token.java @@ -0,0 +1,169 @@ +/* Token.java -- + 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.swing.text.html.parser.support.low; + +/** + * A token. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class Token +{ + /** + * The place of this token in the document. + */ + public Location where; + + /** + * The additional category of token. + */ + public int category; + + /** + * An integer that describes the kind of this token. + */ + public int kind; + + /** + * The string image of the token, null if the char image must be used. + */ + private String stringImage; + + /** + * The char image of the token. + */ + private char charImage; + + /** + * Creates a new token with fields, initialized to the default values. + */ + public Token() + { + } + + /** + * Creates a new token of the given kind. + */ + public Token(int _kind, Location _where) + { + kind = _kind; + where = _where; + } + + /** + * Creates a new token of the given kind and given single char image. + */ + public Token(int _kind, char _image, Location _where) + { + kind = _kind; + charImage = _image; + where = _where; + } + + /** + * Creates a new token of the given kind and given string image. + */ + public Token(int _kind, String _image, Location _where) + { + kind = _kind; + stringImage = _image; + where = _where; + } + + /** + * Creates a new token of the given kind, category and given string image. + */ + public Token(int _kind, int _category, String _image, Location _where) + { + kind = _kind; + category = _category; + stringImage = _image; + where = _where; + } + + /** + * Creates a new token, where location fields are set as for token, + * spanning over two provided tokens and any tokens between them. + * The image field is initialized to null, the kind field is set to -1. + */ + public Token(Token fromInclusive, Token toInclusive) + { + where = new Location(); + where.beginLine = fromInclusive.where.beginLine; + where.startPosition = fromInclusive.where.startPosition; + + where.endLine = toInclusive.where.endLine; + where.endPosition = toInclusive.where.endPosition; + } + + public String getImage() + { + if (kind == 3) + return "#"; + if (stringImage == null) + { + if (charImage == 0) + return null; + stringImage = new String(new char[] { charImage }); + } + return stringImage; + } + + /** + * Append the token image to the given string buffer. + * This may be more effective that buffer.append(this.getImage()). + * @param buffer A buffer to append. + */ + public void appendTo(StringBuffer buffer) + { + if (charImage == 0) + buffer.append(getImage()); + else + buffer.append(charImage); + } + + /** + * Returns the string image or, if null, the bounding positions. + */ + public String toString() + { + return getImage() != null ? kind + "'" + getImage() + : "<line " + where.beginLine + ", abs pos " + where.startPosition + + ".." + where.endPosition + ">"; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/node.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/node.java new file mode 100644 index 000000000..b54ed86a3 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/node.java @@ -0,0 +1,78 @@ +/* node.java -- + 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.swing.text.html.parser.support.low; + +/** + * A text level content model node. The only required unary operations + * here are "appears" and "optionally appears" ('?'). + * <p>@author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)</p> + */ +public class node +{ + /** + * True for node that is optional for the given position. + */ + public boolean optional; + + /** + * The kind of the token to match. + */ + public int kind; + + /** + * Creates the new node for matching a given kind of the token. + * @param kind The kind of the token to match. + * @param modifier The modifier (*?+). + */ + public node(int kind, boolean _optional) + { + this.kind = kind; + optional = _optional; + } + + /** + * Creates the node, indicating that token must match exactluy one time. + * @param kind The kind of token to match. + */ + public node(int kind) + { + this.kind = kind; + optional = false; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/package.html b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/package.html new file mode 100644 index 000000000..173583015 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/package.html @@ -0,0 +1,47 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> +<!-- package.html - describes classes in javax.swing.text.html.parser package. + Copyright (C) 2002 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>GNU Classpath - gnu.javax.swing.text.html.parser.support.low + + +

      This package contains classes that are directly used to process +the text input: adapted stream tokenizer, specialized buffer and text-level content models .

      +@author Audrius Meskauskas, Lithuania + + diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/pattern.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/pattern.java new file mode 100644 index 000000000..0fe03fdbe --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/low/pattern.java @@ -0,0 +1,105 @@ +/* pattern.java -- + 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.swing.text.html.parser.support.low; + + +/** + * The simple pattern, consisting from the sequence of tokens that + * may have the unary modifier '?'. Choices and grouping + * are not required here. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class pattern +{ + /** + * The nodes of this pattern. + */ + public final node[] nodes; + + /** + * Create a pattern, containing the given list of nodes. + * @param a_nodes + */ + public pattern(node[] a_nodes) + { + nodes = a_nodes; + } + + /** + * Checks if the pattern can match the tokens in this + * tokenizer. Does not change the state of tokenizer. + * @param stream The tokenizer to read data from + * @return True if the pattern sequence matches the + * beginning of the tokenizer content. + */ + public boolean matches(ReaderTokenizer stream) + { + try + { + int pt = 0; + int pn = 0; + Token t; + node n; + + while (pn < nodes.length) + { + n = nodes [ pn ]; + t = stream.getTokenAhead(pt); + + if (t.kind == n.kind) + { + pn++; + pt++; + } + else + { + if (!n.optional) + return false; + else + pn++; + } + } + return true; + } + catch (Exception ex) + { + throw new ParseException("Exception", ex); + } + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/package.html b/libjava/classpath/gnu/javax/swing/text/html/parser/support/package.html new file mode 100644 index 000000000..97c6439b3 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/package.html @@ -0,0 +1,47 @@ + + + + +GNU Classpath - gnu.javax.swing.text.html.parser.support + + +

      This package provides various specialised classes, needed by HTML parser. +

      +@author Audrius Meskauskas, Lithuania + + diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/parameterDefaulter.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/parameterDefaulter.java new file mode 100644 index 000000000..43c07572a --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/parameterDefaulter.java @@ -0,0 +1,106 @@ +/* parameterDefaulter.java -- + 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.swing.text.html.parser.support; + +import gnu.javax.swing.text.html.parser.htmlAttributeSet; + +import java.util.Hashtable; + +import javax.swing.text.html.parser.AttributeList; +import javax.swing.text.html.parser.DTD; +import javax.swing.text.html.parser.Element; + +/** + * Returns an attribute set, containing default + * parameters for the given element. Caches sets of default + * parameters. + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class parameterDefaulter +{ + public final DTD dtd; + Hashtable sets = new Hashtable(); + + /** + * Create a parameterDefaulter that looks for the default attribute + * values in the given DTD. + * @param a_dtd + */ + public parameterDefaulter(DTD a_dtd) + { + dtd = a_dtd; + } + + /** + * Get the default parameter set for the given element. + * @param element The element name (case insensitive). + * @return the default attrbute set. + */ + public htmlAttributeSet getDefaultParameters(String element) + { + String key = element.toLowerCase(); + htmlAttributeSet atts = (htmlAttributeSet) sets.get(key); + + if (atts == null) + { + htmlAttributeSet set = new htmlAttributeSet(); + Element e = dtd.elementHash.get(element.toLowerCase()); + + if (e != null) + { + AttributeList a = e.getAttributes(); + + while (a != null) + { + if (a.value != null) + set.addAttribute(a.name, a.value); + a = a.next; + } + } + + if (set.getAttributeCount() > 0) + sets.put(key, set); + else + sets.put(key, htmlAttributeSet.EMPTY_HTML_ATTRIBUTE_SET); + + atts = set; + } + return atts; + } +} diff --git a/libjava/classpath/gnu/javax/swing/text/html/parser/support/textPreProcessor.java b/libjava/classpath/gnu/javax/swing/text/html/parser/support/textPreProcessor.java new file mode 100644 index 000000000..22c44be4f --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/text/html/parser/support/textPreProcessor.java @@ -0,0 +1,189 @@ +/* textPreProcessor.java -- + 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.swing.text.html.parser.support; + +import gnu.javax.swing.text.html.parser.support.low.Constants; + +/** + * Pre - processes text in text parts of the html document. + * + * @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org) + */ +public class textPreProcessor +{ + /** + * Pre - process non-preformatted text. \t, \r and \n mutate into spaces, then + * multiple spaces mutate into single one, all whitespace around tags is + * consumed. The content of the passed buffer is destroyed. + * + * @param a_text A text to pre-process. + */ + public char[] preprocess(StringBuffer a_text) + { + if (a_text.length() == 0) + return null; + + char[] text = toCharArray(a_text); + + int a = 0; + int b = text.length - 1; + + // Remove leading/trailing whitespace, leaving at most one character + int len = text.length; + while (a + 1 < len && Constants.bWHITESPACE.get(text[a]) + && Constants.bWHITESPACE.get(text[a + 1])) + a++; + + while (b > a && Constants.bWHITESPACE.get(text[b]) + && Constants.bWHITESPACE.get(text[b - 1])) + b--; + + a_text.setLength(0); + + boolean spacesWere = false; + boolean spaceNow; + char c; + + chars: for (int i = a; i <= b; i++) + { + c = text[i]; + spaceNow = Constants.bWHITESPACE.get(c); + if (spacesWere && spaceNow) + continue chars; + if (spaceNow) + a_text.append(' '); + else + a_text.append(c); + spacesWere = spaceNow; + } + + if (a_text.length() == text.length) + { + a_text.getChars(0, a_text.length(), text, 0); + return text; + } + else + return toCharArray(a_text); + } + + /** + * Pre - process pre-formatted text. + * Heading/closing spaces and tabs preserved. + * ONE bounding \r, \n or \r\n is removed. + * \r or \r\n mutate into \n. Tabs are + * preserved. + * The content of the passed buffer is destroyed. + * @param a_text + * @return + */ + public char[] preprocessPreformatted(StringBuffer a_text) + { + if (a_text.length() == 0) + return null; + + char[] text = toCharArray(a_text); + + int a = 0; + int n = text.length - 1; + int b = n; + + if (text [ 0 ] == '\n') + a++; + else + { + if (text [ 0 ] == '\r') + { + a++; + if (text.length > 1 && text [ 1 ] == '\n') + a++; + } + } + + if (text [ n ] == '\r') + b--; + else + { + if (text [ n ] == '\n') + { + b--; + if (n > 0 && text [ n - 1 ] == '\r') + b--; + } + } + + a_text.setLength(0); + + if (a > b) + return null; + + char c; + + for (int i = a; i <= b; i++) + { + c = text [ i ]; + if (c == '\r') + { + if (i == b || text [ i + 1 ] != '\n') + a_text.append('\n'); + } + else + a_text.append(c); + } + + if (a_text.length() == text.length) + { + a_text.getChars(0, a_text.length(), text, 0); + return text; + } + else + return toCharArray(a_text); + } + + /** + * Return array of chars, present in the given buffer. + * @param a_text The buffer + * @return + */ + private static char[] toCharArray(StringBuffer a_text) + { + char[] text = new char[ a_text.length() ]; + a_text.getChars(0, text.length, text, 0); + return text; + } +} diff --git a/libjava/classpath/gnu/javax/swing/tree/GnuPath.java b/libjava/classpath/gnu/javax/swing/tree/GnuPath.java new file mode 100644 index 000000000..568ffd102 --- /dev/null +++ b/libjava/classpath/gnu/javax/swing/tree/GnuPath.java @@ -0,0 +1,65 @@ +/* GnuPath.java -- The extended version of TreePath + 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.swing.tree; + +import javax.swing.tree.TreePath; + +/** + * The tree path with additional data. Needed for the optimized tree drawing. + * Returned by layout caches. + * + * @author Audrius Meskauskas + */ +public class GnuPath extends TreePath +{ + /** + * The flag, marking the last visible child. + */ + public boolean isLastChild; + + /** + * Create a new path, specifying flag if this path is the path to the + * last visible child (needed for optimized tree drawing). + */ + public GnuPath(Object[] path, boolean lastChild) + { + super(path); + isLastChild = lastChild; + } +} diff --git a/libjava/classpath/gnu/test/.cvsignore b/libjava/classpath/gnu/test/.cvsignore new file mode 100644 index 000000000..70845e08e --- /dev/null +++ b/libjava/classpath/gnu/test/.cvsignore @@ -0,0 +1 @@ +Makefile.in diff --git a/libjava/classpath/gnu/test/Fail.java b/libjava/classpath/gnu/test/Fail.java new file mode 100644 index 000000000..b3a032077 --- /dev/null +++ b/libjava/classpath/gnu/test/Fail.java @@ -0,0 +1,57 @@ +/* Fail.java -- Result code returned when test failed but was expected to + Copyright (c) 1998 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.test; + +/** + * Test failed but was expected to pass. + */ +public class Fail extends Result +{ + /** + * Constructs a Fail result code with additional information. + */ + public Fail(String msg) { + super("FAIL", msg); + } + /** + * Constructs a Fail result code. + */ + public Fail() { + this(""); + } +} diff --git a/libjava/classpath/gnu/test/Makefile.am b/libjava/classpath/gnu/test/Makefile.am new file mode 100644 index 000000000..49bc66916 --- /dev/null +++ b/libjava/classpath/gnu/test/Makefile.am @@ -0,0 +1,5 @@ +## Input file for automake to generate the Makefile.in used by configure + +##gnutestdir = $(datadir)/gnu/test/ + +##gnutest_JAVA = Fail.java Test.java Untested.java Pass.java Unresolved.java XFail.java Result.java Unsupported.java XPass.java diff --git a/libjava/classpath/gnu/test/Pass.java b/libjava/classpath/gnu/test/Pass.java new file mode 100644 index 000000000..fbbd3b29f --- /dev/null +++ b/libjava/classpath/gnu/test/Pass.java @@ -0,0 +1,57 @@ +/* Pass.java -- Result code returned when test passed and was excepted to + Copyright (c) 1998 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.test; + +/** + * Test passed and was excepted to pass. + */ +public class Pass extends Result +{ + /** + * Constructs a Pass result code with additional information. + */ + public Pass(String msg) { + super("PASS", msg); + } + /** + * Constructs a Pass result code. + */ + public Pass() { + this(""); + } +} diff --git a/libjava/classpath/gnu/test/Result.java b/libjava/classpath/gnu/test/Result.java new file mode 100644 index 000000000..908d4b485 --- /dev/null +++ b/libjava/classpath/gnu/test/Result.java @@ -0,0 +1,85 @@ +/* Result.java -- Abstract base class for all Result types. + Copyright (c) 1998 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.test; + +/** + * Class which all usable Result objects extend. + */ +public abstract class Result +{ + String name, msg; + + /** + * Create a result of a given type, with a given message. + * + * @param name name of type + * @param msg message + */ + public Result(String name, String msg) { + this.name = name; + this.msg = msg; + } + + /** + * Create a result of a given type. + * + * @param name name of type + */ + public Result(String name) { + this(name, ""); + } + + /** + * Returns the name of the type. + */ + public String getName() { + return name; + } + + /** + * Returns the message associated with this instance of Result, or + * the empty string if no message exists. + */ + public String getMsg() { + return (msg != null) ? msg : ""; + } + + public String toString() { + return getName() + ":" + getMsg(); + } +} diff --git a/libjava/classpath/gnu/test/Test.java b/libjava/classpath/gnu/test/Test.java new file mode 100644 index 000000000..f60c6dffc --- /dev/null +++ b/libjava/classpath/gnu/test/Test.java @@ -0,0 +1,57 @@ +/* Test.java -- Interface representing a single test. + Copyright (c) 1998 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.test; + +/** + * Interface which all GNU Classpath tests must implement. + * The method test is invoked once for each test. + */ +public interface Test +{ + /** + * Returns the name of the test. + */ + public String getName(); + + /** + * Performs a test. + * + * @return result from running the test + */ + public Result test(); +} diff --git a/libjava/classpath/gnu/test/Unresolved.java b/libjava/classpath/gnu/test/Unresolved.java new file mode 100644 index 000000000..280d8b699 --- /dev/null +++ b/libjava/classpath/gnu/test/Unresolved.java @@ -0,0 +1,57 @@ +/* Unresolved.java - Result code returned when test gives indeterminate results. + Copyright (c) 1998 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.test; + +/** + * Test produced indeterminate results. + */ +public class Unresolved extends Result +{ + /** + * Constructs an Unresolved result code with additional information. + */ + public Unresolved(String msg) { + super("UNRESOLVED", msg); + } + /** + * Constructs an Unresolved result code. + */ + public Unresolved() { + this(""); + } +} diff --git a/libjava/classpath/gnu/test/Unsupported.java b/libjava/classpath/gnu/test/Unsupported.java new file mode 100644 index 000000000..a1ad03290 --- /dev/null +++ b/libjava/classpath/gnu/test/Unsupported.java @@ -0,0 +1,59 @@ +/* Unsupported.java -- Result code returned when test does not have the + Copyright (c) 1998 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.test; + +/** + * Test does not have the required support to run. For example, + * Unsupported could be returned when a needed resource + * (ie. multicasting) is not available. + */ +public class Unsupported extends Result +{ + /** + * Constructs an Unsupported result code with additional information. + */ + public Unsupported(String msg) { + super("UNSUPPORTED", msg); + } + /** + * Constructs an Unsupported result code. + */ + public Unsupported() { + this(""); + } +} diff --git a/libjava/classpath/gnu/test/Untested.java b/libjava/classpath/gnu/test/Untested.java new file mode 100644 index 000000000..5627fa8ca --- /dev/null +++ b/libjava/classpath/gnu/test/Untested.java @@ -0,0 +1,57 @@ +/* Untested.java -- Result code returned when test was not run -- placeholder. + Copyright (c) 1998 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.test; + +/** + * Test was not run -- a placeholder. + */ +public class Untested extends Result +{ + /** + * Constructs an Untested result code with additional information. + */ + public Untested(String msg) { + super("UNTESTED", msg); + } + /** + * Constructs an Untested result code. + */ + public Untested() { + this(""); + } +} diff --git a/libjava/classpath/gnu/test/XFail.java b/libjava/classpath/gnu/test/XFail.java new file mode 100644 index 000000000..793ff117f --- /dev/null +++ b/libjava/classpath/gnu/test/XFail.java @@ -0,0 +1,57 @@ +/* XFail.java - Result code returned when test failed and was expected to fail. + Copyright (c) 1998 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.test; + +/** + * Test failed and was expected to fail. + */ +public class XFail extends Result +{ + /** + * Constructs an XFail result code with additional information. + */ + public XFail(String msg) { + super("XFAIL", msg); + } + /** + * Constructs an XFail result code. + */ + public XFail() { + this(""); + } +} diff --git a/libjava/classpath/gnu/test/XPass.java b/libjava/classpath/gnu/test/XPass.java new file mode 100644 index 000000000..b41dd1c37 --- /dev/null +++ b/libjava/classpath/gnu/test/XPass.java @@ -0,0 +1,56 @@ +/* XPass.java - Result code returned when test passed but was expected to fail. + Copyright (c) 1998 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.test; + +/** + * Test passed but was expected to fail. + */ +public class XPass extends Result +{ + /** + * Constructs an XPass result code with additional information. + */ + public XPass(String msg) { + super("XPASS", msg); + } + /** + * Constructs an XPass result code. + */ + public XPass() { + this(""); + } +} diff --git a/libjava/classpath/gnu/xml/aelfred2/JAXPFactory.java b/libjava/classpath/gnu/xml/aelfred2/JAXPFactory.java new file mode 100644 index 000000000..094442765 --- /dev/null +++ b/libjava/classpath/gnu/xml/aelfred2/JAXPFactory.java @@ -0,0 +1,230 @@ +/* JAXPFactory.java -- + Copyright (C) 2001 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.aelfred2; + +import java.util.Enumeration; +import java.util.Hashtable; + +import org.xml.sax.Parser; +import org.xml.sax.XMLReader; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.helpers.XMLReaderAdapter; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + + +/** + * Configurable factory to create an Ælfred2 JAXP parser; required + * to bootstrap using JAXP. You should use SAX2 directly where possible, + * rather than through JAXP, since that gives you better control. + * This class would normally be configured as a platform default factory. + * + * @author David Brownell + */ +public final class JAXPFactory + extends SAXParserFactory +{ + + private Hashtable flags = new Hashtable(); + + /** + * Constructs a factory which normally returns a non-validating + * parser. + */ + public JAXPFactory() + { + } + + public SAXParser newSAXParser() + throws ParserConfigurationException, SAXException + { + JaxpParser jaxp = new JaxpParser(); + Enumeration e = flags.keys(); + XMLReader parser = jaxp.getXMLReader(); + + parser.setFeature(SAXDriver.FEATURE + "namespaces", + isNamespaceAware()); + parser.setFeature(SAXDriver.FEATURE + "validation", + isValidating()); + // that makes SAX2 feature flags trump JAXP + + while (e.hasMoreElements()) + { + String uri = (String) e.nextElement(); + Boolean value = (Boolean) flags.get(uri); + parser.setFeature(uri, value.booleanValue()); + } + + return jaxp; + } + + // yes, this "feature transfer" mechanism doesn't play well + + public void setFeature(String name, boolean value) + throws ParserConfigurationException, SAXNotRecognizedException, + SAXNotSupportedException + { + try + { + // force "early" detection of errors where possible + // (flags can't necessarily be set before parsing) + new JaxpParser().getXMLReader().setFeature(name, value); + + flags.put(name, Boolean.valueOf(value)); + } + catch (SAXNotRecognizedException e) + { + throw new SAXNotRecognizedException(name); + } + catch (SAXNotSupportedException e) + { + throw new SAXNotSupportedException(name); + } + catch (Exception e) + { + throw new ParserConfigurationException(e.getClass().getName() + + ": " + + e.getMessage()); + } + } + + public boolean getFeature(String name) + throws ParserConfigurationException, SAXNotRecognizedException, + SAXNotSupportedException + { + Boolean value = (Boolean) flags.get(name); + + if (value != null) + { + return value.booleanValue(); + } + else + { + try + { + return new JaxpParser().getXMLReader().getFeature(name); + } + catch (SAXNotRecognizedException e) + { + throw new SAXNotRecognizedException(name); + } + catch (SAXNotSupportedException e) + { + throw new SAXNotSupportedException(name); + } + catch (SAXException e) + { + throw new ParserConfigurationException(e.getClass().getName() + + ": " + + e.getMessage()); + } + } + } + + private static class JaxpParser + extends SAXParser + { + + private XmlReader ae2 = new XmlReader(); + private XMLReaderAdapter parser = null; + + JaxpParser() + { + } + + public void setProperty(String id, Object value) + throws SAXNotRecognizedException, SAXNotSupportedException + { + ae2.setProperty(id, value); + } + + public Object getProperty(String id) + throws SAXNotRecognizedException, SAXNotSupportedException + { + return ae2.getProperty(id); + } + + public Parser getParser() + throws SAXException + { + if (parser == null) + { + parser = new XMLReaderAdapter(ae2); + } + return parser; + } + + public XMLReader getXMLReader () + throws SAXException + { + return ae2; + } + + public boolean isNamespaceAware() + { + try + { + return ae2.getFeature(SAXDriver.FEATURE + "namespaces"); + } + catch (Exception e) + { + throw new Error(); + } + } + + public boolean isValidating() + { + try + { + return ae2.getFeature(SAXDriver.FEATURE + "validation"); + } + catch (Exception e) + { + throw new Error(); + } + } + + // TODO isXIncludeAware() + + } + +} diff --git a/libjava/classpath/gnu/xml/aelfred2/SAXDriver.java b/libjava/classpath/gnu/xml/aelfred2/SAXDriver.java new file mode 100644 index 000000000..6ce14707b --- /dev/null +++ b/libjava/classpath/gnu/xml/aelfred2/SAXDriver.java @@ -0,0 +1,1609 @@ +/* SAXDriver.java -- + Copyright (C) 1999,2000,2001,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. + +Portions derived from code which carried the following notice: + + Copyright (c) 1997, 1998 by Microstar Software Ltd. + + AElfred is free for both commercial and non-commercial use and + redistribution, provided that Microstar's copyright and disclaimer are + retained intact. You are free to modify AElfred for your own use and + to redistribute AElfred with your modifications, provided that the + modifications are clearly documented. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + merchantability or fitness for a particular purpose. Please use it AT + YOUR OWN RISK. +*/ + +package gnu.xml.aelfred2; + +import java.io.*; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Locale; +import java.util.Stack; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; + +import org.xml.sax.*; +import org.xml.sax.ext.*; +import org.xml.sax.helpers.NamespaceSupport; + + +/** + * An enhanced SAX2 version of Microstar's Ælfred XML parser. + * The enhancements primarily relate to significant improvements in + * conformance to the XML specification, and SAX2 support. Performance + * has been improved. See the package level documentation for more + * information. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
      NameNotes
      Features ... URL prefix is + * http://xml.org/sax/features/
      (URL)/external-general-entitiesValue defaults to true
      (URL)/external-parameter-entitiesValue defaults to true
      (URL)/is-standalone(PRELIMINARY) Returns true iff the document's parsing + * has started (some non-error event after startDocument() + * was reported) and the document's standalone flag is set.
      (URL)/namespace-prefixesValue defaults to false (but XML 1.0 names are + * always reported)
      (URL)/lexical-handler/parameter-entitiesValue is fixed at true
      (URL)/namespacesValue defaults to true
      (URL)/resolve-dtd-uris(PRELIMINARY) Value defaults to true
      (URL)/string-interningValue is fixed at true
      (URL)/use-attributes2(PRELIMINARY) Value is fixed at true
      (URL)/use-entity-resolver2(PRELIMINARY) Value defaults to true
      (URL)/validationValue is fixed at false
      Handler Properties ... URL prefix is + * http://xml.org/sax/properties/
      (URL)/declaration-handlerA declaration handler may be provided.
      (URL)/lexical-handlerA lexical handler may be provided.
      + * + *

      This parser currently implements the SAX1 Parser API, but + * it may not continue to do so in the future. + * + * @author Written by David Megginson (version 1.2a from Microstar) + * @author Updated by David Brownell <dbrownell@users.sourceforge.net> + * @see org.xml.sax.Parser + */ +final public class SAXDriver + implements Locator, Attributes2, XMLReader, Parser, AttributeList +{ + + private final DefaultHandler2 base = new DefaultHandler2(); + private XmlParser parser; + + private EntityResolver entityResolver = base; + private EntityResolver2 resolver2 = null; + private ContentHandler contentHandler = base; + private DTDHandler dtdHandler = base; + private ErrorHandler errorHandler = base; + private DeclHandler declHandler = base; + private LexicalHandler lexicalHandler = base; + + private String elementName; + private Stack entityStack; + + // one vector (of object/struct): faster, smaller + private List attributesList; + + private boolean namespaces = true; + private boolean xmlNames = false; + private boolean extGE = true; + private boolean extPE = true; + private boolean resolveAll = true; + private boolean useResolver2 = true; + + // package private to allow (read-only) access in XmlParser + boolean stringInterning = true; + + private int attributeCount; + private boolean attributes; + private String[] nsTemp; + private NamespaceSupport prefixStack; + + // + // Constructor. + // + + /** + * Constructs a SAX Parser. + */ + public SAXDriver() + { + reset(); + } + + private void reset() + { + elementName = null; + entityStack = new Stack(); + attributesList = Collections.synchronizedList(new ArrayList()); + attributeCount = 0; + attributes = false; + nsTemp = new String[3]; + prefixStack = null; + } + + + // + // Implementation of org.xml.sax.Parser. + // + + /** + * SAX1: Sets the locale used for diagnostics; currently, + * only locales using the English language are supported. + * @param locale The locale for which diagnostics will be generated + */ + public void setLocale(Locale locale) + throws SAXException + { + if ("en".equals(locale.getLanguage())) + { + return; + } + throw new SAXException ("AElfred2 only supports English locales."); + } + + /** + * SAX2: Returns the object used when resolving external + * entities during parsing (both general and parameter entities). + */ + public EntityResolver getEntityResolver() + { + return (entityResolver == base) ? null : entityResolver; + } + + /** + * SAX1, SAX2: Set the entity resolver for this parser. + * @param handler The object to receive entity events. + */ + public void setEntityResolver(EntityResolver resolver) + { + if (resolver instanceof EntityResolver2) + { + resolver2 = (EntityResolver2) resolver; + } + else + { + resolver2 = null; + } + if (resolver == null) + { + resolver = base; + } + entityResolver = resolver; + } + + /** + * SAX2: Returns the object used to process declarations related + * to notations and unparsed entities. + */ + public DTDHandler getDTDHandler() + { + return (dtdHandler == base) ? null : dtdHandler; + } + + /** + * SAX1, SAX2: Set the DTD handler for this parser. + * @param handler The object to receive DTD events. + */ + public void setDTDHandler(DTDHandler handler) + { + if (handler == null) + { + handler = base; + } + this.dtdHandler = handler; + } + + + /** + * SAX1: Set the document handler for this parser. If a + * content handler was set, this document handler will supplant it. + * The parser is set to report all XML 1.0 names rather than to + * filter out "xmlns" attributes (the "namespace-prefixes" feature + * is set to true). + * + * @deprecated SAX2 programs should use the XMLReader interface + * and a ContentHandler. + * + * @param handler The object to receive document events. + */ + public void setDocumentHandler(DocumentHandler handler) + { + contentHandler = new Adapter(handler); + xmlNames = true; + } + + /** + * SAX2: Returns the object used to report the logical + * content of an XML document. + */ + public ContentHandler getContentHandler() + { + return (contentHandler == base) ? null : contentHandler; + } + + /** + * SAX2: Assigns the object used to report the logical + * content of an XML document. If a document handler was set, + * this content handler will supplant it (but XML 1.0 style name + * reporting may remain enabled). + */ + public void setContentHandler(ContentHandler handler) + { + if (handler == null) + { + handler = base; + } + contentHandler = handler; + } + + /** + * SAX1, SAX2: Set the error handler for this parser. + * @param handler The object to receive error events. + */ + public void setErrorHandler(ErrorHandler handler) + { + if (handler == null) + { + handler = base; + } + this.errorHandler = handler; + } + + /** + * SAX2: Returns the object used to receive callbacks for XML + * errors of all levels (fatal, nonfatal, warning); this is never null; + */ + public ErrorHandler getErrorHandler() + { + return (errorHandler == base) ? null : errorHandler; + } + + /** + * SAX1, SAX2: Auxiliary API to parse an XML document, used mostly + * when no URI is available. + * If you want anything useful to happen, you should set + * at least one type of handler. + * @param source The XML input source. Don't set 'encoding' unless + * you know for a fact that it's correct. + * @see #setEntityResolver + * @see #setDTDHandler + * @see #setContentHandler + * @see #setErrorHandler + * @exception SAXException The handlers may throw any SAXException, + * and the parser normally throws SAXParseException objects. + * @exception IOException IOExceptions are normally through through + * the parser if there are problems reading the source document. + */ + public void parse(InputSource source) + throws SAXException, IOException + { + synchronized (base) + { + parser = new XmlParser(); + if (namespaces) + { + prefixStack = new NamespaceSupport(); + } + else if (!xmlNames) + { + throw new IllegalStateException(); + } + parser.setHandler(this); + + try + { + Reader r = source.getCharacterStream(); + InputStream in = source.getByteStream(); + + parser.doParse(source.getSystemId(), + source.getPublicId(), + r, + in, + source.getEncoding()); + } + catch (SAXException e) + { + throw e; + } + catch (IOException e) + { + throw e; + } + catch (RuntimeException e) + { + throw e; + } + catch (Exception e) + { + throw new SAXParseException(e.getMessage(), this, e); + } + finally + { + contentHandler.endDocument(); + reset(); + } + } + } + + /** + * SAX1, SAX2: Preferred API to parse an XML document, using a + * system identifier (URI). + */ + public void parse(String systemId) + throws SAXException, IOException + { + parse(new InputSource(systemId)); + } + + // + // Implementation of SAX2 "XMLReader" interface + // + static final String FEATURE = "http://xml.org/sax/features/"; + static final String PROPERTY = "http://xml.org/sax/properties/"; + + /** + * SAX2: Tells the value of the specified feature flag. + * + * @exception SAXNotRecognizedException thrown if the feature flag + * is neither built in, nor yet assigned. + */ + public boolean getFeature(String featureId) + throws SAXNotRecognizedException, SAXNotSupportedException + { + if ((FEATURE + "validation").equals(featureId)) + { + return false; + } + + // external entities (both types) are optionally included + if ((FEATURE + "external-general-entities").equals(featureId)) + { + return extGE; + } + if ((FEATURE + "external-parameter-entities").equals(featureId)) + { + return extPE; + } + + // element/attribute names are as written in document; no mangling + if ((FEATURE + "namespace-prefixes").equals(featureId)) + { + return xmlNames; + } + + // report element/attribute namespaces? + if ((FEATURE + "namespaces").equals(featureId)) + { + return namespaces; + } + + // all PEs and GEs are reported + if ((FEATURE + "lexical-handler/parameter-entities").equals(featureId)) + { + return true; + } + + // default is true + if ((FEATURE + "string-interning").equals(featureId)) + { + return stringInterning; + } + + // EXTENSIONS 1.1 + + // always returns isSpecified info + if ((FEATURE + "use-attributes2").equals(featureId)) + { + return true; + } + + // meaningful between startDocument/endDocument + if ((FEATURE + "is-standalone").equals(featureId)) + { + if (parser == null) + { + throw new SAXNotSupportedException(featureId); + } + return parser.isStandalone(); + } + + // optionally don't absolutize URIs in declarations + if ((FEATURE + "resolve-dtd-uris").equals(featureId)) + { + return resolveAll; + } + + // optionally use resolver2 interface methods, if possible + if ((FEATURE + "use-entity-resolver2").equals(featureId)) + { + return useResolver2; + } + + throw new SAXNotRecognizedException(featureId); + } + + // package private + DeclHandler getDeclHandler() + { + return declHandler; + } + + // package private + boolean resolveURIs() + { + return resolveAll; + } + + /** + * SAX2: Returns the specified property. + * + * @exception SAXNotRecognizedException thrown if the property value + * is neither built in, nor yet stored. + */ + public Object getProperty(String propertyId) + throws SAXNotRecognizedException + { + if ((PROPERTY + "declaration-handler").equals(propertyId)) + { + return (declHandler == base) ? null : declHandler; + } + + if ((PROPERTY + "lexical-handler").equals(propertyId)) + { + return (lexicalHandler == base) ? null : lexicalHandler; + } + + // unknown properties + throw new SAXNotRecognizedException(propertyId); + } + + /** + * SAX2: Sets the state of feature flags in this parser. Some + * built-in feature flags are mutable. + */ + public void setFeature(String featureId, boolean value) + throws SAXNotRecognizedException, SAXNotSupportedException + { + boolean state; + + // Features with a defined value, we just change it if we can. + state = getFeature (featureId); + + if (state == value) + { + return; + } + if (parser != null) + { + throw new SAXNotSupportedException("not while parsing"); + } + + if ((FEATURE + "namespace-prefixes").equals(featureId)) + { + // in this implementation, this only affects xmlns reporting + xmlNames = value; + // forcibly prevent illegal parser state + if (!xmlNames) + { + namespaces = true; + } + return; + } + + if ((FEATURE + "namespaces").equals(featureId)) + { + namespaces = value; + // forcibly prevent illegal parser state + if (!namespaces) + { + xmlNames = true; + } + return; + } + + if ((FEATURE + "external-general-entities").equals(featureId)) + { + extGE = value; + return; + } + if ((FEATURE + "external-parameter-entities").equals(featureId)) + { + extPE = value; + return; + } + if ((FEATURE + "resolve-dtd-uris").equals(featureId)) + { + resolveAll = value; + return; + } + + if ((FEATURE + "use-entity-resolver2").equals(featureId)) + { + useResolver2 = value; + return; + } + + throw new SAXNotRecognizedException(featureId); + } + + /** + * SAX2: Assigns the specified property. Like SAX1 handlers, + * these may be changed at any time. + */ + public void setProperty(String propertyId, Object value) + throws SAXNotRecognizedException, SAXNotSupportedException + { + // see if the property is recognized + getProperty(propertyId); + + // Properties with a defined value, we just change it if we can. + + if ((PROPERTY + "declaration-handler").equals(propertyId)) + { + if (value == null) + { + declHandler = base; + } + else if (!(value instanceof DeclHandler)) + { + throw new SAXNotSupportedException(propertyId); + } + else + { + declHandler = (DeclHandler) value; + } + return ; + } + + if ((PROPERTY + "lexical-handler").equals(propertyId)) + { + if (value == null) + { + lexicalHandler = base; + } + else if (!(value instanceof LexicalHandler)) + { + throw new SAXNotSupportedException(propertyId); + } + else + { + lexicalHandler = (LexicalHandler) value; + } + return; + } + + throw new SAXNotSupportedException(propertyId); + } + + // + // This is where the driver receives XmlParser callbacks and translates + // them into SAX callbacks. Some more callbacks have been added for + // SAX2 support. + // + + void startDocument() + throws SAXException + { + contentHandler.setDocumentLocator(this); + contentHandler.startDocument(); + attributesList.clear(); + } + + void skippedEntity(String name) + throws SAXException + { + contentHandler.skippedEntity(name); + } + + InputSource getExternalSubset(String name, String baseURI) + throws SAXException, IOException + { + if (resolver2 == null || !useResolver2 || !extPE) + { + return null; + } + return resolver2.getExternalSubset(name, baseURI); + } + + InputSource resolveEntity(boolean isPE, String name, + InputSource in, String baseURI) + throws SAXException, IOException + { + InputSource source; + + // external entities might be skipped + if (isPE && !extPE) + { + return null; + } + if (!isPE && !extGE) + { + return null; + } + + // ... or not + lexicalHandler.startEntity(name); + if (resolver2 != null && useResolver2) + { + source = resolver2.resolveEntity(name, in.getPublicId(), + baseURI, in.getSystemId()); + if (source == null) + { + in.setSystemId(absolutize(baseURI, + in.getSystemId(), false)); + source = in; + } + } + else + { + in.setSystemId(absolutize(baseURI, + in.getSystemId(), + entityResolver != base)); + source = entityResolver.resolveEntity(in.getPublicId(), + in.getSystemId()); + if (source == null) + { + source = in; + } + } + startExternalEntity(name, source.getSystemId(), true); + return source; + } + + // absolutize a system ID relative to the specified base URI + // (temporarily) package-visible for external entity decls + String absolutize(String baseURI, String systemId, boolean nice) + throws MalformedURLException, SAXException + { + // FIXME normalize system IDs -- when? + // - Convert to UTF-8 + // - Map reserved and non-ASCII characters to %HH + + try + { + if (baseURI == null) + { + if (XmlParser.uriWarnings) + { + warn ("No base URI; hope this SYSTEM id is absolute: " + + systemId); + } + return new URL(systemId).toString(); + } + else + { + return new URL(new URL(baseURI), systemId).toString(); + } + } + catch (MalformedURLException e) + { + // Let unknown URI schemes pass through unless we need + // the JVM to map them to i/o streams for us... + if (!nice) + { + throw e; + } + + // sometimes sysids for notations or unparsed entities + // aren't really URIs... + warn("Can't absolutize SYSTEM id: " + e.getMessage()); + return systemId; + } + } + + void startExternalEntity(String name, String systemId, boolean stackOnly) + throws SAXException + { + // The following warning was deleted because the application has the + // option of not setting systemId. Sun's JAXP or Xerces seems to + // ignore this case. + /* + if (systemId == null) + warn ("URI was not reported to parser for entity " + name); + */ + if (!stackOnly) // spliced [dtd] needs startEntity + { + lexicalHandler.startEntity(name); + } + entityStack.push(systemId); + } + + void endExternalEntity(String name) + throws SAXException + { + if (!"[document]".equals(name)) + { + lexicalHandler.endEntity(name); + } + entityStack.pop(); + } + + void startInternalEntity(String name) + throws SAXException + { + lexicalHandler.startEntity(name); + } + + void endInternalEntity(String name) + throws SAXException + { + lexicalHandler.endEntity(name); + } + + void doctypeDecl(String name, String publicId, String systemId) + throws SAXException + { + lexicalHandler.startDTD(name, publicId, systemId); + + // ... the "name" is a declaration and should be given + // to the DeclHandler (but sax2 doesn't). + + // the IDs for the external subset are lexical details, + // as are the contents of the internal subset; but sax2 + // doesn't provide the internal subset "pre-parse" + } + + void notationDecl(String name, String publicId, String systemId, + String baseUri) + throws SAXException + { + try + { + dtdHandler.notationDecl(name, publicId, + (resolveAll && systemId != null) + ? absolutize(baseUri, systemId, true) + : systemId); + } + catch (IOException e) + { + // "can't happen" + throw new SAXParseException(e.getMessage(), this, e); + } + } + + void unparsedEntityDecl(String name, String publicId, String systemId, + String baseUri, String notation) + throws SAXException + { + try + { + dtdHandler.unparsedEntityDecl(name, publicId, + resolveAll + ? absolutize(baseUri, systemId, true) + : systemId, + notation); + } + catch (IOException e) + { + // "can't happen" + throw new SAXParseException(e.getMessage(), this, e); + } + } + + void endDoctype() + throws SAXException + { + lexicalHandler.endDTD(); + } + + private void declarePrefix(String prefix, String uri) + throws SAXException + { + int index = uri.indexOf(':'); + + // many versions of nwalsh docbook stylesheets + // have bogus URLs; so this can't be an error... + if (index < 1 && uri.length() != 0) + { + warn("relative URI for namespace: " + uri); + } + + // FIXME: char [0] must be ascii alpha; chars [1..index] + // must be ascii alphanumeric or in "+-." [RFC 2396] + + //Namespace Constraints + //name for xml prefix must be http://www.w3.org/XML/1998/namespace + boolean prefixEquality = prefix.equals("xml"); + boolean uriEquality = uri.equals("http://www.w3.org/XML/1998/namespace"); + if ((prefixEquality || uriEquality) && !(prefixEquality && uriEquality)) + { + fatal("xml is by definition bound to the namespace name " + + "http://www.w3.org/XML/1998/namespace"); + } + + //xmlns prefix declaration is illegal but xml prefix declaration is llegal... + if (prefixEquality && uriEquality) + { + return; + } + + //name for xmlns prefix must be http://www.w3.org/2000/xmlns/ + prefixEquality = prefix.equals("xmlns"); + uriEquality = uri.equals("http://www.w3.org/2000/xmlns/"); + if ((prefixEquality || uriEquality) && !(prefixEquality && uriEquality)) + { + fatal("http://www.w3.org/2000/xmlns/ is by definition bound" + + " to prefix xmlns"); + } + + //even if the uri is http://www.w3.org/2000/xmlns/ + // it is illegal to declare it + if (prefixEquality && uriEquality) + { + fatal ("declaring the xmlns prefix is illegal"); + } + + uri = uri.intern(); + prefixStack.declarePrefix(prefix, uri); + contentHandler.startPrefixMapping(prefix, uri); + } + + void attribute(String qname, String value, boolean isSpecified) + throws SAXException + { + if (!attributes) + { + attributes = true; + if (namespaces) + { + prefixStack.pushContext(); + } + } + + // process namespace decls immediately; + // then maybe forget this as an attribute + if (namespaces) + { + int index; + + // default NS declaration? + if (stringInterning) + { + if ("xmlns" == qname) + { + declarePrefix("", value); + if (!xmlNames) + { + return; + } + } + // NS prefix declaration? + else if ((index = qname.indexOf(':')) == 5 + && qname.startsWith("xmlns")) + { + String prefix = qname.substring(6); + + if (prefix.equals("")) + { + fatal("missing prefix " + + "in namespace declaration attribute"); + } + if (value.length() == 0) + { + verror("missing URI in namespace declaration attribute: " + + qname); + } + else + { + declarePrefix(prefix, value); + } + if (!xmlNames) + { + return; + } + } + } + else + { + if ("xmlns".equals(qname)) + { + declarePrefix("", value); + if (!xmlNames) + { + return; + } + } + // NS prefix declaration? + else if ((index = qname.indexOf(':')) == 5 + && qname.startsWith("xmlns")) + { + String prefix = qname.substring(6); + + if (value.length() == 0) + { + verror("missing URI in namespace decl attribute: " + + qname); + } + else + { + declarePrefix(prefix, value); + } + if (!xmlNames) + { + return; + } + } + } + } + // remember this attribute ... + attributeCount++; + + // attribute type comes from querying parser's DTD records + attributesList.add(new Attribute(qname, value, isSpecified)); + + } + + void startElement(String elname) + throws SAXException + { + ContentHandler handler = contentHandler; + + // + // NOTE: this implementation of namespace support adds something + // like six percent to parsing CPU time, in a large (~50 MB) + // document that doesn't use namespaces at all. (Measured by PC + // sampling, with a bug where endElement processing was omitted.) + // [Measurement referred to older implementation, older JVM ...] + // + // It ought to become notably faster in such cases. Most + // costs are the prefix stack calling Hashtable.get() (2%), + // String.hashCode() (1.5%) and about 1.3% each for pushing + // the context, and two chunks of name processing. + // + + if (!attributes) + { + if (namespaces) + { + prefixStack.pushContext(); + } + } + else if (namespaces) + { + + // now we can patch up namespace refs; we saw all the + // declarations, so now we'll do the Right Thing + Iterator itt = attributesList.iterator(); + while (itt.hasNext()) + { + Attribute attribute = (Attribute) itt.next(); + String qname = attribute.name; + int index; + + // default NS declaration? + if (stringInterning) + { + if ("xmlns" == qname) + { + continue; + } + } + else + { + if ("xmlns".equals(qname)) + { + continue; + } + } + //Illegal in the new Namespaces Draft + //should it be only in 1.1 docs?? + if (qname.equals (":")) + { + fatal("namespace names consisting of a single colon " + + "character are invalid"); + } + index = qname.indexOf(':'); + + // NS prefix declaration? + if (index == 5 && qname.startsWith("xmlns")) + { + continue; + } + + // it's not a NS decl; patch namespace info items + if (prefixStack.processName(qname, nsTemp, true) == null) + { + fatal("undeclared attribute prefix in: " + qname); + } + else + { + attribute.nameSpace = nsTemp[0]; + attribute.localName = nsTemp[1]; + } + } + } + + // save element name so attribute callbacks work + elementName = elname; + if (namespaces) + { + if (prefixStack.processName(elname, nsTemp, false) == null) + { + fatal("undeclared element prefix in: " + elname); + nsTemp[0] = nsTemp[1] = ""; + } + handler.startElement(nsTemp[0], nsTemp[1], elname, this); + } + else + { + handler.startElement("", "", elname, this); + } + // elementName = null; + + // elements with no attributes are pretty common! + if (attributes) + { + attributesList.clear(); + attributeCount = 0; + attributes = false; + } + } + + void endElement(String elname) + throws SAXException + { + ContentHandler handler = contentHandler; + + if (!namespaces) + { + handler.endElement("", "", elname); + return; + } + prefixStack.processName(elname, nsTemp, false); + handler.endElement(nsTemp[0], nsTemp[1], elname); + + Enumeration prefixes = prefixStack.getDeclaredPrefixes(); + + while (prefixes.hasMoreElements()) + { + handler.endPrefixMapping((String) prefixes.nextElement()); + } + prefixStack.popContext(); + } + + void startCDATA() + throws SAXException + { + lexicalHandler.startCDATA(); + } + + void charData(char[] ch, int start, int length) + throws SAXException + { + contentHandler.characters(ch, start, length); + } + + void endCDATA() + throws SAXException + { + lexicalHandler.endCDATA(); + } + + void ignorableWhitespace(char[] ch, int start, int length) + throws SAXException + { + contentHandler.ignorableWhitespace(ch, start, length); + } + + void processingInstruction(String target, String data) + throws SAXException + { + contentHandler.processingInstruction(target, data); + } + + void comment(char[] ch, int start, int length) + throws SAXException + { + if (lexicalHandler != base) + { + lexicalHandler.comment(ch, start, length); + } + } + + void fatal(String message) + throws SAXException + { + SAXParseException fatal; + + fatal = new SAXParseException(message, this); + errorHandler.fatalError(fatal); + + // Even if the application can continue ... we can't! + throw fatal; + } + + // We can safely report a few validity errors that + // make layered SAX2 DTD validation more conformant + void verror(String message) + throws SAXException + { + SAXParseException err; + + err = new SAXParseException(message, this); + errorHandler.error(err); + } + + void warn(String message) + throws SAXException + { + SAXParseException err; + + err = new SAXParseException(message, this); + errorHandler.warning(err); + } + + // + // Implementation of org.xml.sax.Attributes. + // + + /** + * SAX1 AttributeList, SAX2 Attributes method + * (don't invoke on parser); + */ + public int getLength() + { + return attributesList.size(); + } + + /** + * SAX2 Attributes method (don't invoke on parser); + */ + public String getURI(int index) + { + if (index < 0 || index >= attributesList.size()) + { + return null; + } + return ((Attribute) attributesList.get(index)).nameSpace; + } + + /** + * SAX2 Attributes method (don't invoke on parser); + */ + public String getLocalName(int index) + { + if (index < 0 || index >= attributesList.size()) + { + return null; + } + Attribute attr = (Attribute) attributesList.get(index); + // FIXME attr.localName is sometimes null, why? + if (namespaces && attr.localName == null) + { + // XXX fix this here for now + int ci = attr.name.indexOf(':'); + attr.localName = (ci == -1) ? attr.name : + attr.name.substring(ci + 1); + } + return (attr.localName == null) ? "" : attr.localName; + } + + /** + * SAX2 Attributes method (don't invoke on parser); + */ + public String getQName(int index) + { + if (index < 0 || index >= attributesList.size()) + { + return null; + } + Attribute attr = (Attribute) attributesList.get(index); + return (attr.name == null) ? "" : attr.name; + } + + /** + * SAX1 AttributeList method (don't invoke on parser); + */ + public String getName(int index) + { + return getQName(index); + } + + /** + * SAX1 AttributeList, SAX2 Attributes method + * (don't invoke on parser); + */ + public String getType(int index) + { + if (index < 0 || index >= attributesList.size()) + { + return null; + } + String type = parser.getAttributeType(elementName, getQName(index)); + if (type == null) + { + return "CDATA"; + } + // ... use DeclHandler.attributeDecl to see enumerations + if (type == "ENUMERATION") + { + return "NMTOKEN"; + } + return type; + } + + /** + * SAX1 AttributeList, SAX2 Attributes method + * (don't invoke on parser); + */ + public String getValue(int index) + { + if (index < 0 || index >= attributesList.size()) + { + return null; + } + return ((Attribute) attributesList.get(index)).value; + } + + /** + * SAX2 Attributes method (don't invoke on parser); + */ + public int getIndex(String uri, String local) + { + int length = getLength(); + + for (int i = 0; i < length; i++) + { + if (!getURI(i).equals(uri)) + { + continue; + } + if (getLocalName(i).equals(local)) + { + return i; + } + } + return -1; + } + + /** + * SAX2 Attributes method (don't invoke on parser); + */ + public int getIndex(String xmlName) + { + int length = getLength(); + + for (int i = 0; i < length; i++) + { + if (getQName(i).equals(xmlName)) + { + return i; + } + } + return -1; + } + + /** + * SAX2 Attributes method (don't invoke on parser); + */ + public String getType(String uri, String local) + { + int index = getIndex(uri, local); + + if (index < 0) + { + return null; + } + return getType(index); + } + + /** + * SAX1 AttributeList, SAX2 Attributes method + * (don't invoke on parser); + */ + public String getType(String xmlName) + { + int index = getIndex(xmlName); + + if (index < 0) + { + return null; + } + return getType(index); + } + + /** + * SAX Attributes method (don't invoke on parser); + */ + public String getValue(String uri, String local) + { + int index = getIndex(uri, local); + + if (index < 0) + { + return null; + } + return getValue(index); + } + + /** + * SAX1 AttributeList, SAX2 Attributes method + * (don't invoke on parser); + */ + public String getValue(String xmlName) + { + int index = getIndex(xmlName); + + if (index < 0) + { + return null; + } + return getValue(index); + } + + // + // Implementation of org.xml.sax.ext.Attributes2 + // + + /** @return false unless the attribute was declared in the DTD. + * @throws java.lang.ArrayIndexOutOfBoundsException + * When the supplied index does not identify an attribute. + */ + public boolean isDeclared(int index) + { + if (index < 0 || index >= attributeCount) + { + throw new ArrayIndexOutOfBoundsException(); + } + String type = parser.getAttributeType(elementName, getQName(index)); + return (type != null); + } + + /** @return false unless the attribute was declared in the DTD. + * @throws java.lang.IllegalArgumentException + * When the supplied names do not identify an attribute. + */ + public boolean isDeclared(String qName) + { + int index = getIndex(qName); + if (index < 0) + { + throw new IllegalArgumentException(); + } + String type = parser.getAttributeType(elementName, qName); + return (type != null); + } + + /** @return false unless the attribute was declared in the DTD. + * @throws java.lang.IllegalArgumentException + * When the supplied names do not identify an attribute. + */ + public boolean isDeclared(String uri, String localName) + { + int index = getIndex(uri, localName); + return isDeclared(index); + } + + /** + * SAX-ext Attributes2 method (don't invoke on parser); + */ + public boolean isSpecified(int index) + { + return ((Attribute) attributesList.get(index)).specified; + } + + /** + * SAX-ext Attributes2 method (don't invoke on parser); + */ + public boolean isSpecified(String uri, String local) + { + int index = getIndex (uri, local); + return isSpecified(index); + } + + /** + * SAX-ext Attributes2 method (don't invoke on parser); + */ + public boolean isSpecified(String xmlName) + { + int index = getIndex (xmlName); + return isSpecified(index); + } + + // + // Implementation of org.xml.sax.Locator. + // + + /** + * SAX Locator method (don't invoke on parser); + */ + public String getPublicId() + { + return null; // FIXME track public IDs too + } + + /** + * SAX Locator method (don't invoke on parser); + */ + public String getSystemId() + { + if (entityStack.empty()) + { + return null; + } + else + { + return (String) entityStack.peek(); + } + } + + /** + * SAX Locator method (don't invoke on parser); + */ + public int getLineNumber() + { + return parser.getLineNumber(); + } + + /** + * SAX Locator method (don't invoke on parser); + */ + public int getColumnNumber() + { + return parser.getColumnNumber(); + } + + // adapter between SAX2 content handler and SAX1 document handler callbacks + private static class Adapter + implements ContentHandler + { + + private DocumentHandler docHandler; + + Adapter(DocumentHandler dh) + { + docHandler = dh; + } + + public void setDocumentLocator(Locator l) + { + docHandler.setDocumentLocator(l); + } + + public void startDocument() + throws SAXException + { + docHandler.startDocument(); + } + + public void processingInstruction(String target, String data) + throws SAXException + { + docHandler.processingInstruction(target, data); + } + + public void startPrefixMapping(String prefix, String uri) + { + /* ignored */ + } + + public void startElement(String namespace, + String local, + String name, + Attributes attrs) + throws SAXException + { + docHandler.startElement(name, (AttributeList) attrs); + } + + public void characters(char[] buf, int offset, int len) + throws SAXException + { + docHandler.characters(buf, offset, len); + } + + public void ignorableWhitespace(char[] buf, int offset, int len) + throws SAXException + { + docHandler.ignorableWhitespace(buf, offset, len); + } + + public void skippedEntity(String name) + { + /* ignored */ + } + + public void endElement(String u, String l, String name) + throws SAXException + { + docHandler.endElement(name); + } + + public void endPrefixMapping(String prefix) + { + /* ignored */ + } + + public void endDocument() + throws SAXException + { + docHandler.endDocument(); + } + } + + private static class Attribute + { + + String name; + String value; + String nameSpace; + String localName; + boolean specified; + + Attribute(String name, String value, boolean specified) + { + this.name = name; + this.value = value; + this.nameSpace = ""; + this.specified = specified; + } + + } + +} diff --git a/libjava/classpath/gnu/xml/aelfred2/XmlParser.java b/libjava/classpath/gnu/xml/aelfred2/XmlParser.java new file mode 100644 index 000000000..813593d93 --- /dev/null +++ b/libjava/classpath/gnu/xml/aelfred2/XmlParser.java @@ -0,0 +1,5831 @@ +/* XmlParser.java -- + Copyright (C) 1999,2000,2001 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. + +Partly derived from code which carried the following notice: + + Copyright (c) 1997, 1998 by Microstar Software Ltd. + + AElfred is free for both commercial and non-commercial use and + redistribution, provided that Microstar's copyright and disclaimer are + retained intact. You are free to modify AElfred for your own use and + to redistribute AElfred with your modifications, provided that the + modifications are clearly documented. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + merchantability or fitness for a particular purpose. Please use it AT + YOUR OWN RISK. +*/ + +package gnu.xml.aelfred2; + +import gnu.java.security.action.GetPropertyAction; + +import java.io.BufferedInputStream; +import java.io.CharConversionException; +import java.io.EOFException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.IOException; +import java.io.Reader; +import java.io.UnsupportedEncodingException; +import java.net.URL; +import java.net.URLConnection; +import java.security.AccessController; + +import java.util.Iterator; +import java.util.HashMap; +import java.util.LinkedList; + +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + + +/** + * Parse XML documents and return parse events through call-backs. + * Use the SAXDriver class as your entry point, as all + * internal parser interfaces are subject to change. + * + * @author Written by David Megginson <dmeggins@microstar.com> + * (version 1.2a with bugfixes) + * @author Updated by David Brownell <dbrownell@users.sourceforge.net> + * @see SAXDriver + */ +final class XmlParser +{ + + // avoid slow per-character readCh() + private final static boolean USE_CHEATS = true; + + //////////////////////////////////////////////////////////////////////// + // Constants. + //////////////////////////////////////////////////////////////////////// + + // + // Constants for element content type. + // + + /** + * Constant: an element has not been declared. + * @see #getElementContentType + */ + public final static int CONTENT_UNDECLARED = 0; + + /** + * Constant: the element has a content model of ANY. + * @see #getElementContentType + */ + public final static int CONTENT_ANY = 1; + + /** + * Constant: the element has declared content of EMPTY. + * @see #getElementContentType + */ + public final static int CONTENT_EMPTY = 2; + + /** + * Constant: the element has mixed content. + * @see #getElementContentType + */ + public final static int CONTENT_MIXED = 3; + + /** + * Constant: the element has element content. + * @see #getElementContentType + */ + public final static int CONTENT_ELEMENTS = 4; + + + // + // Constants for the entity type. + // + + /** + * Constant: the entity has not been declared. + * @see #getEntityType + */ + public final static int ENTITY_UNDECLARED = 0; + + /** + * Constant: the entity is internal. + * @see #getEntityType + */ + public final static int ENTITY_INTERNAL = 1; + + /** + * Constant: the entity is external, non-parsable data. + * @see #getEntityType + */ + public final static int ENTITY_NDATA = 2; + + /** + * Constant: the entity is external XML data. + * @see #getEntityType + */ + public final static int ENTITY_TEXT = 3; + + // + // Attribute type constants are interned literal strings. + // + + // + // Constants for supported encodings. "external" is just a flag. + // + private final static int ENCODING_EXTERNAL = 0; + private final static int ENCODING_UTF_8 = 1; + private final static int ENCODING_ISO_8859_1 = 2; + private final static int ENCODING_UCS_2_12 = 3; + private final static int ENCODING_UCS_2_21 = 4; + private final static int ENCODING_UCS_4_1234 = 5; + private final static int ENCODING_UCS_4_4321 = 6; + private final static int ENCODING_UCS_4_2143 = 7; + private final static int ENCODING_UCS_4_3412 = 8; + private final static int ENCODING_ASCII = 9; + + // + // Constants for attribute default value. + // + + /** + * Constant: the attribute is not declared. + * @see #getAttributeDefaultValueType + */ + public final static int ATTRIBUTE_DEFAULT_UNDECLARED = 30; + + /** + * Constant: the attribute has a literal default value specified. + * @see #getAttributeDefaultValueType + * @see #getAttributeDefaultValue + */ + public final static int ATTRIBUTE_DEFAULT_SPECIFIED = 31; + + /** + * Constant: the attribute was declared #IMPLIED. + * @see #getAttributeDefaultValueType + */ + public final static int ATTRIBUTE_DEFAULT_IMPLIED = 32; + + /** + * Constant: the attribute was declared #REQUIRED. + * @see #getAttributeDefaultValueType + */ + public final static int ATTRIBUTE_DEFAULT_REQUIRED = 33; + + /** + * Constant: the attribute was declared #FIXED. + * @see #getAttributeDefaultValueType + * @see #getAttributeDefaultValue + */ + public final static int ATTRIBUTE_DEFAULT_FIXED = 34; + + // + // Constants for input. + // + private final static int INPUT_NONE = 0; + private final static int INPUT_INTERNAL = 1; + private final static int INPUT_STREAM = 3; + private final static int INPUT_READER = 5; + + // + // Flags for reading literals. + // + // expand general entity refs (attribute values in dtd and content) + private final static int LIT_ENTITY_REF = 2; + // normalize this value (space chars) (attributes, public ids) + private final static int LIT_NORMALIZE = 4; + // literal is an attribute value + private final static int LIT_ATTRIBUTE = 8; + // don't expand parameter entities + private final static int LIT_DISABLE_PE = 16; + // don't expand [or parse] character refs + private final static int LIT_DISABLE_CREF = 32; + // don't parse general entity refs + private final static int LIT_DISABLE_EREF = 64; + // literal is a public ID value + private final static int LIT_PUBID = 256; + + // + // Flags affecting PE handling in DTDs (if expandPE is true). + // PEs expand with space padding, except inside literals. + // + private final static int CONTEXT_NORMAL = 0; + private final static int CONTEXT_LITERAL = 1; + + // Emit warnings for relative URIs with no base URI. + static boolean uriWarnings; + static + { + String key = "gnu.xml.aelfred2.XmlParser.uriWarnings"; + GetPropertyAction a = new GetPropertyAction(key); + uriWarnings = "true".equals(AccessController.doPrivileged(a)); + } + + // + // The current XML handler interface. + // + private SAXDriver handler; + + // + // I/O information. + // + private Reader reader; // current reader + private InputStream is; // current input stream + private int line; // current line number + private int column; // current column number + private int sourceType; // type of input source + private LinkedList inputStack; // stack of input soruces + private URLConnection externalEntity; // current external entity + private int encoding; // current character encoding + private int currentByteCount; // bytes read from current source + private InputSource scratch; // temporary + + // + // Buffers for decoded but unparsed character input. + // + private char[] readBuffer; + private int readBufferPos; + private int readBufferLength; + private int readBufferOverflow; // overflow from last data chunk. + + // + // Buffer for undecoded raw byte input. + // + private final static int READ_BUFFER_MAX = 16384; + private byte[] rawReadBuffer; + + + // + // Buffer for attribute values, char refs, DTD stuff. + // + private static int DATA_BUFFER_INITIAL = 4096; + private char[] dataBuffer; + private int dataBufferPos; + + // + // Buffer for parsed names. + // + private static int NAME_BUFFER_INITIAL = 1024; + private char[] nameBuffer; + private int nameBufferPos; + + // + // Save any standalone flag + // + private boolean docIsStandalone; + + // + // Hashtables for DTD information on elements, entities, and notations. + // Populated until we start ignoring decls (because of skipping a PE) + // + private HashMap elementInfo; + private HashMap entityInfo; + private HashMap notationInfo; + private boolean skippedPE; + + // + // Element type currently in force. + // + private String currentElement; + private int currentElementContent; + + // + // Stack of entity names, to detect recursion. + // + private LinkedList entityStack; + + // + // PE expansion is enabled in most chunks of the DTD, not all. + // When it's enabled, literals are treated differently. + // + private boolean inLiteral; + private boolean expandPE; + private boolean peIsError; + + // + // can't report entity expansion inside two constructs: + // - attribute expansions (internal entities only) + // - markup declarations (parameter entities only) + // + private boolean doReport; + + // + // Symbol table, for caching interned names. + // + // These show up wherever XML names or nmtokens are used: naming elements, + // attributes, PIs, notations, entities, and enumerated attribute values. + // + // NOTE: This hashtable doesn't grow. The default size is intended to be + // rather large for most documents. Example: one snapshot of the DocBook + // XML 4.1 DTD used only about 350 such names. As a rule, only pathological + // documents (ones that don't reuse names) should ever see much collision. + // + // Be sure that SYMBOL_TABLE_LENGTH always stays prime, for best hashing. + // "2039" keeps the hash table size at about two memory pages on typical + // 32 bit hardware. + // + private final static int SYMBOL_TABLE_LENGTH = 2039; + + private Object[][] symbolTable; + + // + // Hash table of attributes found in current start tag. + // + private String[] tagAttributes; + private int tagAttributePos; + + // + // Utility flag: have we noticed a CR while reading the last + // data chunk? If so, we will have to go back and normalise + // CR or CR/LF line ends. + // + private boolean sawCR; + + // + // Utility flag: are we in CDATA? If so, whitespace isn't ignorable. + // + private boolean inCDATA; + + // + // Xml version. + // + private static final int XML_10 = 0; + private static final int XML_11 = 1; + private int xmlVersion = XML_10; + + ////////////////////////////////////////////////////////////////////// + // Constructors. + //////////////////////////////////////////////////////////////////////// + + /** + * Construct a new parser with no associated handler. + * @see #setHandler + * @see #parse + */ + // package private + XmlParser() + { + } + + /** + * Set the handler that will receive parsing events. + * @param handler The handler to receive callback events. + * @see #parse + */ + // package private + void setHandler(SAXDriver handler) + { + this.handler = handler; + } + + /** + * Parse an XML document from the character stream, byte stream, or URI + * that you provide (in that order of preference). Any URI that you + * supply will become the base URI for resolving relative URI, and may + * be used to acquire a reader or byte stream. + * + *

      Only one thread at a time may use this parser; since it is + * private to this package, post-parse cleanup is done by the caller, + * which MUST NOT REUSE the parser (just null it). + * + * @param systemId Absolute URI of the document; should never be null, + * but may be so iff a reader or a stream is provided. + * @param publicId The public identifier of the document, or null. + * @param reader A character stream; must be null if stream isn't. + * @param stream A byte input stream; must be null if reader isn't. + * @param encoding The suggested encoding, or null if unknown. + * @exception java.lang.Exception Basically SAXException or IOException + */ + // package private + void doParse(String systemId, String publicId, Reader reader, + InputStream stream, String encoding) + throws Exception + { + if (handler == null) + { + throw new IllegalStateException("no callback handler"); + } + + initializeVariables(); + + // predeclare the built-in entities here (replacement texts) + // we don't need to intern(), since we're guaranteed literals + // are always (globally) interned. + setInternalEntity("amp", "&"); + setInternalEntity("lt", "<"); + setInternalEntity("gt", ">"); + setInternalEntity("apos", "'"); + setInternalEntity("quot", """); + + try + { + // pushURL first to ensure locator is correct in startDocument + // ... it might report an IO or encoding exception. + handler.startDocument(); + pushURL(false, "[document]", + // default baseURI: null + new ExternalIdentifiers(publicId, systemId, null), + reader, stream, encoding, false); + + parseDocument(); + } + catch (EOFException e) + { + //empty input + error("empty document, with no root element."); + } + finally + { + if (reader != null) + { + try + { + reader.close(); + } + catch (IOException e) + { + /* ignore */ + } + } + if (stream != null) + { + try + { + stream.close(); + } + catch (IOException e) + { + /* ignore */ + } + } + if (is != null) + { + try + { + is.close(); + } + catch (IOException e) + { + /* ignore */ + } + } + scratch = null; + } + } + + ////////////////////////////////////////////////////////////////////// + // Error reporting. + ////////////////////////////////////////////////////////////////////// + + /** + * Report an error. + * @param message The error message. + * @param textFound The text that caused the error (or null). + * @see SAXDriver#error + * @see #line + */ + private void error(String message, String textFound, String textExpected) + throws SAXException + { + if (textFound != null) + { + message = message + " (found \"" + textFound + "\")"; + } + if (textExpected != null) + { + message = message + " (expected \"" + textExpected + "\")"; + } + handler.fatal(message); + + // "can't happen" + throw new SAXException(message); + } + + /** + * Report a serious error. + * @param message The error message. + * @param textFound The text that caused the error (or null). + */ + private void error(String message, char textFound, String textExpected) + throws SAXException + { + error(message, Character.toString(textFound), textExpected); + } + + /** + * Report typical case fatal errors. + */ + private void error(String message) + throws SAXException + { + handler.fatal(message); + } + + ////////////////////////////////////////////////////////////////////// + // Major syntactic productions. + ////////////////////////////////////////////////////////////////////// + + /** + * Parse an XML document. + *

      +   * [1] document ::= prolog element Misc*
      +   * 
      + *

      This is the top-level parsing function for a single XML + * document. As a minimum, a well-formed document must have + * a document element, and a valid document must have a prolog + * (one with doctype) as well. + */ + private void parseDocument() + throws Exception + { + try + { // added by MHK + boolean sawDTD = parseProlog(); + require('<'); + parseElement(!sawDTD); + } + catch (EOFException ee) + { // added by MHK + error("premature end of file", "[EOF]", null); + } + + try + { + parseMisc(); //skip all white, PIs, and comments + char c = readCh(); //if this doesn't throw an exception... + error("unexpected characters after document end", c, null); + } + catch (EOFException e) + { + return; + } + } + + static final char[] startDelimComment = { '<', '!', '-', '-' }; + static final char[] endDelimComment = { '-', '-' }; + + /** + * Skip a comment. + *

      +   * [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* "-->"
      +   * 
      + *

      (The <!-- has already been read.) + */ + private void parseComment() + throws Exception + { + char c; + boolean saved = expandPE; + + expandPE = false; + parseUntil(endDelimComment); + require('>'); + expandPE = saved; + handler.comment(dataBuffer, 0, dataBufferPos); + dataBufferPos = 0; + } + + static final char[] startDelimPI = { '<', '?' }; + static final char[] endDelimPI = { '?', '>' }; + + /** + * Parse a processing instruction and do a call-back. + *

      +   * [16] PI ::= '<?' PITarget
      +   *    (S (Char* - (Char* '?>' Char*)))?
      +   *    '?>'
      +   * [17] PITarget ::= Name - ( ('X'|'x') ('M'|m') ('L'|l') )
      +   * 
      + *

      (The <? has already been read.) + */ + private void parsePI() + throws SAXException, IOException + { + String name; + boolean saved = expandPE; + + expandPE = false; + name = readNmtoken(true); + //NE08 + if (name.indexOf(':') >= 0) + { + error("Illegal character(':') in processing instruction name ", + name, null); + } + if ("xml".equalsIgnoreCase(name)) + { + error("Illegal processing instruction target", name, null); + } + if (!tryRead(endDelimPI)) + { + requireWhitespace(); + parseUntil(endDelimPI); + } + expandPE = saved; + handler.processingInstruction(name, dataBufferToString()); + } + + static final char[] endDelimCDATA = { ']', ']', '>' }; + + private boolean isDirtyCurrentElement; + + /** + * Parse a CDATA section. + *

      +   * [18] CDSect ::= CDStart CData CDEnd
      +   * [19] CDStart ::= '<![CDATA['
      +   * [20] CData ::= (Char* - (Char* ']]>' Char*))
      +   * [21] CDEnd ::= ']]>'
      +   * 
      + *

      (The '<![CDATA[' has already been read.) + */ + private void parseCDSect() + throws Exception + { + parseUntil(endDelimCDATA); + dataBufferFlush(); + } + + /** + * Parse the prolog of an XML document. + *

      +   * [22] prolog ::= XMLDecl? Misc* (Doctypedecl Misc*)?
      +   * 
      + *

      We do not look for the XML declaration here, because it was + * handled by pushURL (). + * @see pushURL + * @return true if a DTD was read. + */ + private boolean parseProlog() + throws Exception + { + parseMisc(); + + if (tryRead(" + * [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>' + * [24] VersionInfo ::= S 'version' Eq + * ("'" VersionNum "'" | '"' VersionNum '"' ) + * [26] VersionNum ::= ([a-zA-Z0-9_.:] | '-')* + * [32] SDDecl ::= S 'standalone' Eq + * ( "'"" ('yes' | 'no') "'"" | '"' ("yes" | "no") '"' ) + * [80] EncodingDecl ::= S 'encoding' Eq + * ( "'" EncName "'" | "'" EncName "'" ) + * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')* + *

      + *

      (The <?xml and whitespace have already been read.) + * @return the encoding in the declaration, uppercased; or null + * @see #parseTextDecl + * @see #setupDecoding + */ + private String parseXMLDecl(boolean ignoreEncoding) + throws SAXException, IOException + { + String version; + String encodingName = null; + String standalone = null; + int flags = LIT_DISABLE_CREF | LIT_DISABLE_PE | LIT_DISABLE_EREF; + String inputEncoding = null; + + switch (this.encoding) + { + case ENCODING_EXTERNAL: + case ENCODING_UTF_8: + inputEncoding = "UTF-8"; + break; + case ENCODING_ISO_8859_1: + inputEncoding = "ISO-8859-1"; + break; + case ENCODING_UCS_2_12: + inputEncoding = "UTF-16BE"; + break; + case ENCODING_UCS_2_21: + inputEncoding = "UTF-16LE"; + break; + } + + // Read the version. + require("version"); + parseEq(); + checkLegalVersion(version = readLiteral(flags)); + if (!version.equals("1.0")) + { + if (version.equals("1.1")) + { + handler.warn("expected XML version 1.0, not: " + version); + xmlVersion = XML_11; + } + else + { + error("illegal XML version", version, "1.0 or 1.1"); + } + } + else + { + xmlVersion = XML_10; + } + // Try reading an encoding declaration. + boolean white = tryWhitespace(); + + if (tryRead("encoding")) + { + if (!white) + { + error("whitespace required before 'encoding='"); + } + parseEq(); + encodingName = readLiteral(flags); + if (!ignoreEncoding) + { + setupDecoding(encodingName); + } + } + + // Try reading a standalone declaration + if (encodingName != null) + { + white = tryWhitespace(); + } + if (tryRead("standalone")) + { + if (!white) + { + error("whitespace required before 'standalone='"); + } + parseEq(); + standalone = readLiteral(flags); + if ("yes".equals(standalone)) + { + docIsStandalone = true; + } + else if (!"no".equals(standalone)) + { + error("standalone flag must be 'yes' or 'no'"); + } + } + + skipWhitespace(); + require("?>"); + + if (inputEncoding == null) + { + inputEncoding = encodingName; + } + return encodingName; + } + + /** + * Parse a text declaration. + *

      +   * [79] TextDecl ::= '<?xml' VersionInfo? EncodingDecl S? '?>'
      +   * [80] EncodingDecl ::= S 'encoding' Eq
      +   *    ( '"' EncName '"' | "'" EncName "'" )
      +   * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
      +   * 
      + *

      (The <?xml' and whitespace have already been read.) + * @return the encoding in the declaration, uppercased; or null + * @see #parseXMLDecl + * @see #setupDecoding + */ + private String parseTextDecl(boolean ignoreEncoding) + throws SAXException, IOException + { + String encodingName = null; + int flags = LIT_DISABLE_CREF | LIT_DISABLE_PE | LIT_DISABLE_EREF; + + // Read an optional version. + if (tryRead ("version")) + { + String version; + parseEq(); + checkLegalVersion(version = readLiteral(flags)); + + if (version.equals("1.1")) + { + if (xmlVersion == XML_10) + { + error("external subset has later version number.", "1.0", + version); + } + handler.warn("expected XML version 1.0, not: " + version); + xmlVersion = XML_11; + } + else if (!version.equals("1.0")) + { + error("illegal XML version", version, "1.0 or 1.1"); + } + requireWhitespace(); + } + + // Read the encoding. + require("encoding"); + parseEq(); + encodingName = readLiteral(flags); + if (!ignoreEncoding) + { + setupDecoding(encodingName); + } + skipWhitespace(); + require("?>"); + + return encodingName; + } + + /** + * Sets up internal state so that we can decode an entity using the + * specified encoding. This is used when we start to read an entity + * and we have been given knowledge of its encoding before we start to + * read any data (e.g. from a SAX input source or from a MIME type). + * + *

      It is also used after autodetection, at which point only very + * limited adjustments to the encoding may be used (switching between + * related builtin decoders). + * + * @param encodingName The name of the encoding specified by the user. + * @exception IOException if the encoding isn't supported either + * internally to this parser, or by the hosting JVM. + * @see #parseXMLDecl + * @see #parseTextDecl + */ + private void setupDecoding(String encodingName) + throws SAXException, IOException + { + encodingName = encodingName.toUpperCase(); + + // ENCODING_EXTERNAL indicates an encoding that wasn't + // autodetected ... we can use builtin decoders, or + // ones from the JVM (InputStreamReader). + + // Otherwise we can only tweak what was autodetected, and + // only for single byte (ASCII derived) builtin encodings. + + // ASCII-derived encodings + if (encoding == ENCODING_UTF_8 || encoding == ENCODING_EXTERNAL) + { + if (encodingName.equals("ISO-8859-1") + || encodingName.equals("8859_1") + || encodingName.equals("ISO8859_1")) + { + encoding = ENCODING_ISO_8859_1; + return; + } + else if (encodingName.equals("US-ASCII") + || encodingName.equals("ASCII")) + { + encoding = ENCODING_ASCII; + return; + } + else if (encodingName.equals("UTF-8") + || encodingName.equals("UTF8")) + { + encoding = ENCODING_UTF_8; + return; + } + else if (encoding != ENCODING_EXTERNAL) + { + // used to start with a new reader ... + throw new UnsupportedEncodingException(encodingName); + } + // else fallthrough ... + // it's ASCII-ish and something other than a builtin + } + + // Unicode and such + if (encoding == ENCODING_UCS_2_12 || encoding == ENCODING_UCS_2_21) + { + if (!(encodingName.equals("ISO-10646-UCS-2") + || encodingName.equals("UTF-16") + || encodingName.equals("UTF-16BE") + || encodingName.equals("UTF-16LE"))) + { + error("unsupported Unicode encoding", encodingName, "UTF-16"); + } + return; + } + + // four byte encodings + if (encoding == ENCODING_UCS_4_1234 + || encoding == ENCODING_UCS_4_4321 + || encoding == ENCODING_UCS_4_2143 + || encoding == ENCODING_UCS_4_3412) + { + // Strictly: "UCS-4" == "UTF-32BE"; also, "UTF-32LE" exists + if (!encodingName.equals("ISO-10646-UCS-4")) + { + error("unsupported 32-bit encoding", encodingName, + "ISO-10646-UCS-4"); + } + return; + } + + // assert encoding == ENCODING_EXTERNAL + // if (encoding != ENCODING_EXTERNAL) + // throw new RuntimeException ("encoding = " + encoding); + + if (encodingName.equals("UTF-16BE")) + { + encoding = ENCODING_UCS_2_12; + return; + } + if (encodingName.equals("UTF-16LE")) + { + encoding = ENCODING_UCS_2_21; + return; + } + + // We couldn't use the builtin decoders at all. But we can try to + // create a reader, since we haven't messed up buffering. Tweak + // the encoding name if necessary. + + if (encodingName.equals("UTF-16") + || encodingName.equals("ISO-10646-UCS-2")) + { + encodingName = "Unicode"; + } + // Ignoring all the EBCDIC aliases here + + reader = new InputStreamReader(is, encodingName); + sourceType = INPUT_READER; + } + + /** + * Parse miscellaneous markup outside the document element and DOCTYPE + * declaration. + *

      +   * [27] Misc ::= Comment | PI | S
      +   * 
      + */ + private void parseMisc() + throws Exception + { + while (true) + { + skipWhitespace(); + if (tryRead(startDelimPI)) + { + parsePI(); + } + else if (tryRead(startDelimComment)) + { + parseComment(); + } + else + { + return; + } + } + } + + /** + * Parse a document type declaration. + *
      +   * [28] doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S?
      +   *    ('[' (markupdecl | PEReference | S)* ']' S?)? '>'
      +   * 
      + *

      (The <!DOCTYPE has already been read.) + */ + private void parseDoctypedecl() + throws Exception + { + String rootName; + ExternalIdentifiers ids; + + // Read the document type name. + requireWhitespace(); + rootName = readNmtoken(true); + + // Read the External subset's IDs + skipWhitespace(); + ids = readExternalIds(false, true); + + // report (a) declaration of name, (b) lexical info (ids) + handler.doctypeDecl(rootName, ids.publicId, ids.systemId); + + // Internal subset is parsed first, if present + skipWhitespace(); + if (tryRead('[')) + { + + // loop until the subset ends + while (true) + { + doReport = expandPE = true; + skipWhitespace(); + doReport = expandPE = false; + if (tryRead(']')) + { + break; // end of subset + } + else + { + // WFC, PEs in internal subset (only between decls) + peIsError = expandPE = true; + parseMarkupdecl(); + peIsError = expandPE = false; + } + } + } + skipWhitespace(); + require('>'); + + // Read the external subset, if any + InputSource subset; + + if (ids.systemId == null) + { + subset = handler.getExternalSubset(rootName, + handler.getSystemId()); + } + else + { + subset = null; + } + if (ids.systemId != null || subset != null) + { + pushString(null, ">"); + + // NOTE: [dtd] is so we say what SAX2 expects, + // though it's misleading (subset, not entire dtd) + if (ids.systemId != null) + { + pushURL(true, "[dtd]", ids, null, null, null, true); + } + else + { + handler.warn("modifying document by adding external subset"); + pushURL(true, "[dtd]", + new ExternalIdentifiers(subset.getPublicId(), + subset.getSystemId(), + null), + subset.getCharacterStream(), + subset.getByteStream(), + subset.getEncoding(), + false); + } + + // Loop until we end up back at '>' + while (true) + { + doReport = expandPE = true; + skipWhitespace(); + doReport = expandPE = false; + if (tryRead('>')) + { + break; + } + else + { + expandPE = true; + parseMarkupdecl(); + expandPE = false; + } + } + + // the ">" string isn't popped yet + if (inputStack.size() != 1) + { + error("external subset has unmatched '>'"); + } + } + + // done dtd + handler.endDoctype(); + expandPE = false; + doReport = true; + } + + /** + * Parse a markup declaration in the internal or external DTD subset. + *

      +   * [29] markupdecl ::= elementdecl | Attlistdecl | EntityDecl
      +   *    | NotationDecl | PI | Comment
      +   * [30] extSubsetDecl ::= (markupdecl | conditionalSect
      +   *    | PEReference | S) *
      +   * 
      + *

      Reading toplevel PE references is handled as a lexical issue + * by the caller, as is whitespace. + */ + private void parseMarkupdecl() + throws Exception + { + char[] saved = null; + boolean savedPE = expandPE; + + // prevent "<%foo;" and ensures saved entity is right + require('<'); + unread('<'); + expandPE = false; + + if (tryRead(" 0) + { + parseConditionalSect(saved); + } + else + { + error("conditional sections illegal in internal subset"); + } + } + else + { + error("expected markup declaration"); + } + + // VC: Proper Decl/PE Nesting + if (readBuffer != saved) + { + handler.verror("Illegal Declaration/PE nesting"); + } + } + + /** + * Parse an element, with its tags. + *

      +   * [39] element ::= EmptyElementTag | STag content ETag
      +   * [40] STag ::= '<' Name (S Attribute)* S? '>'
      +   * [44] EmptyElementTag ::= '<' Name (S Attribute)* S? '/>'
      +   * 
      + *

      (The '<' has already been read.) + *

      NOTE: this method actually chains onto parseContent (), if necessary, + * and parseContent () will take care of calling parseETag (). + */ + private void parseElement(boolean maybeGetSubset) + throws Exception + { + String gi; + char c; + int oldElementContent = currentElementContent; + String oldElement = currentElement; + ElementDecl element; + + // This is the (global) counter for the + // array of specified attributes. + tagAttributePos = 0; + + // Read the element type name. + gi = readNmtoken(true); + + // If we saw no DTD, and this is the document root element, + // let the application modify the input stream by providing one. + if (maybeGetSubset) + { + InputSource subset = handler.getExternalSubset(gi, + handler.getSystemId()); + if (subset != null) + { + String publicId = subset.getPublicId(); + String systemId = subset.getSystemId(); + + handler.warn("modifying document by adding DTD"); + handler.doctypeDecl(gi, publicId, systemId); + pushString(null, ">"); + + // NOTE: [dtd] is so we say what SAX2 expects, + // though it's misleading (subset, not entire dtd) + pushURL(true, "[dtd]", + new ExternalIdentifiers(publicId, systemId, null), + subset.getCharacterStream(), + subset.getByteStream(), + subset.getEncoding(), + false); + + // Loop until we end up back at '>' + while (true) + { + doReport = expandPE = true; + skipWhitespace(); + doReport = expandPE = false; + if (tryRead('>')) + { + break; + } + else + { + expandPE = true; + parseMarkupdecl(); + expandPE = false; + } + } + + // the ">" string isn't popped yet + if (inputStack.size() != 1) + { + error("external subset has unmatched '>'"); + } + + handler.endDoctype(); + } + } + + // Determine the current content type. + currentElement = gi; + element = (ElementDecl) elementInfo.get(gi); + currentElementContent = getContentType(element, CONTENT_ANY); + + // Read the attributes, if any. + // After this loop, "c" is the closing delimiter. + boolean white = tryWhitespace(); + c = readCh(); + while (c != '/' && c != '>') + { + unread(c); + if (!white) + { + error("need whitespace between attributes"); + } + parseAttribute(gi); + white = tryWhitespace(); + c = readCh(); + } + + // Supply any defaulted attributes. + Iterator atts = declaredAttributes(element); + if (atts != null) + { + String aname; +loop: + while (atts.hasNext()) + { + aname = (String) atts.next(); + // See if it was specified. + for (int i = 0; i < tagAttributePos; i++) + { + if (tagAttributes[i] == aname) + { + continue loop; + } + } + // ... or has a default + String value = getAttributeDefaultValue(gi, aname); + + if (value == null) + { + continue; + } + handler.attribute(aname, value, false); + } + } + + // Figure out if this is a start tag + // or an empty element, and dispatch an + // event accordingly. + switch (c) + { + case '>': + handler.startElement(gi); + parseContent(); + break; + case '/': + require('>'); + handler.startElement(gi); + handler.endElement(gi); + break; + } + + // Restore the previous state. + currentElement = oldElement; + currentElementContent = oldElementContent; + } + + /** + * Parse an attribute assignment. + *

      +   * [41] Attribute ::= Name Eq AttValue
      +   * 
      + * @param name The name of the attribute's element. + * @see SAXDriver#attribute + */ + private void parseAttribute(String name) + throws Exception + { + String aname; + String type; + String value; + int flags = LIT_ATTRIBUTE | LIT_ENTITY_REF; + + // Read the attribute name. + aname = readNmtoken(true); + type = getAttributeType(name, aname); + + // Parse '=' + parseEq(); + + // Read the value, normalizing whitespace + // unless it is CDATA. + if (handler.stringInterning) + { + if (type == "CDATA" || type == null) + { + value = readLiteral(flags); + } + else + { + value = readLiteral(flags | LIT_NORMALIZE); + } + } + else + { + if (type == null || type.equals("CDATA")) + { + value = readLiteral(flags); + } + else + { + value = readLiteral(flags | LIT_NORMALIZE); + } + } + + // WFC: no duplicate attributes + for (int i = 0; i < tagAttributePos; i++) + { + if (aname.equals(tagAttributes [i])) + { + error("duplicate attribute", aname, null); + } + } + + // Inform the handler about the + // attribute. + handler.attribute(aname, value, true); + dataBufferPos = 0; + + // Note that the attribute has been + // specified. + if (tagAttributePos == tagAttributes.length) + { + String newAttrib[] = new String[tagAttributes.length * 2]; + System.arraycopy(tagAttributes, 0, newAttrib, 0, tagAttributePos); + tagAttributes = newAttrib; + } + tagAttributes[tagAttributePos++] = aname; + } + + /** + * Parse an equals sign surrounded by optional whitespace. + *
      +   * [25] Eq ::= S? '=' S?
      +   * 
      + */ + private void parseEq() + throws SAXException, IOException + { + skipWhitespace(); + require('='); + skipWhitespace(); + } + + /** + * Parse an end tag. + *
      +   * [42] ETag ::= ''
      +   * 
      + *

      NOTE: parseContent () chains to here, we already read the + * "</". + */ + private void parseETag() + throws Exception + { + require(currentElement); + skipWhitespace(); + require('>'); + handler.endElement(currentElement); + // not re-reporting any SAXException re bogus end tags, + // even though that diagnostic might be clearer ... + } + + /** + * Parse the content of an element. + *

      +   * [43] content ::= (element | CharData | Reference
      +   *    | CDSect | PI | Comment)*
      +   * [67] Reference ::= EntityRef | CharRef
      +   * 
      + *

      NOTE: consumes ETtag. + */ + private void parseContent() + throws Exception + { + char c; + + while (true) + { + // consume characters (or ignorable whitspace) until delimiter + parseCharData(); + + // Handle delimiters + c = readCh(); + switch (c) + { + case '&': // Found "&" + c = readCh(); + if (c == '#') + { + parseCharRef(); + } + else + { + unread(c); + parseEntityRef(true); + } + isDirtyCurrentElement = true; + break; + + case '<': // Found "<" + dataBufferFlush(); + c = readCh(); + switch (c) + { + case '!': // Found " + * [45] elementdecl ::= '<!ELEMENT' S Name S contentspec S? '>' + *

      + *

      NOTE: the '<!ELEMENT' has already been read. + */ + private void parseElementDecl() + throws Exception + { + String name; + + requireWhitespace(); + // Read the element type name. + name = readNmtoken(true); + + requireWhitespace(); + // Read the content model. + parseContentspec(name); + + skipWhitespace(); + require('>'); + } + + /** + * Content specification. + *

      +   * [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | elements
      +   * 
      + */ + private void parseContentspec(String name) + throws Exception + { + // FIXME: move elementDecl() into setElement(), pass EMTPY/ANY ... + if (tryRead("EMPTY")) + { + setElement(name, CONTENT_EMPTY, null, null); + if (!skippedPE) + { + handler.getDeclHandler().elementDecl(name, "EMPTY"); + } + return; + } + else if (tryRead("ANY")) + { + setElement(name, CONTENT_ANY, null, null); + if (!skippedPE) + { + handler.getDeclHandler().elementDecl(name, "ANY"); + } + return; + } + else + { + String model; + char[] saved; + + require('('); + saved = readBuffer; + dataBufferAppend('('); + skipWhitespace(); + if (tryRead("#PCDATA")) + { + dataBufferAppend("#PCDATA"); + parseMixed(saved); + model = dataBufferToString(); + setElement(name, CONTENT_MIXED, model, null); + } + else + { + parseElements(saved); + model = dataBufferToString(); + setElement(name, CONTENT_ELEMENTS, model, null); + } + if (!skippedPE) + { + handler.getDeclHandler().elementDecl(name, model); + } + } + } + + /** + * Parse an element-content model. + *
      +   * [47] elements ::= (choice | seq) ('?' | '*' | '+')?
      +   * [49] choice ::= '(' S? cp (S? '|' S? cp)+ S? ')'
      +   * [50] seq ::= '(' S? cp (S? ',' S? cp)* S? ')'
      +   * 
      + * + *

      NOTE: the opening '(' and S have already been read. + * + * @param saved Buffer for entity that should have the terminal ')' + */ + private void parseElements(char[] saved) + throws Exception + { + char c; + char sep; + + // Parse the first content particle + skipWhitespace(); + parseCp(); + + // Check for end or for a separator. + skipWhitespace(); + c = readCh(); + switch (c) + { + case ')': + // VC: Proper Group/PE Nesting + if (readBuffer != saved) + { + handler.verror("Illegal Group/PE nesting"); + } + + dataBufferAppend(')'); + c = readCh(); + switch (c) + { + case '*': + case '+': + case '?': + dataBufferAppend(c); + break; + default: + unread(c); + } + return; + case ',': // Register the separator. + case '|': + sep = c; + dataBufferAppend(c); + break; + default: + error("bad separator in content model", c, null); + return; + } + + // Parse the rest of the content model. + while (true) + { + skipWhitespace(); + parseCp(); + skipWhitespace(); + c = readCh(); + if (c == ')') + { + // VC: Proper Group/PE Nesting + if (readBuffer != saved) + { + handler.verror("Illegal Group/PE nesting"); + } + + dataBufferAppend(')'); + break; + } + else if (c != sep) + { + error("bad separator in content model", c, null); + return; + } + else + { + dataBufferAppend(c); + } + } + + // Check for the occurrence indicator. + c = readCh(); + switch (c) + { + case '?': + case '*': + case '+': + dataBufferAppend(c); + return; + default: + unread(c); + return; + } + } + + /** + * Parse a content particle. + *

      +   * [48] cp ::= (Name | choice | seq) ('?' | '*' | '+')?
      +   * 
      + */ + private void parseCp() + throws Exception + { + if (tryRead('(')) + { + dataBufferAppend('('); + parseElements(readBuffer); + } + else + { + dataBufferAppend(readNmtoken(true)); + char c = readCh(); + switch (c) + { + case '?': + case '*': + case '+': + dataBufferAppend(c); + break; + default: + unread(c); + break; + } + } + } + + /** + * Parse mixed content. + *
      +   * [51] Mixed ::= '(' S? ( '#PCDATA' (S? '|' S? Name)*) S? ')*'
      +   *        | '(' S? ('#PCDATA') S? ')'
      +   * 
      + * + * @param saved Buffer for entity that should have the terminal ')' + */ + private void parseMixed(char[] saved) + throws Exception + { + // Check for PCDATA alone. + skipWhitespace(); + if (tryRead(')')) + { + // VC: Proper Group/PE Nesting + if (readBuffer != saved) + { + handler.verror("Illegal Group/PE nesting"); + } + + dataBufferAppend(")*"); + tryRead('*'); + return; + } + + // Parse mixed content. + skipWhitespace(); + while (!tryRead(")")) + { + require('|'); + dataBufferAppend('|'); + skipWhitespace(); + dataBufferAppend(readNmtoken(true)); + skipWhitespace(); + } + + // VC: Proper Group/PE Nesting + if (readBuffer != saved) + { + handler.verror("Illegal Group/PE nesting"); + } + + require('*'); + dataBufferAppend(")*"); + } + + /** + * Parse an attribute list declaration. + *
      +   * [52] AttlistDecl ::= '<!ATTLIST' S Name AttDef* S? '>'
      +   * 
      + *

      NOTE: the '<!ATTLIST' has already been read. + */ + private void parseAttlistDecl() + throws Exception + { + String elementName; + + requireWhitespace(); + elementName = readNmtoken(true); + boolean white = tryWhitespace(); + while (!tryRead('>')) + { + if (!white) + { + error("whitespace required before attribute definition"); + } + parseAttDef(elementName); + white = tryWhitespace(); + } + } + + /** + * Parse a single attribute definition. + *

      +   * [53] AttDef ::= S Name S AttType S DefaultDecl
      +   * 
      + */ + private void parseAttDef(String elementName) + throws Exception + { + String name; + String type; + String enumer = null; + + // Read the attribute name. + name = readNmtoken(true); + + // Read the attribute type. + requireWhitespace(); + type = readAttType(); + + // Get the string of enumerated values if necessary. + if (handler.stringInterning) + { + if ("ENUMERATION" == type || "NOTATION" == type) + { + enumer = dataBufferToString(); + } + } + else + { + if ("ENUMERATION".equals(type) || "NOTATION".equals(type)) + { + enumer = dataBufferToString(); + } + } + + // Read the default value. + requireWhitespace(); + parseDefault(elementName, name, type, enumer); + } + + /** + * Parse the attribute type. + *
      +   * [54] AttType ::= StringType | TokenizedType | EnumeratedType
      +   * [55] StringType ::= 'CDATA'
      +   * [56] TokenizedType ::= 'ID' | 'IDREF' | 'IDREFS' | 'ENTITY'
      +   *    | 'ENTITIES' | 'NMTOKEN' | 'NMTOKENS'
      +   * [57] EnumeratedType ::= NotationType | Enumeration
      +   * 
      + */ + private String readAttType() + throws Exception + { + if (tryRead('(')) + { + parseEnumeration(false); + return "ENUMERATION"; + } + else + { + String typeString = readNmtoken(true); + if (handler.stringInterning) + { + if ("NOTATION" == typeString) + { + parseNotationType(); + return typeString; + } + else if ("CDATA" == typeString + || "ID" == typeString + || "IDREF" == typeString + || "IDREFS" == typeString + || "ENTITY" == typeString + || "ENTITIES" == typeString + || "NMTOKEN" == typeString + || "NMTOKENS" == typeString) + { + return typeString; + } + } + else + { + if ("NOTATION".equals(typeString)) + { + parseNotationType(); + return typeString; + } + else if ("CDATA".equals(typeString) + || "ID".equals(typeString) + || "IDREF".equals(typeString) + || "IDREFS".equals(typeString) + || "ENTITY".equals(typeString) + || "ENTITIES".equals(typeString) + || "NMTOKEN".equals(typeString) + || "NMTOKENS".equals(typeString)) + { + return typeString; + } + } + error("illegal attribute type", typeString, null); + return null; + } + } + + /** + * Parse an enumeration. + *
      +   * [59] Enumeration ::= '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')'
      +   * 
      + *

      NOTE: the '(' has already been read. + */ + private void parseEnumeration(boolean isNames) + throws Exception + { + dataBufferAppend('('); + + // Read the first token. + skipWhitespace(); + dataBufferAppend(readNmtoken(isNames)); + // Read the remaining tokens. + skipWhitespace(); + while (!tryRead(')')) + { + require('|'); + dataBufferAppend('|'); + skipWhitespace(); + dataBufferAppend(readNmtoken (isNames)); + skipWhitespace(); + } + dataBufferAppend(')'); + } + + /** + * Parse a notation type for an attribute. + *

      +   * [58] NotationType ::= 'NOTATION' S '(' S? NameNtoks
      +   *    (S? '|' S? name)* S? ')'
      +   * 
      + *

      NOTE: the 'NOTATION' has already been read + */ + private void parseNotationType() + throws Exception + { + requireWhitespace(); + require('('); + + parseEnumeration(true); + } + + /** + * Parse the default value for an attribute. + *

      +   * [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED'
      +   *    | (('#FIXED' S)? AttValue)
      +   * 
      + */ + private void parseDefault(String elementName, String name, + String type, String enumer) + throws Exception + { + int valueType = ATTRIBUTE_DEFAULT_SPECIFIED; + String value = null; + int flags = LIT_ATTRIBUTE; + boolean saved = expandPE; + String defaultType = null; + + // LIT_ATTRIBUTE forces '<' checks now (ASAP) and turns whitespace + // chars to spaces (doesn't matter when that's done if it doesn't + // interfere with char refs expanding to whitespace). + + if (!skippedPE) + { + flags |= LIT_ENTITY_REF; + if (handler.stringInterning) + { + if ("CDATA" != type) + { + flags |= LIT_NORMALIZE; + } + } + else + { + if (!"CDATA".equals(type)) + { + flags |= LIT_NORMALIZE; + } + } + } + + expandPE = false; + if (tryRead('#')) + { + if (tryRead("FIXED")) + { + defaultType = "#FIXED"; + valueType = ATTRIBUTE_DEFAULT_FIXED; + requireWhitespace(); + value = readLiteral(flags); + } + else if (tryRead("REQUIRED")) + { + defaultType = "#REQUIRED"; + valueType = ATTRIBUTE_DEFAULT_REQUIRED; + } + else if (tryRead("IMPLIED")) + { + defaultType = "#IMPLIED"; + valueType = ATTRIBUTE_DEFAULT_IMPLIED; + } + else + { + error("illegal keyword for attribute default value"); + } + } + else + { + value = readLiteral(flags); + } + expandPE = saved; + setAttribute(elementName, name, type, enumer, value, valueType); + if (handler.stringInterning) + { + if ("ENUMERATION" == type) + { + type = enumer; + } + else if ("NOTATION" == type) + { + type = "NOTATION " + enumer; + } + } + else + { + if ("ENUMERATION".equals(type)) + { + type = enumer; + } + else if ("NOTATION".equals(type)) + { + type = "NOTATION " + enumer; + } + } + if (!skippedPE) + { + handler.getDeclHandler().attributeDecl(elementName, name, type, + defaultType, value); + } + } + + /** + * Parse a conditional section. + *
      +   * [61] conditionalSect ::= includeSect || ignoreSect
      +   * [62] includeSect ::= '<![' S? 'INCLUDE' S? '['
      +   *    extSubsetDecl ']]>'
      +   * [63] ignoreSect ::= '<![' S? 'IGNORE' S? '['
      +   *    ignoreSectContents* ']]>'
      +   * [64] ignoreSectContents ::= Ignore
      +   *    ('<![' ignoreSectContents* ']]>' Ignore )*
      +   * [65] Ignore ::= Char* - (Char* ( '<![' | ']]>') Char* )
      +   * 
      + *

      NOTE: the '>![' has already been read. + */ + private void parseConditionalSect(char[] saved) + throws Exception + { + skipWhitespace(); + if (tryRead("INCLUDE")) + { + skipWhitespace(); + require('['); + // VC: Proper Conditional Section/PE Nesting + if (readBuffer != saved) + { + handler.verror("Illegal Conditional Section/PE nesting"); + } + skipWhitespace(); + while (!tryRead("]]>")) + { + parseMarkupdecl(); + skipWhitespace(); + } + } + else if (tryRead("IGNORE")) + { + skipWhitespace(); + require('['); + // VC: Proper Conditional Section/PE Nesting + if (readBuffer != saved) + { + handler.verror("Illegal Conditional Section/PE nesting"); + } + int nesting = 1; + char c; + expandPE = false; + for (int nest = 1; nest > 0; ) + { + c = readCh(); + switch (c) + { + case '<': + if (tryRead("![")) + { + nest++; + } + break; + case ']': + if (tryRead("]>")) + { + nest--; + } + } + } + expandPE = true; + } + else + { + error("conditional section must begin with INCLUDE or IGNORE"); + } + } + + private void parseCharRef() + throws SAXException, IOException + { + parseCharRef(true /* do flushDataBuffer by default */); + } + + /** + * Try to read a character reference without consuming data from buffer. + *

      +   * [66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';'
      +   * 
      + *

      NOTE: the '&#' has already been read. + */ + private void tryReadCharRef() + throws SAXException, IOException + { + int value = 0; + char c; + + if (tryRead('x')) + { +loop1: + while (true) + { + c = readCh(); + if (c == ';') + { + break loop1; + } + else + { + int n = Character.digit(c, 16); + if (n == -1) + { + error("illegal character in character reference", c, null); + break loop1; + } + value *= 16; + value += n; + } + } + } + else + { +loop2: + while (true) + { + c = readCh(); + if (c == ';') + { + break loop2; + } + else + { + int n = Character.digit(c, 10); + if (n == -1) + { + error("illegal character in character reference", c, null); + break loop2; + } + value *= 10; + value += n; + } + } + } + + // check for character refs being legal XML + if ((value < 0x0020 + && ! (value == '\n' || value == '\t' || value == '\r')) + || (value >= 0xD800 && value <= 0xDFFF) + || value == 0xFFFE || value == 0xFFFF + || value > 0x0010ffff) + { + error("illegal XML character reference U+" + + Integer.toHexString(value)); + } + + // Check for surrogates: 00000000 0000xxxx yyyyyyyy zzzzzzzz + // (1101|10xx|xxyy|yyyy + 1101|11yy|zzzz|zzzz: + if (value > 0x0010ffff) + { + // too big for surrogate + error("character reference " + value + " is too large for UTF-16", + Integer.toString(value), null); + } + + } + + /** + * Read and interpret a character reference. + *

      +   * [66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';'
      +   * 
      + *

      NOTE: the '&#' has already been read. + */ + private void parseCharRef(boolean doFlush) + throws SAXException, IOException + { + int value = 0; + char c; + + if (tryRead('x')) + { +loop1: + while (true) + { + c = readCh(); + if (c == ';') + { + break loop1; + } + else + { + int n = Character.digit(c, 16); + if (n == -1) + { + error("illegal character in character reference", c, null); + break loop1; + } + value *= 16; + value += n; + } + } + } + else + { +loop2: + while (true) + { + c = readCh(); + if (c == ';') + { + break loop2; + } + else + { + int n = Character.digit(c, 10); + if (n == -1) + { + error("illegal character in character reference", c, null); + break loop2; + } + value *= 10; + value += c - '0'; + } + } + } + + // check for character refs being legal XML + if ((value < 0x0020 + && ! (value == '\n' || value == '\t' || value == '\r')) + || (value >= 0xD800 && value <= 0xDFFF) + || value == 0xFFFE || value == 0xFFFF + || value > 0x0010ffff) + { + error("illegal XML character reference U+" + + Integer.toHexString(value)); + } + + // Check for surrogates: 00000000 0000xxxx yyyyyyyy zzzzzzzz + // (1101|10xx|xxyy|yyyy + 1101|11yy|zzzz|zzzz: + if (value <= 0x0000ffff) + { + // no surrogates needed + dataBufferAppend((char) value); + } + else if (value <= 0x0010ffff) + { + value -= 0x10000; + // > 16 bits, surrogate needed + dataBufferAppend((char) (0xd800 | (value >> 10))); + dataBufferAppend((char) (0xdc00 | (value & 0x0003ff))); + } + else + { + // too big for surrogate + error("character reference " + value + " is too large for UTF-16", + Integer.toString(value), null); + } + if (doFlush) + { + dataBufferFlush(); + } + } + + /** + * Parse and expand an entity reference. + *

      +   * [68] EntityRef ::= '&' Name ';'
      +   * 
      + *

      NOTE: the '&' has already been read. + * @param externalAllowed External entities are allowed here. + */ + private void parseEntityRef(boolean externalAllowed) + throws SAXException, IOException + { + String name; + + name = readNmtoken(true); + require(';'); + switch (getEntityType(name)) + { + case ENTITY_UNDECLARED: + // NOTE: XML REC describes amazingly convoluted handling for + // this case. Nothing as meaningful as being a WFness error + // unless the processor might _legitimately_ not have seen a + // declaration ... which is what this implements. + String message; + + message = "reference to undeclared general entity " + name; + if (skippedPE && !docIsStandalone) + { + handler.verror(message); + // we don't know this entity, and it might be external... + if (externalAllowed) + { + handler.skippedEntity(name); + } + } + else + { + error(message); + } + break; + case ENTITY_INTERNAL: + pushString(name, getEntityValue(name)); + + //workaround for possible input pop before marking + //the buffer reading position + char t = readCh(); + unread(t); + int bufferPosMark = readBufferPos; + + int end = readBufferPos + getEntityValue(name).length(); + for (int k = readBufferPos; k < end; k++) + { + t = readCh(); + if (t == '&') + { + t = readCh(); + if (t == '#') + { + //try to match a character ref + tryReadCharRef(); + + //everything has been read + if (readBufferPos >= end) + { + break; + } + k = readBufferPos; + continue; + } + else if (Character.isLetter(t)) + { + //looks like an entity ref + unread(t); + readNmtoken(true); + require(';'); + + //everything has been read + if (readBufferPos >= end) + { + break; + } + k = readBufferPos; + continue; + } + error(" malformed entity reference"); + } + + } + readBufferPos = bufferPosMark; + break; + case ENTITY_TEXT: + if (externalAllowed) + { + pushURL(false, name, getEntityIds(name), + null, null, null, true); + } + else + { + error("reference to external entity in attribute value.", + name, null); + } + break; + case ENTITY_NDATA: + if (externalAllowed) + { + error("unparsed entity reference in content", name, null); + } + else + { + error("reference to external entity in attribute value.", + name, null); + } + break; + default: + throw new RuntimeException(); + } + } + + /** + * Parse and expand a parameter entity reference. + *

      +   * [69] PEReference ::= '%' Name ';'
      +   * 
      + *

      NOTE: the '%' has already been read. + */ + private void parsePEReference() + throws SAXException, IOException + { + String name; + + name = "%" + readNmtoken(true); + require(';'); + switch (getEntityType(name)) + { + case ENTITY_UNDECLARED: + // VC: Entity Declared + handler.verror("reference to undeclared parameter entity " + name); + + // we should disable handling of all subsequent declarations + // unless this is a standalone document (info discarded) + break; + case ENTITY_INTERNAL: + if (inLiteral) + { + pushString(name, getEntityValue(name)); + } + else + { + pushString(name, ' ' + getEntityValue(name) + ' '); + } + break; + case ENTITY_TEXT: + if (!inLiteral) + { + pushString(null, " "); + } + pushURL(true, name, getEntityIds(name), null, null, null, true); + if (!inLiteral) + { + pushString(null, " "); + } + break; + } + } + + /** + * Parse an entity declaration. + *

      +   * [70] EntityDecl ::= GEDecl | PEDecl
      +   * [71] GEDecl ::= '<!ENTITY' S Name S EntityDef S? '>'
      +   * [72] PEDecl ::= '<!ENTITY' S '%' S Name S PEDef S? '>'
      +   * [73] EntityDef ::= EntityValue | (ExternalID NDataDecl?)
      +   * [74] PEDef ::= EntityValue | ExternalID
      +   * [75] ExternalID ::= 'SYSTEM' S SystemLiteral
      +   *       | 'PUBLIC' S PubidLiteral S SystemLiteral
      +   * [76] NDataDecl ::= S 'NDATA' S Name
      +   * 
      + *

      NOTE: the '<!ENTITY' has already been read. + */ + private void parseEntityDecl() + throws Exception + { + boolean peFlag = false; + int flags = 0; + + // Check for a parameter entity. + expandPE = false; + requireWhitespace(); + if (tryRead('%')) + { + peFlag = true; + requireWhitespace(); + } + expandPE = true; + + // Read the entity name, and prepend + // '%' if necessary. + String name = readNmtoken(true); + //NE08 + if (name.indexOf(':') >= 0) + { + error("Illegal character(':') in entity name ", name, null); + } + if (peFlag) + { + name = "%" + name; + } + + // Read the entity value. + requireWhitespace(); + char c = readCh(); + unread (c); + if (c == '"' || c == '\'') + { + // Internal entity ... replacement text has expanded refs + // to characters and PEs, but not to general entities + String value = readLiteral(flags); + setInternalEntity(name, value); + } + else + { + // Read the external IDs + ExternalIdentifiers ids = readExternalIds(false, false); + + // Check for NDATA declaration. + boolean white = tryWhitespace(); + if (!peFlag && tryRead("NDATA")) + { + if (!white) + { + error("whitespace required before NDATA"); + } + requireWhitespace(); + String notationName = readNmtoken(true); + if (!skippedPE) + { + setExternalEntity(name, ENTITY_NDATA, ids, notationName); + handler.unparsedEntityDecl(name, ids.publicId, ids.systemId, + ids.baseUri, notationName); + } + } + else if (!skippedPE) + { + setExternalEntity(name, ENTITY_TEXT, ids, null); + handler.getDeclHandler() + .externalEntityDecl(name, ids.publicId, + handler.resolveURIs() + // FIXME: ASSUMES not skipped + // "false" forces error on bad URI + ? handler.absolutize(ids.baseUri, + ids.systemId, + false) + : ids.systemId); + } + } + + // Finish the declaration. + skipWhitespace(); + require('>'); + } + + /** + * Parse a notation declaration. + *

      +   * [82] NotationDecl ::= '<!NOTATION' S Name S
      +   *    (ExternalID | PublicID) S? '>'
      +   * [83] PublicID ::= 'PUBLIC' S PubidLiteral
      +   * 
      + *

      NOTE: the '<!NOTATION' has already been read. + */ + private void parseNotationDecl() + throws Exception + { + String nname; + ExternalIdentifiers ids; + + requireWhitespace(); + nname = readNmtoken(true); + //NE08 + if (nname.indexOf(':') >= 0) + { + error("Illegal character(':') in notation name ", nname, null); + } + requireWhitespace(); + + // Read the external identifiers. + ids = readExternalIds(true, false); + + // Register the notation. + setNotation(nname, ids); + + skipWhitespace(); + require('>'); + } + + /** + * Parse character data. + *

      +   * [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*)
      +   * 
      + */ + private void parseCharData() + throws Exception + { + char c; + int state = 0; + boolean pureWhite = false; + + // assert (dataBufferPos == 0); + + // are we expecting pure whitespace? it might be dirty... + if ((currentElementContent == CONTENT_ELEMENTS) && !isDirtyCurrentElement) + { + pureWhite = true; + } + + // always report right out of readBuffer + // to minimize (pointless) buffer copies + while (true) + { + int lineAugment = 0; + int columnAugment = 0; + int i; + +loop: + for (i = readBufferPos; i < readBufferLength; i++) + { + switch (c = readBuffer[i]) + { + case '\n': + lineAugment++; + columnAugment = 0; + // pureWhite unmodified + break; + case '\r': // should not happen!! + case '\t': + case ' ': + // pureWhite unmodified + columnAugment++; + break; + case '&': + case '<': + columnAugment++; + // pureWhite unmodified + // CLEAN end of text sequence + state = 1; + break loop; + case ']': + // that's not a whitespace char, and + // can not terminate pure whitespace either + pureWhite = false; + if ((i + 2) < readBufferLength) + { + if (readBuffer [i + 1] == ']' + && readBuffer [i + 2] == '>') + { + // ERROR end of text sequence + state = 2; + break loop; + } + } + else + { + // FIXME missing two end-of-buffer cases + } + columnAugment++; + break; + default: + if ((c < 0x0020 || c > 0xFFFD) + || ((c >= 0x007f) && (c <= 0x009f) && (c != 0x0085) + && xmlVersion == XML_11)) + { + error("illegal XML character U+" + + Integer.toHexString(c)); + } + // that's not a whitespace char + pureWhite = false; + columnAugment++; + } + } + + // report text thus far + if (lineAugment > 0) + { + line += lineAugment; + column = columnAugment; + } + else + { + column += columnAugment; + } + + // report characters/whitspace + int length = i - readBufferPos; + + if (length != 0) + { + if (pureWhite) + { + handler.ignorableWhitespace(readBuffer, + readBufferPos, length); + } + else + { + handler.charData(readBuffer, readBufferPos, length); + } + readBufferPos = i; + } + + if (state != 0) + { + break; + } + + // fill next buffer from this entity, or + // pop stack and continue with previous entity + unread(readCh()); + } + if (!pureWhite) + { + isDirtyCurrentElement = true; + } + // finish, maybe with error + if (state != 1) // finish, no error + { + error("character data may not contain ']]>'"); + } + } + + ////////////////////////////////////////////////////////////////////// + // High-level reading and scanning methods. + ////////////////////////////////////////////////////////////////////// + + /** + * Require whitespace characters. + */ + private void requireWhitespace() + throws SAXException, IOException + { + char c = readCh(); + if (isWhitespace(c)) + { + skipWhitespace(); + } + else + { + error("whitespace required", c, null); + } + } + + /** + * Skip whitespace characters. + *
      +   * [3] S ::= (#x20 | #x9 | #xd | #xa)+
      +   * 
      + */ + private void skipWhitespace() + throws SAXException, IOException + { + // Start with a little cheat. Most of + // the time, the white space will fall + // within the current read buffer; if + // not, then fall through. + if (USE_CHEATS) + { + int lineAugment = 0; + int columnAugment = 0; + +loop: + for (int i = readBufferPos; i < readBufferLength; i++) + { + switch (readBuffer[i]) + { + case ' ': + case '\t': + case '\r': + columnAugment++; + break; + case '\n': + lineAugment++; + columnAugment = 0; + break; + case '%': + if (expandPE) + { + break loop; + } + // else fall through... + default: + readBufferPos = i; + if (lineAugment > 0) + { + line += lineAugment; + column = columnAugment; + } + else + { + column += columnAugment; + } + return; + } + } + } + + // OK, do it the slow way. + char c = readCh (); + while (isWhitespace(c)) + { + c = readCh(); + } + unread(c); + } + + /** + * Read a name or (when parsing an enumeration) name token. + *
      +   * [5] Name ::= (Letter | '_' | ':') (NameChar)*
      +   * [7] Nmtoken ::= (NameChar)+
      +   * 
      + */ + private String readNmtoken(boolean isName) + throws SAXException, IOException + { + char c; + + if (USE_CHEATS) + { +loop: + for (int i = readBufferPos; i < readBufferLength; i++) + { + c = readBuffer[i]; + switch (c) + { + case '%': + if (expandPE) + { + break loop; + } + // else fall through... + + // What may legitimately come AFTER a name/nmtoken? + case '<': case '>': case '&': + case ',': case '|': case '*': case '+': case '?': + case ')': + case '=': + case '\'': case '"': + case '[': + case ' ': case '\t': case '\r': case '\n': + case ';': + case '/': + int start = readBufferPos; + if (i == start) + { + error("name expected", readBuffer[i], null); + } + readBufferPos = i; + return intern(readBuffer, start, i - start); + + default: + // FIXME ... per IBM's OASIS test submission, these: + // ? U+06dd + // Combining U+309B + //these switches are kind of ugly but at least we won't + //have to go over the whole lits for each char + if (isName && i == readBufferPos) + { + char c2 = (char) (c & 0x00f0); + switch (c & 0xff00) + { + //starting with 01 + case 0x0100: + switch (c2) + { + case 0x0030: + if (c == 0x0132 || c == 0x0133 || c == 0x013f) + { + error("Not a name start character, U+" + + Integer.toHexString(c)); + } + break; + case 0x0040: + if (c == 0x0140 || c == 0x0149) + { + error("Not a name start character, U+" + + Integer.toHexString(c)); + } + break; + case 0x00c0: + if (c == 0x01c4 || c == 0x01cc) + { + error("Not a name start character, U+" + + Integer.toHexString(c)); + } + break; + case 0x00f0: + if (c == 0x01f1 || c == 0x01f3) + { + error("Not a name start character, U+" + + Integer.toHexString(c)); + } + break; + case 0x00b0: + if (c == 0x01f1 || c == 0x01f3) + { + error("Not a name start character, U+" + + Integer.toHexString(c)); + } + break; + default: + if (c == 0x017f) + { + error("Not a name start character, U+" + + Integer.toHexString(c)); + } + } + + break; + //starting with 11 + case 0x1100: + switch (c2) + { + case 0x0000: + if (c == 0x1104 || c == 0x1108 || + c == 0x110a || c == 0x110d) + { + error("Not a name start character, U+" + + Integer.toHexString(c)); + } + break; + case 0x0030: + if (c == 0x113b || c == 0x113f) + { + error("Not a name start character, U+" + + Integer.toHexString(c)); + } + break; + case 0x0040: + if (c == 0x1141 || c == 0x114d + || c == 0x114f ) + { + error("Not a name start character, U+" + + Integer.toHexString(c)); + } + break; + case 0x0050: + if (c == 0x1151 || c == 0x1156) + { + error("Not a name start character, U+" + + Integer.toHexString(c)); + } + break; + case 0x0060: + if (c == 0x1162 || c == 0x1164 + || c == 0x1166 || c == 0x116b + || c == 0x116f) + { + error("Not a name start character, U+" + + Integer.toHexString(c)); + } + break; + case 0x00b0: + if (c == 0x11b6 || c == 0x11b9 + || c == 0x11bb || c == 0x116f) + { + error("Not a name start character, U+" + + Integer.toHexString(c)); + } + break; + default: + if (c == 0x1174 || c == 0x119f + || c == 0x11ac || c == 0x11c3 + || c == 0x11f1) + { + error("Not a name start character, U+" + + Integer.toHexString(c)); + } + } + break; + default: + if (c == 0x0e46 || c == 0x1011 + || c == 0x212f || c == 0x0587 + || c == 0x0230 ) + { + error("Not a name start character, U+" + + Integer.toHexString(c)); + } + } + } + // punt on exact tests from Appendix A; approximate + // them using the Unicode ID start/part rules + if (i == readBufferPos && isName) + { + if (!Character.isUnicodeIdentifierStart(c) + && c != ':' && c != '_') + { + error("Not a name start character, U+" + + Integer.toHexString(c)); + } + } + else if (!Character.isUnicodeIdentifierPart(c) + && c != '-' && c != ':' && c != '_' && c != '.' + && !isExtender(c)) + { + error("Not a name character, U+" + + Integer.toHexString(c)); + } + } + } + } + + nameBufferPos = 0; + + // Read the first character. + while (true) + { + c = readCh(); + switch (c) + { + case '%': + case '<': case '>': case '&': + case ',': case '|': case '*': case '+': case '?': + case ')': + case '=': + case '\'': case '"': + case '[': + case ' ': case '\t': case '\n': case '\r': + case ';': + case '/': + unread(c); + if (nameBufferPos == 0) + { + error ("name expected"); + } + // punt on exact tests from Appendix A, but approximate them + if (isName + && !Character.isUnicodeIdentifierStart(nameBuffer[0]) + && ":_".indexOf(nameBuffer[0]) == -1) + { + error("Not a name start character, U+" + + Integer.toHexString(nameBuffer[0])); + } + String s = intern(nameBuffer, 0, nameBufferPos); + nameBufferPos = 0; + return s; + default: + // punt on exact tests from Appendix A, but approximate them + + if ((nameBufferPos != 0 || !isName) + && !Character.isUnicodeIdentifierPart(c) + && ":-_.".indexOf(c) == -1 + && !isExtender(c)) + { + error("Not a name character, U+" + + Integer.toHexString(c)); + } + if (nameBufferPos >= nameBuffer.length) + { + nameBuffer = + (char[]) extendArray(nameBuffer, + nameBuffer.length, nameBufferPos); + } + nameBuffer[nameBufferPos++] = c; + } + } + } + + private static boolean isExtender(char c) + { + // [88] Extender ::= ... + return c == 0x00b7 || c == 0x02d0 || c == 0x02d1 || c == 0x0387 + || c == 0x0640 || c == 0x0e46 || c == 0x0ec6 || c == 0x3005 + || (c >= 0x3031 && c <= 0x3035) + || (c >= 0x309d && c <= 0x309e) + || (c >= 0x30fc && c <= 0x30fe); + } + + /** + * Read a literal. With matching single or double quotes as + * delimiters (and not embedded!) this is used to parse: + *
      +   *  [9] EntityValue ::= ... ([^%&] | PEReference | Reference)* ...
      +   *  [10] AttValue ::= ... ([^<&] | Reference)* ...
      +   *  [11] SystemLiteral ::= ... (URLchar - "'")* ...
      +   *  [12] PubidLiteral ::= ... (PubidChar - "'")* ...
      +   * 
      + * as well as the quoted strings in XML and text declarations + * (for version, encoding, and standalone) which have their + * own constraints. + */ + private String readLiteral(int flags) + throws SAXException, IOException + { + char delim, c; + int startLine = line; + boolean saved = expandPE; + boolean savedReport = doReport; + + // Find the first delimiter. + delim = readCh(); + if (delim != '"' && delim != '\'') + { + error("expected '\"' or \"'\"", delim, null); + return null; + } + inLiteral = true; + if ((flags & LIT_DISABLE_PE) != 0) + { + expandPE = false; + } + doReport = false; + + // Each level of input source has its own buffer; remember + // ours, so we won't read the ending delimiter from any + // other input source, regardless of entity processing. + char[] ourBuf = readBuffer; + + // Read the literal. + try + { + c = readCh(); + boolean ampRead = false; +loop: + while (! (c == delim && readBuffer == ourBuf)) + { + switch (c) + { + // attributes and public ids are normalized + // in almost the same ways + case '\n': + case '\r': + if ((flags & (LIT_ATTRIBUTE | LIT_PUBID)) != 0) + { + c = ' '; + } + break; + case '\t': + if ((flags & LIT_ATTRIBUTE) != 0) + { + c = ' '; + } + break; + case '&': + c = readCh(); + // Char refs are expanded immediately, except for + // all the cases where it's deferred. + if (c == '#') + { + if ((flags & LIT_DISABLE_CREF) != 0) + { + dataBufferAppend('&'); + break; + } + parseCharRef(false /* Do not do flushDataBuffer */); + + // exotic WFness risk: this is an entity literal, + // dataBuffer [dataBufferPos - 1] == '&', and + // following chars are a _partial_ entity/char ref + + // It looks like an entity ref ... + } + else + { + unread(c); + // Expand it? + if ((flags & LIT_ENTITY_REF) > 0) + { + parseEntityRef(false); + if (String.valueOf(readBuffer).equals("&")) + { + ampRead = true; + } + //Is it just data? + } + else if ((flags & LIT_DISABLE_EREF) != 0) + { + dataBufferAppend('&'); + + // OK, it will be an entity ref -- expanded later. + } + else + { + String name = readNmtoken(true); + require(';'); + dataBufferAppend('&'); + dataBufferAppend(name); + dataBufferAppend(';'); + } + } + c = readCh(); + continue loop; + + case '<': + // and why? Perhaps so "&foo;" expands the same + // inside and outside an attribute? + if ((flags & LIT_ATTRIBUTE) != 0) + { + error("attribute values may not contain '<'"); + } + break; + + // We don't worry about case '%' and PE refs, readCh does. + + default: + break; + } + dataBufferAppend(c); + c = readCh(); + } + } + catch (EOFException e) + { + error("end of input while looking for delimiter (started on line " + + startLine + ')', null, Character.toString(delim)); + } + inLiteral = false; + expandPE = saved; + doReport = savedReport; + + // Normalise whitespace if necessary. + if ((flags & LIT_NORMALIZE) > 0) + { + dataBufferNormalize(); + } + + // Return the value. + return dataBufferToString(); + } + + /** + * Try reading external identifiers. + * A system identifier is not required for notations. + * @param inNotation Are we parsing a notation decl? + * @param isSubset Parsing external subset decl (may be omitted)? + * @return A three-member String array containing the identifiers, + * or nulls. Order: public, system, baseURI. + */ + private ExternalIdentifiers readExternalIds(boolean inNotation, + boolean isSubset) + throws Exception + { + char c; + ExternalIdentifiers ids = new ExternalIdentifiers(); + int flags = LIT_DISABLE_CREF | LIT_DISABLE_PE | LIT_DISABLE_EREF; + + if (tryRead("PUBLIC")) + { + requireWhitespace(); + ids.publicId = readLiteral(LIT_NORMALIZE | LIT_PUBID | flags); + if (inNotation) + { + skipWhitespace(); + c = readCh(); + unread(c); + if (c == '"' || c == '\'') + { + ids.systemId = readLiteral(flags); + } + } + else + { + requireWhitespace(); + ids.systemId = readLiteral(flags); + } + + for (int i = 0; i < ids.publicId.length(); i++) + { + c = ids.publicId.charAt(i); + if (c >= 'a' && c <= 'z') + { + continue; + } + if (c >= 'A' && c <= 'Z') + { + continue; + } + if (" \r\n0123456789-' ()+,./:=?;!*#@$_%".indexOf(c) != -1) + { + continue; + } + error("illegal PUBLIC id character U+" + + Integer.toHexString(c)); + } + } + else if (tryRead("SYSTEM")) + { + requireWhitespace(); + ids.systemId = readLiteral(flags); + } + else if (!isSubset) + { + error("missing SYSTEM or PUBLIC keyword"); + } + + if (ids.systemId != null) + { + if (ids.systemId.indexOf('#') != -1) + { + handler.verror("SYSTEM id has a URI fragment: " + ids.systemId); + } + ids.baseUri = handler.getSystemId(); + if (ids.baseUri == null && uriWarnings) + { + handler.warn("No base URI; hope URI is absolute: " + + ids.systemId); + } + } + + return ids; + } + + /** + * Test if a character is whitespace. + *
      +   * [3] S ::= (#x20 | #x9 | #xd | #xa)+
      +   * 
      + * @param c The character to test. + * @return true if the character is whitespace. + */ + private final boolean isWhitespace(char c) + { + if (c > 0x20) + { + return false; + } + if (c == 0x20 || c == 0x0a || c == 0x09 || c == 0x0d) + { + return true; + } + return false; // illegal ... + } + + ////////////////////////////////////////////////////////////////////// + // Utility routines. + ////////////////////////////////////////////////////////////////////// + + /** + * Add a character to the data buffer. + */ + private void dataBufferAppend(char c) + { + // Expand buffer if necessary. + if (dataBufferPos >= dataBuffer.length) + { + dataBuffer = (char[]) extendArray(dataBuffer, + dataBuffer.length, dataBufferPos); + } + dataBuffer[dataBufferPos++] = c; + } + + /** + * Add a string to the data buffer. + */ + private void dataBufferAppend(String s) + { + dataBufferAppend(s.toCharArray(), 0, s.length()); + } + + /** + * Append (part of) a character array to the data buffer. + */ + private void dataBufferAppend(char[] ch, int start, int length) + { + dataBuffer = (char[]) extendArray(dataBuffer, dataBuffer.length, + dataBufferPos + length); + + System.arraycopy(ch, start, dataBuffer, dataBufferPos, length); + dataBufferPos += length; + } + + /** + * Normalise space characters in the data buffer. + */ + private void dataBufferNormalize() + { + int i = 0; + int j = 0; + int end = dataBufferPos; + + // Skip spaces at the start. + while (j < end && dataBuffer[j] == ' ') + { + j++; + } + + // Skip whitespace at the end. + while (end > j && dataBuffer[end - 1] == ' ') + { + end --; + } + + // Start copying to the left. + while (j < end) + { + + char c = dataBuffer[j++]; + + // Normalise all other spaces to + // a single space. + if (c == ' ') + { + while (j < end && dataBuffer[j++] == ' ') + { + continue; + } + dataBuffer[i++] = ' '; + dataBuffer[i++] = dataBuffer[j - 1]; + } + else + { + dataBuffer[i++] = c; + } + } + + // The new length is <= the old one. + dataBufferPos = i; + } + + /** + * Convert the data buffer to a string. + */ + private String dataBufferToString() + { + String s = new String(dataBuffer, 0, dataBufferPos); + dataBufferPos = 0; + return s; + } + + /** + * Flush the contents of the data buffer to the handler, as + * appropriate, and reset the buffer for new input. + */ + private void dataBufferFlush() + throws SAXException + { + if (currentElementContent == CONTENT_ELEMENTS + && dataBufferPos > 0 + && !inCDATA) + { + // We can't just trust the buffer to be whitespace, there + // are (error) cases when it isn't + for (int i = 0; i < dataBufferPos; i++) + { + if (!isWhitespace(dataBuffer[i])) + { + handler.charData(dataBuffer, 0, dataBufferPos); + dataBufferPos = 0; + } + } + if (dataBufferPos > 0) + { + handler.ignorableWhitespace(dataBuffer, 0, dataBufferPos); + dataBufferPos = 0; + } + } + else if (dataBufferPos > 0) + { + handler.charData(dataBuffer, 0, dataBufferPos); + dataBufferPos = 0; + } + } + + /** + * Require a string to appear, or throw an exception. + *

      Precondition: Entity expansion is not required. + *

      Precondition: data buffer has no characters that + * will get sent to the application. + */ + private void require(String delim) + throws SAXException, IOException + { + int length = delim.length(); + char[] ch; + + if (length < dataBuffer.length) + { + ch = dataBuffer; + delim.getChars(0, length, ch, 0); + } + else + { + ch = delim.toCharArray(); + } + + if (USE_CHEATS && length <= (readBufferLength - readBufferPos)) + { + int offset = readBufferPos; + + for (int i = 0; i < length; i++, offset++) + { + if (ch[i] != readBuffer[offset]) + { + error ("required string", null, delim); + } + } + readBufferPos = offset; + + } + else + { + for (int i = 0; i < length; i++) + { + require(ch[i]); + } + } + } + + /** + * Require a character to appear, or throw an exception. + */ + private void require(char delim) + throws SAXException, IOException + { + char c = readCh(); + + if (c != delim) + { + error("required character", c, Character.toString(delim)); + } + } + + /** + * Create an interned string from a character array. + * Ælfred uses this method to create an interned version + * of all names and name tokens, so that it can test equality + * with == instead of String.equals (). + * + *

      This is much more efficient than constructing a non-interned + * string first, and then interning it. + * + * @param ch an array of characters for building the string. + * @param start the starting position in the array. + * @param length the number of characters to place in the string. + * @return an interned string. + * @see #intern (String) + * @see java.lang.String#intern + */ + public String intern(char[] ch, int start, int length) + { + int index = 0; + int hash = 0; + Object[] bucket; + + // Generate a hash code. This is a widely used string hash, + // often attributed to Brian Kernighan. + for (int i = start; i < start + length; i++) + { + hash = 31 * hash + ch[i]; + } + hash = (hash & 0x7fffffff) % SYMBOL_TABLE_LENGTH; + + // Get the bucket -- consists of {array,String} pairs + if ((bucket = symbolTable[hash]) == null) + { + // first string in this bucket + bucket = new Object[8]; + + // Search for a matching tuple, and + // return the string if we find one. + } + else + { + while (index < bucket.length) + { + char[] chFound = (char[]) bucket[index]; + + // Stop when we hit an empty entry. + if (chFound == null) + { + break; + } + + // If they're the same length, check for a match. + if (chFound.length == length) + { + for (int i = 0; i < chFound.length; i++) + { + // continue search on failure + if (ch[start + i] != chFound[i]) + { + break; + } + else if (i == length - 1) + { + // That's it, we have a match! + return (String) bucket[index + 1]; + } + } + } + index += 2; + } + // Not found -- we'll have to add it. + + // Do we have to grow the bucket? + bucket = (Object[]) extendArray(bucket, bucket.length, index); + } + symbolTable[hash] = bucket; + + // OK, add it to the end of the bucket -- "local" interning. + // Intern "globally" to let applications share interning benefits. + // That is, "!=" and "==" work on our strings, not just equals(). + String s = new String(ch, start, length).intern(); + bucket[index] = s.toCharArray(); + bucket[index + 1] = s; + return s; + } + + /** + * Ensure the capacity of an array, allocating a new one if + * necessary. Usually extends only for name hash collisions. + */ + private Object extendArray(Object array, int currentSize, int requiredSize) + { + if (requiredSize < currentSize) + { + return array; + } + else + { + Object newArray = null; + int newSize = currentSize * 2; + + if (newSize <= requiredSize) + { + newSize = requiredSize + 1; + } + + if (array instanceof char[]) + { + newArray = new char[newSize]; + } + else if (array instanceof Object[]) + { + newArray = new Object[newSize]; + } + else + { + throw new RuntimeException(); + } + + System.arraycopy(array, 0, newArray, 0, currentSize); + return newArray; + } + } + + ////////////////////////////////////////////////////////////////////// + // XML query routines. + ////////////////////////////////////////////////////////////////////// + + boolean isStandalone() + { + return docIsStandalone; + } + + // + // Elements + // + + private int getContentType(ElementDecl element, int defaultType) + { + int retval; + + if (element == null) + { + return defaultType; + } + retval = element.contentType; + if (retval == CONTENT_UNDECLARED) + { + retval = defaultType; + } + return retval; + } + + /** + * Look up the content type of an element. + * @param name The element type name. + * @return An integer constant representing the content type. + * @see #CONTENT_UNDECLARED + * @see #CONTENT_ANY + * @see #CONTENT_EMPTY + * @see #CONTENT_MIXED + * @see #CONTENT_ELEMENTS + */ + public int getElementContentType(String name) + { + ElementDecl element = (ElementDecl) elementInfo.get(name); + return getContentType(element, CONTENT_UNDECLARED); + } + + /** + * Register an element. + * Array format: + * [0] element type name + * [1] content model (mixed, elements only) + * [2] attribute hash table + */ + private void setElement(String name, int contentType, + String contentModel, HashMap attributes) + throws SAXException + { + if (skippedPE) + { + return; + } + + ElementDecl element = (ElementDecl) elementInfo.get(name); + + // first or for this type? + if (element == null) + { + element = new ElementDecl(); + element.contentType = contentType; + element.contentModel = contentModel; + element.attributes = attributes; + elementInfo.put(name, element); + return; + } + + // declaration? + if (contentType != CONTENT_UNDECLARED) + { + // ... following an associated + if (element.contentType == CONTENT_UNDECLARED) + { + element.contentType = contentType; + element.contentModel = contentModel; + } + else + { + // VC: Unique Element Type Declaration + handler.verror("multiple declarations for element type: " + + name); + } + } + + // first , before ? + else if (attributes != null) + { + element.attributes = attributes; + } + } + + /** + * Look up the attribute hash table for an element. + * The hash table is the second item in the element array. + */ + private HashMap getElementAttributes(String name) + { + ElementDecl element = (ElementDecl) elementInfo.get(name); + return (element == null) ? null : element.attributes; + } + + // + // Attributes + // + + /** + * Get the declared attributes for an element type. + * @param elname The name of the element type. + * @return An iterator over all the attributes declared for + * a specific element type. The results will be valid only + * after the DTD (if any) has been parsed. + * @see #getAttributeType + * @see #getAttributeEnumeration + * @see #getAttributeDefaultValueType + * @see #getAttributeDefaultValue + * @see #getAttributeExpandedValue + */ + private Iterator declaredAttributes(ElementDecl element) + { + HashMap attlist; + + if (element == null) + { + return null; + } + if ((attlist = element.attributes) == null) + { + return null; + } + return attlist.keySet().iterator(); + } + + /** + * Get the declared attributes for an element type. + * @param elname The name of the element type. + * @return An iterator over all the attributes declared for + * a specific element type. The results will be valid only + * after the DTD (if any) has been parsed. + * @see #getAttributeType + * @see #getAttributeEnumeration + * @see #getAttributeDefaultValueType + * @see #getAttributeDefaultValue + * @see #getAttributeExpandedValue + */ + public Iterator declaredAttributes(String elname) + { + return declaredAttributes((ElementDecl) elementInfo.get(elname)); + } + + /** + * Retrieve the declared type of an attribute. + * @param name The name of the associated element. + * @param aname The name of the attribute. + * @return An interend string denoting the type, or null + * indicating an undeclared attribute. + */ + public String getAttributeType(String name, String aname) + { + AttributeDecl attribute = getAttribute(name, aname); + return (attribute == null) ? null : attribute.type; + } + + /** + * Retrieve the allowed values for an enumerated attribute type. + * @param name The name of the associated element. + * @param aname The name of the attribute. + * @return A string containing the token list. + */ + public String getAttributeEnumeration(String name, String aname) + { + AttributeDecl attribute = getAttribute(name, aname); + // assert: attribute.enumeration is "ENUMERATION" or "NOTATION" + return (attribute == null) ? null : attribute.enumeration; + } + + /** + * Retrieve the default value of a declared attribute. + * @param name The name of the associated element. + * @param aname The name of the attribute. + * @return The default value, or null if the attribute was + * #IMPLIED or simply undeclared and unspecified. + * @see #getAttributeExpandedValue + */ + public String getAttributeDefaultValue(String name, String aname) + { + AttributeDecl attribute = getAttribute(name, aname); + return (attribute == null) ? null : attribute.value; + } + + /* + +// FIXME: Leaving this in, until W3C finally resolves the confusion +// between parts of the XML 2nd REC about when entity declararations +// are guaranteed to be known. Current code matches what section 5.1 +// (conformance) describes, but some readings of the self-contradicting +// text in 4.1 (the "Entity Declared" WFC and VC) seem to expect that +// attribute expansion/normalization must be deferred in some cases +// (just TRY to identify them!). + + * Retrieve the expanded value of a declared attribute. + *

      General entities (and char refs) will be expanded (once). + * @param name The name of the associated element. + * @param aname The name of the attribute. + * @return The expanded default value, or null if the attribute was + * #IMPLIED or simply undeclared + * @see #getAttributeDefaultValue + public String getAttributeExpandedValue (String name, String aname) + throws Exception + { + AttributeDecl attribute = getAttribute (name, aname); + + if (attribute == null) { + return null; + } else if (attribute.defaultValue == null && attribute.value != null) { + // we MUST use the same buf for both quotes else the literal + // can't be properly terminated + char buf [] = new char [1]; + int flags = LIT_ENTITY_REF | LIT_ATTRIBUTE; + String type = getAttributeType (name, aname); + + if (type != "CDATA" && type != null) + flags |= LIT_NORMALIZE; + buf [0] = '"'; + pushCharArray (null, buf, 0, 1); + pushString (null, attribute.value); + pushCharArray (null, buf, 0, 1); + attribute.defaultValue = readLiteral (flags); + } + return attribute.defaultValue; + } + */ + + /** + * Retrieve the default value mode of a declared attribute. + * @see #ATTRIBUTE_DEFAULT_SPECIFIED + * @see #ATTRIBUTE_DEFAULT_IMPLIED + * @see #ATTRIBUTE_DEFAULT_REQUIRED + * @see #ATTRIBUTE_DEFAULT_FIXED + */ + public int getAttributeDefaultValueType(String name, String aname) + { + AttributeDecl attribute = getAttribute(name, aname); + return (attribute == null) ? ATTRIBUTE_DEFAULT_UNDECLARED : + attribute.valueType; + } + + /** + * Register an attribute declaration for later retrieval. + * Format: + * - String type + * - String default value + * - int value type + * - enumeration + * - processed default value + */ + private void setAttribute(String elName, String name, String type, + String enumeration, String value, int valueType) + throws Exception + { + HashMap attlist; + + if (skippedPE) + { + return; + } + + // Create a new hashtable if necessary. + attlist = getElementAttributes(elName); + if (attlist == null) + { + attlist = new HashMap(); + } + + // ignore multiple attribute declarations! + if (attlist.get(name) != null) + { + // warn ... + return; + } + else + { + AttributeDecl attribute = new AttributeDecl(); + attribute.type = type; + attribute.value = value; + attribute.valueType = valueType; + attribute.enumeration = enumeration; + attlist.put(name, attribute); + + // save; but don't overwrite any existing + setElement(elName, CONTENT_UNDECLARED, null, attlist); + } + } + + /** + * Retrieve the attribute declaration for the given element name and name. + */ + private AttributeDecl getAttribute(String elName, String name) + { + HashMap attlist = getElementAttributes(elName); + return (attlist == null) ? null : (AttributeDecl) attlist.get(name); + } + + // + // Entities + // + + /** + * Find the type of an entity. + * @returns An integer constant representing the entity type. + * @see #ENTITY_UNDECLARED + * @see #ENTITY_INTERNAL + * @see #ENTITY_NDATA + * @see #ENTITY_TEXT + */ + public int getEntityType(String ename) + { + EntityInfo entity = (EntityInfo) entityInfo.get(ename); + return (entity == null) ? ENTITY_UNDECLARED : entity.type; + } + + /** + * Return an external entity's identifiers. + * @param ename The name of the external entity. + * @return The entity's public identifier, system identifier, and base URI. + * Null if the entity was not declared as an external entity. + * @see #getEntityType + */ + public ExternalIdentifiers getEntityIds(String ename) + { + EntityInfo entity = (EntityInfo) entityInfo.get(ename); + return (entity == null) ? null : entity.ids; + } + + /** + * Return an internal entity's replacement text. + * @param ename The name of the internal entity. + * @return The entity's replacement text, or null if + * the entity was not declared as an internal entity. + * @see #getEntityType + */ + public String getEntityValue(String ename) + { + EntityInfo entity = (EntityInfo) entityInfo.get(ename); + return (entity == null) ? null : entity.value; + } + + /** + * Register an entity declaration for later retrieval. + */ + private void setInternalEntity(String eName, String value) + throws SAXException + { + if (skippedPE) + { + return; + } + + if (entityInfo.get(eName) == null) + { + EntityInfo entity = new EntityInfo(); + entity.type = ENTITY_INTERNAL; + entity.value = value; + entityInfo.put(eName, entity); + } + if (handler.stringInterning) + { + if ("lt" == eName || "gt" == eName || "quot" == eName + || "apos" == eName || "amp" == eName) + { + return; + } + } + else + { + if ("lt".equals(eName) || "gt".equals(eName) || "quot".equals(eName) + || "apos".equals(eName) || "amp".equals(eName)) + { + return; + } + } + handler.getDeclHandler().internalEntityDecl(eName, value); + } + + /** + * Register an external entity declaration for later retrieval. + */ + private void setExternalEntity(String eName, int eClass, + ExternalIdentifiers ids, String nName) + { + if (entityInfo.get(eName) == null) + { + EntityInfo entity = new EntityInfo(); + entity.type = eClass; + entity.ids = ids; + entity.notationName = nName; + entityInfo.put(eName, entity); + } + } + + // + // Notations. + // + + /** + * Report a notation declaration, checking for duplicates. + */ + private void setNotation(String nname, ExternalIdentifiers ids) + throws SAXException + { + if (skippedPE) + { + return; + } + + handler.notationDecl(nname, ids.publicId, ids.systemId, ids.baseUri); + if (notationInfo.get(nname) == null) + { + notationInfo.put(nname, nname); + } + else + { + // VC: Unique Notation Name + handler.verror("Duplicate notation name decl: " + nname); + } + } + + // + // Location. + // + + /** + * Return the current line number. + */ + public int getLineNumber() + { + return line; + } + + /** + * Return the current column number. + */ + public int getColumnNumber() + { + return column; + } + + ////////////////////////////////////////////////////////////////////// + // High-level I/O. + ////////////////////////////////////////////////////////////////////// + + /** + * Read a single character from the readBuffer. + *

      The readDataChunk () method maintains the buffer. + *

      If we hit the end of an entity, try to pop the stack and + * keep going. + *

      (This approach doesn't really enforce XML's rules about + * entity boundaries, but this is not currently a validating + * parser). + *

      This routine also attempts to keep track of the current + * position in external entities, but it's not entirely accurate. + * @return The next available input character. + * @see #unread (char) + * @see #readDataChunk + * @see #readBuffer + * @see #line + * @return The next character from the current input source. + */ + private char readCh() + throws SAXException, IOException + { + // As long as there's nothing in the + // read buffer, try reading more data + // (for an external entity) or popping + // the entity stack (for either). + while (readBufferPos >= readBufferLength) + { + switch (sourceType) + { + case INPUT_READER: + case INPUT_STREAM: + readDataChunk(); + while (readBufferLength < 1) + { + popInput(); + if (readBufferLength < 1) + { + readDataChunk(); + } + } + break; + + default: + + popInput(); + break; + } + } + + char c = readBuffer[readBufferPos++]; + + if (c == '\n') + { + line++; + column = 0; + } + else + { + if (c == '<') + { + /* the most common return to parseContent () ... NOP */ + } + else if (((c < 0x0020 && (c != '\t') && (c != '\r')) || c > 0xFFFD) + || ((c >= 0x007f) && (c <= 0x009f) && (c != 0x0085) + && xmlVersion == XML_11)) + { + error("illegal XML character U+" + Integer.toHexString(c)); + } + + // If we're in the DTD and in a context where PEs get expanded, + // do so ... 1/14/2000 errata identify those contexts. There + // are also spots in the internal subset where PE refs are fatal + // errors, hence yet another flag. + else if (c == '%' && expandPE) + { + if (peIsError) + { + error("PE reference within decl in internal subset."); + } + parsePEReference(); + return readCh(); + } + column++; + } + + return c; + } + + /** + * Push a single character back onto the current input stream. + *

      This method usually pushes the character back onto + * the readBuffer. + *

      I don't think that this would ever be called with + * readBufferPos = 0, because the methods always reads a character + * before unreading it, but just in case, I've added a boundary + * condition. + * @param c The character to push back. + * @see #readCh + * @see #unread (char[]) + * @see #readBuffer + */ + private void unread(char c) + throws SAXException + { + // Normal condition. + if (c == '\n') + { + line--; + column = -1; + } + if (readBufferPos > 0) + { + readBuffer[--readBufferPos] = c; + } + else + { + pushString(null, Character.toString(c)); + } + } + + /** + * Push a char array back onto the current input stream. + *

      NOTE: you must never push back characters that you + * haven't actually read: use pushString () instead. + * @see #readCh + * @see #unread (char) + * @see #readBuffer + * @see #pushString + */ + private void unread(char[] ch, int length) + throws SAXException + { + for (int i = 0; i < length; i++) + { + if (ch[i] == '\n') + { + line--; + column = -1; + } + } + if (length < readBufferPos) + { + readBufferPos -= length; + } + else + { + pushCharArray(null, ch, 0, length); + } + } + + /** + * Push, or skip, a new external input source. + * The source will be some kind of parsed entity, such as a PE + * (including the external DTD subset) or content for the body. + * + * @param url The java.net.URL object for the entity. + * @see SAXDriver#resolveEntity + * @see #pushString + * @see #sourceType + * @see #pushInput + * @see #detectEncoding + * @see #sourceType + * @see #readBuffer + */ + private void pushURL(boolean isPE, + String ename, + ExternalIdentifiers ids, + Reader reader, + InputStream stream, + String encoding, + boolean doResolve) + throws SAXException, IOException + { + boolean ignoreEncoding; + String systemId; + InputSource source; + + if (!isPE) + { + dataBufferFlush(); + } + + scratch.setPublicId(ids.publicId); + scratch.setSystemId(ids.systemId); + + // See if we should skip or substitute the entity. + // If we're not skipping, resolving reports startEntity() + // and updates the (handler's) stack of URIs. + if (doResolve) + { + // assert (stream == null && reader == null && encoding == null) + source = handler.resolveEntity(isPE, ename, scratch, ids.baseUri); + if (source == null) + { + handler.warn("skipping entity: " + ename); + handler.skippedEntity(ename); + if (isPE) + { + skippedPE = true; + } + return; + } + + // we might be using alternate IDs/encoding + systemId = source.getSystemId(); + // The following warning and setting systemId was deleted bcause + // the application has the option of not setting systemId + // provided that it has set the characte/byte stream. + /* + if (systemId == null) { + handler.warn ("missing system ID, using " + ids.systemId); + systemId = ids.systemId; + } + */ + } + else + { + // "[document]", or "[dtd]" via getExternalSubset() + scratch.setCharacterStream(reader); + scratch.setByteStream(stream); + scratch.setEncoding(encoding); + source = scratch; + systemId = ids.systemId; + if (handler.stringInterning) + { + handler.startExternalEntity(ename, systemId, + "[document]" == ename); + } + else + { + handler.startExternalEntity(ename, systemId, + "[document]".equals(ename)); + } + } + + // we may have been given I/O streams directly + if (source.getCharacterStream() != null) + { + if (source.getByteStream() != null) + error("InputSource has two streams!"); + reader = source.getCharacterStream(); + } + else if (source.getByteStream() != null) + { + encoding = source.getEncoding(); + if (encoding == null) + { + stream = source.getByteStream(); + } + else + { + try + { + reader = new InputStreamReader(source.getByteStream(), + encoding); + } + catch (IOException e) + { + stream = source.getByteStream(); + } + } + } + else if (systemId == null) + { + error("InputSource has no URI!"); + } + scratch.setCharacterStream(null); + scratch.setByteStream(null); + scratch.setEncoding(null); + + // Push the existing status. + pushInput(ename); + + // Create a new read buffer. + // (Note the four-character margin) + readBuffer = new char[READ_BUFFER_MAX + 4]; + readBufferPos = 0; + readBufferLength = 0; + readBufferOverflow = -1; + is = null; + line = 1; + column = 0; + currentByteCount = 0; + + // If there's an explicit character stream, just + // ignore encoding declarations. + if (reader != null) + { + sourceType = INPUT_READER; + this.reader = reader; + tryEncodingDecl(true); + return; + } + + // Else we handle the conversion, and need to ensure + // it's done right. + sourceType = INPUT_STREAM; + if (stream != null) + { + is = stream; + } + else + { + // We have to open our own stream to the URL. + URL url = new URL(systemId); + + externalEntity = url.openConnection(); + externalEntity.connect(); + is = externalEntity.getInputStream(); + } + + // If we get to here, there must be + // an InputStream available. + if (!is.markSupported()) + { + is = new BufferedInputStream(is); + } + + // Get any external encoding label. + if (encoding == null && externalEntity != null) + { + // External labels can be untrustworthy; filesystems in + // particular often have the wrong default for content + // that wasn't locally originated. Those we autodetect. + if (!"file".equals(externalEntity.getURL().getProtocol())) + { + int temp; + + // application/xml;charset=something;otherAttr=... + // ... with many variants on 'something' + encoding = externalEntity.getContentType(); + + // MHK code (fix for Saxon 5.5.1/007): + // protect against encoding==null + if (encoding == null) + { + temp = -1; + } + else + { + temp = encoding.indexOf("charset"); + } + + // RFC 2376 sez MIME text defaults to ASCII, but since the + // JDK will create a MIME type out of thin air, we always + // autodetect when there's no explicit charset attribute. + if (temp < 0) + { + encoding = null; // autodetect + } + else + { + // only this one attribute + if ((temp = encoding.indexOf(';')) > 0) + { + encoding = encoding.substring(0, temp); + } + + if ((temp = encoding.indexOf('=', temp + 7)) > 0) + { + encoding = encoding.substring(temp + 1); + + // attributes can have comment fields (RFC 822) + if ((temp = encoding.indexOf('(')) > 0) + { + encoding = encoding.substring(0, temp); + } + // ... and values may be quoted + if ((temp = encoding.indexOf('"')) > 0) + { + encoding = + encoding.substring(temp + 1, + encoding.indexOf('"', temp + 2)); + } + encoding = encoding.trim(); + } + else + { + handler.warn("ignoring illegal MIME attribute: " + + encoding); + encoding = null; + } + } + } + } + + // if we got an external encoding label, use it ... + if (encoding != null) + { + this.encoding = ENCODING_EXTERNAL; + setupDecoding(encoding); + ignoreEncoding = true; + + // ... else autodetect from first bytes. + } + else + { + detectEncoding(); + ignoreEncoding = false; + } + + // Read any XML or text declaration. + // If we autodetected, it may tell us the "real" encoding. + try + { + tryEncodingDecl(ignoreEncoding); + } + catch (UnsupportedEncodingException x) + { + encoding = x.getMessage(); + + // if we don't handle the declared encoding, + // try letting a JVM InputStreamReader do it + try + { + if (sourceType != INPUT_STREAM) + { + throw x; + } + + is.reset(); + readBufferPos = 0; + readBufferLength = 0; + readBufferOverflow = -1; + line = 1; + currentByteCount = column = 0; + + sourceType = INPUT_READER; + this.reader = new InputStreamReader(is, encoding); + is = null; + + tryEncodingDecl(true); + + } + catch (IOException e) + { + error("unsupported text encoding", + encoding, + null); + } + } + } + + /** + * Check for an encoding declaration. This is the second part of the + * XML encoding autodetection algorithm, relying on detectEncoding to + * get to the point that this part can read any encoding declaration + * in the document (using only US-ASCII characters). + * + *

      Because this part starts to fill parser buffers with this data, + * it's tricky to setup a reader so that Java's built-in decoders can be + * used for the character encodings that aren't built in to this parser + * (such as EUC-JP, KOI8-R, Big5, etc). + * + * @return any encoding in the declaration, uppercased; or null + * @see detectEncoding + */ + private String tryEncodingDecl(boolean ignoreEncoding) + throws SAXException, IOException + { + // Read the XML/text declaration. + if (tryRead(" 0) + { + return parseTextDecl(ignoreEncoding); + } + else + { + return parseXMLDecl(ignoreEncoding); + } + } + else + { + // or similar + unread('l'); + unread('m'); + unread('x'); + unread('?'); + unread('<'); + } + } + return null; + } + + /** + * Attempt to detect the encoding of an entity. + *

      The trick here (as suggested in the XML standard) is that + * any entity not in UTF-8, or in UCS-2 with a byte-order mark, + * must begin with an XML declaration or an encoding + * declaration; we simply have to look for "<?xml" in various + * encodings. + *

      This method has no way to distinguish among 8-bit encodings. + * Instead, it sets up for UTF-8, then (possibly) revises its assumption + * later in setupDecoding (). Any ASCII-derived 8-bit encoding + * should work, but most will be rejected later by setupDecoding (). + * @see #tryEncoding (byte[], byte, byte, byte, byte) + * @see #tryEncoding (byte[], byte, byte) + * @see #setupDecoding + */ + private void detectEncoding() + throws SAXException, IOException + { + byte[] signature = new byte[4]; + + // Read the first four bytes for + // autodetection. + is.mark(4); + is.read(signature); + is.reset(); + + // + // FIRST: four byte encodings (who uses these?) + // + if (tryEncoding(signature, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x3c)) + { + // UCS-4 must begin with "Utility routine for detectEncoding (). + *

      Always looks for some part of "Looks for a UCS-2 byte-order mark. + *

      Utility routine for detectEncoding (). + * @param sig The first four bytes read. + * @param b1 The first byte of the signature + * @param b2 The second byte of the signature + * @see #detectEncoding + */ + private static boolean tryEncoding(byte[] sig, byte b1, byte b2) + { + return ((sig[0] == b1) && (sig[1] == b2)); + } + + /** + * This method pushes a string back onto input. + *

      It is useful either as the expansion of an internal entity, + * or for backtracking during the parse. + *

      Call pushCharArray () to do the actual work. + * @param s The string to push back onto input. + * @see #pushCharArray + */ + private void pushString(String ename, String s) + throws SAXException + { + char[] ch = s.toCharArray(); + pushCharArray(ename, ch, 0, ch.length); + } + + /** + * Push a new internal input source. + *

      This method is useful for expanding an internal entity, + * or for unreading a string of characters. It creates a new + * readBuffer containing the characters in the array, instead + * of characters converted from an input byte stream. + * @param ch The char array to push. + * @see #pushString + * @see #pushURL + * @see #readBuffer + * @see #sourceType + * @see #pushInput + */ + private void pushCharArray(String ename, char[] ch, int start, int length) + throws SAXException + { + // Push the existing status + pushInput(ename); + if (ename != null && doReport) + { + dataBufferFlush(); + handler.startInternalEntity(ename); + } + sourceType = INPUT_INTERNAL; + readBuffer = ch; + readBufferPos = start; + readBufferLength = length; + readBufferOverflow = -1; + } + + /** + * Save the current input source onto the stack. + *

      This method saves all of the global variables associated with + * the current input source, so that they can be restored when a new + * input source has finished. It also tests for entity recursion. + *

      The method saves the following global variables onto a stack + * using a fixed-length array: + *

        + *
      1. sourceType + *
      2. externalEntity + *
      3. readBuffer + *
      4. readBufferPos + *
      5. readBufferLength + *
      6. line + *
      7. encoding + *
      + * @param ename The name of the entity (if any) causing the new input. + * @see #popInput + * @see #sourceType + * @see #externalEntity + * @see #readBuffer + * @see #readBufferPos + * @see #readBufferLength + * @see #line + * @see #encoding + */ + private void pushInput(String ename) + throws SAXException + { + // Check for entity recursion. + if (ename != null) + { + Iterator entities = entityStack.iterator(); + while (entities.hasNext()) + { + String e = (String) entities.next(); + if (e != null && e == ename) + { + error("recursive reference to entity", ename, null); + } + } + } + entityStack.addLast(ename); + + // Don't bother if there is no current input. + if (sourceType == INPUT_NONE) + { + return; + } + + // Set up a snapshot of the current + // input source. + Input input = new Input(); + + input.sourceType = sourceType; + input.externalEntity = externalEntity; + input.readBuffer = readBuffer; + input.readBufferPos = readBufferPos; + input.readBufferLength = readBufferLength; + input.line = line; + input.encoding = encoding; + input.readBufferOverflow = readBufferOverflow; + input.is = is; + input.currentByteCount = currentByteCount; + input.column = column; + input.reader = reader; + + // Push it onto the stack. + inputStack.addLast(input); + } + + /** + * Restore a previous input source. + *

      This method restores all of the global variables associated with + * the current input source. + * @exception java.io.EOFException + * If there are no more entries on the input stack. + * @see #pushInput + * @see #sourceType + * @see #externalEntity + * @see #readBuffer + * @see #readBufferPos + * @see #readBufferLength + * @see #line + * @see #encoding + */ + private void popInput() + throws SAXException, IOException + { + String ename = (String) entityStack.removeLast(); + + if (ename != null && doReport) + { + dataBufferFlush(); + } + switch (sourceType) + { + case INPUT_STREAM: + handler.endExternalEntity(ename); + is.close(); + break; + case INPUT_READER: + handler.endExternalEntity(ename); + reader.close(); + break; + case INPUT_INTERNAL: + if (ename != null && doReport) + { + handler.endInternalEntity(ename); + } + break; + } + + // Throw an EOFException if there + // is nothing else to pop. + if (inputStack.isEmpty()) + { + throw new EOFException("no more input"); + } + + Input input = (Input) inputStack.removeLast(); + + sourceType = input.sourceType; + externalEntity = input.externalEntity; + readBuffer = input.readBuffer; + readBufferPos = input.readBufferPos; + readBufferLength = input.readBufferLength; + line = input.line; + encoding = input.encoding; + readBufferOverflow = input.readBufferOverflow; + is = input.is; + currentByteCount = input.currentByteCount; + column = input.column; + reader = input.reader; + } + + /** + * Return true if we can read the expected character. + *

      Note that the character will be removed from the input stream + * on success, but will be put back on failure. Do not attempt to + * read the character again if the method succeeds. + * @param delim The character that should appear next. For a + * insensitive match, you must supply this in upper-case. + * @return true if the character was successfully read, or false if + * it was not. + * @see #tryRead (String) + */ + private boolean tryRead(char delim) + throws SAXException, IOException + { + char c; + + // Read the character + c = readCh(); + + // Test for a match, and push the character + // back if the match fails. + if (c == delim) + { + return true; + } + else + { + unread(c); + return false; + } + } + + /** + * Return true if we can read the expected string. + *

      This is simply a convenience method. + *

      Note that the string will be removed from the input stream + * on success, but will be put back on failure. Do not attempt to + * read the string again if the method succeeds. + *

      This method will push back a character rather than an + * array whenever possible (probably the majority of cases). + * @param delim The string that should appear next. + * @return true if the string was successfully read, or false if + * it was not. + * @see #tryRead (char) + */ + private boolean tryRead(String delim) + throws SAXException, IOException + { + return tryRead(delim.toCharArray()); + } + + private boolean tryRead(char[] ch) + throws SAXException, IOException + { + char c; + + // Compare the input, character- + // by character. + + for (int i = 0; i < ch.length; i++) + { + c = readCh(); + if (c != ch[i]) + { + unread(c); + if (i != 0) + { + unread(ch, i); + } + return false; + } + } + return true; + } + + /** + * Return true if we can read some whitespace. + *

      This is simply a convenience method. + *

      This method will push back a character rather than an + * array whenever possible (probably the majority of cases). + * @return true if whitespace was found. + */ + private boolean tryWhitespace() + throws SAXException, IOException + { + char c; + c = readCh(); + if (isWhitespace(c)) + { + skipWhitespace(); + return true; + } + else + { + unread(c); + return false; + } + } + + /** + * Read all data until we find the specified string. + * This is useful for scanning CDATA sections and PIs. + *

      This is inefficient right now, since it calls tryRead () + * for every character. + * @param delim The string delimiter + * @see #tryRead (String, boolean) + * @see #readCh + */ + private void parseUntil(String delim) + throws SAXException, IOException + { + parseUntil(delim.toCharArray()); + } + + private void parseUntil(char[] delim) + throws SAXException, IOException + { + char c; + int startLine = line; + + try + { + while (!tryRead(delim)) + { + c = readCh(); + dataBufferAppend(c); + } + } + catch (EOFException e) + { + error("end of input while looking for delimiter " + + "(started on line " + startLine + + ')', null, new String(delim)); + } + } + + ////////////////////////////////////////////////////////////////////// + // Low-level I/O. + ////////////////////////////////////////////////////////////////////// + + /** + * Prefetch US-ASCII XML/text decl from input stream into read buffer. + * Doesn't buffer more than absolutely needed, so that when an encoding + * decl says we need to create an InputStreamReader, we can discard our + * buffer and reset(). Caller knows the first chars of the decl exist + * in the input stream. + */ + private void prefetchASCIIEncodingDecl() + throws SAXException, IOException + { + int ch; + readBufferPos = readBufferLength = 0; + + is.mark(readBuffer.length); + while (true) + { + ch = is.read(); + readBuffer[readBufferLength++] = (char) ch; + switch (ch) + { + case (int) '>': + return; + case -1: + error("file ends before end of XML or encoding declaration.", + null, "?>"); + } + if (readBuffer.length == readBufferLength) + { + error("unfinished XML or encoding declaration"); + } + } + } + + /** + * Read a chunk of data from an external input source. + *

      This is simply a front-end that fills the rawReadBuffer + * with bytes, then calls the appropriate encoding handler. + * @see #encoding + * @see #rawReadBuffer + * @see #readBuffer + * @see #filterCR + * @see #copyUtf8ReadBuffer + * @see #copyIso8859_1ReadBuffer + * @see #copyUcs_2ReadBuffer + * @see #copyUcs_4ReadBuffer + */ + private void readDataChunk() + throws SAXException, IOException + { + int count; + + // See if we have any overflow (filterCR sets for CR at end) + if (readBufferOverflow > -1) + { + readBuffer[0] = (char) readBufferOverflow; + readBufferOverflow = -1; + readBufferPos = 1; + sawCR = true; + } + else + { + readBufferPos = 0; + sawCR = false; + } + + // input from a character stream. + if (sourceType == INPUT_READER) + { + count = reader.read(readBuffer, + readBufferPos, READ_BUFFER_MAX - readBufferPos); + if (count < 0) + { + readBufferLength = readBufferPos; + } + else + { + readBufferLength = readBufferPos + count; + } + if (readBufferLength > 0) + { + filterCR(count >= 0); + } + sawCR = false; + return; + } + + // Read as many bytes as possible into the raw buffer. + count = is.read(rawReadBuffer, 0, READ_BUFFER_MAX); + + // Dispatch to an encoding-specific reader method to populate + // the readBuffer. In most parser speed profiles, these routines + // show up at the top of the CPU usage chart. + if (count > 0) + { + switch (encoding) + { + // one byte builtins + case ENCODING_ASCII: + copyIso8859_1ReadBuffer(count, (char) 0x0080); + break; + case ENCODING_UTF_8: + copyUtf8ReadBuffer(count); + break; + case ENCODING_ISO_8859_1: + copyIso8859_1ReadBuffer(count, (char) 0); + break; + + // two byte builtins + case ENCODING_UCS_2_12: + copyUcs2ReadBuffer(count, 8, 0); + break; + case ENCODING_UCS_2_21: + copyUcs2ReadBuffer(count, 0, 8); + break; + + // four byte builtins + case ENCODING_UCS_4_1234: + copyUcs4ReadBuffer(count, 24, 16, 8, 0); + break; + case ENCODING_UCS_4_4321: + copyUcs4ReadBuffer(count, 0, 8, 16, 24); + break; + case ENCODING_UCS_4_2143: + copyUcs4ReadBuffer(count, 16, 24, 0, 8); + break; + case ENCODING_UCS_4_3412: + copyUcs4ReadBuffer(count, 8, 0, 24, 16); + break; + } + } + else + { + readBufferLength = readBufferPos; + } + + readBufferPos = 0; + + // Filter out all carriage returns if we've seen any + // (including any saved from a previous read) + if (sawCR) + { + filterCR(count >= 0); + sawCR = false; + + // must actively report EOF, lest some CRs get lost. + if (readBufferLength == 0 && count >= 0) + { + readDataChunk(); + } + } + + if (count > 0) + { + currentByteCount += count; + } + } + + /** + * Filter carriage returns in the read buffer. + * CRLF becomes LF; CR becomes LF. + * @param moreData true iff more data might come from the same source + * @see #readDataChunk + * @see #readBuffer + * @see #readBufferOverflow + */ + private void filterCR(boolean moreData) + { + int i, j; + + readBufferOverflow = -1; + +loop: + for (i = j = readBufferPos; j < readBufferLength; i++, j++) + { + switch (readBuffer[j]) + { + case '\r': + if (j == readBufferLength - 1) + { + if (moreData) + { + readBufferOverflow = '\r'; + readBufferLength--; + } + else // CR at end of buffer + { + readBuffer[i++] = '\n'; + } + break loop; + } + else if (readBuffer[j + 1] == '\n') + { + j++; + } + readBuffer[i] = '\n'; + break; + + case '\n': + default: + readBuffer[i] = readBuffer[j]; + break; + } + } + readBufferLength = i; + } + + /** + * Convert a buffer of UTF-8-encoded bytes into UTF-16 characters. + *

      When readDataChunk () calls this method, the raw bytes are in + * rawReadBuffer, and the final characters will appear in + * readBuffer. + *

      Note that as of Unicode 3.1, good practice became a requirement, + * so that each Unicode character has exactly one UTF-8 representation. + * @param count The number of bytes to convert. + * @see #readDataChunk + * @see #rawReadBuffer + * @see #readBuffer + * @see #getNextUtf8Byte + */ + private void copyUtf8ReadBuffer(int count) + throws SAXException, IOException + { + int i = 0; + int j = readBufferPos; + int b1; + char c = 0; + + /* + // check once, so the runtime won't (if it's smart enough) + if (count < 0 || count > rawReadBuffer.length) + throw new ArrayIndexOutOfBoundsException (Integer.toString (count)); + */ + + while (i < count) + { + b1 = rawReadBuffer[i++]; + + // Determine whether we are dealing + // with a one-, two-, three-, or four- + // byte sequence. + if (b1 < 0) + { + if ((b1 & 0xe0) == 0xc0) + { + // 2-byte sequence: 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx + c = (char) (((b1 & 0x1f) << 6) + | getNextUtf8Byte(i++, count)); + if (c < 0x0080) + { + encodingError("Illegal two byte UTF-8 sequence", + c, 0); + } + + //Sec 2.11 + // [1] the two-character sequence #xD #xA + // [2] the two-character sequence #xD #x85 + if ((c == 0x0085 || c == 0x000a) && sawCR) + { + continue; + } + + // Sec 2.11 + // [3] the single character #x85 + + if (c == 0x0085 && xmlVersion == XML_11) + { + readBuffer[j++] = '\r'; + } + } + else if ((b1 & 0xf0) == 0xe0) + { + // 3-byte sequence: + // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx + // most CJKV characters + c = (char) (((b1 & 0x0f) << 12) | + (getNextUtf8Byte(i++, count) << 6) | + getNextUtf8Byte(i++, count)); + //sec 2.11 + //[4] the single character #x2028 + if (c == 0x2028 && xmlVersion == XML_11) + { + readBuffer[j++] = '\r'; + sawCR = true; + continue; + } + if (c < 0x0800 || (c >= 0xd800 && c <= 0xdfff)) + { + encodingError("Illegal three byte UTF-8 sequence", + c, 0); + } + } + else if ((b1 & 0xf8) == 0xf0) + { + // 4-byte sequence: 11101110wwwwzzzzyy + 110111yyyyxxxxxx + // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx + // (uuuuu = wwww + 1) + // "Surrogate Pairs" ... from the "Astral Planes" + // Unicode 3.1 assigned the first characters there + int iso646 = b1 & 07; + iso646 = (iso646 << 6) + getNextUtf8Byte(i++, count); + iso646 = (iso646 << 6) + getNextUtf8Byte(i++, count); + iso646 = (iso646 << 6) + getNextUtf8Byte(i++, count); + + if (iso646 <= 0xffff) + { + encodingError("Illegal four byte UTF-8 sequence", + iso646, 0); + } + else + { + if (iso646 > 0x0010ffff) + { + encodingError("UTF-8 value out of range for Unicode", + iso646, 0); + } + iso646 -= 0x010000; + readBuffer[j++] = (char) (0xd800 | (iso646 >> 10)); + readBuffer[j++] = (char) (0xdc00 | (iso646 & 0x03ff)); + continue; + } + } + else + { + // The five and six byte encodings aren't supported; + // they exceed the Unicode (and XML) range. + encodingError("unsupported five or six byte UTF-8 sequence", + 0xff & b1, i); + // NOTREACHED + c = 0; + } + } + else + { + // 1-byte sequence: 000000000xxxxxxx = 0xxxxxxx + // (US-ASCII character, "common" case, one branch to here) + c = (char) b1; + } + readBuffer[j++] = c; + if (c == '\r') + { + sawCR = true; + } + } + // How many characters have we read? + readBufferLength = j; + } + + /** + * Return the next byte value in a UTF-8 sequence. + * If it is not possible to get a byte from the current + * entity, throw an exception. + * @param pos The current position in the rawReadBuffer. + * @param count The number of bytes in the rawReadBuffer + * @return The significant six bits of a non-initial byte in + * a UTF-8 sequence. + * @exception EOFException If the sequence is incomplete. + */ + private int getNextUtf8Byte(int pos, int count) + throws SAXException, IOException + { + int val; + + // Take a character from the buffer + // or from the actual input stream. + if (pos < count) + { + val = rawReadBuffer[pos]; + } + else + { + val = is.read(); + if (val == -1) + { + encodingError("unfinished multi-byte UTF-8 sequence at EOF", + -1, pos); + } + } + + // Check for the correct bits at the start. + if ((val & 0xc0) != 0x80) + { + encodingError("bad continuation of multi-byte UTF-8 sequence", + val, pos + 1); + } + + // Return the significant bits. + return (val & 0x3f); + } + + /** + * Convert a buffer of US-ASCII or ISO-8859-1-encoded bytes into + * UTF-16 characters. + * + *

      When readDataChunk () calls this method, the raw bytes are in + * rawReadBuffer, and the final characters will appear in + * readBuffer. + * + * @param count The number of bytes to convert. + * @param mask For ASCII conversion, 0x7f; else, 0xff. + * @see #readDataChunk + * @see #rawReadBuffer + * @see #readBuffer + */ + private void copyIso8859_1ReadBuffer(int count, char mask) + throws IOException + { + int i, j; + for (i = 0, j = readBufferPos; i < count; i++, j++) + { + char c = (char) (rawReadBuffer[i] & 0xff); + if ((c & mask) != 0) + { + throw new CharConversionException("non-ASCII character U+" + + Integer.toHexString(c)); + } + if (c == 0x0085 && xmlVersion == XML_11) + { + c = '\r'; + } + readBuffer[j] = c; + if (c == '\r') + { + sawCR = true; + } + } + readBufferLength = j; + } + + /** + * Convert a buffer of UCS-2-encoded bytes into UTF-16 characters + * (as used in Java string manipulation). + * + *

      When readDataChunk () calls this method, the raw bytes are in + * rawReadBuffer, and the final characters will appear in + * readBuffer. + * @param count The number of bytes to convert. + * @param shift1 The number of bits to shift byte 1. + * @param shift2 The number of bits to shift byte 2 + * @see #readDataChunk + * @see #rawReadBuffer + * @see #readBuffer + */ + private void copyUcs2ReadBuffer(int count, int shift1, int shift2) + throws SAXException + { + int j = readBufferPos; + + if (count > 0 && (count % 2) != 0) + { + encodingError("odd number of bytes in UCS-2 encoding", -1, count); + } + // The loops are faster with less internal brancing; hence two + if (shift1 == 0) + { // "UTF-16-LE" + for (int i = 0; i < count; i += 2) + { + char c = (char) (rawReadBuffer[i + 1] << 8); + c |= 0xff & rawReadBuffer[i]; + readBuffer[j++] = c; + if (c == '\r') + { + sawCR = true; + } + } + } + else + { // "UTF-16-BE" + for (int i = 0; i < count; i += 2) + { + char c = (char) (rawReadBuffer[i] << 8); + c |= 0xff & rawReadBuffer[i + 1]; + readBuffer[j++] = c; + if (c == '\r') + { + sawCR = true; + } + } + } + readBufferLength = j; + } + + /** + * Convert a buffer of UCS-4-encoded bytes into UTF-16 characters. + * + *

      When readDataChunk () calls this method, the raw bytes are in + * rawReadBuffer, and the final characters will appear in + * readBuffer. + *

      Java has Unicode chars, and this routine uses surrogate pairs + * for ISO-10646 values between 0x00010000 and 0x000fffff. An + * exception is thrown if the ISO-10646 character has no Unicode + * representation. + * + * @param count The number of bytes to convert. + * @param shift1 The number of bits to shift byte 1. + * @param shift2 The number of bits to shift byte 2 + * @param shift3 The number of bits to shift byte 2 + * @param shift4 The number of bits to shift byte 2 + * @see #readDataChunk + * @see #rawReadBuffer + * @see #readBuffer + */ + private void copyUcs4ReadBuffer(int count, int shift1, int shift2, + int shift3, int shift4) + throws SAXException + { + int j = readBufferPos; + + if (count > 0 && (count % 4) != 0) + { + encodingError("number of bytes in UCS-4 encoding " + + "not divisible by 4", + -1, count); + } + for (int i = 0; i < count; i += 4) + { + int value = (((rawReadBuffer [i] & 0xff) << shift1) | + ((rawReadBuffer [i + 1] & 0xff) << shift2) | + ((rawReadBuffer [i + 2] & 0xff) << shift3) | + ((rawReadBuffer [i + 3] & 0xff) << shift4)); + if (value < 0x0000ffff) + { + readBuffer [j++] = (char) value; + if (value == (int) '\r') + { + sawCR = true; + } + } + else if (value < 0x0010ffff) + { + value -= 0x010000; + readBuffer[j++] = (char) (0xd8 | ((value >> 10) & 0x03ff)); + readBuffer[j++] = (char) (0xdc | (value & 0x03ff)); + } + else + { + encodingError("UCS-4 value out of range for Unicode", + value, i); + } + } + readBufferLength = j; + } + + /** + * Report a character encoding error. + */ + private void encodingError(String message, int value, int offset) + throws SAXException + { + if (value != -1) + { + message = message + " (character code: 0x" + + Integer.toHexString(value) + ')'; + error(message); + } + } + + ////////////////////////////////////////////////////////////////////// + // Local Variables. + ////////////////////////////////////////////////////////////////////// + + /** + * Re-initialize the variables for each parse. + */ + private void initializeVariables() + { + // First line + line = 1; + column = 0; + + // Set up the buffers for data and names + dataBufferPos = 0; + dataBuffer = new char[DATA_BUFFER_INITIAL]; + nameBufferPos = 0; + nameBuffer = new char[NAME_BUFFER_INITIAL]; + + // Set up the DTD hash tables + elementInfo = new HashMap(); + entityInfo = new HashMap(); + notationInfo = new HashMap(); + skippedPE = false; + + // Set up the variables for the current + // element context. + currentElement = null; + currentElementContent = CONTENT_UNDECLARED; + + // Set up the input variables + sourceType = INPUT_NONE; + inputStack = new LinkedList(); + entityStack = new LinkedList(); + externalEntity = null; + tagAttributePos = 0; + tagAttributes = new String[100]; + rawReadBuffer = new byte[READ_BUFFER_MAX]; + readBufferOverflow = -1; + + scratch = new InputSource(); + + inLiteral = false; + expandPE = false; + peIsError = false; + + doReport = false; + + inCDATA = false; + + symbolTable = new Object[SYMBOL_TABLE_LENGTH][]; + } + + static class ExternalIdentifiers + { + + String publicId; + String systemId; + String baseUri; + + ExternalIdentifiers() + { + } + + ExternalIdentifiers(String publicId, String systemId, String baseUri) + { + this.publicId = publicId; + this.systemId = systemId; + this.baseUri = baseUri; + } + + } + + static class EntityInfo + { + + int type; + ExternalIdentifiers ids; + String value; + String notationName; + + } + + static class AttributeDecl + { + + String type; + String value; + int valueType; + String enumeration; + String defaultValue; + + } + + static class ElementDecl + { + + int contentType; + String contentModel; + HashMap attributes; + + } + + static class Input + { + + int sourceType; + URLConnection externalEntity; + char[] readBuffer; + int readBufferPos; + int readBufferLength; + int line; + int encoding; + int readBufferOverflow; + InputStream is; + int currentByteCount; + int column; + Reader reader; + + } + +} diff --git a/libjava/classpath/gnu/xml/aelfred2/XmlReader.java b/libjava/classpath/gnu/xml/aelfred2/XmlReader.java new file mode 100644 index 000000000..e0a047612 --- /dev/null +++ b/libjava/classpath/gnu/xml/aelfred2/XmlReader.java @@ -0,0 +1,373 @@ +/* XmlReader.java -- + Copyright (C) 1999,2000,2001 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.aelfred2; + +import java.io.IOException; +import java.util.Locale; + +import org.xml.sax.*; +import org.xml.sax.ext.*; + +import gnu.xml.pipeline.EventFilter; +import gnu.xml.pipeline.ValidationConsumer; + + +/** + * This SAX2 parser optionally layers a validator over the Ælfred2 + * SAX2 parser. While this will not evaluate every XML validity constraint, + * it does support all the validity constraints that are of any real utility + * outside the strict SGML-compatible world. See the documentation for the + * SAXDriver class for information about the SAX2 features and properties + * that are supported, and documentation for the ValidationConsumer for + * information about what validity constraints may not be supported. + * (Ælfred2 tests some of those, even in non-validating mode, to + * achieve better conformance.) + * + *

      Note that due to its internal construction, you can't change most + * handlers until parse() returns. This diverges slightly from SAX, which + * expects later binding to be supported. Early binding involves less + * runtime overhead, which is an issue for event pipelines as used inside + * this parser. Rather than relying on the parser to handle late binding + * to your own handlers, do it yourself. + * + * @see SAXDriver + * @see gnu.xml.pipeline.ValidationConsumer + * + * @author David Brownell + */ +public final class XmlReader + implements XMLReader +{ + + static class FatalErrorHandler + extends DefaultHandler2 + { + + public void error(SAXParseException e) + throws SAXException + { + throw e; + } + + } + + private SAXDriver aelfred2 = new SAXDriver(); + private EventFilter filter = new EventFilter(); + private boolean isValidating; + private boolean active; + + /** + * Constructs a SAX Parser. + */ + public XmlReader() + { + } + + /** + * Constructs a SAX Parser, optionally treating validity errors + * as if they were fatal errors. + */ + public XmlReader(boolean invalidIsFatal) + { + if (invalidIsFatal) + { + setErrorHandler(new FatalErrorHandler()); + } + } + + /** + * SAX2: Returns the object used to report the logical + * content of an XML document. + */ + public ContentHandler getContentHandler() + { + return filter.getContentHandler(); + } + + /** + * SAX2: Assigns the object used to report the logical + * content of an XML document. + * @exception IllegalStateException if called mid-parse + */ + public void setContentHandler(ContentHandler handler) + { + if (active) + { + throw new IllegalStateException("already parsing"); + } + filter.setContentHandler(handler); + } + + /** + * SAX2: Returns the object used to process declarations related + * to notations and unparsed entities. + */ + public DTDHandler getDTDHandler() + { + return filter.getDTDHandler(); + } + + /** + * SAX1 Assigns DTD handler + * @exception IllegalStateException if called mid-parse + */ + public void setDTDHandler(DTDHandler handler) + { + if (active) + { + throw new IllegalStateException("already parsing"); + } + filter.setDTDHandler(handler); + } + + /** + * SAX2: Returns the object used when resolving external + * entities during parsing (both general and parameter entities). + */ + public EntityResolver getEntityResolver() + { + return aelfred2.getEntityResolver(); + } + + /** + * SAX1 Assigns parser's entity resolver + */ + public void setEntityResolver(EntityResolver handler) + { + aelfred2.setEntityResolver(handler); + } + + /** + * SAX2: Returns the object used to receive callbacks for XML + * errors of all levels (fatal, nonfatal, warning); this is never null; + */ + public ErrorHandler getErrorHandler() + { + return aelfred2.getErrorHandler(); + } + + /** + * SAX1 Assigns error handler + * @exception IllegalStateException if called mid-parse + */ + public void setErrorHandler(ErrorHandler handler) + { + if (active) + { + throw new IllegalStateException("already parsing"); + } + aelfred2.setErrorHandler(handler); + } + + /** + * SAX2: Assigns the specified property. + * @exception IllegalStateException if called mid-parse + */ + public void setProperty(String propertyId, Object value) + throws SAXNotRecognizedException, SAXNotSupportedException + { + if (active) + { + throw new IllegalStateException("already parsing"); + } + if (getProperty(propertyId) != value) + { + filter.setProperty(propertyId, value); + } + } + + /** + * SAX2: Returns the specified property. + */ + public Object getProperty(String propertyId) + throws SAXNotRecognizedException + { + if ((SAXDriver.PROPERTY + "declaration-handler").equals(propertyId) + || (SAXDriver.PROPERTY + "lexical-handler").equals(propertyId)) + { + return filter.getProperty(propertyId); + } + throw new SAXNotRecognizedException(propertyId); + } + + private void forceValidating() + throws SAXNotRecognizedException, SAXNotSupportedException + { + aelfred2.setFeature(SAXDriver.FEATURE + "namespace-prefixes", + true); + aelfred2.setFeature(SAXDriver.FEATURE + "external-general-entities", + true); + aelfred2.setFeature(SAXDriver.FEATURE + "external-parameter-entities", + true); + } + + /** + * SAX2: Sets the state of features supported in this parser. + * Note that this parser requires reporting of namespace prefixes when + * validating. + */ + public void setFeature(String featureId, boolean state) + throws SAXNotRecognizedException, SAXNotSupportedException + { + boolean value = getFeature(featureId); + + if (state == value) + { + return; + } + + if ((SAXDriver.FEATURE + "validation").equals(featureId)) + { + if (active) + { + throw new SAXNotSupportedException("already parsing"); + } + if (state) + { + forceValidating(); + } + isValidating = state; + } + else + { + aelfred2.setFeature(featureId, state); + } + } + + /** + * SAX2: Tells whether this parser supports the specified feature. + * At this time, this directly parallels the underlying SAXDriver, + * except that validation is optionally supported. + * + * @see SAXDriver + */ + public boolean getFeature(String featureId) + throws SAXNotRecognizedException, SAXNotSupportedException + { + if ((SAXDriver.FEATURE + "validation").equals(featureId)) + { + return isValidating; + } + + return aelfred2.getFeature(featureId); + } + + /** + * SAX1: Sets the locale used for diagnostics; currently, + * only locales using the English language are supported. + * @param locale The locale for which diagnostics will be generated + */ + public void setLocale(Locale locale) + throws SAXException + { + aelfred2.setLocale(locale); + } + + /** + * SAX1: Preferred API to parse an XML document, using a + * system identifier (URI). + */ + public void parse(String systemId) + throws SAXException, IOException + { + parse(new InputSource(systemId)); + } + + /** + * SAX1: Underlying API to parse an XML document, used + * directly when no URI is available. When this is invoked, + * and the parser is set to validate, some features will be + * automatically reset to appropriate values: for reporting + * namespace prefixes, and incorporating external entities. + * + * @param source The XML input source. + * + * @exception IllegalStateException if called mid-parse + * @exception SAXException The handlers may throw any SAXException, + * and the parser normally throws SAXParseException objects. + * @exception IOException IOExceptions are normally through through + * the parser if there are problems reading the source document. + */ + public void parse(InputSource source) + throws SAXException, IOException + { + EventFilter next; + boolean nsdecls; + + synchronized (aelfred2) + { + if (active) + { + throw new IllegalStateException("already parsing"); + } + active = true; + } + + // set up the output pipeline + if (isValidating) + { + forceValidating(); + next = new ValidationConsumer(filter); + } + else + { + next = filter; + } + + // connect pipeline and error handler + // don't let _this_ call to bind() affect xmlns* attributes + nsdecls = aelfred2.getFeature(SAXDriver.FEATURE + "namespace-prefixes"); + EventFilter.bind(aelfred2, next); + if (!nsdecls) + { + aelfred2.setFeature(SAXDriver.FEATURE + "namespace-prefixes", + false); + } + + // parse, clean up + try + { + aelfred2.parse(source); + } + finally + { + active = false; + } + } + +} diff --git a/libjava/classpath/gnu/xml/aelfred2/package.html b/libjava/classpath/gnu/xml/aelfred2/package.html new file mode 100644 index 000000000..e20425844 --- /dev/null +++ b/libjava/classpath/gnu/xml/aelfred2/package.html @@ -0,0 +1,506 @@ + + + + package overview + + + +

      This package contains Ælfred2, which includes an +enhanced SAX2-compatible version of the Ælfred +non-validating XML parser, a modular (and hence optional) +DTD validating parser, and modular (and hence optional) +JAXP glue to those. +Use these like any other SAX2 parsers.

      + + + +

      About Ælfred

      + +

      Ælfred is a XML parser written in the java programming language. + +

      Design Principles

      + +

      In most Java applets and applications, XML should not be the central +feature; instead, XML is the means to another end, such as loading +configuration information, reading meta-data, or parsing transactions.

      + +

      When an XML parser is only a single component of a much larger +program, it cannot be large, slow, or resource-intensive. With Java +applets, in particular, code size is a significant issue. The standard +modem is still not operating at 56 Kbaud, or sometimes even with data +compression. Assuming an uncompressed 28.8 Kbaud modem, only about +3 KBytes can be downloaded in one second; compression often doubles +that speed, but a V.90 modem may not provide another doubling. When +used with embedded processors, similar size concerns apply.

      + +

      Ælfred is designed for easy and efficient use over the Internet, +based on the following principles:

        + +
      1. Ælfred must be as small as possible, so that it doesn't add too + much to an applet's download time.
      2. + +
      3. Ælfred must use as few class files as possible, to minimize the + number of HTTP connections necessary. (The use of JAR files has made this + be less of a concern.)
      4. + +
      5. Ælfred must be compatible with most or all Java implementations + and platforms. (Write once, run anywhere.)
      6. + +
      7. Ælfred must use as little memory as possible, so that it does + not take away resources from the rest of your program. (It doesn't force + you to use DOM or a similar costly data structure API.)
      8. + +
      9. Ælfred must run as fast as possible, so that it does not slow down + the rest of your program.
      10. + +
      11. Ælfred must produce correct output for well-formed and valid + documents, but need not reject every document that is not valid or + not well-formed. (In Ælfred2, correctness was a bigger concern + than in the original version; and a validation option is available.)
      12. + +
      13. Ælfred must provide full internationalization from the first + release. (Ælfred2 now automatically handles all encodings + supported by the underlying JVM; previous versions handled only + UTF-8, UTF_16, ASCII, and ISO-8859-1.)
      14. + +
      + +

      As you can see from this list, Ælfred is designed for production +use, but neither validation nor perfect conformance was a requirement. +Good validating parsers exist, including one in this package, +and you should use them as appropriate. (See conformance reviews +available at http://www.xml.com) +

      + +

      One of the main goals of Ælfred2 was to significantly improve +conformance, while not significantly affecting the other goals stated above. +Since the only use of this parser is with SAX, some classes could be +removed, and so the overall size of Ælfred was actually reduced. +Subsequent performance work produced a notable speedup (over twenty +percent on larger files). That is, the tradeoffs between speed, size, and +conformance were re-targeted towards conformance and support of newer APIs +(SAX2), with a a positive performance impact.

      + +

      The role anticipated for this version of Ælfred is as a +lightweight Free Software SAX parser that can be used in essentially every +Java program where the handful of conformance violations (noted below) +are acceptable. +That certainly includes applets, and +nowadays one must also mention embedded systems as being even more +size-critical. +At this writing, all parsers that are more conformant are +significantly larger, even when counting the optional +validation support in this version of Ælfred.

      + + +

      About the Name Ælfred

      + +

      Ælfred the Great (AElfred in ASCII) was King of Wessex, and +some say of King of England, at the time of his death in 899 AD. +Ælfred introduced a wide-spread literacy program in the hope that +his people would learn to read English, at least, if Latin was too +difficult for them. This Ælfred hopes to bring another sort of +literacy to Java, using XML, at least, if full SGML is too difficult.

      + +

      The initial Æ ligature ("AE)" is also a reminder that XML is +not limited to ASCII.

      + + +

      Character Encodings

      + +

      The Ælfred parser currently builds in support for a handful +of input encodings. Of course these include UTF-8 and UTF-16, which +all XML parsers are required to support:

        + +
      • UTF-8 ... the standard eight bit encoding, used unless + you provide an encoding declaration or a MIME charset tag.
      • + +
      • US-ASCII ... an extremely common seven bit encoding, + which happens to be a subset of UTF-8 and ISO-8859-1 as well + as many other encodings. XHTML web pages using US-ASCII + (without an encoding declaration) are probably more + widely interoperable than those in any other encoding.
      • + +
      • ISO-8859-1 ... includes accented characters used in + much of western Europe (but excluding the Euro currency + symbol).
      • + +
      • UTF-16 ... with several variants, this encodes each + sixteen bit Unicode character in sixteen bits of output. + Variants include UTF-16BE (big endian, no byte order mark), + UTF-16LE (little endian, no byte order mark), and + ISO-10646-UCS-2 (an older and less used encoding, using a + version of Unicode without surrogate pairs). This is + essentially the native encoding used by Java.
      • + +
      • ISO-10646-UCS-4 ... a seldom-used four byte encoding, + also known as UTF-32BE. Four byte order variants are supported, + including one known as UTF-32LE. Some operating systems + standardized on UCS-4 despite its significant size penalty, + in anticipation that Unicode (even with surrogate pairs) + would eventually become limiting. UCS-4 permits encoding + of non-Unicode characters, which Java can't represent (and + XML doesn't allow). +
      • + +
      + +

      If you use any encoding other than UTF-8 or UTF-16 you should +make sure to label your data appropriately:

      + +
      +<?xml version="1.0" encoding="ISO-8859-15"?> +
      + +

      Encodings accessed through java.io.InputStreamReader +are now fully supported for both external labels (such as MIME types) +and internal types (as shown above). +There is one limitation in the support for internal labels: +the encodings must be derived from the US-ASCII encoding, +the EBCDIC family of encodings is not recognized. +Note that Java defines its +own encoding names, which don't always correspond to the standard +Internet encoding names defined by the IETF/IANA, and that Java +may even require use of nonstandard encoding names. +Please report +such problems; some of them can be worked around in this parser, +and many can be worked around by using external labels. +

      + +

      Note that if you are using the Euro symbol with an fixed length +eight bit encoding, you should probably be using the encoding label +iso-8859-15 or, with a Microsoft OS, cp-1252. +Of course, UTF-8 and UTF-16 handle the Euro symbol directly. +

      + + +

      Known Conformance Violations

      + +

      Known conformance issues should be of negligible importance for +most applications, and include:

        + +
      • Rather than following the voluminous "Appendix B" rules about + what characters may appear in names (and name tokens), the Unicode + rules embedded in java.lang.Character are used. + This means mostly that some names are inappropriately accepted, + though a few are inappropriately rejected. (It's much simpler + to avoid that much special case code. Recent OASIS/NIST test + cases may have these rules be realistically testable.)
      • + +
      • Text containing "]]>" is not rejected unless it fully resides + in an internal buffer ... which is, thankfully, the typical case. This + text is illegal, but sometimes appears in illegal attempts to + nest CDATA sections. (Not catching that boundary condition + substantially simplifies parsing text.)
      • + +
      • Surrogate characters that aren't correctly paired are ignored + rather than rejected, unless they were encoded using UTF-8. (This + simplifies parsing text.) Unicode 3.1 assigned the first characters + to those character codes, in early 2001, so few documents (or tools) + use such characters in any case.
      • + +
      • Declarations following references to an undefined parameter + entity reference are not ignored. (Not maintaining and using state + about this validity error simplifies declaration handling; few + XML parsers address this constraint in any case.)
      • + +
      • Well formedness constraints for general entity references + are not enforced. (The code to handle the "content" production + is merged with the element parsing code, making it hard to reuse + for this additional situation.)
      • + +
      + +

      When tested against the July 12, 1999 version of the OASIS +XML Conformance test suite, an earlier version passed 1057 of 1067 tests. +That contrasts with the original version, which passed 867. The +current parser is top-ranked in terms of conformance, as is its +validating sibling (which has some additional conformance violations +imposed on it by SAX2 API deficiencies as well as some of the more +curious SGML layering artifacts found in the XML specification).

      + +

      The XML 1.0 specification itself was not without problems, +and after some delays the W3C has come out with a revised +"second edition" specification. While that doesn't resolve all +the problems identified the XML specification, many of the most +egregious problems have been resolved. (You still need to drink +magic Kool-Aid before some DTD-related issues make sense.) +To the extent possible, this parser conforms to that second +edition specification, and does well against corrected versions +of the OASIS/NIST XML conformance test cases. See http://xmlconf.sourceforge.net +for more information about SAX2/XML conformance testing.

      + + +

      Copyright and distribution terms

      + +

      +The software in this package is distributed under the GNU General Public +License (with a special exception described below). +

      + +

      +A copy of GNU General Public License (GPL) is included in this distribution, +in the file COPYING. If you do not have the source code, it is available at: + + http://www.gnu.org/software/classpath/ +

      + +
      +  Linking this library statically or dynamically with other modules is
      +  making a combined work based on this library.  Thus, the terms and
      +  conditions of the GNU General Public License cover the whole
      +  combination.
      +
      +  As a special exception, the copyright holders of this library give you
      +  permission to link this library with independent modules to produce an
      +  executable, regardless of the license terms of these independent
      +  modules, and to copy and distribute the resulting executable under
      +  terms of your choice, provided that you also meet, for each linked
      +  independent module, the terms and conditions of the license of that
      +  module.  An independent module is a module which is not derived from
      +  or based on this library.  If you modify this library, you may extend
      +  this exception to your version of the library, but you are not
      +  obligated to do so.  If you do not wish to do so, delete this
      +  exception statement from your version.
      +
      +  Parts derived from code which carried the following notice:
      +
      +  Copyright (c) 1997, 1998 by Microstar Software Ltd.
      +
      +  AElfred is free for both commercial and non-commercial use and
      +  redistribution, provided that Microstar's copyright and disclaimer are
      +  retained intact.  You are free to modify AElfred for your own use and
      +  to redistribute AElfred with your modifications, provided that the
      +  modifications are clearly documented.
      +
      +  This program is distributed in the hope that it will be useful, but
      +  WITHOUT ANY WARRANTY; without even the implied warranty of
      +  merchantability or fitness for a particular purpose.  Please use it AT
      +  YOUR OWN RISK.
      +
      + +

      Some of this documentation was modified from the original +Ælfred README.txt file. All of it has been updated.

      + +

      + + +

      Changes Since the last Microstar Release

      + +

      As noted above, Microstar has not updated this parser since +the summer of 1998, when it released version 1.2a on its web site. +This release is intended to benefit the developer community by +refocusing the API on SAX2, and improving conformance to the extent +that most developers should not need to use another XML parser.

      + +

      The code has been cleaned up (referring to the XML 1.0 spec in +all the production numbers in +comments, rather than some preliminary draft, for one example) and +has been sped up a bit as well. +JAXP support has been added, although developers are still +strongly encouraged to use the SAX2 APIs directly.

      + + +

      SAX2 Support

      + +

      The original version of Ælfred did not support the +SAX2 APIs.

      + +

      This version supports the SAX2 APIs, exposing the standard +boolean feature descriptors. It supports the "DeclHandler" property +to provide access to all DTD declarations not already exposed +through the SAX1 API. The "LexicalHandler" property is supported, +exposing entity boundaries (including the unnamed external subset) and +things like comments and CDATA boundaries. SAX1 compatibility is +currently provided.

      + + +

      Validation

      + +

      In the 'pipeline' package in this same software distribution is an +XML Validation component +using any full SAX2 event stream (including all document type declarations) +to validate. There is now a XmlReader class +which combines that class and this enhanced Ælfred parser, creating +an optionally validating SAX2 parser.

      + +

      As noted in the documentation for that validating component, certain +validity constraints can't reliably be tested by a layered validator. +These include all constraints relying on +layering violations (exposing XML at the level of tokens or below, +required since XML isn't a context-free grammar), some that +SAX2 doesn't support, and a few others. The resulting validating +parser is conformant enough for most applications that aren't doing +strange SGML tricks with DTDs. +Moreover, that validating filter can be used without +a parser ... any application component that emits SAX event streams +can DTD-validate its output on demand.

      + +

      You want Smaller?

      + +

      You'll have noticed that the original version of Ælfred +had small size as a top goal. Ælfred2 normally includes a +DTD validation layer, but you can package without that. +Similarly, JAXP factory support is available but optional. +Then the main added cost due to this revision are for +supporting the SAX2 API itself; DTD validation is as +cleanly layered as allowed by SAX2.

      + +

      Bugs Fixed

      + +

      Bugs fixed in Ælfred2 include:

      + +
        +
      1. Originally Ælfred didn't close file descriptors, which + led to file descriptor leakage on programs which ran for any + length of time.
      2. + +
      3. NOTATION declarations without system identifiers are + now handled correctly.
      4. + +
      5. DTD events are now reported for all invocations of a + given parser, not just the first one.
      6. + +
      7. More correct character handling:
          + +
        • Rejects out-of-range characters, both in text and in + character references.
        • + +
        • Correctly handles character references that expand to + surrogate pairs.
        • + +
        • Correctly handles UTF-8 encodings of surrogate pairs.
        • + +
        • Correctly handles Unicode 3.1 rules about illegal UTF-8 + encodings: there is only one legal encoding per character.
        • + +
        • PUBLIC identifiers are now rejected if they have illegal + characters.
        • + +
        • The parser is more correct about what characters are allowed + in names and name tokens. Uses Unicode rules (built in to Java) + rather than the voluminous XML rules, although some extensions + have been made to match XML rules more closely.
        • + +
        • Line ends are now normalized to newlines in all known + cases.
        • + +
      8. + +
      9. Certain validity errors were previously treated as well + formedness violations.
          + +
        • Repeated declarations of an element type are no + longer fatal errors.
        • + +
        • Undeclared parameter entity references are no longer + fatal errors.
        • + +
      10. + +
      11. Attribute handling is improved:
          + +
        • Whitespace must exist between attributes.
        • + +
        • Only one value for a given attribute is permitted.
        • + +
        • ATTLIST declarations don't need to declare attributes.
        • + +
        • Attribute values are normalized when required.
        • + +
        • Tabs in attribute values are normalized to spaces.
        • + +
        • Attribute values containing a literal "<" are rejected.
        • + +
      12. + +
      13. More correct entity handling:
          + +
        • Whitespace must precede NDATA when declaring unparsed + entities.
        • + +
        • Parameter entity declarations may not have NDATA annotations.
        • + +
        • The XML specification has a bug in that it doesn't specify + that certain contexts exist within which parameter entity + expansion must not be performed. Lacking an offical erratum, + this parser now disables such expansion inside comments, + processing instructions, ignored sections, public identifiers, + and parts of entity declarations.
        • + +
        • Entity expansions that include quote characters no longer + confuse parsing of strings using such expansions.
        • + +
        • Whitespace in the values of internal entities is not mapped + to space characters.
        • + +
        • General Entity references in attribute defaults within the + DTD now cause fatal errors when the entity is not defined at the + time it is referenced.
        • + +
        • Malformed general entity references in entity declarations are + now detected.
        • + +
      14. + +
      15. Neither conditional sections + nor parameter entity references within markup declarations + are permitted in the internal subset.
      16. + +
      17. Processing instructions whose target names are "XML" + (ignoring case) are now rejected.
      18. + +
      19. Comments may not include "--".
      20. + +
      21. Most "]]>" sequences in text are rejected.
      22. + +
      23. Correct syntax for standalone declarations is enforced.
      24. + +
      25. Setting a locale for diagnostics only produces an exception + if the language of that locale isn't English.
      26. + +
      27. Some more encoding names are recognized. These include the + Unicode 3.0 variants of UTF-16 (UTF-16BE, UTF-16LE) as well as + US-ASCII and a few commonly seen synonyms.
      28. + +
      29. Text (from character content, PIs, or comments) large enough + not to fit into internal buffers is now handled correctly even in + some cases which were originally handled incorrectly.
      30. + +
      31. Content is now reported for element types for which attributes + have been declared, but no content model is known. (Such documents + are invalid, but may still be well formed.)
      32. + +
      + +

      Other bugs may also have been fixed.

      + +

      For better overall validation support, some of the validity +constraints that can't be verified using the SAX2 event stream +are now reported directly by Ælfred2.

      + + + diff --git a/libjava/classpath/gnu/xml/dom/Consumer.java b/libjava/classpath/gnu/xml/dom/Consumer.java new file mode 100644 index 000000000..836c8d257 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/Consumer.java @@ -0,0 +1,352 @@ +/* Consumer.java -- + Copyright (C) 2001,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.xml.dom; + +import org.w3c.dom.DocumentType; +import org.w3c.dom.Node; +import org.w3c.dom.Text; + +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.ext.Attributes2; + +import gnu.xml.pipeline.DomConsumer; +import gnu.xml.pipeline.EventConsumer; + + +/** + * Event consumer which constructs DOM documents using the implementation + * in this package, using SAX2 events. This packages various backdoors + * into this DOM implementation, as needed to address DOM requirements + * that can't be met by strictly conforming implementations of DOM. + * + *

      These requirements all relate to {@link DocumentType} nodes and + * features of that node type. These features are normally not used, + * because that interface only exposes a subset of the information found + * in DTDs. More, that subset does not include the most important typing + * information. For example, it excludes element content models and + * attribute typing. It does expose some entity management issues, + * although entity management doesn't relate to document typing. + * + *

      Note that SAX2 does not expose the literal text of the DTD's + * internal subset, so it will not be present in DOM trees constructed + * using this API. (Though with a good SAX2 implementation, it could + * be partially recreated...) + * + * @author David Brownell + */ +public class Consumer extends DomConsumer +{ + /** + * Constructs an unconfigured event consumer, + * as a terminus in a SAX event pipeline. + */ + // used by PipelineFactory [terminus] + public Consumer () + throws SAXException + { + super (DomDocument.class); + setHandler (new Backdoor (this)); + } + + /** + * Constructs an unconfigured event consumer, + * as a stage in a SAX event pipeline. + */ + // used by PipelineFactory [filter] + public Consumer (EventConsumer next) + throws SAXException + { + super (DomDocument.class, next); + setHandler (new Backdoor (this)); + } + + /** + * Implements the backdoors needed by DOM. + * All methods in this class use implementation-specific APIs that are + * implied by the DOM specification (needed to implement testable + * behavior) but which are excluded from the DOM specification. + */ + public static class Backdoor extends DomConsumer.Handler + { + /** + * Constructor. + * @param consumer must have been initialized to use the + * {@link DomDocument} class (or a subclass) for + * constructing DOM trees + */ + protected Backdoor (DomConsumer consumer) + throws SAXException + { super (consumer); } + + // helper routine + private DomDoctype getDoctype () + throws SAXException + { + DomDocument doc = (DomDocument) getDocument (); + DocumentType dt = doc.getDoctype (); + + if (dt == null) + throw new SAXException ("doctype missing!"); + return (DomDoctype) dt; + } + + // SAX2 "lexical" event + public void startDTD (String name, String publicId, String systemId) + throws SAXException + { + DomDocument doc = (DomDocument) getDocument (); + + super.startDTD (name, publicId, systemId); + // DOM L2 doctype creation model is bizarre + DomDoctype dt = new DomDoctype (doc, name, publicId, systemId); + doc.appendChild (dt); + } + + // SAX2 "lexical" event + public void endDTD () + throws SAXException + { + super.endDTD (); + // DOM L2 has no way to make things readonly + getDoctype ().makeReadonly (); + } + + // SAX1 DTD event + public void notationDecl ( + String name, + String publicId, String systemId + ) throws SAXException + { + // DOM L2 can't create/save notation nodes + getDoctype ().declareNotation (name, publicId, systemId); + } + + // SAX1 DTD event + public void unparsedEntityDecl ( + String name, + String publicId, String systemId, + String notationName + ) throws SAXException + { + // DOM L2 can't create/save entity nodes + getDoctype ().declareEntity (name, publicId, systemId, + notationName); + } + + // SAX2 declaration event + public void internalEntityDecl (String name, String value) + throws SAXException + { + // DOM L2 can't create/save entity nodes + // NOTE: this doesn't save the value as a child of this + // node, though it could realistically do so. + getDoctype ().declareEntity (name, null, null, null); + } + + // SAX2 declaration event + public void externalEntityDecl ( + String name, + String publicId, + String systemId + ) throws SAXException + { + // DOM L2 can't create/save entity nodes + // NOTE: DOM allows for these to have children, if + // they don't have unbound namespace references. + getDoctype ().declareEntity (name, publicId, systemId, null); + } + + // SAX2 element + public void startElement ( + String uri, + String localName, + String qName, + Attributes atts + ) throws SAXException + { + Node top; + + super.startElement (uri, localName, qName, atts); + + // might there be more work? + top = getTop (); + if (!top.hasAttributes () || !(atts instanceof Attributes2)) + return; + + // remember any attributes that got defaulted + DomNamedNodeMap map = (DomNamedNodeMap) top.getAttributes (); + Attributes2 attrs = (Attributes2) atts; + int length = atts.getLength (); + + //map.compact (); + for (int i = 0; i < length; i++) { + if (attrs.isSpecified (i)) + continue; + + // value was defaulted. + String temp = attrs.getQName (i); + DomAttr attr; + + if ("".equals (temp)) + attr = (DomAttr) map.getNamedItemNS (attrs.getURI (i), + atts.getLocalName (i)); + else + attr = (DomAttr) map.getNamedItem (temp); + + // DOM L2 can't write this flag, only read it + attr.setSpecified (false); + } + } + + public void endElement ( + String uri, + String localName, + String qName + ) throws SAXException + { + DomNode top = (DomNode) getTop (); + top.compact (); + super.endElement (uri, localName, qName); + } + + protected Text createText ( + boolean isCDATA, + char buf [], + int off, + int len + ) { + DomDocument doc = (DomDocument) getDocument (); + + if (isCDATA) + return doc.createCDATASection (buf, off, len); + else + return doc.createTextNode (buf, off, len); + } + + public void elementDecl(String name, String model) + throws SAXException + { + getDoctype().elementDecl(name, model); + } + + public void attributeDecl ( + String ename, + String aname, + String type, + String mode, + String value + ) throws SAXException + { + getDoctype().attributeDecl(ename, aname, type, mode, value); + /* + if (value == null && !"ID".equals (type)) + return; + + DomDoctype.ElementInfo info; + + info = getDoctype ().getElementInfo (ename); + if (value != null) + info.setAttrDefault (aname, value); + if ("ID".equals (type)) + info.setIdAttr (aname); + */ + + } + + // force duplicate name checking off while we're + // using parser output (don't duplicate the work) + public void startDocument () throws SAXException + { + super.startDocument (); + + DomDocument doc = (DomDocument) getDocument (); + doc.setStrictErrorChecking(false); + doc.setBuilding(true); + } + + public void endDocument () + throws SAXException + { + DomDocument doc = (DomDocument) getDocument (); + doc.setStrictErrorChecking(true); + doc.setBuilding(false); + doc.compact (); + DomDoctype doctype = (DomDoctype) doc.getDoctype(); + if (doctype != null) + { + doctype.makeReadonly(); + } + super.endDocument (); + } + + // these three methods collaborate to populate entity + // refs, marking contents readonly on end-of-entity + + public boolean canPopulateEntityRefs () + { return true; } + + public void startEntity (String name) + throws SAXException + { + if (name.charAt (0) == '%' || "[dtd]".equals (name)) + return; + super.startEntity (name); + + DomNode top = (DomNode) getTop (); + + if (top.getNodeType () == Node.ENTITY_REFERENCE_NODE) + top.readonly = false; + } + + public void endEntity (String name) + throws SAXException + { + if (name.charAt (0) == '%' || "[dtd]".equals (name)) + return; + DomNode top = (DomNode) getTop (); + + if (top.getNodeType () == Node.ENTITY_REFERENCE_NODE) { + top.compact (); + top.makeReadonly (); + } + super.endEntity (name); + } + } +} diff --git a/libjava/classpath/gnu/xml/dom/DTDAttributeTypeInfo.java b/libjava/classpath/gnu/xml/dom/DTDAttributeTypeInfo.java new file mode 100644 index 000000000..d6e25529d --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DTDAttributeTypeInfo.java @@ -0,0 +1,83 @@ +/* DTDAttributeTypeInfo.java -- + 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.xml.dom; + +import org.w3c.dom.TypeInfo; + +/** + * Attribute type information supplied by a DTD attribute declaration. + * + * @author Chris Burdess + */ +class DTDAttributeTypeInfo + implements TypeInfo +{ + + final String elementName; + final String name; + final String type; + final String mode; + final String value; + + DTDAttributeTypeInfo(String elementName, String name, String type, + String mode, String value) + { + this.elementName = elementName; + this.name = name; + this.type = type; + this.mode = mode; + this.value = value; + } + + public final String getTypeName() + { + return type; + } + + public final String getTypeNamespace() + { + return "http://www.w3.org/TR/REC-xml"; + } + + public final boolean isDerivedFrom(String typeNamespace, String typeName, + int derivationMethod) + { + return false; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DTDElementTypeInfo.java b/libjava/classpath/gnu/xml/dom/DTDElementTypeInfo.java new file mode 100644 index 000000000..9063d4c79 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DTDElementTypeInfo.java @@ -0,0 +1,111 @@ +/* DTDElementTypeInfo.java -- + 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.xml.dom; + +import java.util.HashMap; +import java.util.Iterator; +import org.w3c.dom.TypeInfo; + +/** + * Element type information provided by a DTD element declaration. + * + * @author Chris Burdess + */ +class DTDElementTypeInfo + implements TypeInfo +{ + + final String name; + String model; + HashMap attributes; + String idAttrName; + + DTDElementTypeInfo(String name, String model) + { + this.name = name; + this.model = model; + } + + public final String getTypeName() + { + return null; + } + + public final String getTypeNamespace() + { + return "http://www.w3.org/TR/REC-xml"; + } + + public final boolean isDerivedFrom(String typeNamespace, String typeName, + int derivationMethod) + { + return false; + } + + DTDAttributeTypeInfo getAttributeTypeInfo(String name) + { + if (attributes == null) + { + return null; + } + return (DTDAttributeTypeInfo) attributes.get(name); + } + + void setAttributeTypeInfo(String name, DTDAttributeTypeInfo info) + { + if (attributes == null) + { + attributes = new HashMap(); + } + attributes.put(name, info); + if ("ID".equals(info.type)) + { + idAttrName = name; + } + } + + Iterator attributes() + { + if (attributes == null) + { + return null; + } + return attributes.values().iterator(); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomAttr.java b/libjava/classpath/gnu/xml/dom/DomAttr.java new file mode 100644 index 000000000..421baf76a --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomAttr.java @@ -0,0 +1,411 @@ +/* DomAttr.java -- + Copyright (C) 1999,2000,2001,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.xml.dom; + +import gnu.java.lang.CPStringBuilder; + +import org.w3c.dom.Attr; +import org.w3c.dom.DOMException; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.TypeInfo; +import org.w3c.dom.events.MutationEvent; + + +/** + *

      "Attr" implementation. In DOM, attributes cost quite a lot of + * memory because their values are complex structures rather than just + * simple strings. To reduce your costs, avoid having more than one + * child of an attribute; stick to a single Text node child, and ignore + * even that by using the attribute's "nodeValue" property.

      + * + *

      As a bit of general advice, only look at attribute modification + * events through the DOMAttrModified event (sent to the associated + * element). Implementations are not guaranteed to report other events + * in the same order, so you're very likely to write nonportable code if + * you monitor events at the "children of Attr" level.

      + * + *

      At this writing, not all attribute modifications will cause the + * DOMAttrModified event to be triggered ... only the ones using the string + * methods (setNodeValue, setValue, and Element.setAttribute) to modify + * those values. That is, if you manipulate those children directly, + * elements won't get notified that attribute values have changed. + * The natural fix for that will report other modifications, but won't + * be able to expose "previous" attribute value; it'll need to be cached + * or something (at which point why bother using child nodes).

      + * + *

      You are strongly advised not to use "children" of any attribute + * nodes you work with.

      + * + * @author David Brownell + * @author Chris Burdess + */ +public class DomAttr + extends DomNsNode + implements Attr +{ + + private boolean specified; + private String value; // string value cache + + /** + * Constructs an Attr node associated with the specified document. + * The "specified" flag is initialized to true, since this DOM has + * no current "back door" mechanisms to manage default values so + * that every value must effectively be "specified". + * + *

      This constructor should only be invoked by a Document as part of + * its createAttribute functionality, or through a subclass which is + * similarly used in a "Sub-DOM" style layer. + * + * @param owner The document with which this node is associated + * @param namespaceURI Combined with the local part of the name, + * this is used to uniquely identify a type of attribute + * @param name Name of this attribute, which may include a prefix + */ + protected DomAttr(DomDocument owner, String namespaceURI, String name) + { + super(ATTRIBUTE_NODE, owner, namespaceURI, name); + specified = true; + length = 1; + + // XXX register self to get insertion/removal events + // and character data change events and when they happen, + // report self-mutation + } + + /** + * Constructs an Attr node associated with the specified document. + * The "specified" flag is initialized to true, since this DOM has + * no current "back door" mechanisms to manage default values so + * that every value must effectively be "specified". + * + *

      This constructor should only be invoked by a Document as part of + * its createAttribute functionality, or through a subclass which is + * similarly used in a "Sub-DOM" style layer. + *

      + * With this constructor, the prefix and local part are given explicitly + * rather than being computed. This allows them to be explicitly set to + * {@code null} as required by {@link Document#createAttribute(String)}. + *

      + * + * @param owner The document with which this node is associated + * @param namespaceURI Combined with the local part of the name, + * this is used to uniquely identify a type of attribute + * @param name Name of this attribute, which may include a prefix + * @param prefix the namespace prefix of the name. May be {@code null}. + * @param localName the local part of the name. May be {@code null}. + */ + protected DomAttr(DomDocument owner, String namespaceURI, String name, + String prefix, String localName) + { + super(ATTRIBUTE_NODE, owner, namespaceURI, name, prefix, localName); + specified = true; + length = 1; + } + + /** + * DOM L1 + * Returns the attribute name (same as getNodeName) + */ + public final String getName() + { + return getNodeName(); + } + + /** + * DOM L1 + * Returns true if a parser reported this was in the source text. + */ + public final boolean getSpecified() + { + return specified; + } + + /** + * Records whether this attribute was in the source text. + */ + public final void setSpecified(boolean value) + { + specified = value; + } + + /** + * DOM L1 + * Returns the attribute value, with character and entity + * references substituted. + * NOTE: entity refs as children aren't currently handled. + */ + public String getNodeValue() + { + // If we have a simple node-value, use that + if (first == null) + { + return (value == null) ? "" : value; + } + // Otherwise collect child node-values + CPStringBuilder buf = new CPStringBuilder(); + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + switch (ctx.nodeType) + { + case Node.TEXT_NODE: + buf.append(ctx.getNodeValue()); + break; + case Node.ENTITY_REFERENCE_NODE: + // TODO + break; + } + } + return buf.toString(); + } + + /** + * DOM L1 + * Assigns the value of the attribute; it will have one child, + * which is a text node with the specified value (same as + * setNodeValue). + */ + public final void setValue(String value) + { + setNodeValue(value); + } + + /** + * DOM L1 + * Returns the value of the attribute as a non-null string; same + * as getNodeValue. + * NOTE: entity refs as children aren't currently handled. + */ + public final String getValue() + { + return getNodeValue(); + } + + /** + * DOM L1 + * Assigns the attribute value; using this API, no entity or + * character references will exist. + * Causes a DOMAttrModified mutation event to be sent. + */ + public void setNodeValue(String value) + { + if (readonly) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + if (value == null) + { + value = ""; + } + String oldValue = getNodeValue(); + while (last != null) + { + removeChild(last); + } + // don't create a new node just for this... + /* + Node text = owner.createTextNode(value); + appendChild(text); + */ + this.value = value; + length = 1; + specified = true; + + mutating(oldValue, value, MutationEvent.MODIFICATION); + } + + public final Node getFirstChild() + { + // Create a child text node if necessary + if (first == null) + { + length = 0; + Node text = owner.createTextNode((value == null) ? "" : value); + appendChild(text); + } + return first; + } + + public final Node getLastChild() + { + // Create a child text node if necessary + if (last == null) + { + length = 0; + Node text = owner.createTextNode((value == null) ? "" : value); + appendChild(text); + } + return last; + } + + public Node item(int index) + { + // Create a child text node if necessary + if (first == null) + { + length = 0; + Node text = owner.createTextNode((value == null) ? "" : value); + appendChild(text); + } + return super.item(index); + } + + /** + * DOM L2 + * Returns the element with which this attribute is associated. + */ + public final Element getOwnerElement() + { + return (Element) parent; + } + + public final Node getNextSibling() + { + return null; + } + + public final Node getPreviousSibling() + { + return null; + } + + public Node getParentNode() + { + return null; + } + + /** + * Records the element with which this attribute is associated. + */ + public final void setOwnerElement(Element e) + { + if (parent != null) + { + throw new DomDOMException(DOMException.HIERARCHY_REQUEST_ERR); + } + if (!(e instanceof DomElement)) + { + throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR); + } + parent = (DomElement) e; + depth = parent.depth + 1; + } + + /** + * The base URI of an Attr is always null. + */ + public final String getBaseURI() + { + return null; + } + + /** + * Shallow clone of the attribute, breaking all ties with any + * elements. + */ + public Object clone() + { + DomAttr retval = (DomAttr) super.clone(); + retval.specified = true; + return retval; + } + + private void mutating(String oldValue, String newValue, short why) + { + if (!reportMutations || parent == null || equal(newValue, oldValue)) + { + return; + } + + // EVENT: DOMAttrModified, target = parent, + // prev/new values provided, also attr name + MutationEvent event; + + event = (MutationEvent) createEvent ("MutationEvents"); + event.initMutationEvent ("DOMAttrModified", + true /* bubbles */, false /* nocancel */, + null, oldValue, newValue, getNodeName (), why); + parent.dispatchEvent (event); + } + + // DOM Level 3 methods + + public TypeInfo getSchemaTypeInfo() + { + if (parent != null) + { + // DTD implementation + DomDoctype doctype = (DomDoctype) parent.owner.getDoctype(); + if (doctype != null) + { + return doctype.getAttributeTypeInfo(parent.getNodeName(), + getNodeName()); + } + // TODO XML Schema implementation + } + return null; + } + + public boolean isId() + { + if (parent != null) + { + DomDoctype doctype = (DomDoctype) parent.owner.getDoctype(); + if (doctype != null) + { + DTDAttributeTypeInfo info = + doctype.getAttributeTypeInfo(parent.getNodeName(), + getNodeName()); + if (info != null && "ID".equals(info.type)) + { + return true; + } + } + DomElement element = (DomElement) parent; + if (element.userIdAttrs != null && + element.userIdAttrs.contains(this)) + { + return true; + } + // TODO XML Schema implementation + } + return false; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomCDATASection.java b/libjava/classpath/gnu/xml/dom/DomCDATASection.java new file mode 100644 index 000000000..770f7d5dd --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomCDATASection.java @@ -0,0 +1,90 @@ +/* DomCDATASection.java -- + Copyright (C) 1999,2000,2001,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.xml.dom; + +import org.w3c.dom.CDATASection; + +/** + *

      "CDATASection" implementation. + * This is a non-core DOM class, supporting the "XML" feature. + * CDATA sections are just ways to represent text using different + * delimeters.

      + * + *

      You are strongly advised not to use CDATASection nodes. + * The advantage of having slightly prettier ways to print text that may + * have lots of embedded XML delimiters, such as "&" and "<", + * can be dwarfed by the cost of dealing with multiple kinds of text + * nodes in all your algorithms.

      + * + * @author David Brownell + * @author Chris Burdess + */ +public class DomCDATASection + extends DomText + implements CDATASection +{ + + /** + * Constructs a CDATA section node associated with the specified + * document and holding the specified data. + * + *

      This constructor should only be invoked by a Document as part of + * its createCDATASection functionality, or through a subclass which is + * similarly used in a "Sub-DOM" style layer. + * + */ + protected DomCDATASection(DomDocument owner, String value) + { + super(CDATA_SECTION_NODE, owner, value); + } + + protected DomCDATASection(DomDocument owner, char buf [], int off, int len) + { + super(CDATA_SECTION_NODE, owner, buf, off, len); + } + + /** + * DOM L1 + * Returns the string "#cdata-section". + */ + final public String getNodeName() + { + return "#cdata-section"; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomCharacterData.java b/libjava/classpath/gnu/xml/dom/DomCharacterData.java new file mode 100644 index 000000000..396c5f7a7 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomCharacterData.java @@ -0,0 +1,344 @@ +/* DomCharacterData.java -- + Copyright (C) 1999,2000,2001,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.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; + + +/** + *

      Abstract "CharacterData" implementation. This + * facilitates reusing code in classes implementing subtypes of that DOM + * interface (Text, Comment, CDATASection).

      + * + * @author David Brownell + * @author Chris Burdess + */ +public abstract class DomCharacterData + extends DomNode + 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 + DomCharacterData(short nodeType, DomDocument doc, String value) + { + super(nodeType, doc); + text = (value == null) ? "" : value; + } + + // package private + DomCharacterData(short nodeType, DomDocument doc, + char[] buf, int offset, int length) + { + super(nodeType, doc); + text = (buf == null) ? "" : new String(buf, offset, length); + } + + /** + * DOM L1 + * Appends the specified data to the value of this node. + * Causes a DOMCharacterDataModified mutation event to be reported. + */ + public void appendData(String arg) + { + if (isReadonly()) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + String value = text + arg; + mutating(value); + text = value; + } + + /** + * DOM L1 + * Modifies the value of this node. + * Causes a DOMCharacterDataModified mutation event to be reported. + */ + public void deleteData(int offset, int count) + { + if (isReadonly()) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + char[] raw = text.toCharArray(); + if (offset < 0 || count < 0 || offset > raw.length) + { + throw new DomDOMException(DOMException.INDEX_SIZE_ERR); + } + if ((offset + count) > raw.length) + { + count = raw.length - offset; + } + if (count == 0) + { + return; + } + try + { + char[] buf = new char[raw.length - count]; + System.arraycopy(raw, 0, buf, 0, offset); + System.arraycopy(raw, offset + count, buf, offset, + raw.length - (offset + count)); + String value = new String(buf); + mutating(value); + text = value; + } + catch (IndexOutOfBoundsException x) + { + throw new DomDOMException(DOMException.INDEX_SIZE_ERR); + } + } + + /** + * DOM L1 + * Returns the value of this node. + */ + public String getNodeValue() + { + return text; + } + + /** + * DOM L1 + * Returns the value of this node; same as getNodeValue. + */ + public final String getData() + { + return text; + } + + /** + * DOM L1 + * Returns the length of the data. + */ + public int getLength() + { + return text.length(); + } + + /** + * DOM L1 + * Modifies the value of this node. + */ + public void insertData(int offset, String arg) + { + if (isReadonly()) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + char[] raw = text.toCharArray(); + char[] tmp = arg.toCharArray (); + char[] buf = new char[raw.length + tmp.length]; + + try + { + System.arraycopy(raw, 0, buf, 0, offset); + System.arraycopy(tmp, 0, buf, offset, tmp.length); + System.arraycopy(raw, offset, buf, offset + tmp.length, + raw.length - offset); + String value = new String(buf); + mutating(value); + text = value; + } + catch (IndexOutOfBoundsException x) + { + throw new DomDOMException(DOMException.INDEX_SIZE_ERR); + } + } + + /** + * DOM L1 + * Modifies the value of this node. Causes DOMCharacterDataModified + * mutation events to be reported (at least one). + */ + public void replaceData(int offset, int count, String arg) + { + if (readonly) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + char[] raw = text.toCharArray(); + + // deleteData + if (offset < 0 || count < 0 || offset > raw.length) + { + throw new DomDOMException(DOMException.INDEX_SIZE_ERR); + } + if ((offset + count) > raw.length) + { + count = raw.length - offset; + } + try + { + char[] buf = new char[raw.length - count]; + System.arraycopy(raw, 0, buf, 0, offset); + System.arraycopy(raw, offset + count, buf, offset, + raw.length - (offset + count)); + + // insertData + char[] tmp = arg.toCharArray (); + char[] buf2 = new char[buf.length + tmp.length]; + System.arraycopy(raw, 0, buf, 0, offset); + System.arraycopy(tmp, 0, buf, offset, tmp.length); + System.arraycopy(raw, offset, buf, offset + tmp.length, + raw.length - offset); + String value = new String(buf); + mutating(value); + text = value; + } + catch (IndexOutOfBoundsException x) + { + throw new DomDOMException(DOMException.INDEX_SIZE_ERR); + } + } + + /** + * DOM L1 + * Assigns the value of this node. + * Causes a DOMCharacterDataModified mutation event to be reported. + */ + public void setNodeValue(String value) + { + if (isReadonly()) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + if (value == null) + { + value = ""; + } + mutating(value); + text = value; + } + + /** + * DOM L1 + * Assigns the value of this node; same as setNodeValue. + */ + final public void setData(String data) + { + setNodeValue(data); + } + + /** + * DOM L1 + * Returns the specified substring. + */ + public String substringData(int offset, int count) + { + try + { + return text.substring(offset, count); + } + catch (StringIndexOutOfBoundsException e) + { + if (offset >= 0 && count >= 0 && offset < text.length()) + { + return text.substring(offset); + } + throw new DomDOMException(DOMException.INDEX_SIZE_ERR); + } + } + + /** + * 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 + */ + public final String getBaseURI() + { + return null; + } + + private void mutating(String newValue) + { + if (!reportMutations) + { + return; + } + + // EVENT: DOMCharacterDataModified, target = this, + // prev/new values provided + MutationEvent event; + + event = (MutationEvent) createEvent("MutationEvents"); + event.initMutationEvent("DOMCharacterDataModified", + true /* bubbles */, false /* nocancel */, + null, text, newValue, null, (short) 0); + dispatchEvent(event); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomComment.java b/libjava/classpath/gnu/xml/dom/DomComment.java new file mode 100644 index 000000000..5be6bd518 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomComment.java @@ -0,0 +1,80 @@ +/* DomComment.java -- + Copyright (C) 1999,2000,2001,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.xml.dom; + +import org.w3c.dom.Comment; + +/** + *

      "Comment" implementation. + * Comments hold data intended for direct consumption by people; + * programs should only use ProcessingInstruction nodes. Note that + * since SAX makes comment reporting optional, XML systems that + * rely on comments (such as by using this class) will often lose + * those comments at some point in the processing pipeline.

      + * + * @author David Brownell + * @author Chris Burdess + */ +public class DomComment + extends DomCharacterData + implements Comment +{ + + /** + * Constructs a comment node associated with the specified + * document and holding the specified data. + * + *

      This constructor should only be invoked by a Document as part of + * its createComment functionality, or through a subclass which is + * similarly used in a "Sub-DOM" style layer. + */ + protected DomComment(DomDocument owner, String value) + { + super(COMMENT_NODE, owner, value); + } + + /** + * DOM L1 + * Returns the string "#comment". + */ + final public String getNodeName() + { + return "#comment"; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomDOMException.java b/libjava/classpath/gnu/xml/dom/DomDOMException.java new file mode 100644 index 000000000..4a3ba7a8c --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomDOMException.java @@ -0,0 +1,174 @@ +/* DomDOMException.java -- + Copyright (C) 1999,2000,2001,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.xml.dom; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; + +/** + *

      DOMException implementation. The version that + * is provided by the W3C is abstract, so it can't be instantiated. + * + *

      This also provides a bit more information about the error + * that is being reported, in terms of the relevant DOM structures + * and data. + * + * @author David Brownell + */ +public class DomDOMException + extends DOMException +{ + + /** @serial Data that caused an error to be reported */ + private String data; + + /** @serial Node associated with the error. */ + private Node node; + + /** @serial Data associated with the error. */ + private int value; + + /** + * Constructs an exception, with the diagnostic message + * corresponding to the specified code. + */ + public DomDOMException(short code) + { + super(code, diagnostic(code)); + } + + /** + * Constructs an exception, with the diagnostic message + * corresponding to the specified code and additional + * information as provided. + */ + public DomDOMException(short code, String data, Node node, int value) + { + super(code, diagnostic(code)); + this.data = data; + this.node = node; + this.value = value; + } + + /** Returns the node to which the diagnotic applies, or null. */ + final public Node getNode() + { + return node; + } + + /** Returns data to which the diagnotic applies, or null. */ + final public String getData() + { + return data; + } + + /** Returns data to which the diagnotic applies, or null. */ + final public int getValue() + { + return value; + } + + /** + * Returns a diagnostic message that may be slightly more useful + * than the generic one, where possible. + */ + public String getMessage() + { + String retval = super.getMessage(); + + if (data != null) + { + retval += "\nMore Information: " + data; + } + if (value != 0) + { + retval += "\nNumber: " + value; + } + if (node != null) + { + retval += "\nNode Name: " + node.getNodeName(); + } + return retval; + } + + // these strings should be localizable. + + private static String diagnostic(short code) + { + switch (code) + { + // DOM L1: + case INDEX_SIZE_ERR: + return "An index or size is out of range."; + case DOMSTRING_SIZE_ERR: + return "A string is too big."; + case HIERARCHY_REQUEST_ERR: + return "The node doesn't belong here."; + case WRONG_DOCUMENT_ERR: + return "The node belongs in another document."; + case INVALID_CHARACTER_ERR: + return "That character is not permitted."; + case NO_DATA_ALLOWED_ERR: + return "This node does not permit data."; + case NO_MODIFICATION_ALLOWED_ERR: + return "No changes are allowed."; + case NOT_FOUND_ERR: + return "The node was not found in that context."; + case NOT_SUPPORTED_ERR: + return "That object is not supported."; + case INUSE_ATTRIBUTE_ERR: + return "The attribute belongs to a different element."; + + // DOM L2: + case INVALID_STATE_ERR: + return "The object is not usable."; + case SYNTAX_ERR: + return "An illegal string was provided."; + case INVALID_MODIFICATION_ERR: + return "An object's type may not be changed."; + case NAMESPACE_ERR: + return "The operation violates XML Namespaces."; + case INVALID_ACCESS_ERR: + return "Parameter or operation isn't supported by this node."; + case TYPE_MISMATCH_ERR: + return "The type of the argument is incompatible with the expected type."; + } + return "Reserved exception number: " + code; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomDoctype.java b/libjava/classpath/gnu/xml/dom/DomDoctype.java new file mode 100644 index 000000000..ecf7a9588 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomDoctype.java @@ -0,0 +1,455 @@ +/* DomDoctype.java -- + Copyright (C) 1999,2000,2001,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.xml.dom; + +import java.util.HashMap; +import org.w3c.dom.DocumentType; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Entity; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.Notation; + +/** + *

      "DocumentType" implementation (with no extensions for supporting + * any document typing information). This is a non-core DOM class, + * supporting the "XML" feature.

      + * + *

      Few XML applications will actually care about this partial + * DTD support, since it doesn't expose any (!) of the data typing + * facilities which can motivate applications to use DTDs. It does not + * expose element content models, or information about attribute typing + * rules. Plus the information it exposes isn't very useful; as one example, + * DOM exposes information about unparsed ENTITY objects, which is only used + * with certain element attributes, but does not expose the information about + * those attributes which is needed to apply that data!

      + * + *

      Also, note that there are no nonportable ways to associate even the + * notation and entity information exposed by DOM with a DocumentType. While + * there is a DOM L2 method to construct a DocumentType, it only gives access + * to the textual content of the <!DOCTYPE ...> declaration.

      + * + *

      In short, you are strongly advised not to rely on this incomplete + * DTD functionality in your application code.

      + * + * @see DomEntity + * @see DomEntityReference + * @see DomNotation + * + * @author David Brownell + * @author Chris Burdess + */ +public class DomDoctype + extends DomExtern + implements DocumentType +{ + + private DomNamedNodeMap notations; + private DomNamedNodeMap entities; + private final DOMImplementation implementation; + private String subset; + + private HashMap elements = new HashMap(); + private boolean ids; + + /** + * Constructs a DocumentType node associated with the specified + * implementation, with the specified name. + * + *

      This constructor should only be invoked by a DOMImplementation as + * part of its createDocumentType functionality, or through a subclass + * which is similarly used in a "Sub-DOM" style layer. + * + *

      Note that at this time there is no standard SAX API granting + * access to the internal subset text, so that relying on that value + * is not currently portable. + * + * @param impl The implementation with which this object is associated + * @param name Name of this root element + * @param publicId If non-null, provides the external subset's + * PUBLIC identifier + * @param systemId If non-null, provides the external subset's + * SYSTEM identifier + * @param internalSubset Provides the literal value (unparsed, no + * entities expanded) of the DTD's internal subset. + */ + protected DomDoctype(DOMImplementation impl, + String name, + String publicId, + String systemId, + String internalSubset) + { + super(DOCUMENT_TYPE_NODE, null, name, publicId, systemId); + implementation = impl; + subset = internalSubset; + } + + /** + * JAXP builder constructor. + * @param doc the document + * @param name the name of the document element + * @param publicId the public ID of the document type declaration + * @param systemId the system ID of the document type declaration + */ + public DomDoctype(DomDocument doc, + String name, + String publicId, + String systemId) + { + super(DOCUMENT_TYPE_NODE, doc, name, publicId, systemId); + implementation = doc.getImplementation(); + } + + /** + * DOM L1 + * Returns the root element's name (just like getNodeName). + */ + final public String getName() + { + return getNodeName(); + } + + /** + * DOM L1 + * Returns information about any general entities declared + * in the DTD. + * + *

      Note: DOM L1 doesn't throw a DOMException here, but + * then it doesn't have the strange construction rules of L2. + * + * @exception DOMException HIERARCHY_REQUEST_ERR if the DocumentType + * is not associated with a document. + */ + public NamedNodeMap getEntities() + { + if (entities == null) + { + entities = new DomNamedNodeMap(this, Node.ENTITY_NODE); + } + return entities; + } + + /** + * Records the declaration of a general entity in this DocumentType. + * + * @param name Name of the entity + * @param publicId If non-null, provides the entity's PUBLIC identifier + * @param systemId Provides the entity's SYSTEM identifier + * @param notation If non-null, provides the entity's notation + * (indicating an unparsed entity) + * @return The Entity that was declared, or null if the entity wasn't + * recorded (because it's a parameter entity or because an entity with + * this name was already declared). + * + * @exception DOMException NO_MODIFICATION_ALLOWED_ERR if the + * DocumentType is no longer writable. + * @exception DOMException HIERARCHY_REQUEST_ERR if the DocumentType + * is not associated with a document. + */ + public Entity declareEntity(String name, + String publicId, + String systemId, + String notation) + { + DomEntity entity; + + if (name.charAt(0) == '%' || "[dtd]".equals(name)) + { + return null; + } + if (isReadonly()) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + getEntities(); + + DomDocument.checkName(name, (owner != null) ? + "1.1".equals(owner.getXmlVersion()) : false); + if (entities.getNamedItem(name) != null) + { + return null; + } + + entity = new DomEntity(owner, name, publicId, systemId, notation); + entities.setNamedItem(entity); + return entity; + } + + /** + * DOM L1 + * Returns information about any notations declared in the DTD. + * + *

      Note: DOM L1 doesn't throw a DOMException here, but + * then it doesn't have the strange construction rules of L2. + * + * @exception DOMException HIERARCHY_REQUEST_ERR if the DocumentType + * is not associated with a document. + */ + public NamedNodeMap getNotations() + { + if (notations == null) + { + notations = new DomNamedNodeMap(this, Node.NOTATION_NODE); + } + return notations; + } + + /** + * Records the declaration of a notation in this DocumentType. + * + * @param name Name of the notation + * @param publicId If non-null, provides the notation's PUBLIC identifier + * @param systemId If non-null, provides the notation's SYSTEM identifier + * @return The notation that was declared. + * + * @exception DOMException NO_MODIFICATION_ALLOWED_ERR if the + * DocumentType is no longer writable. + * @exception DOMException HIERARCHY_REQUEST_ERR if the DocumentType + * is not associated with a document. + */ + public Notation declareNotation(String name, + String publicId, + String systemId) + { + DomNotation notation; + + if (isReadonly()) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + getNotations(); + + DomDocument.checkName(name, (owner != null) ? + "1.1".equals(owner.getXmlVersion()) : false); + + notation = new DomNotation(owner, name, publicId, systemId); + notations.setNamedItem(notation); + return notation; + } + + /** + * DOM L2 + * Returns the internal subset of the document, as a string of unparsed + * XML declarations (and comments, PIs, whitespace); or returns null if + * there is no such subset. There is no vendor-independent expectation + * that this attribute be set, or that declarations found in it be + * reflected in the entities or notations attributes + * of this Document "Type" object. + * + *

      Some application-specific XML profiles require that documents + * only use specific PUBLIC identifiers, without an internal subset + * to modify the interperetation of the declarations associated with + * that PUBLIC identifier through some standard. + */ + public String getInternalSubset() + { + return subset; + } + + /** + * The base URI of a DocumentType is always null. + * See the Infoset Mapping, appendix C. + */ + public final String getBaseURI() + { + return null; + } + + /** + * Sets the internal "readonly" flag so the node and its associated + * data (only lists of entities and notations, no type information + * at the moment) can't be changed. + */ + public void makeReadonly() + { + super.makeReadonly(); + if (entities != null) + { + entities.makeReadonly(); + } + if (notations != null) + { + notations.makeReadonly(); + } + } + + void setOwner(DomDocument doc) + { + if (entities != null) + { + for (DomNode ctx = entities.first; ctx != null; ctx = ctx.next) + { + ctx.setOwner(doc); + } + } + if (notations != null) + { + for (DomNode ctx = notations.first; ctx != null; ctx = ctx.next) + { + ctx.setOwner(doc); + } + } + super.setOwner(doc); + } + + /** + * DOM L2 + * Consults the DOM implementation to determine if the requested + * feature is supported. + */ + final public boolean supports(String feature, String version) + { + return implementation.hasFeature(feature, version); + } + + /** + * Returns the implementation associated with this document type. + */ + final public DOMImplementation getImplementation() + { + return implementation; + } + + public void elementDecl(String name, String model) + { + DTDElementTypeInfo info = getElementTypeInfo(name); + if (info == null) + { + info = new DTDElementTypeInfo(name, model); + elements.put(name, info); + } + else + { + info.model = model; + } + } + + DTDElementTypeInfo getElementTypeInfo(String name) + { + return (DTDElementTypeInfo) elements.get(name); + } + + public void attributeDecl(String eName, String aName, String type, + String mode, String value) + { + DTDAttributeTypeInfo info = new DTDAttributeTypeInfo(eName, aName, type, + mode, value); + DTDElementTypeInfo elementInfo = getElementTypeInfo(eName); + if (elementInfo == null) + { + elementInfo = new DTDElementTypeInfo(eName, null); + elements.put(eName, elementInfo); + } + elementInfo.setAttributeTypeInfo(aName, info); + if ("ID".equals(type)) + { + ids = true; + } + } + + DTDAttributeTypeInfo getAttributeTypeInfo(String elementName, String name) + { + DTDElementTypeInfo elementInfo = + (DTDElementTypeInfo) elements.get(elementName); + return (elementInfo == null) ? null : + elementInfo.getAttributeTypeInfo(name); + } + + boolean hasIds() + { + return ids; + } + + public boolean isSameNode(Node arg) + { + if (equals(arg)) + { + return true; + } + if (!(arg instanceof DocumentType)) + { + return false; + } + DocumentType doctype = (DocumentType) arg; + if (!equal(getPublicId(), doctype.getPublicId())) + { + return false; + } + if (!equal(getSystemId(), doctype.getSystemId())) + { + return false; + } + if (!equal(getInternalSubset(), doctype.getInternalSubset())) + { + return false; + } + // TODO entities + // TODO notations + return true; + } + + /** + * Shallow clone of the doctype, except that associated + * entities and notations are (deep) cloned. + */ + public Object clone() + { + DomDoctype node = (DomDoctype) super.clone(); + + if (entities != null) + { + node.entities = new DomNamedNodeMap(node, Node.ENTITY_NODE); + for (DomNode ctx = entities.first; ctx != null; ctx = ctx.next) + { + node.entities.setNamedItem(ctx.cloneNode(true)); + } + } + if (notations != null) + { + node.notations = new DomNamedNodeMap(node, Node.NOTATION_NODE); + for (DomNode ctx = notations.first; ctx != null; ctx = ctx.next) + { + node.notations.setNamedItem(ctx.cloneNode(true)); + } + } + return node; + } + + +} diff --git a/libjava/classpath/gnu/xml/dom/DomDocument.java b/libjava/classpath/gnu/xml/dom/DomDocument.java new file mode 100644 index 000000000..b1e99f46d --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomDocument.java @@ -0,0 +1,1555 @@ +/* DomDocument.java -- + Copyright (C) 1999,2000,2001,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.xml.dom; + +import java.util.Iterator; +import javax.xml.XMLConstants; + +import org.w3c.dom.Attr; +import org.w3c.dom.CDATASection; +import org.w3c.dom.Comment; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.DocumentType; +import org.w3c.dom.DOMConfiguration; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.DOMException; +import org.w3c.dom.Element; +import org.w3c.dom.Entity; +import org.w3c.dom.EntityReference; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.Notation; +import org.w3c.dom.ProcessingInstruction; +import org.w3c.dom.Text; +import org.w3c.dom.UserDataHandler; +import org.w3c.dom.traversal.DocumentTraversal; +import org.w3c.dom.traversal.NodeFilter; +import org.w3c.dom.traversal.NodeIterator; +import org.w3c.dom.traversal.TreeWalker; +import org.w3c.dom.xpath.XPathEvaluator; +import org.w3c.dom.xpath.XPathException; +import org.w3c.dom.xpath.XPathExpression; +import org.w3c.dom.xpath.XPathNSResolver; + +/** + *

      "Document" and "DocumentTraversal" implementation. + * + *

      Note that when this checks names for legality, it uses an + * approximation of the XML rules, not the real ones. Specifically, + * it uses Unicode rules, with sufficient tweaks to pass a majority + * of basic XML conformance tests. (The huge XML character tables are + * hairy to implement.) + * + * @author David Brownell + * @author Chris Burdess + */ +public class DomDocument + extends DomNode + implements Document, DocumentTraversal, XPathEvaluator +{ + + private final DOMImplementation implementation; + private boolean checkingCharacters = true; + boolean checkingWellformedness = true; + private boolean defaultAttributes = true; + + boolean building; // if true, skip mutation events in the tree + + DomDocumentConfiguration config; + + String inputEncoding; + String encoding; + String version = "1.0"; + boolean standalone; + String systemId; + + /** + * Constructs a Document node, associating it with an instance + * of the DomImpl class. + * + *

      Note that this constructor disables character checking. + * It is normally used when connecting a DOM to an XML parser, + * and duplicating such checks is undesirable. When used for + * purposes other than connecting to a parser, you should + * re-enable that checking. + * + * @see #setCheckingCharacters + */ + public DomDocument() + { + this(new DomImpl()); + } + + /** + * Constructs a Document node, associating it with the specified + * implementation. This should only be used in conjunction with + * a specialized implementation; it will normally be called by + * that implementation. + * + * @see DomImpl + * @see #setCheckingCharacters + */ + protected DomDocument(DOMImplementation impl) + { + super(DOCUMENT_NODE, null); + implementation = impl; + } + + /** + * Sets the building flag. + * Mutation events in the document are not reported. + */ + public void setBuilding(boolean flag) + { + building = flag; + } + + /** + * Sets whether to check for document well-formedness. + * If true, an exception will be raised if a second doctype or root + * element node is added to the document. + */ + public void setCheckWellformedness(boolean flag) + { + checkingWellformedness = flag; + } + + /** + * Sets whether to check for document characters. + */ + public void setCheckingCharacters(boolean flag) + { + checkingCharacters = flag; + } + + /** + * Sets whether to default attributes for new elements. + */ + public void setDefaultAttributes(boolean flag) + { + defaultAttributes = flag; + } + + /** + * DOM L1 + * Returns the constant "#document". + */ + final public String getNodeName() + { + return "#document"; + } + + /** + * DOM L1 + * Returns the document's root element, or null. + */ + final public Element getDocumentElement() + { + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + if (ctx.nodeType == ELEMENT_NODE) + { + return (Element) ctx; + } + } + return null; + } + + /** + * DOM L1 + * Returns the document's DocumentType, or null. + */ + final public DocumentType getDoctype() + { + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + if (ctx.nodeType == DOCUMENT_TYPE_NODE) + { + return (DocumentType) ctx; + } + } + return null; + } + + /** + * DOM L1 + * Returns the document's DOMImplementation. + */ + final public DOMImplementation getImplementation() + { + return implementation; + } + + /** + * DOM L1 (relocated in DOM L2) + * Returns the element with the specified "ID" attribute, or null. + * + *

      Returns null unless {@link Consumer} was used to populate internal + * DTD declaration information, using package-private APIs. If that + * internal DTD information is available, the document may be searched for + * the element with that ID. + */ + public Element getElementById(String id) + { + if (id == null || id.length() == 0) + { + return null; + } + DomDoctype doctype = (DomDoctype) getDoctype(); + if (doctype != null && !doctype.hasIds()) + { + doctype = null; + } + + // yes, this is linear in size of document. + // it'd be easy enough to maintain a hashtable. + Node current = getDocumentElement(); + Node temp; + + if (current == null) + { + return null; + } + while (current != this) + { + // done? + if (current.getNodeType() == ELEMENT_NODE) + { + DomElement element = (DomElement) current; + if (element.userIdAttrs != null) + { + for (Iterator i = element.userIdAttrs.iterator(); + i.hasNext(); ) + { + Node idAttr = (Node) i.next(); + if (id.equals(idAttr.getNodeValue())) + { + return element; + } + } + } + if (doctype != null) + { + DTDElementTypeInfo info = + doctype.getElementTypeInfo(current.getNodeName()); + if (info != null && + id.equals(element.getAttribute(info.idAttrName))) + { + return element; + } + } + // xml:id + String xmlId = element.getAttribute("xml:id"); + if (xmlId == null) + { + xmlId = element.getAttributeNS(XMLConstants.XML_NS_URI, + "id"); + } + if (id.equals(xmlId)) + { + return element; + } + } + + // descend? + if (current.hasChildNodes()) + { + current = current.getFirstChild(); + continue; + } + + // lateral? + temp = current.getNextSibling(); + if (temp != null) + { + current = temp; + continue; + } + + // back up ... + do + { + temp = current.getParentNode(); + if (temp == null) + { + return null; + } + current = temp; + temp = current.getNextSibling(); + } + while (temp == null); + current = temp; + } + return null; + } + + private void checkNewChild(Node newChild) + { + if (newChild.getNodeType() == ELEMENT_NODE + && getDocumentElement() != null) + { + throw new DomDOMException(DOMException.HIERARCHY_REQUEST_ERR, + "document element already present: " + + getDocumentElement(), newChild, 0); + } + if (newChild.getNodeType() == DOCUMENT_TYPE_NODE + && getDoctype() != null) + { + throw new DomDOMException(DOMException.HIERARCHY_REQUEST_ERR, + "document type already present: " + + getDoctype(), newChild, 0); + } + } + + /** + * DOM L1 + * Appends the specified node to this node's list of children, + * enforcing the constraints that there be only one root element + * and one document type child. + */ + public Node appendChild(Node newChild) + { + if (checkingWellformedness) + { + checkNewChild(newChild); + } + return super.appendChild(newChild); + } + + /** + * DOM L1 + * Inserts the specified node in this node's list of children, + * enforcing the constraints that there be only one root element + * and one document type child. + */ + public Node insertBefore(Node newChild, Node refChild) + { + if (checkingWellformedness) + { + checkNewChild(newChild); + } + return super.insertBefore(newChild, refChild); + } + + /** + * DOM L1 + * Replaces the specified node in this node's list of children, + * enforcing the constraints that there be only one root element + * and one document type child. + */ + public Node replaceChild(Node newChild, Node refChild) + { + if (checkingWellformedness && + ((newChild.getNodeType() == ELEMENT_NODE && + refChild.getNodeType() != ELEMENT_NODE) || + (newChild.getNodeType() == DOCUMENT_TYPE_NODE && + refChild.getNodeType() != DOCUMENT_TYPE_NODE))) + { + checkNewChild(newChild); + } + return super.replaceChild(newChild, refChild); + } + + // NOTE: DOM can't really tell when the name of an entity, + // notation, or PI must follow the namespace rules (excluding + // colons) instead of the XML rules (which allow them without + // much restriction). That's an API issue. verifyXmlName + // aims to enforce the XML rules, not the namespace rules. + + /** + * Throws a DOM exception if the specified name is not a legal XML 1.0 + * Name. + * @deprecated This method is deprecated and may be removed in future + * versions of GNU JAXP + */ + public static void verifyXmlName(String name) + { + // XXX why is this public? + checkName(name, false); + } + + static void checkName(String name, boolean xml11) + { + if (name == null) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, name, null, 0); + } + int len = name.length(); + if (len == 0) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, name, null, 0); + } + + // dog: rewritten to use the rules for XML 1.0 and 1.1 + + // Name start character + char c = name.charAt(0); + if (xml11) + { + // XML 1.1 + if ((c < 0x0041 || c > 0x005a) && + (c < 0x0061 || c > 0x007a) && + c != ':' && c != '_' && + (c < 0x00c0 || c > 0x00d6) && + (c < 0x00d8 || c > 0x00f6) && + (c < 0x00f8 || c > 0x02ff) && + (c < 0x0370 || c > 0x037d) && + (c < 0x037f || c > 0x1fff) && + (c < 0x200c || c > 0x200d) && + (c < 0x2070 || c > 0x218f) && + (c < 0x2c00 || c > 0x2fef) && + (c < 0x3001 || c > 0xd7ff) && + (c < 0xf900 || c > 0xfdcf) && + (c < 0xfdf0 || c > 0xfffd) && + (c < 0x10000 || c > 0xeffff)) + { + throw new DomDOMException(DOMException.INVALID_CHARACTER_ERR, + name, null, c); + } + } + else + { + // XML 1.0 + int type = Character.getType(c); + switch (type) + { + case Character.LOWERCASE_LETTER: // Ll + case Character.UPPERCASE_LETTER: // Lu + case Character.OTHER_LETTER: // Lo + case Character.TITLECASE_LETTER: // Lt + case Character.LETTER_NUMBER: // Nl + if ((c > 0xf900 && c < 0xfffe) || + (c >= 0x20dd && c <= 0x20e0)) + { + // Compatibility area and Unicode 2.0 exclusions + throw new DomDOMException(DOMException.INVALID_CHARACTER_ERR, + name, null, c); + } + break; + default: + if (c != ':' && c != '_' && (c < 0x02bb || c > 0x02c1) && + c != 0x0559 && c != 0x06e5 && c != 0x06e6) + { + throw new DomDOMException(DOMException.INVALID_CHARACTER_ERR, + name, null, c); + } + } + } + + // Subsequent characters + for (int i = 1; i < len; i++) + { + c = name.charAt(i); + if (xml11) + { + // XML 1.1 + if ((c < 0x0041 || c > 0x005a) && + (c < 0x0061 || c > 0x007a) && + (c < 0x0030 || c > 0x0039) && + c != ':' && c != '_' && c != '-' && c != '.' && + (c < 0x00c0 || c > 0x00d6) && + (c < 0x00d8 || c > 0x00f6) && + (c < 0x00f8 || c > 0x02ff) && + (c < 0x0370 || c > 0x037d) && + (c < 0x037f || c > 0x1fff) && + (c < 0x200c || c > 0x200d) && + (c < 0x2070 || c > 0x218f) && + (c < 0x2c00 || c > 0x2fef) && + (c < 0x3001 || c > 0xd7ff) && + (c < 0xf900 || c > 0xfdcf) && + (c < 0xfdf0 || c > 0xfffd) && + (c < 0x10000 || c > 0xeffff) && + c != 0x00b7 && + (c < 0x0300 || c > 0x036f) && + (c < 0x203f || c > 0x2040)) + { + throw new DomDOMException(DOMException.INVALID_CHARACTER_ERR, name, + null, c); + } + } + else + { + // XML 1.0 + int type = Character.getType(c); + switch (type) + { + case Character.LOWERCASE_LETTER: // Ll + case Character.UPPERCASE_LETTER: // Lu + case Character.DECIMAL_DIGIT_NUMBER: // Nd + case Character.OTHER_LETTER: // Lo + case Character.TITLECASE_LETTER: // Lt + case Character.LETTER_NUMBER: // Nl + case Character.COMBINING_SPACING_MARK: // Mc + case Character.ENCLOSING_MARK: // Me + case Character.NON_SPACING_MARK: // Mn + case Character.MODIFIER_LETTER: // Lm + if ((c > 0xf900 && c < 0xfffe) || + (c >= 0x20dd && c <= 0x20e0)) + { + // Compatibility area and Unicode 2.0 exclusions + throw new DomDOMException(DOMException.INVALID_CHARACTER_ERR, + name, null, c); + } + break; + default: + if (c != '-' && c != '.' && c != ':' && c != '_' && + c != 0x0387 && (c < 0x02bb || c > 0x02c1) && + c != 0x0559 && c != 0x06e5 && c != 0x06e6 && c != 0x00b7) + { + throw new DomDOMException(DOMException.INVALID_CHARACTER_ERR, + name, null, c); + } + } + } + } + + // FIXME characters with a font or compatibility decomposition (i.e. + // those with a "compatibility formatting tag" in field 5 of the + // database -- marked by field 5 beginning with a "<") are not allowed. + } + + // package private + static void checkNCName(String name, boolean xml11) + { + checkName(name, xml11); + int len = name.length(); + int index = name.indexOf(':'); + if (index != -1) + { + if (index == 0 || index == (len - 1) || name.lastIndexOf(':') != index) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, name, null, 0); + } + } + } + + // package private + static void checkChar(String value, boolean xml11) + { + char[] chars = value.toCharArray(); + checkChar(chars, 0, chars.length, xml11); + } + + static void checkChar(char[] buf, int off, int len, boolean xml11) + { + for (int i = 0; i < len; i++) + { + char c = buf[i]; + + // assume surrogate pairing checks out OK, for simplicity + if ((c >= 0x0020 && c <= 0xd7ff) || + (c == 0x000a || c == 0x000d || c == 0x0009) || + (c >= 0xe000 && c <= 0xfffd) || + (c >= 0x10000 && c <= 0x10ffff)) + { + continue; + } + if (xml11) + { + if ((c >= 0x0001 && c <= 0x001f) || + (c >= 0x007f && c <= 0x0084) || + (c >= 0x0086 && c <= 0x009f)) + { + continue; + } + } + throw new DomDOMException(DOMException.INVALID_CHARACTER_ERR, + new String(buf, off, len), null, c); + } + } + + /** + * DOM L1 + * Returns a newly created element with the specified name. + * The node name of the created element will be equal to {@code name}. + * The namespace, prefix and local name will all be {@code null}. + */ + public Element createElement(String name) + { + Element element; + + if (checkingCharacters) + { + checkName(name, "1.1".equals(version)); + } + if (name.startsWith("xml:")) + { + element = createElementNS(null, name); + } + else + { + DomElement domElement = new DomElement(this, null, name, null, null); + element = domElement; + } + if (defaultAttributes) + setDefaultAttributes(element, name); + return element; + } + + /** + * DOM L2 + * Returns a newly created element with the specified name + * and namespace information. + */ + public Element createElementNS(String namespaceURI, String name) + { + if (checkingCharacters) + { + checkNCName(name, "1.1".equals(version)); + } + + if ("".equals(namespaceURI)) + { + namespaceURI = null; + } + if (name.startsWith("xml:")) + { + if (namespaceURI != null + && !XMLConstants.XML_NS_URI.equals(namespaceURI)) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "xml namespace is always " + + XMLConstants.XML_NS_URI, this, 0); + } + namespaceURI = XMLConstants.XML_NS_URI; + } + else if (XMLConstants.XMLNS_ATTRIBUTE.equals(name) || + name.startsWith("xmlns:")) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "xmlns is reserved", this, 0); + } + else if (namespaceURI == null && name.indexOf(':') != -1) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "prefixed name '" + name + + "' needs a URI", this, 0); + } + + Element element = new DomElement(this, namespaceURI, name); + if (defaultAttributes) + setDefaultAttributes(element, name); + return element; + } + + private void setDefaultAttributes(Element element, String name) + { + DomDoctype doctype = (DomDoctype) getDoctype(); + if (doctype == null) + { + return; + } + + // default any attributes that need it + DTDElementTypeInfo info = doctype.getElementTypeInfo(name); + if (info != null) + { + for (Iterator i = info.attributes(); i != null && i.hasNext(); ) + { + DTDAttributeTypeInfo attr = (DTDAttributeTypeInfo) i.next(); + String value = attr.value; + if ("#IMPLIED".equals(attr.mode) && value == null) + continue; + DomAttr node = (DomAttr) createAttribute(attr.name); + + if (value == null) + { + value = ""; + } + node.setValue(value); + node.setSpecified(false); + element.setAttributeNode(node); + } + } + } + + /** + * DOM L1 + * Returns a newly created document fragment. + */ + public DocumentFragment createDocumentFragment() + { + return new DomDocumentFragment(this); + } + + /** + * DOM L1 + * Returns a newly created text node with the specified value. + */ + public Text createTextNode(String value) + { + if (checkingCharacters) + { + checkChar(value, "1.1".equals(version)); + } + return new DomText(this, value); + } + + /** + * Returns a newly created text node with the specified value. + */ + public Text createTextNode(char[] buf, int off, int len) + { + if (checkingCharacters) + { + checkChar(buf, off, len, "1.1".equals(version)); + } + return new DomText(this, buf, off, len); + } + + /** + * DOM L1 + * Returns a newly created comment node with the specified value. + */ + public Comment createComment(String value) + { + if (checkingCharacters) + { + checkChar(value, "1.1".equals(version)); + } + return new DomComment(this, value); + } + + /** + * DOM L1 + * Returns a newly created CDATA section node with the specified value. + */ + public CDATASection createCDATASection(String value) + { + if (checkingCharacters) + { + checkChar(value, "1.1".equals(version)); + } + return new DomCDATASection(this, value); + } + + /** + * Returns a newly created CDATA section node with the specified value. + */ + public CDATASection createCDATASection(char[] buf, int off, int len) + { + if (checkingCharacters) + { + checkChar(buf, off, len, "1.1".equals(version)); + } + return new DomCDATASection(this, buf, off, len); + } + + /** + * DOM L1 + * Returns a newly created processing instruction. + */ + public ProcessingInstruction createProcessingInstruction(String target, + String data) + { + if (checkingCharacters) + { + boolean xml11 = "1.1".equals(version); + checkName(target, xml11); + if ("xml".equalsIgnoreCase(target)) + { + throw new DomDOMException(DOMException.SYNTAX_ERR, + "illegal PI target name", + this, 0); + } + checkChar(data, xml11); + } + return new DomProcessingInstruction(this, target, data); + } + + /** + * DOM L1 + * Returns a newly created attribute with the specified name. + */ + public Attr createAttribute(String name) + { + if (checkingCharacters) + { + checkName(name, "1.1".equals(version)); + } + if (name.startsWith("xml:")) + { + return createAttributeNS(XMLConstants.XML_NS_URI, name); + } + else if (XMLConstants.XMLNS_ATTRIBUTE.equals(name) || + name.startsWith("xmlns:")) + { + return createAttributeNS(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, name); + } + else + { + DomAttr ret = new DomAttr(this, null, name, null, null); + return ret; + } + } + + /** + * DOM L2 + * Returns a newly created attribute with the specified name + * and namespace information. + */ + public Attr createAttributeNS(String namespaceURI, String name) + { + if (checkingCharacters) + { + checkNCName(name, "1.1".equals(version)); + } + + if ("".equals(namespaceURI)) + { + namespaceURI = null; + } + if (name.startsWith ("xml:")) + { + if (namespaceURI == null) + { + namespaceURI = XMLConstants.XML_NS_URI; + } + else if (!XMLConstants.XML_NS_URI.equals(namespaceURI)) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "xml namespace is always " + + XMLConstants.XML_NS_URI, + this, 0); + } + } + else if (XMLConstants.XMLNS_ATTRIBUTE.equals(name) || + name.startsWith("xmlns:")) + { + if (namespaceURI == null) + { + namespaceURI = XMLConstants.XMLNS_ATTRIBUTE_NS_URI; + } + else if (!XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI)) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "xmlns namespace must be " + + XMLConstants.XMLNS_ATTRIBUTE_NS_URI, + this, 0); + } + } + else if (namespaceURI == null && name.indexOf(':') != -1) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "prefixed name needs a URI: " + name, this, 0); + } + return new DomAttr(this, namespaceURI, name); + } + + /** + * DOM L1 + * Returns a newly created reference to the specified entity. + * The caller should populate this with the appropriate children + * and then mark it as readonly. + * + * @see DomNode#makeReadonly + */ + public EntityReference createEntityReference(String name) + { + DomEntityReference ret = new DomEntityReference(this, name); + DocumentType doctype = getDoctype(); + if (doctype != null) + { + DomEntity ent = (DomEntity) doctype.getEntities().getNamedItem(name); + if (ent != null) + { + for (DomNode ctx = ent.first; ctx != null; ctx = ctx.next) + { + ret.appendChild(ctx.cloneNode(true)); + } + } + } + ret.makeReadonly(); + return ret; + } + + /** + * DOM L2 + * Makes a copy of the specified node, with all nodes "owned" by + * this document and with children optionally copied. This type + * of standard utility has become, well, a standard utility. + * + *

      Note that EntityReference nodes created through this method (either + * directly, or recursively) never have children, and that there is no + * portable way to associate them with such children. + * + *

      Note also that there is no requirement that the specified node + * be associated with a different document. This differs from the + * cloneNode operation in that the node itself is not given + * an opportunity to participate, so that any information managed + * by node subclasses will be lost. + */ + public Node importNode(Node src, boolean deep) + { + Node dst = null; + switch (src.getNodeType()) + { + case TEXT_NODE: + dst = createTextNode(src.getNodeValue()); + break; + case CDATA_SECTION_NODE: + dst = createCDATASection(src.getNodeValue()); + break; + case COMMENT_NODE: + dst = createComment(src.getNodeValue()); + break; + case PROCESSING_INSTRUCTION_NODE: + dst = createProcessingInstruction(src.getNodeName(), + src.getNodeValue()); + break; + case NOTATION_NODE: + // NOTE: There's no standard way to create + // these, or add them to a doctype. Useless. + Notation notation = (Notation) src; + dst = new DomNotation(this, notation.getNodeName(), + notation.getPublicId(), + notation.getSystemId()); + break; + case ENTITY_NODE: + // NOTE: There's no standard way to create + // these, or add them to a doctype. Useless. + Entity entity = (Entity) src; + dst = new DomEntity(this, entity.getNodeName(), + entity.getPublicId(), + entity.getSystemId(), + entity.getNotationName()); + if (deep) + { + for (Node ctx = src.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + dst.appendChild(importNode(ctx, deep)); + } + } + break; + case ENTITY_REFERENCE_NODE: + dst = createEntityReference(src.getNodeName()); + break; + case DOCUMENT_FRAGMENT_NODE: + dst = new DomDocumentFragment(this); + if (deep) + { + for (Node ctx = src.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + dst.appendChild(importNode(ctx, deep)); + } + } + break; + case ATTRIBUTE_NODE: + String attr_nsuri = src.getNamespaceURI(); + if (attr_nsuri != null) + { + dst = createAttributeNS(attr_nsuri, src.getNodeName()); + } + else + { + dst = createAttribute(src.getNodeName()); + } + // this is _always_ done regardless of "deep" setting + for (Node ctx = src.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + dst.appendChild(importNode(ctx, false)); + } + break; + case ELEMENT_NODE: + String elem_nsuri = src.getNamespaceURI(); + if (elem_nsuri != null) + { + dst = createElementNS(elem_nsuri, src.getNodeName()); + } + else + { + dst = createElement(src.getNodeName()); + } + NamedNodeMap srcAttrs = src.getAttributes(); + NamedNodeMap dstAttrs = dst.getAttributes(); + int len = srcAttrs.getLength(); + for (int i = 0; i < len; i++) + { + Attr a = (Attr) srcAttrs.item(i); + Attr dflt; + + // maybe update defaulted attributes + dflt = (Attr) dstAttrs.getNamedItem(a.getNodeName()); + if (dflt != null) + { + String newval = a.getNodeValue(); + if (!dflt.getNodeValue().equals(newval) + || a.getSpecified () == true) + { + dflt.setNodeValue (newval); + } + continue; + } + + dstAttrs.setNamedItem((Attr) importNode(a, false)); + } + if (deep) + { + for (Node ctx = src.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + dst.appendChild(importNode(ctx, true)); + } + } + break; + // can't import document or doctype nodes + case DOCUMENT_NODE: + case DOCUMENT_TYPE_NODE: + // FALLTHROUGH + // can't import unrecognized or nonstandard nodes + default: + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR, null, src, 0); + } + + // FIXME cleanup a bit -- for deep copies, copy those + // children in one place, here (code sharing is healthy) + + if (src instanceof DomNode) + { + ((DomNode) src).notifyUserDataHandlers(UserDataHandler.NODE_IMPORTED, + src, dst); + } + return dst; + } + + /** + * DOM L2 (Traversal) + * Returns a newly created node iterator. Don't forget to detach + * this iterator when you're done using it! + * + * @see DomIterator + */ + public NodeIterator createNodeIterator(Node root, + int whatToShow, + NodeFilter filter, + boolean expandEntities) + { + return new DomNodeIterator(root, whatToShow, filter, expandEntities, + false); + } + + public TreeWalker createTreeWalker(Node root, + int whatToShow, + NodeFilter filter, + boolean expandEntities) + { + return new DomNodeIterator(root, whatToShow, filter, expandEntities, + true); + } + + // DOM Level 3 methods + + /** + * DOM L3 + */ + public String getInputEncoding() + { + return inputEncoding; + } + + public void setInputEncoding(String inputEncoding) + { + this.inputEncoding = inputEncoding; + } + + /** + * DOM L3 + */ + public String getXmlEncoding() + { + return encoding; + } + + public void setXmlEncoding(String encoding) + { + this.encoding = encoding; + } + + public boolean getXmlStandalone() + { + return standalone; + } + + public void setXmlStandalone(boolean xmlStandalone) + { + standalone = xmlStandalone; + } + + public String getXmlVersion() + { + return version; + } + + public void setXmlVersion(String xmlVersion) + { + if (xmlVersion == null) + { + xmlVersion = "1.0"; + } + if ("1.0".equals(xmlVersion) || + "1.1".equals(xmlVersion)) + { + version = xmlVersion; + } + else + { + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR); + } + } + + public boolean getStrictErrorChecking() + { + return checkingCharacters; + } + + public void setStrictErrorChecking(boolean strictErrorChecking) + { + checkingCharacters = strictErrorChecking; + } + + public String lookupPrefix(String namespaceURI) + { + Node root = getDocumentElement(); + return (root == null) ? null : root.lookupPrefix(namespaceURI); + } + + public boolean isDefaultNamespace(String namespaceURI) + { + Node root = getDocumentElement(); + return (root == null) ? false : root.isDefaultNamespace(namespaceURI); + } + + public String lookupNamespaceURI(String prefix) + { + Node root = getDocumentElement(); + return (root == null) ? null : root.lookupNamespaceURI(prefix); + } + + public String getBaseURI() + { + return getDocumentURI(); + /* + Node root = getDocumentElement(); + if (root != null) + { + NamedNodeMap attrs = root.getAttributes(); + Node xmlBase = attrs.getNamedItemNS(XMLConstants.XML_NS_URI, "base"); + if (xmlBase != null) + { + return xmlBase.getNodeValue(); + } + } + return systemId; + */ + } + + public String getDocumentURI() + { + return systemId; + } + + public void setDocumentURI(String documentURI) + { + systemId = documentURI; + } + + public Node adoptNode(Node source) + { + int sourceNodeType = source.getNodeType(); + switch (sourceNodeType) + { + case DOCUMENT_NODE: + case DOCUMENT_TYPE_NODE: + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR); + case ENTITY_NODE: + case NOTATION_NODE: + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + if (source instanceof DomNode) + { + // GNU native + DomNode src = (DomNode) source; + DomNode dst = src; + if (dst.parent != null) + { + dst = (DomNode) dst.cloneNode(true); + } + dst.setOwner(this); + src.notifyUserDataHandlers(UserDataHandler.NODE_ADOPTED, src, dst); + return dst; + } + else + { + // Some other implementation + Node dst = null; + switch (sourceNodeType) + { + case Node.ATTRIBUTE_NODE: + { + Attr src = (Attr) source; + String nodeName = src.getNodeName(); + String localName = src.getLocalName(); + String namespaceUri = src.getNamespaceURI(); + dst = (localName == null) ? + createAttribute(nodeName) : + createAttributeNS(namespaceUri, nodeName); + adoptChildren(src, dst); + break; + } + case Node.CDATA_SECTION_NODE: + { + CDATASection src = (CDATASection) source; + dst = createCDATASection(src.getData()); + break; + } + case Node.COMMENT_NODE: + { + Comment src = (Comment) source; + dst = createComment(src.getData()); + break; + } + case Node.DOCUMENT_FRAGMENT_NODE: + { + DocumentFragment src = (DocumentFragment) source; + dst = createDocumentFragment(); + adoptChildren(src, dst); + break; + } + case Node.ELEMENT_NODE: + { + Element src = (Element) source; + String nodeName = src.getNodeName(); + String localName = src.getLocalName(); + String namespaceUri = src.getNamespaceURI(); + dst = (localName == null) ? + createElement(nodeName) : + createElementNS(namespaceUri, nodeName); + adoptAttributes(src, dst); + adoptChildren(src, dst); + break; + } + case Node.ENTITY_REFERENCE_NODE: + { + EntityReference src = (EntityReference) source; + dst = createEntityReference(src.getNodeName()); + adoptChildren(src, dst); + break; + } + case Node.PROCESSING_INSTRUCTION_NODE: + { + ProcessingInstruction src = (ProcessingInstruction) source; + dst = createProcessingInstruction(src.getTarget(), + src.getData()); + break; + } + case Node.TEXT_NODE: + { + Text src = (Text) source; + dst = createTextNode(src.getData()); + break; + } + } + return dst; + } + } + + void adoptChildren(Node src, Node dst) + { + Node node = src.getFirstChild(); + while (node != null) + { + Node next = node.getNextSibling(); + dst.appendChild(adoptNode(node)); + node = next; + } + } + + void adoptAttributes(Node src, Node dst) + { + NamedNodeMap srcAttrs = src.getAttributes(); + NamedNodeMap dstAttrs = dst.getAttributes(); + int len = srcAttrs.getLength(); + for (int i = 0; i < len; i++) + { + Node node = srcAttrs.item(i); + String localName = node.getLocalName(); + if (localName == null) + { + dstAttrs.setNamedItem(adoptNode(node)); + } + else + { + dstAttrs.setNamedItemNS(adoptNode(node)); + } + } + } + + public DOMConfiguration getDomConfig() + { + if (config == null) + { + config = new DomDocumentConfiguration(); + } + return config; + } + + public boolean isEqualNode(Node arg) + { + if (!super.isEqualNode(arg)) + return false; + Document d = (Document) arg; + String dversion = d.getXmlVersion(); + if (dversion == null || !dversion.equals(version)) + return false; + boolean dstandalone = d.getXmlStandalone(); + if (dstandalone != standalone) + return false; + String dencoding = d.getXmlEncoding(); + if (dencoding == null || dencoding.equalsIgnoreCase("UTF-8")) + { + if (encoding != null && !encoding.equalsIgnoreCase("UTF-8")) + return false; + } + else + { + if (!dencoding.equals(encoding)) + return false; + } + return true; + } + + public void normalizeDocument() + { + boolean save = building; + building = true; + normalizeNode(this); + building = save; + } + + void normalizeNode(DomNode node) + { + node.normalize(); + if (config != null) + { + switch (node.nodeType) + { + case CDATA_SECTION_NODE: + if (!config.cdataSections) + { + // replace CDATA section with text node + Text text = createTextNode(node.getNodeValue()); + node.parent.insertBefore(text, node); + node.parent.removeChild(node); + // merge adjacent text nodes + String data = text.getWholeText(); + node = (DomNode) text.replaceWholeText(data); + } + else if (config.splitCdataSections) + { + String value = node.getNodeValue(); + int i = value.indexOf("]]>"); + while (i != -1) + { + Node node2 = createCDATASection(value.substring(0, i)); + node.parent.insertBefore(node2, node); + value = value.substring(i + 3); + node.setNodeValue(value); + i = value.indexOf("]]>"); + } + } + break; + case COMMENT_NODE: + if (!config.comments) + { + node.parent.removeChild(node); + } + break; + case TEXT_NODE: + if (!config.elementContentWhitespace && + ((Text) node).isElementContentWhitespace()) + { + node.parent.removeChild(node); + } + break; + case ENTITY_REFERENCE_NODE: + if (!config.entities) + { + for (DomNode ctx = node.first; ctx != null; ) + { + DomNode ctxNext = ctx.next; + node.parent.insertBefore(ctx, node); + ctx = ctxNext; + } + node.parent.removeChild(node); + } + break; + case ELEMENT_NODE: + if (!config.namespaceDeclarations) + { + DomNamedNodeMap attrs = + (DomNamedNodeMap) node.getAttributes(); + boolean aro = attrs.readonly; + attrs.readonly = false; // Ensure we can delete if necessary + int len = attrs.getLength(); + for (int i = 0; i < len; i++) + { + Node attr = attrs.item(i); + String namespace = attr.getNamespaceURI(); + if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespace)) + { + attrs.removeNamedItemNS(namespace, + attr.getLocalName()); + i--; + len--; + } + } + attrs.readonly = aro; + } + break; + } + } + for (DomNode ctx = node.first; ctx != null; ) + { + DomNode ctxNext = ctx.next; + normalizeNode(ctx); + ctx = ctxNext; + } + } + + public Node renameNode(Node n, String namespaceURI, String qualifiedName) + throws DOMException + { + if (n instanceof DomNsNode) + { + DomNsNode src = (DomNsNode) n; + if (src == null) + { + throw new DomDOMException(DOMException.NOT_FOUND_ERR); + } + if (src.owner != this) + { + throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR, + null, src, 0); + } + boolean xml11 = "1.1".equals(version); + checkName(qualifiedName, xml11); + int ci = qualifiedName.indexOf(':'); + if ("".equals(namespaceURI)) + { + namespaceURI = null; + } + if (namespaceURI != null) + { + checkNCName(qualifiedName, xml11); + String prefix = (ci == -1) ? "" : + qualifiedName.substring(0, ci); + if (XMLConstants.XML_NS_PREFIX.equals(prefix) && + !XMLConstants.XML_NS_URI.equals(namespaceURI)) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "xml namespace must be " + + XMLConstants.XML_NS_URI, src, 0); + } + else if (src.nodeType == ATTRIBUTE_NODE && + (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix) || + XMLConstants.XMLNS_ATTRIBUTE.equals(qualifiedName)) && + !XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI)) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "xmlns namespace must be " + + XMLConstants.XMLNS_ATTRIBUTE_NS_URI, src, 0); + } + if (XMLConstants.XML_NS_URI.equals(namespaceURI) && + !XMLConstants.XML_NS_PREFIX.equals(prefix)) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "xml namespace must be " + + XMLConstants.XML_NS_URI, src, 0); + } + else if (src.nodeType == ATTRIBUTE_NODE && + XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI) && + !(XMLConstants.XMLNS_ATTRIBUTE.equals(prefix) || + XMLConstants.XMLNS_ATTRIBUTE.equals(qualifiedName))) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "xmlns namespace must be " + + XMLConstants.XMLNS_ATTRIBUTE_NS_URI, src, 0); + } + + } + src.setNodeName(qualifiedName); + src.setNamespaceURI(namespaceURI); + src.notifyUserDataHandlers(UserDataHandler.NODE_RENAMED, src, src); + // TODO MutationNameEvents + // DOMElementNameChanged or DOMAttributeNameChanged + return src; + } + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR, null, n, 0); + } + + // -- XPathEvaluator -- + + public XPathExpression createExpression(String expression, + XPathNSResolver resolver) + throws XPathException, DOMException + { + return new DomXPathExpression(this, expression, resolver); + } + + public XPathNSResolver createNSResolver(Node nodeResolver) + { + return new DomXPathNSResolver(nodeResolver); + } + + public Object evaluate(String expression, + Node contextNode, + XPathNSResolver resolver, + short type, + Object result) + throws XPathException, DOMException + { + XPathExpression xpe = + new DomXPathExpression(this, expression, resolver); + return xpe.evaluate(contextNode, type, result); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomDocumentBuilder.java b/libjava/classpath/gnu/xml/dom/DomDocumentBuilder.java new file mode 100644 index 000000000..99c254481 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomDocumentBuilder.java @@ -0,0 +1,227 @@ +/* DomDocumentBuilder.java -- + Copyright (C) 2004,2006,2007 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.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; +import org.w3c.dom.DOMConfiguration; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.ls.DOMImplementationLS; +import org.w3c.dom.ls.LSException; +import org.w3c.dom.ls.LSInput; +import org.w3c.dom.ls.LSParser; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/** + * Document builder using the GNU DOM Load & Save implementation. + * + * @author Chris Burdess + */ +class DomDocumentBuilder + extends DocumentBuilder +{ + + final DOMImplementation impl; + final DOMImplementationLS ls; + final LSParser parser; + + DomDocumentBuilder(DOMImplementation impl, + DOMImplementationLS ls, + LSParser parser) + { + this.impl = impl; + this.ls = ls; + this.parser = parser; + } + + public boolean isNamespaceAware() + { + DOMConfiguration config = parser.getDomConfig(); + return ((Boolean) config.getParameter("namespaces")).booleanValue(); + } + + public boolean isValidating() + { + DOMConfiguration config = parser.getDomConfig(); + return ((Boolean) config.getParameter("validating")).booleanValue(); + } + + public boolean isXIncludeAware() + { + DOMConfiguration config = parser.getDomConfig(); + return ((Boolean) config.getParameter("xinclude-aware")).booleanValue(); + } + + public void setEntityResolver(EntityResolver resolver) + { + DOMConfiguration config = parser.getDomConfig(); + config.setParameter("entity-resolver", resolver); + } + + public void setErrorHandler(ErrorHandler handler) + { + DOMConfiguration config = parser.getDomConfig(); + config.setParameter("error-handler", handler); + } + + public DOMImplementation getDOMImplementation() + { + return impl; + } + + public Document newDocument() + { + return impl.createDocument(null, null, null); + } + + public Document parse(InputStream in) + throws SAXException, IOException + { + LSInput input = ls.createLSInput(); + input.setByteStream(in); + try + { + return parser.parse(input); + } + catch (LSException e) + { + Throwable e2 = e.getCause(); + if (e2 instanceof IOException) + throw (IOException) e2; + else + throw e; + } + } + + public Document parse(InputStream in, String systemId) + throws SAXException, IOException + { + LSInput input = ls.createLSInput(); + input.setByteStream(in); + input.setSystemId(systemId); + try + { + return parser.parse(input); + } + catch (LSException e) + { + Throwable e2 = e.getCause(); + if (e2 instanceof IOException) + throw (IOException) e2; + else + throw e; + } + } + + public Document parse(String systemId) + throws SAXException, IOException + { + try + { + return parser.parseURI(systemId); + } + catch (LSException e) + { + Throwable e2 = e.getCause(); + if (e2 instanceof IOException) + throw (IOException) e2; + else + throw e; + } + } + + public Document parse(InputSource is) + throws SAXException, IOException + { + LSInput input = ls.createLSInput(); + String systemId = is.getSystemId(); + InputStream in = is.getByteStream(); + if (in != null) + { + input.setByteStream(in); + } + else + { + Reader reader = is.getCharacterStream(); + if (reader != null) + { + input.setCharacterStream(reader); + } + else + { + 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()); + input.setSystemId(systemId); + input.setEncoding(is.getEncoding()); + try + { + return parser.parse(input); + } + catch (LSException e) + { + Throwable e2 = e.getCause(); + if (e2 instanceof IOException) + throw (IOException) e2; + else + throw e; + } + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomDocumentBuilderFactory.java b/libjava/classpath/gnu/xml/dom/DomDocumentBuilderFactory.java new file mode 100644 index 000000000..1e3eaa582 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomDocumentBuilderFactory.java @@ -0,0 +1,181 @@ +/* DomDocumentBuilderFactory.java -- + 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.xml.dom; + +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.FactoryConfigurationError; +import javax.xml.parsers.ParserConfigurationException; +import org.w3c.dom.DOMConfiguration; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.bootstrap.DOMImplementationRegistry; +import org.w3c.dom.ls.DOMImplementationLS; +import org.w3c.dom.ls.LSParser; + +/** + * Document builder factory that uses a DOM Level 3 Load & Save + * implementation. + * + * @author Chris Burdess + */ +public class DomDocumentBuilderFactory + extends DocumentBuilderFactory +{ + + final DOMImplementation impl; + final DOMImplementationLS ls; + private boolean secureProcessing; + + public DomDocumentBuilderFactory() + { + try + { + DOMImplementationRegistry reg = + DOMImplementationRegistry.newInstance(); + impl = reg.getDOMImplementation("LS 3.0"); + if (impl == null) + { + throw new FactoryConfigurationError("no LS implementations found"); + } + ls = (DOMImplementationLS) impl; + } + catch (Exception e) + { + throw new FactoryConfigurationError(e); + } + } + + public DocumentBuilder newDocumentBuilder() + throws ParserConfigurationException + { + LSParser parser = null; + try + { + parser = ls.createLSParser(DOMImplementationLS.MODE_ASYNCHRONOUS, + "http://www.w3.org/TR/REC-xml"); + } + catch (DOMException e) + { + if (e.code == DOMException.NOT_SUPPORTED_ERR) + { + // Fall back to synchronous parser + try + { + parser = ls.createLSParser(DOMImplementationLS.MODE_SYNCHRONOUS, + "http://www.w3.org/TR/REC-xml"); + } + catch (DOMException e2) + { + ParserConfigurationException pce = + new ParserConfigurationException(); + pce.initCause(e2); + throw pce; + } + } + else + { + ParserConfigurationException pce = + new ParserConfigurationException(); + pce.initCause(e); + throw pce; + } + } + DOMConfiguration config = parser.getDomConfig(); + setParameter(config, "namespaces", + isNamespaceAware() ? Boolean.TRUE : Boolean.FALSE); + setParameter(config, "element-content-whitespace", + isIgnoringElementContentWhitespace() ? Boolean.FALSE : + Boolean.TRUE); + setParameter(config, "comments", + isIgnoringComments() ? Boolean.FALSE : Boolean.TRUE); + setParameter(config, "expand-entity-references", + isExpandEntityReferences() ? Boolean.TRUE : Boolean.FALSE); + setParameter(config, "coalescing", + isCoalescing() ? Boolean.TRUE : Boolean.FALSE); + setParameter(config, "validating", + isValidating() ? Boolean.TRUE : Boolean.FALSE); + setParameter(config, "xinclude-aware", + isXIncludeAware() ? Boolean.TRUE : Boolean.FALSE); + return new DomDocumentBuilder(impl, ls, parser); + } + + void setParameter(DOMConfiguration config, String name, Object value) + throws ParserConfigurationException + { + if (!config.canSetParameter(name, value)) + { + throw new ParserConfigurationException(name); + } + config.setParameter(name, value); + } + + public Object getAttribute(String name) + { + // TODO + return null; + } + + public void setAttribute(String name, Object value) + { + // 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/libjava/classpath/gnu/xml/dom/DomDocumentConfiguration.java b/libjava/classpath/gnu/xml/dom/DomDocumentConfiguration.java new file mode 100644 index 000000000..9aab44532 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomDocumentConfiguration.java @@ -0,0 +1,260 @@ +/* DomDocumentConfiguration.java -- + 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.xml.dom; + +import java.util.Arrays; +import java.util.List; +import org.w3c.dom.DOMConfiguration; +import org.w3c.dom.DOMErrorHandler; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMStringList; + +/** + * Document configuration, used to store normalization and other parameters. + * + * @author Chris Burdess + */ +class DomDocumentConfiguration + implements DOMConfiguration, DOMStringList +{ + + private static final List SUPPORTED_PARAMETERS = + Arrays.asList(new String[] { "cdata-sections", + "comments", + "element-content-whitespace", + "entities", + "error-handler", + "namespace-declarations", + "split-cdata-sections", + "infoset"}); + + boolean cdataSections = true; + boolean comments = true; + boolean elementContentWhitespace = true; + boolean entities = true; + DOMErrorHandler errorHandler; + boolean namespaceDeclarations = true; + boolean splitCdataSections = true; + + public void setParameter(String name, Object value) + throws DOMException + { + name = name.toLowerCase(); + if ("cdata-sections".equals(name)) + { + cdataSections = "true".equals(value.toString()); + } + else if ("comments".equals(name)) + { + comments = "true".equals(value.toString()); + } + else if ("element-content-whitespace".equals(name)) + { + elementContentWhitespace = "true".equals(value.toString()); + } + else if ("entities".equals(name)) + { + entities = "true".equals(value.toString()); + } + else if ("error-handler".equals(name)) + { + try + { + errorHandler = (DOMErrorHandler) value; + } + catch (ClassCastException e) + { + throw new DomDOMException(DOMException.TYPE_MISMATCH_ERR, + value.getClass().getName(), null, 0); + } + } + else if ("namespace-declarations".equals(name)) + { + namespaceDeclarations = "true".equals(value.toString()); + } + else if ("split-cdata-sections".equals(name)) + { + comments = "true".equals(value.toString()); + } + else if ("infoset".equals(name)) + { + if ("true".equals(value.toString())) + { + entities = false; + cdataSections = false; + namespaceDeclarations = true; + elementContentWhitespace = true; + comments = true; + } + } + else if (("canonical-form".equals(name) || + "check-character-normalization".equals(name) || + "datatype-normalization".equals(name) || + "normalize-characters".equals(name) || + "validate".equals(name) || + "validate-if-schema".equals(name)) && + "false".equals(value.toString())) + { + // NOOP + } + else if (("namespaces".equals(name) || + "well-formed".equals(name)) && + "true".equals(value.toString())) + { + // NOOP + } + else + { + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR, + name, null, 0); + } + } + + public Object getParameter(String name) + throws DOMException + { + name = name.toLowerCase(); + if ("cdata-sections".equals(name)) + { + return cdataSections ? Boolean.TRUE : Boolean.FALSE; + } + else if ("comments".equals(name)) + { + return comments ? Boolean.TRUE : Boolean.FALSE; + } + else if ("element-content-whitespace".equals(name)) + { + return elementContentWhitespace ? Boolean.TRUE : Boolean.FALSE; + } + else if ("entities".equals(name)) + { + return entities ? Boolean.TRUE : Boolean.FALSE; + } + else if ("error-handler".equals(name)) + { + return errorHandler; + } + else if ("namespace-declarations".equals(name)) + { + return namespaceDeclarations ? Boolean.TRUE : Boolean.FALSE; + } + else if ("split-cdata-sections".equals(name)) + { + return comments ? Boolean.TRUE : Boolean.FALSE; + } + else if ("canonical-form".equals(name) || + "check-character-normalization".equals(name) || + "datatype-normalization".equals(name) || + "normalize-characters".equals(name) || + "validate".equals(name) || + "validate-if-schema".equals(name)) + { + return Boolean.FALSE; + } + else if ("namespaces".equals(name) || + "well-formed".equals(name)) + { + return Boolean.TRUE; + } + else if ("infoset".equals(name)) + { + return (entities == false && + cdataSections == false && + namespaceDeclarations == true && + comments == true) ? Boolean.TRUE : Boolean.FALSE; + } + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR, name, null, 0); + } + + public boolean canSetParameter(String name, Object value) + { + name = name.toLowerCase(); + if ("error-handler".equals(name)) + { + return (value == null || value instanceof DOMErrorHandler); + } + else if (contains(name)) + { + return true; + } + else if ("canonical-form".equals(name) || + "check-character-normalization".equals(name) || + "datatype-normalization".equals(name) || + "normalize-characters".equals(name) || + "validate".equals(name) || + "validate-if-schema".equals(name)) + { + return "false".equals(value.toString()); + } + else if ("namespaces".equals(name) || + "well-formed".equals(name)) + { + return "true".equals(value.toString()); + } + return false; + } + + public DOMStringList getParameterNames() + { + return this; + } + + public String item(int i) + { + try + { + return (String) SUPPORTED_PARAMETERS.get(i); + } + catch (IndexOutOfBoundsException e) + { + return null; + } + } + + public int getLength() + { + return SUPPORTED_PARAMETERS.size(); + } + + public boolean contains(String str) + { + str = str.toLowerCase(); + return SUPPORTED_PARAMETERS.contains(str); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomDocumentFragment.java b/libjava/classpath/gnu/xml/dom/DomDocumentFragment.java new file mode 100644 index 000000000..8c4e0db3b --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomDocumentFragment.java @@ -0,0 +1,75 @@ +/* DomDocumentFragment.java -- + Copyright (C) 1999,2000,2001,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.xml.dom; + +import org.w3c.dom.DocumentFragment; + +/** + *

      "DocumentFragment" implementation.

      + * + * @author David Brownell + * @author Chris Burdess + */ +public class DomDocumentFragment + extends DomNode + implements DocumentFragment +{ + + /** + * Constructs a DocumentFragment node associated with the + * specified document. + * + *

      This constructor should only be invoked by a Document as part of + * its createDocumentFragment functionality, or through a subclass which + * is similarly used in a "Sub-DOM" style layer. + */ + protected DomDocumentFragment(DomDocument owner) + { + super(DOCUMENT_FRAGMENT_NODE, owner); + } + + /** + * DOM L1 + * Returns the string "#document-fragment". + */ + final public String getNodeName() + { + return "#document-fragment"; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomElement.java b/libjava/classpath/gnu/xml/dom/DomElement.java new file mode 100644 index 000000000..429749978 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomElement.java @@ -0,0 +1,582 @@ +/* DomElement.java -- + Copyright (C) 1999,2000,2001,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.xml.dom; + +import java.util.HashSet; +import java.util.Set; +import javax.xml.XMLConstants; + +import org.w3c.dom.Attr; +import org.w3c.dom.DOMException; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.TypeInfo; + +/** + *

      "Element" implementation. + * + * @author David Brownell + * @author Chris Burdess + */ +public class DomElement + extends DomNsNode + implements Element +{ + + /** + * User-defined ID attributes. + * Used by DomAttr.isId and DomDocument.getElementById + */ + Set userIdAttrs; + + // Attributes are VERY expensive in DOM, and not just for + // this implementation. Avoid creating them. + private DomNamedNodeMap attributes; + + // xml:space cache + String xmlSpace = ""; + + /** + * Constructs an Element node associated with the specified document. + * + *

      This constructor should only be invoked by a Document as part + * of its createElement functionality, or through a subclass which is + * similarly used in a "Sub-DOM" style layer. + * + * @param owner The document with which this node is associated + * @param namespaceURI Combined with the local part of the name, + * this is used to uniquely identify a type of element + * @param name Name of this element, which may include a prefix + */ + protected DomElement(DomDocument owner, String namespaceURI, String name) + { + super(ELEMENT_NODE, owner, namespaceURI, name); + } + + /** + *

      + * Constructs an Element node associated with the specified document. + * This constructor should only be invoked by a Document as part + * of its createElement functionality, or through a subclass which is + * similarly used in a "Sub-DOM" style layer. + *

      + *

      + * With this constructor, the prefix and local part are given explicitly + * rather than being computed. This allows them to be explicitly set to + * {@code null} as required by {@link Document#createElement(String)}. + *

      + * + * @param owner The document with which this node is associated + * @param namespaceURI Combined with the local part of the name, + * this is used to uniquely identify a type of element + * @param name Name of this element, which may include a prefix + * @param prefix the namespace prefix of the name. May be {@code null}. + * @param localName the local part of the name. May be {@code null}. + */ + protected DomElement(DomDocument owner, String namespaceURI, String name, + String prefix, String localName) + { + super(ELEMENT_NODE, owner, namespaceURI, name, prefix, localName); + } + + /** + * DOM L1 + * Returns the element's attributes + */ + public NamedNodeMap getAttributes() + { + if (attributes == null) + { + attributes = new DomNamedNodeMap(this, Node.ATTRIBUTE_NODE); + } + return attributes; + } + + /** + * DOM L2> + * Returns true iff this is an element node with attributes. + */ + public boolean hasAttributes() + { + return attributes != null && attributes.length != 0; + } + + /** + * Shallow clone of the element, except that associated + * attributes are (deep) cloned. + */ + public Object clone() + { + DomElement node = (DomElement) super.clone(); + + if (attributes != null) + { + node.attributes = new DomNamedNodeMap(node, Node.ATTRIBUTE_NODE); + for (DomNode ctx = attributes.first; ctx != null; ctx = ctx.next) + { + node.attributes.setNamedItem(ctx.cloneNode(true), true, true); + } + } + return node; + } + + void setOwner(DomDocument doc) + { + if (attributes != null) + { + for (DomNode ctx = attributes.first; ctx != null; ctx = ctx.next) + { + ctx.setOwner(doc); + } + } + super.setOwner(doc); + } + + /** + * Marks this element, its children, and its associated attributes as + * readonly. + */ + public void makeReadonly() + { + super.makeReadonly(); + if (attributes != null) + { + attributes.makeReadonly(); + } + } + + /** + * DOM L1 + * Returns the element name (same as getNodeName). + */ + final public String getTagName() + { + return getNodeName(); + } + + /** + * DOM L1 + * Returns the value of the specified attribute, or an + * empty string. + */ + public String getAttribute(String name) + { + if ("xml:space" == name) // NB only works on interned string + { + // Use cached value + return xmlSpace; + } + Attr attr = getAttributeNode(name); + return (attr == null) ? "" : attr.getValue(); + } + + /** + * DOM L2 + * Returns true if the element has an attribute with the + * specified name (specified or DTD defaulted). + */ + public boolean hasAttribute(String name) + { + return getAttributeNode(name) != null; + } + + /** + * DOM L2 + * Returns true if the element has an attribute with the + * specified name (specified or DTD defaulted). + */ + public boolean hasAttributeNS(String namespaceURI, String local) + { + return getAttributeNodeNS(namespaceURI, local) != null; + } + + /** + * DOM L2 + * Returns the value of the specified attribute, or an + * empty string. + */ + public String getAttributeNS(String namespaceURI, String local) + { + Attr attr = getAttributeNodeNS(namespaceURI, local); + return (attr == null) ? "" : attr.getValue(); + } + + /** + * DOM L1 + * Returns the appropriate attribute node; the name is the + * nodeName property of the attribute. + */ + public Attr getAttributeNode(String name) + { + return (attributes == null) ? null : + (Attr) attributes.getNamedItem(name); + } + + /** + * DOM L2 + * Returns the appropriate attribute node; the name combines + * the namespace name and the local part. + */ + public Attr getAttributeNodeNS(String namespace, String localPart) + { + return (attributes == null) ? null : + (Attr) attributes.getNamedItemNS(namespace, localPart); + } + + /** + * DOM L1 + * Modifies an existing attribute to have the specified value, + * or creates a new one with that value. The name used is the + * nodeName value. + */ + public void setAttribute(String name, String value) + { + Attr attr = getAttributeNode(name); + if (attr != null) + { + attr.setNodeValue(value); + ((DomAttr) attr).setSpecified(true); + return; + } + attr = owner.createAttribute(name); + attr.setNodeValue(value); + setAttributeNode(attr); + } + + /** + * DOM L2 + * Modifies an existing attribute to have the specified value, + * or creates a new one with that value. + */ + public void setAttributeNS(String uri, String aname, String value) + { + if (("xmlns".equals (aname) || aname.startsWith ("xmlns:")) + && !XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals (uri)) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "setting xmlns attribute to illegal value", this, 0); + } + + Attr attr = getAttributeNodeNS(uri, aname); + if (attr != null) + { + attr.setNodeValue(value); + return; + } + attr = owner.createAttributeNS(uri, aname); + attr.setNodeValue(value); + setAttributeNodeNS(attr); + } + + /** + * DOM L1 + * Stores the specified attribute, optionally overwriting any + * existing one with that name. + */ + public Attr setAttributeNode(Attr attr) + { + return (Attr) getAttributes().setNamedItem(attr); + } + + /** + * DOM L2 + * Stores the specified attribute, optionally overwriting any + * existing one with that name. + */ + public Attr setAttributeNodeNS(Attr attr) + { + return (Attr) getAttributes().setNamedItemNS(attr); + } + + /** + * DOM L1 + * Removes the appropriate attribute node. + * If there is no such node, this is (bizarrely enough) a NOP so you + * won't see exceptions if your code deletes non-existent attributes. + * + *

      Note that since there is no portable way for DOM to record + * DTD information, default values for attributes will never be + * provided automatically. + */ + public void removeAttribute(String name) + { + if (attributes == null) + { + return; + } + + try + { + attributes.removeNamedItem(name); + } + catch (DomDOMException e) + { + if (e.code != DOMException.NOT_FOUND_ERR) + { + throw e; + } + } + } + + /** + * DOM L1 + * Removes the appropriate attribute node; the name is the + * nodeName property of the attribute. + * + *

      Note that since there is no portable way for DOM to record + * DTD information, default values for attributes will never be + * provided automatically. + */ + public Attr removeAttributeNode(Attr node) + { + if (attributes == null) + { + throw new DomDOMException(DOMException.NOT_FOUND_ERR, null, node, 0); + } + return (Attr) attributes.removeNamedItem(node.getNodeName()); + } + + /** + * DOM L2 + * Removes the appropriate attribute node; the name combines + * the namespace name and the local part. + * + *

      Note that since there is no portable way for DOM to record + * DTD information, default values for attributes will never be + * provided automatically. + */ + public void removeAttributeNS(String namespace, String localPart) + { + if (attributes == null) + { + throw new DomDOMException(DOMException.NOT_FOUND_ERR, localPart, null, 0); + } + attributes.removeNamedItemNS (namespace, localPart); + } + + // DOM Level 3 methods + + public String lookupPrefix(String namespaceURI) + { + if (namespaceURI == null) + { + return null; + } + String namespace = getNamespaceURI(); + if (namespace != null && namespace.equals(namespaceURI)) + { + return getPrefix(); + } + if (attributes != null) + { + for (DomNode ctx = attributes.first; ctx != null; ctx = ctx.next) + { + if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI + .equals(ctx.getNamespaceURI())) + { + String value = ctx.getNodeValue(); + if (value.equals(namespaceURI)) + { + return ctx.getLocalName(); + } + } + } + } + return super.lookupPrefix(namespaceURI); + } + + public boolean isDefaultNamespace(String namespaceURI) + { + String namespace = getNamespaceURI(); + if (namespace != null && namespace.equals(namespaceURI)) + { + return getPrefix() == null; + } + if (attributes != null) + { + for (DomNode ctx = attributes.first; ctx != null; ctx = ctx.next) + { + if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI + .equals(ctx.getNamespaceURI())) + { + String qName = ctx.getNodeName(); + return (XMLConstants.XMLNS_ATTRIBUTE.equals(qName)); + } + } + } + return super.isDefaultNamespace(namespaceURI); + } + + public String lookupNamespaceURI(String prefix) + { + String namespace = getNamespaceURI(); + if (namespace != null && equal(prefix, getPrefix())) + { + return namespace; + } + if (attributes != null) + { + for (DomNode ctx = attributes.first; ctx != null; ctx = ctx.next) + { + if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI + .equals(ctx.getNamespaceURI())) + { + if (prefix == null) + { + if (XMLConstants.XMLNS_ATTRIBUTE.equals(ctx.getNodeName())) + { + return ctx.getNodeValue(); + } + } + else + { + if (prefix.equals(ctx.getLocalName())) + { + return ctx.getNodeValue(); + } + } + } + } + } + return super.lookupNamespaceURI(prefix); + } + + public String getBaseURI() + { + if (attributes != null) + { + Node xmlBase = + attributes.getNamedItemNS(XMLConstants.XML_NS_URI, "base"); + if (xmlBase != null) + { + return xmlBase.getNodeValue(); + } + } + return super.getBaseURI(); + } + + public TypeInfo getSchemaTypeInfo() + { + // DTD implementation + DomDoctype doctype = (DomDoctype) owner.getDoctype(); + if (doctype != null) + { + return doctype.getElementTypeInfo(getNodeName()); + } + // TODO XML Schema implementation + return null; + } + + public void setIdAttribute(String name, boolean isId) + { + NamedNodeMap attrs = getAttributes(); + Attr attr = (Attr) attrs.getNamedItem(name); + setIdAttributeNode(attr, isId); + } + + public void setIdAttributeNode(Attr attr, boolean isId) + { + if (readonly) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + if (attr == null || attr.getOwnerElement() != this) + { + throw new DomDOMException(DOMException.NOT_FOUND_ERR); + } + if (isId) + { + if (userIdAttrs == null) + { + userIdAttrs = new HashSet(); + } + userIdAttrs.add(attr); + } + else if (userIdAttrs != null) + { + userIdAttrs.remove(attr); + if (userIdAttrs.isEmpty()) + { + userIdAttrs = null; + } + } + } + + public void setIdAttributeNS(String namespaceURI, String localName, + boolean isId) + { + NamedNodeMap attrs = getAttributes(); + Attr attr = (Attr) attrs.getNamedItemNS(namespaceURI, localName); + setIdAttributeNode(attr, isId); + } + + public boolean isEqualNode(Node arg) + { + if (!super.isEqualNode(arg)) + return false; + getAttributes(); + NamedNodeMap argAttrs = arg.getAttributes(); + int len = argAttrs.getLength(); + if (argAttrs == null || (len != attributes.length)) + return false; + for (int i = 0; i < len; i++) + { + Node argCtx = argAttrs.item(i); + // Don't compare namespace nodes + if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI + .equals(argCtx.getNamespaceURI())) + continue; + // Find corresponding attribute node + DomNode ctx = attributes.first; + for (; ctx != null; ctx = ctx.next) + { + if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI + .equals(ctx.getNamespaceURI())) + continue; + if (!ctx.isEqualNode(argCtx)) + continue; + break; + } + if (ctx == null) + return false; // not found + } + return true; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomEntity.java b/libjava/classpath/gnu/xml/dom/DomEntity.java new file mode 100644 index 000000000..be44d7359 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomEntity.java @@ -0,0 +1,146 @@ +/* DomEntity.java -- + Copyright (C) 1999,2000,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.xml.dom; + +import org.w3c.dom.Entity; + +/** + *

      "Entity" implementation. This is a non-core DOM class, supporting the + * "XML" feature. There are two types of entities, neither of which works + * particularly well in this API:

      + * + *
      Unparsed Entities
      + *
      Since ENTITY/ENTITIES attributes, the only legal use of unparsed + * entities in XML, can't be detected with DOM, there isn't much point in + * trying to use unparsed entities in DOM applications. (XML Linking is + * working to provide a better version of this functionality.)
      + * + *
      Parsed Entities
      + *
      While the DOM specification permits nodes for parsed entities + * to have a readonly set of children, this is not required and there + * is no portable way to provide such children. This implementation + * currently does not permit children to be added to Entities. + * There are related issues with the use of EntityReference nodes.
      + * + *
      + * + *

      In short, avoid using this DOM functionality. + * + * @see DomDoctype + * @see DomEntityReference + * @see DomNotation + * + * @author David Brownell + * @author Chris Burdess + */ +public class DomEntity + extends DomExtern + implements Entity +{ + + private String notation; + + /** + * Constructs an Entity node associated with the specified document, + * with the specified descriptive data. + * + *

      This constructor should only be invoked by a DomDoctype as part + * of its declareEntity functionality, or through a subclass which is + * similarly used in a "Sub-DOM" style layer. + * + * @param owner The document with which this entity is associated + * @param name Name of this entity + * @param publicId If non-null, provides the entity's PUBLIC identifier + * @param systemId Provides the entity's SYSTEM identifier (URI) + * @param notation If non-null, provides the unparsed entity's notation. + */ + protected DomEntity(DomDocument owner, + String name, + String publicId, + String systemId, + String notation) + { + super(ENTITY_NODE, owner, name, publicId, systemId); + this.notation = notation; + + // NOTE: if notation == null, this is a parsed entity + // which could reasonably be given child nodes ... + makeReadonly(); + } + + /** + * DOM L1 + * Returns the NOTATION identifier associated with this entity, if any. + */ + final public String getNotationName() + { + return notation; + } + + // DOM Level 3 methods + + public String getInputEncoding() + { + // TODO + return null; + } + + public String getXmlEncoding() + { + // TODO + return null; + } + + public String getXmlVersion() + { + // TODO + return null; + } + + /** + * The base URI of an external entity is its system ID. + * The base URI of an internal entity is the parent document's base URI. + * @since DOM Level 3 Core + */ + public String getBaseURI() + { + String systemId = getSystemId(); + return (systemId == null) ? owner.getBaseURI() : systemId; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomEntityReference.java b/libjava/classpath/gnu/xml/dom/DomEntityReference.java new file mode 100644 index 000000000..1fa2ea628 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomEntityReference.java @@ -0,0 +1,130 @@ +/* DomEntityReference.java -- + Copyright (C) 1999,2000,2001,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.xml.dom; + +import org.w3c.dom.DocumentType; +import org.w3c.dom.Entity; +import org.w3c.dom.EntityReference; + +/** + *

      "EntityReference" implementation (reference to parsed entity). + * This is a non-core DOM class, supporting the "XML" feature. + * It does not represent builtin entities (such as "&amp;") + * or character references, which are always directly expanded in + * DOM trees.

      + * + *

      Note that while the DOM specification permits these nodes to have + * a readonly set of children, this is not required. Similarly, it does + * not require a DOM to couple EntityReference nodes with any Entity nodes + * that have the same entity name (and equivalent children). It also + * effectively guarantees that references created directly or indirectly + * through the Document.ImportNode method will not have children. + * The level of functionality you may get is extremely variable. + * + *

      Also significant is that even at their most functional level, the fact + * that EntityReference children must be readonly has caused significant + * problems when modifying work products held in DOM trees. Other problems + * include issues related to undeclared namespace prefixes (and references + * to the current default namespace) that may be found in the text of such + * parsed entities nodes. These must be contextually bound as part of DOM + * tree construction. When such nodes are moved, the namespace associated + * with a given prefix (or default) may change to be in conflict with the + * namespace bound to the node at creation time. + * + *

      In short, avoid using this DOM functionality. + * + * @see DomDoctype + * @see DomEntity + * + * @author David Brownell + * @author Chris Burdess + */ +public class DomEntityReference + extends DomNode + implements EntityReference +{ + + private String name; + + /** + * Constructs an EntityReference node associated with the specified + * document. The creator should populate this with whatever contents + * are appropriate, and then mark it as readonly. + * + *

      This constructor should only be invoked by a Document as part of + * its createEntityReference functionality, or through a subclass which + * is similarly used in a "Sub-DOM" style layer. + * + * @see DomNode#makeReadonly + */ + protected DomEntityReference(DomDocument owner, String name) + { + super(ENTITY_REFERENCE_NODE, owner); + this.name = name; + } + + /** + * Returns the name of the referenced entity. + * @since DOM Level 1 Core + */ + public final String getNodeName() + { + return name; + } + + /** + * The base URI of an entity reference is the base URI where the entity + * declaration occurs. + * @since DOM Level 3 Core + */ + public final String getBaseURI() + { + DocumentType doctype = owner.getDoctype(); + if (doctype == null) + { + return null; + } + Entity entity = (Entity) doctype.getEntities().getNamedItem(name); + if (entity == null) + { + return null; + } + return entity.getBaseURI(); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomEvent.java b/libjava/classpath/gnu/xml/dom/DomEvent.java new file mode 100644 index 000000000..3e9a6550a --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomEvent.java @@ -0,0 +1,351 @@ +/* DomEvent.java -- + Copyright (C) 1999,2000,2001 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.dom; + +import gnu.java.lang.CPStringBuilder; + +import org.w3c.dom.Node; + +import org.w3c.dom.events.Event; +import org.w3c.dom.events.EventTarget; +import org.w3c.dom.events.MutationEvent; +import org.w3c.dom.events.UIEvent; + +import org.w3c.dom.views.AbstractView; // used by UIEvent + +/** + * "Event" implementation. Events are + * created (through DocumentEvent interface methods on the document object), + * and are sent to any target node in the document. + * + *

      Applications may define application specific event subclasses, but + * should otherwise use the DocumentTraversal interface to acquire + * event objects. + * + * @author David Brownell + */ +public class DomEvent + implements Event +{ + + String type; // init + EventTarget target; + EventTarget currentNode; + short eventPhase; + boolean bubbles; // init + boolean cancelable; // init + long timeStamp; // ? + + /** Returns the event's type (name) as initialized */ + public final String getType() + { + return type; + } + + /** + * Returns event's target; delivery of an event is initiated + * by a target.dispatchEvent(event) invocation. + */ + public final EventTarget getTarget() + { + return target; + } + + /** + * Returns the target to which events are currently being + * delivered. When capturing or bubbling, this will not + * be what getTarget returns. + */ + public final EventTarget getCurrentTarget() + { + return currentNode; + } + + /** + * Returns CAPTURING_PHASE, AT_TARGET, or BUBBLING; + * only meaningful within EventListener.handleEvent + */ + public final short getEventPhase() + { + return eventPhase; + } + + /** + * Returns true if the news of the event bubbles to tree tops + * (as specified during initialization). + */ + public final boolean getBubbles() + { + return bubbles; + } + + /** + * Returns true if the default handling may be canceled + * (as specified during initialization). + */ + public final boolean getCancelable() + { + return cancelable; + } + + /** + * Returns the event's timestamp. + */ + public final long getTimeStamp() + { + return timeStamp; + } + + boolean stop; + boolean doDefault; + + /** + * Requests the event no longer be captured or bubbled; only + * listeners on the event target will see the event, if they + * haven't yet been notified. + * + *

      Avoid using this except for application-specific + * events, for which you the protocol explicitly "blesses" the use + * of this with some event types. Otherwise, you are likely to break + * algorithms which depend on event notification either directly or + * through bubbling or capturing.

      + * + *

      Note that this method is not final, specifically to enable + * enforcing of policies about events always propagating.

      + */ + public void stopPropagation() + { + stop = true; + } + + /** + * Requests that whoever dispatched the event not perform their + * default processing when event delivery completes. Initializes + * event timestamp. + */ + public final void preventDefault() + { + doDefault = false; + } + + /** Initializes basic event state. */ + public void initEvent(String typeArg, + boolean canBubbleArg, + boolean cancelableArg) + { + eventPhase = 0; + type = typeArg; + bubbles = canBubbleArg; + cancelable = cancelableArg; + timeStamp = System.currentTimeMillis(); + } + + /** Constructs, but does not initialize, an event. */ + public DomEvent(String type) + { + this.type = type; + } + + /** + * Returns a basic printable description of the event's type, + * state, and delivery conditions + */ + public String toString() + { + CPStringBuilder buf = new CPStringBuilder("[Event "); + buf.append(type); + switch (eventPhase) + { + case CAPTURING_PHASE: + buf.append(", CAPTURING"); + break; + case AT_TARGET: + buf.append(", AT TARGET"); + break; + case BUBBLING_PHASE: + buf.append(", BUBBLING"); + break; + default: + buf.append(", (inactive)"); + break; + } + if (bubbles && eventPhase != BUBBLING_PHASE) + { + buf.append(", bubbles"); + } + if (cancelable) + { + buf.append(", can cancel"); + } + // were we to provide subclass info, this's where it'd live + buf.append("]"); + return buf.toString(); + } + + /** + * "MutationEvent" implementation. + */ + public static final class DomMutationEvent + extends DomEvent + implements MutationEvent + { + + // package private + Node relatedNode; // init + + private String prevValue; // init + private String newValue; // init + + private String attrName; // init + private short attrChange; // init + + /** Returns any "related" node provided by this type of event */ + public final Node getRelatedNode() + { + return relatedNode; + } + + /** Returns any "previous value" provided by this type of event */ + public final String getPrevValue() + { + return prevValue; + } + + /** Returns any "new value" provided by this type of event */ + public final String getNewValue() + { + return newValue; + } + + /** For attribute change events, returns the attribute's name */ + public final String getAttrName() + { + return attrName; + } + + /** For attribute change events, returns how the attribuet changed */ + public final short getAttrChange() + { + return attrChange; + } + + /** Initializes a mutation event */ + public final void initMutationEvent(String typeArg, + boolean canBubbleArg, + boolean cancelableArg, + Node relatedNodeArg, + String prevValueArg, + String newValueArg, + String attrNameArg, + short attrChangeArg) + { + // super.initEvent is inlined here for speed + // (mutation events are issued on all DOM changes) + eventPhase = 0; + type = typeArg; + bubbles = canBubbleArg; + cancelable = cancelableArg; + timeStamp = System.currentTimeMillis(); + + relatedNode = relatedNodeArg; + prevValue = prevValueArg; + newValue = newValueArg; + attrName = attrNameArg; + attrChange = attrChangeArg; + } + + // clear everything that should be GC-able + void clear() + { + type = null; + target = null; + relatedNode = null; + currentNode = null; + prevValue = newValue = attrName = null; + } + + /** Constructs an uninitialized mutation event. */ + public DomMutationEvent(String type) + { + super(type); + } + + } + + /** + * "UIEvent" implementation. + */ + public static class DomUIEvent + extends DomEvent + implements UIEvent + { + + private AbstractView view; // init + private int detail; // init + + /** Constructs an uninitialized User Interface (UI) event */ + public DomUIEvent (String type) { super (type); } + + public final AbstractView getView () { return view; } + public final int getDetail () { return detail; } + + /** Initializes a UI event */ + public final void initUIEvent(String typeArg, + boolean canBubbleArg, + boolean cancelableArg, + AbstractView viewArg, + int detailArg) + { + super.initEvent(typeArg, canBubbleArg, cancelableArg); + view = viewArg; + detail = detailArg; + } + + } + + /* + + static final class DomMouseEvent extends DomUIEvent + implements MouseEvent + { + // another half dozen state variables/accessors + } + + */ + +} diff --git a/libjava/classpath/gnu/xml/dom/DomExtern.java b/libjava/classpath/gnu/xml/dom/DomExtern.java new file mode 100644 index 000000000..7f2e55afc --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomExtern.java @@ -0,0 +1,116 @@ +/* DomExtern.java -- + Copyright (C) 1999,2000,2001,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.xml.dom; + +/** + *

      Abstract implemention of nodes describing external DTD-related + * objects. This facilitates reusing code for Entity, Notation, and + * DocumentType (really, external subset) nodes. Such support is not + * part of the core DOM; it's for the "XML" feature.

      + * + *

      Note that you are strongly advised to avoid using the DOM + * features that take advantage of this class, since (as of L2) none + * of them is defined fully enough to permit full use of the + * XML feature they partially expose.

      + * + * @author David Brownell + * @author Chris Burdess + */ +public abstract class DomExtern + extends DomNode +{ + + private final String name; + private final String publicId; + private final String systemId; + + /** + * Constructs a node associated with the specified document, + * with the specified descriptive data. + * + * @param owner The document with which this object is associated + * @param name Name of this object + * @param publicId If non-null, provides the entity's PUBLIC identifier + * @param systemId If non-null, provides the entity's SYSTEM identifier + */ + // package private + DomExtern(short nodeType, + DomDocument owner, + String name, + String publicId, + String systemId) + { + super(nodeType, owner); + this.name = name; + this.publicId = publicId; + this.systemId = systemId; + } + + /** + * DOM L1 + * Returns the SYSTEM identifier associated with this object, if any. + */ + public final String getSystemId() + { + return systemId; + } + + /** + * DOM L1 + * Returns the PUBLIC identifier associated with this object, if any. + */ + public final String getPublicId() + { + return publicId; + } + + /** + * DOM L1 + * Returns the object's name. + */ + public final String getNodeName() + { + return name; + } + + public final String getLocalName() + { + return name; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomImpl.java b/libjava/classpath/gnu/xml/dom/DomImpl.java new file mode 100644 index 000000000..76a63caf6 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomImpl.java @@ -0,0 +1,277 @@ +/* DomImpl.java -- + Copyright (C) 1999,2000,2001,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.xml.dom; + +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Element; +import org.w3c.dom.ls.DOMImplementationLS; +import org.w3c.dom.ls.LSInput; +import org.w3c.dom.ls.LSOutput; +import org.w3c.dom.ls.LSParser; +import org.w3c.dom.ls.LSSerializer; +import gnu.xml.dom.html2.DomHTMLImpl; +import gnu.xml.dom.ls.DomLSInput; +import gnu.xml.dom.ls.DomLSOutput; +import gnu.xml.dom.ls.DomLSParser; +import gnu.xml.dom.ls.DomLSSerializer; + +/** + *

      "DOMImplementation" implementation.

      + * + *

      At this writing, the following features are supported: + * "XML" (L1, L2, L3), + * "Events" (L2), "MutationEvents" (L2), "USER-Events" (a conformant extension), + * "HTMLEvents" (L2), "UIEvents" (L2), "Traversal" (L2), "XPath" (L3), + * "LS" (L3) "LS-Async" (L3). + * It is possible to compile the package so it doesn't support some of these + * features (notably, Traversal). + * + * @author David Brownell + * @author Chris Burdess + */ +public class DomImpl + implements DOMImplementation, DOMImplementationLS +{ + + /** + * Constructs a DOMImplementation object which supports + * "XML" and other DOM Level 2 features. + */ + public DomImpl() + { + } + + /** + * DOM L1 + * Returns true if the specified feature and version are + * supported. Note that the case of the feature name is ignored. + */ + public boolean hasFeature(String name, String version) + { + if (name.length() == 0) + { + return false; + } + name = name.toLowerCase(); + if (name.charAt(0) == '+') + { + name = name.substring(1); + } + + if ("xml".equals(name) || "core".equals(name)) + { + return (version == null || + "".equals(version) || + "1.0".equals(version) || + "2.0".equals(version) || + "3.0".equals(version)); + + } + else if ("ls".equals(name) || "ls-async".equals(name)) + { + return (version == null || + "".equals(version) || + "3.0".equals(version)); + } + else if ("events".equals(name) + || "mutationevents".equals(name) + || "uievents".equals(name) + // || "mouseevents".equals(name) + || "htmlevents".equals(name)) + { + return (version == null || + "".equals(version) || + "2.0".equals(version)); + + // Extension: "USER-" prefix event types can + // be created and passed through the DOM. + + } + else if ("user-events".equals(name)) + { + return (version == null || + "".equals(version) || + "0.1".equals(version)); + + // NOTE: "hasFeature" for events is here interpreted to + // mean the DOM can manufacture those sorts of events, + // since actually choosing to report the events is more + // often part of the environment or application. It's + // only really an issue for mutation events. + + } + else if (DomNode.reportMutations + && "traversal".equals(name)) + { + return (version == null || + "".equals(version) || + "2.0".equals(version)); + } + else if ("xpath".equals(name)) + { + return (version == null || + "".equals(version) || + "3.0".equals(version)); + } + else if ("html".equals(name) || "xhtml".equals(name)) + { + return (version == null || + "".equals(version) || + "2.0".equals(version)); + } + + // views + // stylesheets + // css, css2 + // range + + return false; + } + + /** + * DOM L2 + * Creates and returns a DocumentType, associated with this + * implementation. This DocumentType can have no associated + * objects(notations, entities) until the DocumentType is + * first associated with a document. + * + *

      Note that there is no implication that this DTD will + * be parsed by the DOM, or ever have contents. Moreover, the + * DocumentType created here can only be added to a document by + * the createDocument method(below). That means that the only + * portable way to create a Document object is to start parsing, + * queue comment and processing instruction (PI) nodes, and then only + * create a DOM Document after (a) it's known if a DocumentType + * object is needed, and (b) the name and namespace of the root + * element is known. Queued comment and PI nodes would then be + * inserted appropriately in the document prologue, both before and + * after the DTD node, and additional attributes assigned to the + * root element. + *(One hopes that the final DOM REC fixes this serious botch.) + */ + public DocumentType createDocumentType(String rootName, + String publicId, + String systemId) + // CR2 deleted internal subset, ensuring DocumentType + // is 100% useless instead of just 90% so. + { + DomDocument.checkNCName(rootName, false); + return new DomDoctype(this, rootName, publicId, systemId, null); + } + + /** + * DOM L2 + * Creates and returns a Document, populated only with a root element and + * optionally a document type(if that was provided). + */ + public Document createDocument(String namespaceURI, + String rootName, + DocumentType doctype) + { + Document doc = createDocument(); + Element root = null; + + if (rootName != null) + { + root = doc.createElementNS(namespaceURI, rootName); + if (rootName.startsWith("xmlns:")) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "xmlns is reserved", null, 0); + } + } + // Bleech -- L2 seemingly _requires_ omission of xmlns attributes. + if (doctype != null) + { + doc.appendChild(doctype); // handles WRONG_DOCUMENT error + } + if (root != null) + { + doc.appendChild(root); + } + return doc; + } + + protected Document createDocument() + { + return new DomDocument(this); + } + + // DOM Level 3 + + public Object getFeature(String feature, String version) + { + if (hasFeature(feature, version)) + { + if ("html".equalsIgnoreCase(feature) || + "xhtml".equalsIgnoreCase(feature)) + { + return new DomHTMLImpl(); + } + return this; + } + return null; + } + + // -- DOMImplementationLS -- + + public LSParser createLSParser(short mode, String schemaType) + throws DOMException + { + return new DomLSParser(mode, schemaType); + } + + public LSSerializer createLSSerializer() + { + return new DomLSSerializer(); + } + + public LSInput createLSInput() + { + return new DomLSInput(); + } + + public LSOutput createLSOutput() + { + return new DomLSOutput(); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomIterator.java b/libjava/classpath/gnu/xml/dom/DomIterator.java new file mode 100644 index 000000000..d5f305cd8 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomIterator.java @@ -0,0 +1,380 @@ +/* DomIterator.java -- + Copyright (C) 1999, 2000, 2001, 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.dom; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.events.Event; +import org.w3c.dom.events.EventListener; +import org.w3c.dom.events.EventTarget; +import org.w3c.dom.events.MutationEvent; +import org.w3c.dom.traversal.NodeFilter; +import org.w3c.dom.traversal.NodeIterator; + +/** + *

      "NodeIterator" implementation, usable with any L2 DOM which + * supports MutationEvents.

      + * + * @author David Brownell + */ +public final class DomIterator + implements NodeIterator, EventListener +{ + + private Node reference; + private boolean right; + private boolean done; + + private final Node root; + private final int whatToShow; + private final NodeFilter filter; + private final boolean expandEntityReferences; + + /** + * Constructs and initializes an iterator. + */ + protected DomIterator(Node root, + int whatToShow, + NodeFilter filter, + boolean entityReferenceExpansion) + { + if (!root.isSupported("MutationEvents", "2.0")) + { + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR, + "Iterator needs mutation events", root, 0); + } + + this.root = root; + this.whatToShow = whatToShow; + this.filter = filter; + this.expandEntityReferences = entityReferenceExpansion; + + // start condition: going right, seen nothing yet. + reference = null; + right = true; + + EventTarget target = (EventTarget) root; + target.addEventListener("DOMNodeRemoved", this, false); + } + + /** + * DOM L2 + * Flags the iterator as done, unregistering its event listener so + * that the iterator can be garbage collected without relying on weak + * references (a "Java 2" feature) in the event subsystem. + */ + public void detach() + { + EventTarget target = (EventTarget) root; + target.removeEventListener("DOMNodeRemoved", this, false); + done = true; + } + + /** + * DOM L2 + * Returns the flag controlling whether iteration descends + * through entity references. + */ + public boolean getExpandEntityReferences() + { + return expandEntityReferences; + } + + /** + * DOM L2 + * Returns the filter provided during construction. + */ + public NodeFilter getFilter() + { + return filter; + } + + /** + * DOM L2 + * Returns the root of the tree this is iterating through. + */ + public Node getRoot() + { + return root; + } + + /** + * DOM L2 + * Returns the mask of flags provided during construction. + */ + public int getWhatToShow() + { + return whatToShow; + } + + /** + * DOM L2 + * Returns the next node in a forward iteration, masked and filtered. + * Note that the node may be read-only due to entity expansions. + * A null return indicates the iteration is complete, but may still + * be processed backwards. + */ + public Node nextNode() + { + if (done) + { + throw new DomDOMException(DOMException.INVALID_STATE_ERR); + } + right = true; + return walk(true); + } + + /** + * DOM L2 + * Returns the next node in a backward iteration, masked and filtered. + * Note that the node may be read-only due to entity expansions. + * A null return indicates the iteration is complete, but may still + * be processed forwards. + */ + public Node previousNode() + { + if (done) + { + throw new DomDOMException(DOMException.INVALID_STATE_ERR); + } + Node previous = reference; + right = false; + walk(false); + return previous; + } + + private boolean shouldShow(Node node) + // raises Runtime exceptions indirectly, via acceptNode() + { + if ((whatToShow & (1 << (node.getNodeType() - 1))) == 0) + { + return false; + } + if (filter == null) + { + return true; + } + return filter.acceptNode(node) == NodeFilter.FILTER_ACCEPT; + } + + // + // scenario: root = 1, sequence = 1 2 ... 3 4 + // forward walk: 1 2 ... 3 4 null + // then backward: 4 3 ... 2 1 null + // + // At the leftmost end, "previous" == null + // At the rightmost end, "previous" == 4 + // + // The current draft spec really seem to make no sense re the + // role of the reference node, so what it says is ignored here. + // + private Node walk(boolean forward) + { + Node here = reference; + + while ((here = successor(here, forward)) != null + && !shouldShow(here)) + { + continue; + } + if (here != null || !forward) + { + reference = here; + } + return here; + } + + private boolean isLeaf(Node here) + { + boolean leaf = !here.hasChildNodes(); + if (!leaf && !expandEntityReferences) + { + leaf = (here.getNodeType() == Node.ENTITY_REFERENCE_NODE); + } + return leaf; + } + + // + // Returns the immediate successor in a forward (or backward) + // document order walk, sans filtering ... except that it knows + // how to stop, returning null when done. This is a depth first + // preorder traversal when run in the forward direction. + // + private Node successor(Node here, boolean forward) + { + Node next; + + // the "leftmost" end is funky + if (here == null) + { + return forward ? root : null; + } + + // + // Forward, this is preorder: children before siblings. + // Backward, it's postorder: we saw the children already. + // + if (forward && !isLeaf(here)) + { + return here.getFirstChild(); + } + + // There's no way up or sideways from the root, so if we + // couldn't move down to a child, there's nowhere to go. + // + if (here == root) + return null; + + // + // Siblings ... if forward, we visit them, if backwards + // we visit their children first. + // + if (forward) + { + if ((next = here.getNextSibling()) != null) + { + return next; + } + } + else if ((next = here.getPreviousSibling()) != null) + { + if (isLeaf(next)) + { + return next; + } + next = next.getLastChild(); + while (!isLeaf(next)) + { + next = next.getLastChild(); + } + return next; + } + + // + // We can't go down or lateral -- it's up, then. The logic is + // the converse of what's above: backwards is easy (the parent + // is next), forwards isn't. + // + next = here.getParentNode(); + if (!forward) + { + return next; + } + + Node temp = null; + while (next != null + && next != root + && (temp = next.getNextSibling()) == null) + { + next = next.getParentNode(); + } + + // If we have exceeded the root node then stop traversing. + if (next == root.getParentNode()) + { + return null; + } + return temp; + } + + /** + * Not for public use. This lets the iterator know when its + * reference node will be removed from the tree, so that a new + * one may be selected. + * + *

      This version works by watching removal events as they + * bubble up. So, don't prevent them from bubbling. + */ + public void handleEvent(Event e) + { + MutationEvent event; + Node ancestor, removed; + + if (reference == null + || !"DOMNodeRemoved".equals(e.getType()) + || e.getEventPhase() != Event.BUBBLING_PHASE) + { + return; + } + + event = (MutationEvent) e; + removed = (Node) event.getTarget(); + + // See if the removal will cause trouble for this iterator + // by being the reference node or an ancestor of it. + for (ancestor = reference; + ancestor != null && ancestor != root; + ancestor = ancestor.getParentNode()) + { + if (ancestor == removed) + { + break; + } + } + if (ancestor != removed) + { + return; + } + + // OK, it'll cause trouble. We want to make the "next" + // node in our current traversal direction seem right. + // So we pick the nearest node that's not getting removed, + // but go in the _opposite_ direction from our current + // traversal ... so the "next" doesn't skip anything. + Node candidate; + +search: + while ((candidate = walk(!right)) != null) + { + for (ancestor = candidate; + ancestor != null && ancestor != root; + ancestor = ancestor.getParentNode()) + { + if (ancestor == removed) + { + continue search; + } + } + return; + } + + // The current DOM WD talks about a special case here; + // I've not yet seen it. + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomNSResolverContext.java b/libjava/classpath/gnu/xml/dom/DomNSResolverContext.java new file mode 100644 index 000000000..3dd957560 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomNSResolverContext.java @@ -0,0 +1,90 @@ +/* DomNSResolverContext.java -- + 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.xml.dom; + +import java.util.Iterator; +import javax.xml.namespace.NamespaceContext; +import org.w3c.dom.xpath.XPathNSResolver; + +/** + * Namespace content wrapper for an XPathNSResolver. + * + * @author Chris Burdess + */ +class DomNSResolverContext + implements NamespaceContext, Iterator +{ + + final XPathNSResolver resolver; + + DomNSResolverContext(XPathNSResolver resolver) + { + this.resolver = resolver; + } + + public String getNamespaceURI(String prefix) + { + return resolver.lookupNamespaceURI(prefix); + } + + public String getPrefix(String namespaceURI) + { + return null; + } + + public Iterator getPrefixes(String namespaceURI) + { + return this; + } + + public boolean hasNext() + { + return false; + } + + public Object next() + { + return null; + } + + public void remove() + { + throw new UnsupportedOperationException(); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomNamedNodeMap.java b/libjava/classpath/gnu/xml/dom/DomNamedNodeMap.java new file mode 100644 index 000000000..7a767355a --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomNamedNodeMap.java @@ -0,0 +1,421 @@ +/* DomNamedNodeMap.java -- + Copyright (C) 1999,2000,2001,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.xml.dom; + +import org.w3c.dom.DOMException; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +/** + *

      "NamedNodeMap" implementation.

      + * Used mostly to hold element attributes, but sometimes also + * to list notations or entities. + * + * @author David Brownell + * @author Chris Burdess + */ +public class DomNamedNodeMap + implements NamedNodeMap +{ + + final DomNode owner; + final short type; + + DomNode first; + int length; + boolean readonly; + + // package private + DomNamedNodeMap(DomNode owner, short type) + { + this.owner = owner; + this.type = type; + } + + /** + * Exposes the internal "readonly" flag. In DOM, all NamedNodeMap + * objects found in a DocumentType object are read-only (after + * they are fully constructed), and those holding attributes of + * a readonly element will also be readonly. + */ + public final boolean isReadonly() + { + return readonly; + } + + /** + * Sets the internal "readonly" flag so the node and its + * children can't be changed. + */ + public void makeReadonly() + { + readonly = true; + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + ctx.makeReadonly(); + } + } + + /** + * DOM L1 + * Returns the named item from the map, or null; names are just + * the nodeName property. + */ + public Node getNamedItem(String name) + { + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + if (ctx.getNodeName().equals(name)) + { + return ctx; + } + } + return null; + } + + /** + * DOM L2 + * Returns the named item from the map, or null; names are the + * localName and namespaceURI properties, ignoring any prefix. + */ + public Node getNamedItemNS(String namespaceURI, String localName) + { + if ("".equals(namespaceURI)) + { + namespaceURI = null; + } + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + String name = ctx.getLocalName(); + if ((localName == null && name == null) || + (localName != null && localName.equals(name))) + { + String uri = ctx.getNamespaceURI(); + if ("".equals(uri)) + { + uri = null; + } + if ((namespaceURI == null && uri == null) || + (namespaceURI != null && namespaceURI.equals(uri))) + { + return ctx; + } + } + } + return null; + } + + /** + * DOM L1 + * Stores the named item into the map, optionally overwriting + * any existing node with that name. The name used is just + * the nodeName attribute. + */ + public Node setNamedItem(Node arg) + { + return setNamedItem(arg, false, false); + } + + /** + * DOM L2 + * Stores the named item into the map, optionally overwriting + * any existing node with that fully qualified name. The name + * used incorporates the localName and namespaceURI properties, + * and ignores any prefix. + */ + public Node setNamedItemNS(Node arg) + { + return setNamedItem(arg, true, false); + } + + Node setNamedItem(Node arg, boolean ns, boolean cloning) + { + if (readonly) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + + DomNode node = (DomNode) arg; + if (!cloning && node.owner != owner.owner) + { + throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR); + } + if (node.nodeType != type) + { + throw new DomDOMException(DOMException.HIERARCHY_REQUEST_ERR); + } + if (node.nodeType == Node.ATTRIBUTE_NODE) + { + DomNode element = node.parent; + if (element != null && element != owner) + { + throw new DomDOMException(DOMException.INUSE_ATTRIBUTE_ERR); + } + node.parent = owner; + node.depth = owner.depth + 1; + } + + String nodeName = node.getNodeName(); + String localName = ns ? node.getLocalName() : null; + String namespaceURI = ns ? node.getNamespaceURI() : null; + if ("".equals(namespaceURI)) + { + namespaceURI = null; + } + + // maybe attribute ADDITION events (?) + DomNode last = null; + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + boolean test = false; + if (ns) + { + String tln = ctx.getLocalName(); + if (tln == null) + { + tln = ctx.getNodeName(); + } + if (tln.equals(localName)) + { + String tu = ctx.getNamespaceURI(); + if ((tu == null && namespaceURI == null) || + (tu != null && tu.equals(namespaceURI))) + { + test = true; + } + } + } + else + { + test = ctx.getNodeName().equals(nodeName); + } + if (test) + { + // replace + node.previous = ctx.previous; + node.next = ctx.next; + if (ctx.previous != null) + { + ctx.previous.next = node; + } + if (ctx.next != null) + { + ctx.next.previous = node; + } + if (first == ctx) + { + first = node; + } + reparent(node, nodeName, ctx.index); + ctx.parent = null; + ctx.next = null; + ctx.previous = null; + ctx.setDepth(0); + ctx.index = 0; + return ctx; + } + last = ctx; + } + // append + if (last != null) + { + last.next = node; + node.previous = last; + } + else + { + first = node; + } + length++; + reparent(node, nodeName, 0); + return null; + } + + void reparent(DomNode node, String nodeName, int i) + { + node.parent = owner; + node.setDepth(owner.depth + 1); + // index renumbering + for (DomNode ctx = node; ctx != null; ctx = ctx.next) + { + ctx.index = i++; + } + // cache xml:space + boolean xmlSpace = "xml:space".equals(nodeName); + if (xmlSpace && owner instanceof DomElement) + { + ((DomElement) owner).xmlSpace = node.getNodeValue(); + } + } + + /** + * DOM L1 + * Removes the named item from the map, or reports an exception; + * names are just the nodeName property. + */ + public Node removeNamedItem(String name) + { + return removeNamedItem(null, name, false); + } + + /** + * DOM L2 + * Removes the named item from the map, or reports an exception; + * names are the localName and namespaceURI properties. + */ + public Node removeNamedItemNS(String namespaceURI, String localName) + { + return removeNamedItem(namespaceURI, localName, true); + } + + Node removeNamedItem(String uri, String name, boolean ns) + { + if (readonly) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + + // report attribute REMOVAL event? + + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + boolean test = false; + String nodeName = ctx.getNodeName(); + if (ns) + { + String tln = ctx.getLocalName(); + if (name != null && name.equals(tln)) + { + String tu = ctx.getNamespaceURI(); + if ((tu == null && uri == null) || + (tu != null && tu.equals(uri))) + { + test = true; + } + } + } + else + { + test = nodeName.equals(name); + } + if (test) + { + // uncache xml:space + boolean xmlSpace = "xml:space".equals(nodeName); + if (xmlSpace && owner instanceof DomElement) + { + ((DomElement) owner).xmlSpace = ""; + } + // is this a default attribute? + if (ctx.nodeType == Node.ATTRIBUTE_NODE) + { + String def = getDefaultValue(ctx.getNodeName()); + if (def != null) + { + ctx.setNodeValue(def); + ((DomAttr) ctx).setSpecified(false); + return null; + } + } + // remove + if (ctx == first) + { + first = ctx.next; + } + if (ctx.previous != null) + { + ctx.previous.next = ctx.next; + } + if (ctx.next != null) + { + ctx.next.previous = ctx.previous; + } + length--; + ctx.previous = null; + ctx.next = null; + ctx.parent = null; + ctx.setDepth(0); + ctx.index = 0; + return ctx; + } + } + throw new DomDOMException(DOMException.NOT_FOUND_ERR); + } + + String getDefaultValue(String name) + { + DomDoctype doctype = (DomDoctype) owner.owner.getDoctype(); + if (doctype == null) + { + return null; + } + DTDAttributeTypeInfo info = + doctype.getAttributeTypeInfo(owner.getNodeName(), name); + if (info == null) + { + return null; + } + return info.value; + } + + /** + * DOM L1 + * Returns the indexed item from the map, or null. + */ + public Node item(int index) + { + DomNode ctx = first; + int count = 0; + while (ctx != null && count < index) + { + ctx = ctx.next; + count++; + } + return ctx; + } + + /** + * DOM L1 + * Returns the length of the map. + */ + public int getLength() + { + return length; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomNode.java b/libjava/classpath/gnu/xml/dom/DomNode.java new file mode 100644 index 000000000..879baaa8d --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomNode.java @@ -0,0 +1,2222 @@ +/* DomNode.java -- + Copyright (C) 1999,2000,2001,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.xml.dom; + +import gnu.java.lang.CPStringBuilder; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; + +import org.w3c.dom.Document; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; +import org.w3c.dom.UserDataHandler; +import org.w3c.dom.events.DocumentEvent; +import org.w3c.dom.events.Event; +import org.w3c.dom.events.EventException; +import org.w3c.dom.events.EventListener; +import org.w3c.dom.events.EventTarget; +import org.w3c.dom.events.MutationEvent; +import org.w3c.dom.traversal.NodeFilter; +import org.w3c.dom.traversal.NodeIterator; + +/** + *

      "Node", "EventTarget", and "DocumentEvent" implementation. + * This provides most of the core DOM functionality; only more + * specialized features are provided by subclasses. Those subclasses may + * have some particular constraints they must implement, by overriding + * methods defined here. Such constraints are noted here in the method + * documentation.

      + * + *

      Note that you can create events with type names prefixed with "USER-", + * and pass them through this DOM. This lets you use the DOM event scheme + * for application specific purposes, although you must use a predefined event + * structure (such as MutationEvent) to pass data along with those events. + * Test for existence of this feature with the "USER-Events" DOM feature + * name.

      + * + *

      Other kinds of events you can send include the "html" events, + * like "load", "unload", "abort", "error", and "blur"; and the mutation + * events. If this DOM has been compiled with mutation event support + * enabled, it will send mutation events when you change parts of the + * tree; otherwise you may create and send such events yourself, but + * they won't be generated by the DOM itself.

      + * + *

      Note that there is a namespace-aware name comparison method, + * nameAndTypeEquals, which compares the names (and types) of + * two nodes in conformance with the "Namespaces in XML" specification. + * While mostly intended for use with elements and attributes, this should + * also be helpful for ProcessingInstruction nodes and some others which + * do not have namespace URIs. + * + * @author David Brownell + * @author Chris Burdess + */ +public abstract class DomNode + implements Node, NodeList, EventTarget, DocumentEvent, Cloneable, Comparable +{ + + // package private + //final static String xmlNamespace = "http://www.w3.org/XML/1998/namespace"; + //final static String xmlnsURI = "http://www.w3.org/2000/xmlns/"; + + // tunable + // NKIDS_* affects arrays of children (which grow) + // (currently) fixed size: + // ANCESTORS_* is for event capture/bubbling, # ancestors + // NOTIFICATIONS_* is for per-node event delivery, # events + private static final int NKIDS_DELTA = 8; + private static final int ANCESTORS_INIT = 20; + private static final int NOTIFICATIONS_INIT = 10; + + // tunable: enable mutation events or not? Enabling it costs about + // 10-15% in DOM construction time, last time it was measured. + + // package private !!! + static final boolean reportMutations = true; + + // locking protocol changeable only within this class + private static final Object lockNode = new Object(); + + // NON-FINAL class data + + // Optimize event dispatch by not allocating memory each time + private static boolean dispatchDataLock; + private static DomNode[] ancestors = new DomNode[ANCESTORS_INIT]; + private static ListenerRecord[] notificationSet + = new ListenerRecord[NOTIFICATIONS_INIT]; + + // Ditto for the (most common) event object itself! + private static boolean eventDataLock; + private static DomEvent.DomMutationEvent mutationEvent + = new DomEvent.DomMutationEvent(null); + + // + // PER-INSTANCE DATA + // + + DomDocument owner; + DomNode parent; // parent node; + DomNode previous; // previous sibling node + DomNode next; // next sibling node + DomNode first; // first child node + DomNode last; // last child node + int index; // index of this node in its parent's children + int depth; // depth of the node in the document + int length; // number of children + final short nodeType; + + // Bleech ... "package private" so a builder can populate entity refs. + // writable during construction. DOM spec is nasty. + boolean readonly; + + // event registrations + private HashSet listeners; + private int nListeners; + + // DOM Level 3 userData dictionary. + private HashMap userData; + private HashMap userDataHandlers; + + // + // Some of the methods here are declared 'final' because + // knowledge about their implementation is built into this + // class -- for both integrity and performance. + // + + /** + * Reduces space utilization for this node. + */ + public void compact() + { + } + + /** + * Constructs a node and associates it with its owner. Only + * Document and DocumentType nodes may be created with no owner, + * and DocumentType nodes get an owner as soon as they are + * associated with a document. + */ + protected DomNode(short nodeType, DomDocument owner) + { + this.nodeType = nodeType; + + if (owner == null) + { + // DOM calls never go down this path + if (nodeType != DOCUMENT_NODE && nodeType != DOCUMENT_TYPE_NODE) + { + throw new IllegalArgumentException ("no owner!"); + } + } + this.owner = owner; + this.listeners = new HashSet(); + } + + + /** + * DOM L1 + * Returns null; Element subclasses must override this method. + */ + public NamedNodeMap getAttributes() + { + return null; + } + + /** + * DOM L2> + * Returns true iff this is an element node with attributes. + */ + public boolean hasAttributes() + { + return false; + } + + /** + * DOM L1 + * Returns a list, possibly empty, of the children of this node. + * In this implementation, to conserve memory, nodes are the same + * as their list of children. This can have ramifications for + * subclasses, which may need to provide their own getLength method + * for reasons unrelated to the NodeList method of the same name. + */ + public NodeList getChildNodes() + { + return this; + } + + /** + * DOM L1 + * Returns the first child of this node, or null if there are none. + */ + public Node getFirstChild() + { + return first; + } + + /** + * DOM L1 + * Returns the last child of this node, or null if there are none. + */ + public Node getLastChild() + { + return last; + } + + /** + * DOM L1 + * Returns true if this node has children. + */ + public boolean hasChildNodes() + { + return length != 0; + } + + + /** + * Exposes the internal "readonly" flag. In DOM, children of + * entities and entity references are readonly, as are the + * objects associated with DocumentType objets. + */ + public final boolean isReadonly() + { + return readonly; + } + + /** + * Sets the internal "readonly" flag so this subtree can't be changed. + * Subclasses need to override this method for any associated content + * that's not a child node, such as an element's attributes or the + * (few) declarations associated with a DocumentType. + */ + public void makeReadonly() + { + readonly = true; + for (DomNode child = first; child != null; child = child.next) + { + child.makeReadonly(); + } + } + + /** + * Used to adopt a node to a new document. + */ + void setOwner(DomDocument doc) + { + this.owner = doc; + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + ctx.setOwner(doc); + } + } + + // just checks the node for inclusion -- may be called many + // times (docfrag) before anything is allowed to change + private void checkMisc(DomNode child) + { + if (readonly && !owner.building) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, + null, this, 0); + } + for (DomNode ctx = this; ctx != null; ctx = ctx.parent) + { + if (child == ctx) + { + throw new DomDOMException(DOMException.HIERARCHY_REQUEST_ERR, + "can't make ancestor into a child", + this, 0); + } + } + + DomDocument owner = (nodeType == DOCUMENT_NODE) ? (DomDocument) this : + this.owner; + DomDocument childOwner = child.owner; + short childNodeType = child.nodeType; + + if (childOwner != owner) + { + // new in DOM L2, this case -- patch it up later, in reparent() + if (!(childNodeType == DOCUMENT_TYPE_NODE && childOwner == null)) + { + throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR, + null, child, 0); + } + } + + // enforce various structural constraints + switch (nodeType) + { + case DOCUMENT_NODE: + switch (childNodeType) + { + case ELEMENT_NODE: + case PROCESSING_INSTRUCTION_NODE: + case COMMENT_NODE: + case DOCUMENT_TYPE_NODE: + return; + } + break; + + case ATTRIBUTE_NODE: + switch (childNodeType) + { + case TEXT_NODE: + case ENTITY_REFERENCE_NODE: + return; + } + break; + + case DOCUMENT_FRAGMENT_NODE: + case ENTITY_REFERENCE_NODE: + case ELEMENT_NODE: + case ENTITY_NODE: + switch (childNodeType) + { + case ELEMENT_NODE: + case TEXT_NODE: + case COMMENT_NODE: + case PROCESSING_INSTRUCTION_NODE: + case CDATA_SECTION_NODE: + case ENTITY_REFERENCE_NODE: + return; + } + break; + case DOCUMENT_TYPE_NODE: + if (!owner.building) + break; + switch (childNodeType) + { + case COMMENT_NODE: + case PROCESSING_INSTRUCTION_NODE: + return; + } + break; + } + if (owner.checkingWellformedness) + { + throw new DomDOMException(DOMException.HIERARCHY_REQUEST_ERR, + "can't append " + + nodeTypeToString(childNodeType) + + " to node of type " + + nodeTypeToString(nodeType), + this, 0); + } + } + + // Here's hoping a good optimizer will detect the case when the + // next several methods are never called, and won't allocate + // object code space of any kind. (Case: not reporting any + // mutation events. We can also remove some static variables + // listed above.) + + private void insertionEvent(DomEvent.DomMutationEvent event, + DomNode target) + { + if (owner == null || owner.building) + { + return; + } + boolean doFree = false; + + if (event == null) + { + event = getMutationEvent(); + } + if (event != null) + { + doFree = true; + } + else + { + event = new DomEvent.DomMutationEvent(null); + } + event.initMutationEvent("DOMNodeInserted", + true /* bubbles */, false /* nocancel */, + this /* related */, null, null, null, (short) 0); + target.dispatchEvent(event); + + // XXX should really visit every descendant of 'target' + // and sent a DOMNodeInsertedIntoDocument event to it... + // bleech, there's no way to keep that acceptably fast. + + if (doFree) + { + event.target = null; + event.relatedNode = null; + event.currentNode = null; + eventDataLock = false; + } // else we created work for the GC + } + + private void removalEvent(DomEvent.DomMutationEvent event, + DomNode target) + { + if (owner == null || owner.building) + { + return; + } + boolean doFree = false; + + if (event == null) + { + event = getMutationEvent(); + } + if (event != null) + { + doFree = true; + } + else + { + event = new DomEvent.DomMutationEvent(null); + } + event.initMutationEvent("DOMNodeRemoved", + true /* bubbles */, false /* nocancel */, + this /* related */, null, null, null, (short) 0); + target.dispatchEvent(event); + + // XXX should really visit every descendant of 'target' + // and sent a DOMNodeRemovedFromDocument event to it... + // bleech, there's no way to keep that acceptably fast. + + event.target = null; + event.relatedNode = null; + event.currentNode = null; + if (doFree) + { + eventDataLock = false; + } + // else we created more work for the GC + } + + // + // Avoid creating lots of memory management work, by using a simple + // allocation strategy for the mutation event objects that get used + // at least once per tree modification. We can't use stack allocation, + // so we do the next simplest thing -- more or less, static allocation. + // Concurrent notifications should be rare, anyway. + // + // Returns the preallocated object, which needs to be carefully freed, + // or null to indicate the caller needs to allocate their own. + // + static private DomEvent.DomMutationEvent getMutationEvent() + { + synchronized (lockNode) + { + if (eventDataLock) + { + return null; + } + eventDataLock = true; + return mutationEvent; + } + } + + // NOTE: this is manually inlined in the insertion + // and removal event methods above; change in sync. + static private void freeMutationEvent() + { + // clear fields to enable GC + mutationEvent.clear(); + eventDataLock = false; + } + + void setDepth(int depth) + { + this.depth = depth; + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + ctx.setDepth(depth + 1); + } + } + + /** + * DOM L1 + * Appends the specified node to this node's list of children. + * Document subclasses must override this to enforce the restrictions + * that there be only one element and document type child. + * + *

      Causes a DOMNodeInserted mutation event to be reported. + * Will first cause a DOMNodeRemoved event to be reported if the + * parameter already has a parent. If the new child is a document + * fragment node, both events will be reported for each child of + * the fragment; the order in which children are removed and + * inserted is implementation-specific. + * + *

      If this DOM has been compiled without mutation event support, + * these events will not be reported. + */ + public Node appendChild(Node newChild) + { + try + { + DomNode child = (DomNode) newChild; + + if (child.nodeType == DOCUMENT_FRAGMENT_NODE) + { + // Append all nodes in the fragment to this node + for (DomNode ctx = child.first; ctx != null; ctx = ctx.next) + { + checkMisc(ctx); + } + for (DomNode ctx = child.first; ctx != null; ) + { + DomNode ctxNext = ctx.next; + appendChild(ctx); + ctx = ctxNext; + } + } + else + { + checkMisc(child); + if (child.parent != null) + { + child.parent.removeChild(child); + } + child.parent = this; + child.index = length++; + child.setDepth(depth + 1); + child.next = null; + if (last == null) + { + first = child; + child.previous = null; + } + else + { + last.next = child; + child.previous = last; + } + last = child; + + if (reportMutations) + { + insertionEvent(null, child); + } + } + + return child; + } + catch (ClassCastException e) + { + throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR, + null, newChild, 0); + } + } + + /** + * DOM L1 + * Inserts the specified node in this node's list of children. + * Document subclasses must override this to enforce the restrictions + * that there be only one element and document type child. + * + *

      Causes a DOMNodeInserted mutation event to be reported. Will + * first cause a DOMNodeRemoved event to be reported if the newChild + * parameter already has a parent. If the new child is a document + * fragment node, both events will be reported for each child of + * the fragment; the order in which children are removed and inserted + * is implementation-specific. + * + *

      If this DOM has been compiled without mutation event support, + * these events will not be reported. + */ + public Node insertBefore(Node newChild, Node refChild) + { + if (refChild == null) + { + return appendChild(newChild); + } + + try + { + DomNode child = (DomNode) newChild; + DomNode ref = (DomNode) refChild; + + if (child.nodeType == DOCUMENT_FRAGMENT_NODE) + { + // Append all nodes in the fragment to this node + for (DomNode ctx = child.first; ctx != null; ctx = ctx.next) + { + checkMisc(ctx); + } + for (DomNode ctx = child.first; ctx != null; ) + { + DomNode ctxNext = ctx.next; + insertBefore(ctx, ref); + ctx = ctxNext; + } + } + else + { + checkMisc(child); + if (ref == null || ref.parent != this) + { + throw new DomDOMException(DOMException.NOT_FOUND_ERR, + null, ref, 0); + } + if (ref == child) + { + throw new DomDOMException(DOMException.HIERARCHY_REQUEST_ERR, + "can't insert node before itself", + ref, 0); + } + + if (child.parent != null) + { + child.parent.removeChild(child); + } + child.parent = this; + int i = ref.index; + child.setDepth(depth + 1); + child.next = ref; + if (ref.previous != null) + { + ref.previous.next = child; + } + child.previous = ref.previous; + ref.previous = child; + if (first == ref) + { + first = child; + } + // index renumbering + for (DomNode ctx = child; ctx != null; ctx = ctx.next) + { + ctx.index = i++; + } + + if (reportMutations) + { + insertionEvent(null, child); + } + length++; + } + + return child; + } + catch (ClassCastException e) + { + throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR, + null, newChild, 0); + } + } + + /** + * DOM L1 + * Replaces the specified node in this node's list of children. + * Document subclasses must override this to test the restrictions + * that there be only one element and document type child. + * + *

      Causes DOMNodeRemoved and DOMNodeInserted mutation event to be + * reported. Will cause another DOMNodeRemoved event to be reported if + * the newChild parameter already has a parent. These events may be + * delivered in any order, except that the event reporting removal + * from such an existing parent will always be delivered before the + * event reporting its re-insertion as a child of some other node. + * The order in which children are removed and inserted is implementation + * specific. + * + *

      If your application needs to depend on the in which those removal + * and insertion events are delivered, don't use this API. Instead, + * invoke the removeChild and insertBefore methods directly, to guarantee + * a specific delivery order. Similarly, don't use document fragments, + * Otherwise your application code may not work on a DOM which implements + * this method differently. + * + *

      If this DOM has been compiled without mutation event support, + * these events will not be reported. + */ + public Node replaceChild(Node newChild, Node refChild) + { + try + { + DomNode child = (DomNode) newChild; + DomNode ref = (DomNode) refChild; + + DomEvent.DomMutationEvent event = getMutationEvent(); + boolean doFree = (event != null); + + if (child.nodeType == DOCUMENT_FRAGMENT_NODE) + { + // Append all nodes in the fragment to this node + for (DomNode ctx = child.first; ctx != null; ctx = ctx.next) + { + checkMisc(ctx); + } + if (ref == null || ref.parent != this) + { + throw new DomDOMException(DOMException.NOT_FOUND_ERR, + null, ref, 0); + } + + if (reportMutations) + { + removalEvent(event, ref); + } + length--; + length += child.length; + + if (child.length == 0) + { + // Removal + if (ref.previous != null) + { + ref.previous.next = ref.next; + } + if (ref.next != null) + { + ref.next.previous = ref.previous; + } + if (first == ref) + { + first = ref.next; + } + if (last == ref) + { + last = ref.previous; + } + } + else + { + int i = ref.index; + for (DomNode ctx = child.first; ctx != null; ctx = ctx.next) + { + // Insertion + ctx.parent = this; + ctx.index = i++; + ctx.setDepth(ref.depth); + if (ctx == child.first) + { + ctx.previous = ref.previous; + } + if (ctx == child.last) + { + ctx.next = ref.next; + } + } + if (first == ref) + { + first = child.first; + } + if (last == ref) + { + last = child.last; + } + } + } + else + { + checkMisc(child); + if (ref == null || ref.parent != this) + { + throw new DomDOMException(DOMException.NOT_FOUND_ERR, + null, ref, 0); + } + + if (reportMutations) + { + removalEvent(event, ref); + } + + if (child.parent != null) + { + child.parent.removeChild(child); + } + child.parent = this; + child.index = ref.index; + child.setDepth(ref.depth); + if (ref.previous != null) + { + ref.previous.next = child; + } + child.previous = ref.previous; + if (ref.next != null) + { + ref.next.previous = child; + } + child.next = ref.next; + if (first == ref) + { + first = child; + } + if (last == ref) + { + last = child; + } + + if (reportMutations) + { + insertionEvent(event, child); + } + if (doFree) + { + freeMutationEvent(); + } + } + ref.parent = null; + ref.index = 0; + ref.setDepth(0); + ref.previous = null; + ref.next = null; + + return ref; + } + catch (ClassCastException e) + { + throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR, + null, newChild, 0); + } + } + + /** + * DOM L1 + * Removes the specified child from this node's list of children, + * or else reports an exception. + * + *

      Causes a DOMNodeRemoved mutation event to be reported. + * + *

      If this DOM has been compiled without mutation event support, + * these events will not be reported. + */ + public Node removeChild(Node refChild) + { + try + { + DomNode ref = (DomNode) refChild; + + if (ref == null || ref.parent != this) + { + throw new DomDOMException(DOMException.NOT_FOUND_ERR, + null, ref, 0); + } + if (readonly && !owner.building) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, + null, this, 0); + } + + for (DomNode child = first; child != null; child = child.next) + { + if (child == ref) + { + if (reportMutations) + { + removalEvent(null, child); + } + + length--; + if (ref.previous != null) + { + ref.previous.next = ref.next; + } + if (ref.next != null) + { + ref.next.previous = ref.previous; + } + if (first == ref) + { + first = ref.next; + } + if (last == ref) + { + last = ref.previous; + } + // renumber indices + int i = 0; + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + ctx.index = i++; + } + ref.parent = null; + ref.setDepth(0); + ref.index = 0; + ref.previous = null; + ref.next = null; + + return ref; + } + } + throw new DomDOMException(DOMException.NOT_FOUND_ERR, + "that's no child of mine", refChild, 0); + } + catch (ClassCastException e) + { + throw new DomDOMException(DOMException.WRONG_DOCUMENT_ERR, + null, refChild, 0); + } + } + + /** + * DOM L1 (NodeList) + * Returns the item with the specified index in this NodeList, + * else null. + */ + public Node item(int index) + { + DomNode child = first; + int count = 0; + while (child != null && count < index) + { + child = child.next; + count++; + } + return child; + } + + /** + * DOM L1 (NodeList) + * Returns the number of elements in this NodeList. + * (Note that many interfaces have a "Length" property, not just + * NodeList, and if a node subtype must implement one of those, + * it will also need to override getChildNodes.) + */ + public int getLength() + { + return length; + } + + /** + * Minimize extra space consumed by this node to hold children and event + * listeners. + */ + public void trimToSize() + { + } + + /** + * DOM L1 + * Returns the previous sibling, if one is known. + */ + public Node getNextSibling() + { + return next; + } + + /** + * DOM L1 + * Returns the previous sibling, if one is known. + */ + public Node getPreviousSibling() + { + return previous; + } + + /** + * DOM L1 + * Returns the parent node, if one is known. + */ + public Node getParentNode() + { + return parent; + } + + /** + * DOM L2 + * Consults the DOM implementation to determine if the requested + * feature is supported. DocumentType subclasses must override + * this method, and associate themselves directly with the + * DOMImplementation node used. (This method relies on being able + * to access the DOMImplementation from the owner document, but + * DocumentType nodes can be created without an owner.) + */ + public boolean isSupported(String feature, String version) + { + Document doc = owner; + DOMImplementation impl = null; + + if (doc == null && nodeType == DOCUMENT_NODE) + { + doc = (Document) this; + } + + if (doc == null) + { + // possible for DocumentType + throw new IllegalStateException ("unbound ownerDocument"); + } + + impl = doc.getImplementation(); + return impl.hasFeature(feature, version); + } + + /** + * DOM L1 (modified in L2) + * Returns the owner document. This is only null for Document nodes, + * and (new in L2) for DocumentType nodes which have not yet been + * associated with the rest of their document. + */ + final public Document getOwnerDocument() + { + return owner; + } + + /** + * DOM L1 + * Does nothing; this must be overridden (along with the + * getNodeValue method) for nodes with a non-null defined value. + */ + public void setNodeValue(String value) + { + } + + /** + * DOM L1 + * Returns null; this must be overridden for nodes types with + * a defined value, along with the setNodeValue method. + */ + public String getNodeValue() + { + return null; + } + + /** This forces GCJ compatibility. + * Without this method GCJ is unable to compile to byte code. + */ + public final short getNodeType() + { + return nodeType; + } + + /** This forces GCJ compatibility. + * Without this method GCJ seems unable to natively compile GNUJAXP. + */ + public abstract String getNodeName(); + + /** + * DOM L2 + * Does nothing; this must be overridden (along with the + * getPrefix method) for element and attribute nodes. + */ + public void setPrefix(String prefix) + { + } + + /** + * DOM L2 + * Returns null; this must be overridden for element and + * attribute nodes. + */ + public String getPrefix() + { + return null; + } + + /** + * DOM L2 + * Returns null; this must be overridden for element and + * attribute nodes. + */ + public String getNamespaceURI() + { + return null; + } + + /** + * DOM L2 + * Returns the node name; this must be overridden for element and + * attribute nodes. + */ + public String getLocalName() + { + return null; + } + + /** + * DOM L1 + * Returns a clone of this node which optionally includes cloned + * versions of child nodes. Clones are always mutable, except for + * entity reference nodes. + */ + public Node cloneNode(boolean deep) + { + if (deep) + { + return cloneNodeDeepInternal(true, null); + } + + DomNode node = (DomNode) clone(); + if (nodeType == ENTITY_REFERENCE_NODE) + { + node.makeReadonly(); + } + notifyUserDataHandlers(UserDataHandler.NODE_CLONED, this, node); + return node; + } + + /** + * Returns a deep clone of this node. + */ + private DomNode cloneNodeDeepInternal(boolean root, DomDocument doc) + { + DomNode node = (DomNode) clone(); + boolean building = false; // Never used unless root is true + if (root) + { + doc = (nodeType == DOCUMENT_NODE) ? (DomDocument) node : node.owner; + building = doc.building; + doc.building = true; // Permit certain structural rules + } + node.owner = doc; + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + DomNode newChild = ctx.cloneNodeDeepInternal(false, doc); + node.appendChild(newChild); + } + if (nodeType == ENTITY_REFERENCE_NODE) + { + node.makeReadonly(); + } + if (root) + { + doc.building = building; + } + notifyUserDataHandlers(UserDataHandler.NODE_CLONED, this, node); + return node; + } + + void notifyUserDataHandlers(short op, Node src, Node dst) + { + if (userDataHandlers != null) + { + for (Iterator i = userDataHandlers.entrySet().iterator(); i.hasNext(); ) + { + Map.Entry entry = (Map.Entry) i.next(); + String key = (String) entry.getKey(); + UserDataHandler handler = (UserDataHandler) entry.getValue(); + Object data = userData.get(key); + handler.handle(op, key, data, src, dst); + } + } + } + + /** + * Clones this node; roughly equivalent to cloneNode(false). + * Element subclasses must provide a new implementation which + * invokes this method to handle the basics, and then arranges + * to clone any element attributes directly. Attribute subclasses + * must make similar arrangements, ensuring that existing ties to + * elements are broken by cloning. + */ + public Object clone() + { + try + { + DomNode node = (DomNode) super.clone(); + + node.parent = null; + node.depth = 0; + node.index = 0; + node.length = 0; + node.first = null; + node.last = null; + node.previous = null; + node.next = null; + + node.readonly = false; + node.listeners = new HashSet(); + node.nListeners = 0; + return node; + + } + catch (CloneNotSupportedException x) + { + throw new Error("clone didn't work"); + } + } + + // the elements-by-tagname stuff is needed for both + // elements and documents ... this is in lieu of a + // common base class between Node and NodeNS. + + /** + * DOM L1 + * Creates a NodeList giving array-style access to elements with + * the specified name. Access is fastest if indices change by + * small values, and the DOM is not modified. + */ + public NodeList getElementsByTagName(String tag) + { + return new ShadowList(null, tag); + } + + /** + * DOM L2 + * Creates a NodeList giving array-style access to elements with + * the specified namespace and local name. Access is fastest if + * indices change by small values, and the DOM is not modified. + */ + public NodeList getElementsByTagNameNS(String namespace, String local) + { + return new ShadowList(namespace, local); + } + + + // + // This shadow class is GC-able even when the live list it shadows + // can't be, because of event registration hookups. Its finalizer + // makes that live list become GC-able. + // + final class ShadowList + implements NodeList + { + + private LiveNodeList liveList; + + ShadowList(String ns, String local) + { + liveList = new LiveNodeList(ns, local); + } + + public void finalize() + { + liveList.detach(); + liveList = null; + } + + public Node item(int index) + { + return liveList.item(index); + } + + public int getLength() + { + return liveList.getLength(); + } + } + + final class LiveNodeList + implements NodeList, EventListener, NodeFilter + { + + private final boolean matchAnyURI; + private final boolean matchAnyName; + private final String elementURI; + private final String elementName; + + private DomIterator current; + private int lastIndex; + + LiveNodeList(String uri, String name) + { + elementURI = uri; + elementName = name; + matchAnyURI = "*".equals(uri); + matchAnyName = "*".equals(name); + + DomNode.this.addEventListener("DOMNodeInserted", this, true); + DomNode.this.addEventListener("DOMNodeRemoved", this, true); + } + + void detach() + { + if (current != null) + current.detach(); + current = null; + + DomNode.this.removeEventListener("DOMNodeInserted", this, true); + DomNode.this.removeEventListener("DOMNodeRemoved", this, true); + } + + public short acceptNode(Node element) + { + if (element == DomNode.this) + { + return FILTER_SKIP; + } + + // use namespace-aware matching ... + if (elementURI != null) + { + if (!(matchAnyURI + || elementURI.equals(element.getNamespaceURI()))) + { + return FILTER_SKIP; + } + if (!(matchAnyName + || elementName.equals(element.getLocalName()))) + { + return FILTER_SKIP; + } + + // ... or qName-based kind. + } + else + { + if (!(matchAnyName + || elementName.equals(element.getNodeName()))) + { + return FILTER_SKIP; + } + } + return FILTER_ACCEPT; + } + + private DomIterator createIterator() + { + return new DomIterator(DomNode.this, + NodeFilter.SHOW_ELEMENT, + this, /* filter */ + true /* expand entity refs */ + ); + } + + public void handleEvent(Event e) + { + MutationEvent mutation = (MutationEvent) e; + Node related = mutation.getRelatedNode(); + + // XXX if it's got children ... check all kids too, they + // will invalidate our saved index + + if (related.getNodeType() != Node.ELEMENT_NODE || + related.getNodeName() != elementName || + related.getNamespaceURI() != elementURI) + { + return; + } + + if (current != null) + current.detach(); + current = null; + } + + public Node item(int index) + { + if (current == null) + { + current = createIterator(); + lastIndex = -1; + } + + // last node or before? go backwards + if (index <= lastIndex) { + while (index != lastIndex) { + current.previousNode (); + lastIndex--; + } + Node ret = current.previousNode (); + current.detach(); + current = null; + return ret; + } + + // somewhere after last node + while (++lastIndex != index) + current.nextNode (); + + Node ret = current.nextNode (); + current.detach(); + current = null; + return ret; + } + + public int getLength() + { + int retval = 0; + NodeIterator iter = createIterator(); + + while (iter.nextNode() != null) + { + retval++; + } + iter.detach(); + return retval; + } + + } + + // + // EventTarget support + // + static final class ListenerRecord + { + + String type; + EventListener listener; + boolean useCapture; + + // XXX use JDK 1.2 java.lang.ref.WeakReference to listener, + // and we can both get rid of "shadow" classes and remove + // the need for applications to apply similar trix ... but + // JDK 1.2 support isn't generally available yet + + ListenerRecord(String type, EventListener listener, boolean useCapture) + { + this.type = type.intern(); + this.listener = listener; + this.useCapture = useCapture; + } + + public boolean equals(Object o) + { + ListenerRecord rec = (ListenerRecord)o; + return listener == rec.listener + && useCapture == rec.useCapture + && type == rec.type; + } + + public int hashCode() + { + return listener.hashCode() ^ type.hashCode(); + } + } + + /** + * DOM L2 (Events) + * Returns an instance of the specified type of event object. + * Understands about DOM Mutation, HTML, and UI events. + * + *

      If the name of the event type begins with "USER-", then an object + * implementing the "Event" class will be returned; this provides a + * limited facility for application-defined events to use the DOM event + * infrastructure. Alternatively, use one of the standard DOM event + * classes and initialize it using use such a "USER-" event type name; + * or defin, instantiate, and initialize an application-specific subclass + * of DomEvent and pass that to dispatchEvent(). + * + * @param eventType Identifies the particular DOM feature module + * defining the type of event, such as "MutationEvents". + * The event "name" is a different kind of "type". + */ + public Event createEvent(String eventType) + { + eventType = eventType.toLowerCase(); + + if ("mutationevents".equals(eventType)) + { + return new DomEvent.DomMutationEvent(null); + } + + if ("htmlevents".equals(eventType) + || "events".equals(eventType) + || "user-events".equals(eventType)) + { + return new DomEvent(null); + } + + if ("uievents".equals(eventType)) + { + return new DomEvent.DomUIEvent(null); + } + + // mouse events + + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR, + eventType, null, 0); + } + + /** + * DOM L2 (Events) + * Registers an event listener's interest in a class of events. + */ + public final void addEventListener(String type, + EventListener listener, + boolean useCapture) + { + // prune duplicates + ListenerRecord record; + + record = new ListenerRecord(type, listener, useCapture); + listeners.add(record); + nListeners = listeners.size(); + } + + // XXX this exception should be discarded from DOM + + // this class can be instantiated, unlike the one in the spec + static final class DomEventException + extends EventException + { + + DomEventException() + { + super(UNSPECIFIED_EVENT_TYPE_ERR, "unspecified event type"); + } + + } + + /** + * DOM L2 (Events) + * Delivers an event to all relevant listeners, returning true if the + * caller should perform their default action. Note that the event + * must have been provided by the createEvent() method on this + * class, else it can't be dispatched. + * + * @see #createEvent + * + * @exception NullPointerException When a null event is passed. + * @exception ClassCastException When the event wasn't provided by + * the createEvent method, or otherwise isn't a DomEvent. + * @exception EventException If the event type wasn't specified + */ + public final boolean dispatchEvent(Event event) + throws EventException + { + DomEvent e = (DomEvent) event; + DomNode[] ancestors = null; + int ancestorMax = 0; + boolean haveDispatchDataLock = false; + + if (e.type == null) + { + throw new DomEventException(); + } + + e.doDefault = true; + e.target = this; + + // + // Typical case: one nonrecursive dispatchEvent call at a time + // for this class. If that's our case, we can avoid allocating + // garbage, which is overall a big win. Even with advanced GCs + // that deal well with short-lived garbage, and wayfast allocators, + // it still helps. + // + // Remember -- EVERY mutation goes though here at least once. + // + // When populating a DOM tree, trying to send mutation events is + // the primary cost; this dominates the critical path. + // + try + { + DomNode current; + int index; + boolean haveAncestorRegistrations = false; + ListenerRecord[] notificationSet; + int ancestorLen; + + synchronized (lockNode) + { + if (!dispatchDataLock) + { + haveDispatchDataLock = dispatchDataLock = true; + notificationSet = DomNode.notificationSet; + ancestors = DomNode.ancestors; + } + else + { + notificationSet = new ListenerRecord[NOTIFICATIONS_INIT]; + ancestors = new DomNode[ANCESTORS_INIT]; + } + ancestorLen = ancestors.length; + } + + // Climb to the top of this subtree and handle capture, letting + // each node (from the top down) capture until one stops it or + // until we get to this one. + current = (parent == null) ? this : parent; + if (current.depth >= ANCESTORS_INIT) + { + DomNode[] newants = new DomNode[current.depth + 1]; + System.arraycopy(ancestors, 0, newants, 0, ancestors.length); + ancestors = newants; + ancestorLen = ancestors.length; + } + for (index = 0; index < ancestorLen; index++) + { + if (current == null || current.depth == 0) + break; + + if (current.nListeners != 0) + { + haveAncestorRegistrations = true; + } + ancestors [index] = current; + current = current.parent; + } + if (current.depth > 0) + { + throw new RuntimeException("dispatchEvent capture stack size"); + } + + ancestorMax = index; + e.stop = false; + + if (haveAncestorRegistrations) + { + e.eventPhase = Event.CAPTURING_PHASE; + while (!e.stop && index-- > 0) + { + current = ancestors [index]; + if (current.nListeners != 0) + { + notifyNode(e, current, true, notificationSet); + } + } + } + + // Always deliver events to the target node (this) + // unless stopPropagation was called. If we saw + // no registrations yet (typical!), we never will. + if (!e.stop && nListeners != 0) + { + e.eventPhase = Event.AT_TARGET; + notifyNode (e, this, false, notificationSet); + } + else if (!haveAncestorRegistrations) + { + e.stop = true; + } + + // If the event bubbles and propagation wasn't halted, + // walk back up the ancestor list. Stop bubbling when + // any bubbled event handler stops it. + + if (!e.stop && e.bubbles) + { + e.eventPhase = Event.BUBBLING_PHASE; + for (index = 0; + !e.stop + && index < ancestorMax + && (current = ancestors[index]) != null; + index++) + { + if (current.nListeners != 0) + { + notifyNode(e, current, false, notificationSet); + } + } + } + e.eventPhase = 0; + + // Caller chooses whether to perform the default + // action based on return from this method. + return e.doDefault; + + } + finally + { + if (haveDispatchDataLock) + { + // synchronize to force write ordering + synchronized (lockNode) + { + // null out refs to ensure they'll be GC'd + for (int i = 0; i < ancestorMax; i++) + { + ancestors [i] = null; + } + // notificationSet handled by notifyNode + + dispatchDataLock = false; + } + } + } + } + + private void notifyNode(DomEvent e, + DomNode current, + boolean capture, + ListenerRecord[] notificationSet) + { + int count = 0; + Iterator iter; + + iter = current.listeners.iterator(); + + // do any of this set of listeners get notified? + while (iter.hasNext()) + { + ListenerRecord rec = (ListenerRecord)iter.next(); + + if (rec.useCapture != capture) + { + continue; + } + if (!e.type.equals (rec.type)) + { + continue; + } + if (count >= notificationSet.length) + { + // very simple growth algorithm + int len = Math.max(notificationSet.length, 1); + ListenerRecord[] tmp = new ListenerRecord[len * 2]; + System.arraycopy(notificationSet, 0, tmp, 0, + notificationSet.length); + notificationSet = tmp; + } + notificationSet[count++] = rec; + } + iter = null; + + // Notify just those listeners + e.currentNode = current; + for (int i = 0; i < count; i++) + { + try + { + iter = current.listeners.iterator(); + // Late in the DOM CR process (3rd or 4th CR?) the + // removeEventListener spec became asymmetric with respect + // to addEventListener ... effect is now immediate. + while (iter.hasNext()) + { + ListenerRecord rec = (ListenerRecord)iter.next(); + + if (rec.equals(notificationSet[i])) + { + notificationSet[i].listener.handleEvent(e); + break; + } + } + iter = null; + } + catch (Exception x) + { + // ignore all exceptions + } + notificationSet[i] = null; // free for GC + } + } + + /** + * DOM L2 (Events) + * Unregisters an event listener. + */ + public final void removeEventListener(String type, + EventListener listener, + boolean useCapture) + { + listeners.remove(new ListenerRecord(type, listener, useCapture)); + nListeners = listeners.size(); + // no exceptions reported + } + + /** + * DOM L1 (relocated in DOM L2) + * In this node and all contained nodes (including attributes if + * relevant) merge adjacent text nodes. This is done while ignoring + * text which happens to use CDATA delimiters). + */ + public final void normalize() + { + // Suspend readonly status + boolean saved = readonly; + readonly = false; + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + boolean saved2 = ctx.readonly; + ctx.readonly = false; + switch (ctx.nodeType) + { + case TEXT_NODE: + case CDATA_SECTION_NODE: + while (ctx.next != null && + (ctx.next.nodeType == TEXT_NODE || + ctx.next.nodeType == CDATA_SECTION_NODE)) + { + Text text = (Text) ctx; + text.appendData(ctx.next.getNodeValue()); + removeChild(ctx.next); + } + break; + case ELEMENT_NODE: + NamedNodeMap attrs = ctx.getAttributes(); + int len = attrs.getLength(); + for (int i = 0; i < len; i++) + { + DomNode attr = (DomNode) attrs.item(i); + boolean saved3 = attr.readonly; + attr.readonly = false; + attr.normalize(); + attr.readonly = saved3; + } + // Fall through + case DOCUMENT_NODE: + case DOCUMENT_FRAGMENT_NODE: + case ATTRIBUTE_NODE: + case ENTITY_REFERENCE_NODE: + ctx.normalize(); + break; + } + ctx.readonly = saved2; + } + readonly = saved; + } + + /** + * Returns true iff node types match, and either (a) both nodes have no + * namespace and their getNodeName() values are the same, or (b) both + * nodes have the same getNamespaceURI() and same getLocalName() values. + * + *

      Note that notion of a "Per-Element-Type" attribute name scope, as + * found in a non-normative appendix of the XML Namespaces specification, + * is not supported here. Your application must implement that notion, + * typically by not bothering to check nameAndTypeEquals for attributes + * without namespace URIs unless you already know their elements are + * nameAndTypeEquals. + */ + public boolean nameAndTypeEquals(Node other) + { + if (other == this) + { + return true; + } + // node types must match + if (nodeType != other.getNodeType()) + { + return false; + } + + // if both have namespaces, do a "full" comparision + // this is a "global" partition + String ns1 = this.getNamespaceURI(); + String ns2 = other.getNamespaceURI(); + + if (ns1 != null && ns2 != null) + { + return ns1.equals(ns2) && + equal(getLocalName(), other.getLocalName()); + } + + // if neither has a namespace, this is a "no-namespace" name. + if (ns1 == null && ns2 == null) + { + if (!getNodeName().equals(other.getNodeName())) + { + return false; + } + // can test the non-normative "per-element-type" scope here. + // if this is an attribute node and both nodes have been bound + // to elements (!!), then return the nameAndTypeEquals() + // comparison of those elements. + return true; + } + + // otherwise they're unequal: one scoped, one not. + return false; + } + + // DOM Level 3 methods + + public String getBaseURI() + { + return (parent != null) ? parent.getBaseURI() : null; + } + + public short compareDocumentPosition(Node other) + throws DOMException + { + return (short) compareTo(other); + } + + /** + * DOM nodes have a natural ordering: document order. + */ + public final int compareTo(Object other) + { + if (other instanceof DomNode) + { + DomNode n1 = this; + DomNode n2 = (DomNode) other; + if (n1.owner != n2.owner) + { + return 0; + } + int d1 = n1.depth, d2 = n2.depth; + int delta = d1 - d2; + while (d1 > d2) + { + n1 = n1.parent; + d1--; + } + while (d2 > d1) + { + n2 = n2.parent; + d2--; + } + int c = compareTo2(n1, n2); + return (c != 0) ? c : delta; + } + return 0; + } + + /** + * Compare two nodes at the same depth. + */ + final int compareTo2(DomNode n1, DomNode n2) + { + if (n1 == n2 || n1.depth == 0 || n2.depth == 0) + { + return 0; + } + int c = compareTo2(n1.parent, n2.parent); + return (c != 0) ? c : n1.index - n2.index; + } + + public final String getTextContent() + throws DOMException + { + return getTextContent(true); + } + + final String getTextContent(boolean topLevel) + throws DOMException + { + switch (nodeType) + { + case ELEMENT_NODE: + case ENTITY_NODE: + case ENTITY_REFERENCE_NODE: + case DOCUMENT_FRAGMENT_NODE: + CPStringBuilder buffer = new CPStringBuilder(); + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + { + String textContent = ctx.getTextContent(false); + if (textContent != null) + { + buffer.append(textContent); + } + } + return buffer.toString(); + case TEXT_NODE: + case CDATA_SECTION_NODE: + if (((Text) this).isElementContentWhitespace()) + { + return ""; + } + return getNodeValue(); + case ATTRIBUTE_NODE: + return getNodeValue(); + case COMMENT_NODE: + case PROCESSING_INSTRUCTION_NODE: + return topLevel ? getNodeValue() : ""; + default: + return null; + } + } + + public void setTextContent(String textContent) + throws DOMException + { + switch (nodeType) + { + case ELEMENT_NODE: + case ATTRIBUTE_NODE: + case ENTITY_NODE: + case ENTITY_REFERENCE_NODE: + case DOCUMENT_FRAGMENT_NODE: + for (DomNode ctx = first; ctx != null; ) + { + DomNode n = ctx.next; + removeChild(ctx); + ctx = n; + } + if (textContent != null) + { + Text text = owner.createTextNode(textContent); + appendChild(text); + } + break; + case TEXT_NODE: + case CDATA_SECTION_NODE: + case COMMENT_NODE: + case PROCESSING_INSTRUCTION_NODE: + setNodeValue(textContent); + break; + } + } + + public boolean isSameNode(Node other) + { + return this == other; + } + + public String lookupPrefix(String namespaceURI) + { + return (parent == null || parent == owner) ? null : + parent.lookupPrefix(namespaceURI); + } + + public boolean isDefaultNamespace(String namespaceURI) + { + return (parent == null || parent == owner) ? false : + parent.isDefaultNamespace(namespaceURI); + } + + public String lookupNamespaceURI(String prefix) + { + return (parent == null || parent == owner) ? null : + parent.lookupNamespaceURI(prefix); + } + + public boolean isEqualNode(Node arg) + { + if (this == arg) + return true; + if (arg == null) + return false; + if (nodeType != arg.getNodeType()) + return false; + switch (nodeType) + { + case ELEMENT_NODE: + case ATTRIBUTE_NODE: + if (!equal(getLocalName(), arg.getLocalName()) || + !equal(getNamespaceURI(), arg.getNamespaceURI())) + return false; + break; + case PROCESSING_INSTRUCTION_NODE: + if (!equal(getNodeName(), arg.getNodeName()) || + !equal(getNodeValue(), arg.getNodeValue())) + return false; + break; + case COMMENT_NODE: + case TEXT_NODE: + case CDATA_SECTION_NODE: + if (!equal(getNodeValue(), arg.getNodeValue())) + return false; + break; + } + // Children + Node argCtx = arg.getFirstChild(); + getFirstChild(); // because of DomAttr lazy children + DomNode ctx = first; + for (; ctx != null && argCtx != null; ctx = ctx.next) + { + if (nodeType == DOCUMENT_NODE) + { + // Ignore whitespace outside document element + while (ctx != null && ctx.nodeType == TEXT_NODE) + ctx = ctx.next; + while (argCtx != null && ctx.getNodeType() == TEXT_NODE) + argCtx = argCtx.getNextSibling(); + if (ctx == null && argCtx != null) + return false; + else if (argCtx == null && ctx != null) + return false; + } + if (!ctx.isEqualNode(argCtx)) + return false; + argCtx = argCtx.getNextSibling(); + } + if (ctx != null || argCtx != null) + return false; + + // TODO DocumentType + return true; + } + + boolean equal(String arg1, String arg2) + { + return ((arg1 == null && arg2 == null) || + (arg1 != null && arg1.equals(arg2))); + } + + public Object getFeature(String feature, String version) + { + DOMImplementation impl = (nodeType == DOCUMENT_NODE) ? + ((Document) this).getImplementation() : owner.getImplementation(); + if (impl.hasFeature(feature, version)) + { + return this; + } + return null; + } + + public Object setUserData(String key, Object data, UserDataHandler handler) + { + if (userData == null) + { + userData = new HashMap(); + } + if (handler != null) + { + if (userDataHandlers == null) + { + userDataHandlers = new HashMap(); + } + userDataHandlers.put(key, handler); + } + return userData.put(key, data); + } + + public Object getUserData(String key) + { + if (userData == null) + { + return null; + } + return userData.get(key); + } + + public String toString() + { + String nodeName = getNodeName(); + String nodeValue = getNodeValue(); + CPStringBuilder buf = new CPStringBuilder(getClass().getName()); + buf.append('['); + if (nodeName != null) + { + buf.append(nodeName); + } + if (nodeValue != null) + { + if (nodeName != null) + { + buf.append('='); + } + buf.append('\''); + buf.append(encode(nodeValue)); + buf.append('\''); + } + buf.append(']'); + return buf.toString(); + } + + String encode(String value) + { + CPStringBuilder buf = null; + int len = value.length(); + for (int i = 0; i < len; i++) + { + char c = value.charAt(i); + if (c == '\n') + { + if (buf == null) + { + buf = new CPStringBuilder(value.substring(0, i)); + } + buf.append("\\n"); + } + else if (c == '\r') + { + if (buf == null) + { + buf = new CPStringBuilder(value.substring(0, i)); + } + buf.append("\\r"); + } + else if (buf != null) + { + buf.append(c); + } + } + return (buf != null) ? buf.toString() : value; + } + + String nodeTypeToString(short nodeType) + { + switch (nodeType) + { + case ELEMENT_NODE: + return "ELEMENT_NODE"; + case ATTRIBUTE_NODE: + return "ATTRIBUTE_NODE"; + case TEXT_NODE: + return "TEXT_NODE"; + case CDATA_SECTION_NODE: + return "CDATA_SECTION_NODE"; + case DOCUMENT_NODE: + return "DOCUMENT_NODE"; + case DOCUMENT_TYPE_NODE: + return "DOCUMENT_TYPE_NODE"; + case COMMENT_NODE: + return "COMMENT_NODE"; + case PROCESSING_INSTRUCTION_NODE: + return "PROCESSING_INSTRUCTION_NODE"; + case DOCUMENT_FRAGMENT_NODE: + return "DOCUMENT_FRAGMENT_NODE"; + case ENTITY_NODE: + return "ENTITY_NODE"; + case ENTITY_REFERENCE_NODE: + return "ENTITY_REFERENCE_NODE"; + case NOTATION_NODE: + return "NOTATION_NODE"; + default: + return "UNKNOWN"; + } + } + + public void list(java.io.PrintStream out, int indent) + { + for (int i = 0; i < indent; i++) + out.print(" "); + out.println(toString()); + for (DomNode ctx = first; ctx != null; ctx = ctx.next) + ctx.list(out, indent + 1); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomNodeIterator.java b/libjava/classpath/gnu/xml/dom/DomNodeIterator.java new file mode 100644 index 000000000..9f9ec7e39 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomNodeIterator.java @@ -0,0 +1,328 @@ +/* DomNodeIterator.java -- + 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.xml.dom; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.traversal.NodeFilter; +import org.w3c.dom.traversal.NodeIterator; +import org.w3c.dom.traversal.TreeWalker; + +/** + * Node iterator and tree walker. + * + * @author Chris Burdess + */ +public class DomNodeIterator + implements NodeIterator, TreeWalker +{ + + Node root; + final int whatToShow; + final NodeFilter filter; + final boolean entityReferenceExpansion; + final boolean walk; + Node current; + + public DomNodeIterator(Node root, int whatToShow, NodeFilter filter, + boolean entityReferenceExpansion, boolean walk) + { + if (root == null) + { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "null root"); + } + this.root = root; + this.whatToShow = whatToShow; + this.filter = filter; + this.entityReferenceExpansion = entityReferenceExpansion; + this.walk = walk; + current = root; + } + + public Node getRoot() + { + return root; + } + + public int getWhatToShow() + { + return whatToShow; + } + + public NodeFilter getFilter() + { + return filter; + } + + public boolean getExpandEntityReferences() + { + return entityReferenceExpansion; + } + + public Node nextNode() + throws DOMException + { + if (root == null) + { + throw new DOMException(DOMException.INVALID_STATE_ERR, "null root"); + } + Node ret; + do + { + if (current.equals(root)) + { + ret = root.getFirstChild(); + } + else if (walk) + { + ret = current.getFirstChild(); + if (ret == null) + { + ret = current.getNextSibling(); + } + if (ret == null) + { + Node tmp = current; + ret = tmp.getParentNode(); + while (!ret.equals(root) && tmp.equals(ret.getLastChild())) + { + tmp = ret; + ret = tmp.getParentNode(); + } + if (ret.equals(root)) + { + ret = null; + } + else + { + ret = ret.getNextSibling(); + } + } + } + else + { + ret = current.getNextSibling(); + } + current = (ret == null) ? current : ret; + } + while (!accept(ret)); + + return ret; + } + + public Node previousNode() + throws DOMException + { + if (root == null) + { + throw new DOMException(DOMException.INVALID_STATE_ERR, "null root"); + } + Node ret; + do + { + if (current.equals(root)) + { + ret = current.getLastChild(); + } + else if (walk) + { + ret = current.getLastChild(); + if (ret == null) + { + ret = current.getPreviousSibling(); + } + if (ret == null) + { + Node tmp = current; + ret = tmp.getParentNode(); + while (!ret.equals(root) && tmp.equals(ret.getFirstChild())) + { + tmp = ret; + ret = tmp.getParentNode(); + } + if (ret.equals(root)) + { + ret = null; + } + else + { + ret = ret.getPreviousSibling(); + } + } + } + else + { + ret = current.getPreviousSibling(); + } + } + while (!accept(ret)); + current = (ret == null) ? current : ret; + return ret; + } + + public Node getCurrentNode() + { + return current; + } + + public void setCurrentNode(Node current) + throws DOMException + { + if (current == null) + { + throw new DOMException(DOMException.NOT_SUPPORTED_ERR, "null root"); + } + this.current = current; + } + + public Node parentNode() + { + Node ret = current.getParentNode(); + if (!accept (ret)) + { + ret = null; + } + current = (ret == null) ? current : ret; + return ret; + } + + public Node firstChild () + { + Node ret = current.getFirstChild(); + while (!accept(ret)) + { + ret = ret.getNextSibling(); + } + current = (ret == null) ? current : ret; + return ret; + } + + public Node lastChild() + { + Node ret = current.getLastChild(); + while (!accept(ret)) + { + ret = ret.getPreviousSibling(); + } + current = (ret == null) ? current : ret; + return ret; + } + + public Node previousSibling() + { + Node ret = current.getPreviousSibling(); + while (!accept(ret)) + { + ret = ret.getPreviousSibling(); + } + current = (ret == null) ? current : ret; + return ret; + } + + public Node nextSibling() + { + Node ret = current.getNextSibling(); + while (!accept(ret)) + { + ret = ret.getNextSibling(); + } + current = (ret == null) ? current : ret; + return ret; + } + + public void detach() + { + root = null; + } + + boolean accept(Node node) + { + if (node == null) + { + return true; + } + boolean ret; + switch (node.getNodeType()) + { + case Node.ATTRIBUTE_NODE: + ret = (whatToShow & NodeFilter.SHOW_ATTRIBUTE) != 0; + break; + case Node.CDATA_SECTION_NODE: + ret = (whatToShow & NodeFilter.SHOW_CDATA_SECTION) != 0; + break; + case Node.COMMENT_NODE: + ret = (whatToShow & NodeFilter.SHOW_COMMENT) != 0; + break; + case Node.DOCUMENT_NODE: + ret = (whatToShow & NodeFilter.SHOW_DOCUMENT) != 0; + break; + case Node.DOCUMENT_FRAGMENT_NODE: + ret = (whatToShow & NodeFilter.SHOW_DOCUMENT_FRAGMENT) != 0; + break; + case Node.DOCUMENT_TYPE_NODE: + ret = (whatToShow & NodeFilter.SHOW_DOCUMENT_TYPE) != 0; + break; + case Node.ELEMENT_NODE: + ret = (whatToShow & NodeFilter.SHOW_ELEMENT) != 0; + break; + case Node.ENTITY_NODE: + ret = (whatToShow & NodeFilter.SHOW_ENTITY) != 0; + break; + case Node.ENTITY_REFERENCE_NODE: + ret = (whatToShow & NodeFilter.SHOW_ENTITY_REFERENCE) != 0; + ret = ret && entityReferenceExpansion; + break; + case Node.NOTATION_NODE: + ret = (whatToShow & NodeFilter.SHOW_NOTATION) != 0; + break; + case Node.PROCESSING_INSTRUCTION_NODE: + ret = (whatToShow & NodeFilter.SHOW_PROCESSING_INSTRUCTION) != 0; + break; + case Node.TEXT_NODE: + ret = (whatToShow & NodeFilter.SHOW_TEXT) != 0; + break; + default: + ret = true; + } + if (ret && filter != null) + { + ret = (filter.acceptNode(node) == NodeFilter.FILTER_ACCEPT); + } + return ret; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomNotation.java b/libjava/classpath/gnu/xml/dom/DomNotation.java new file mode 100644 index 000000000..abb0e9da9 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomNotation.java @@ -0,0 +1,102 @@ +/* DomNotation.java -- + Copyright (C) 1999,2000,2001,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.xml.dom; + +import org.w3c.dom.Notation; + +/** + *

      "Notation" implementation. This is a non-core DOM class, supporting + * the "XML" feature.

      + * + *

      Although unparsed entities using this notation can be detected using + * DOM, neither NOTATIONS nor ENTITY/ENTITIES attributes can be so detected. + * More, there is no portable way to construct a Notation node, so there's + * no way that vendor-neutral DOM construction APIs could even report a + * NOTATION used to identify the intended meaning of a ProcessingInstruction. + *

      + * + *

      In short, avoid using this DOM functionality. + * + * @see DomDoctype + * @see DomEntity + * @see DomPI + * + * @author David Brownell + * @author Chris Burdess + */ +public class DomNotation + extends DomExtern + implements Notation +{ + + /** + * Constructs a Notation node associated with the specified document, + * with the specified descriptive data. Note that at least one of + * the PUBLIC and SYSTEM identifiers must be provided; unlike other + * external objects in XML, notations may have only a PUBLIC identifier. + * + *

      This constructor should only be invoked by a DomDoctype object + * as part of its declareNotation functionality, or through a subclass + * which is similarly used in a "Sub-DOM" style layer. + * + * @param owner The document with which this notation is associated + * @param name Name of this notation + * @param publicId If non-null, provides the notation's PUBLIC identifier + * @param systemId If non-null, rovides the notation's SYSTEM identifier + */ + protected DomNotation(DomDocument owner, + String name, + String publicId, + String systemId) + { + super(NOTATION_NODE, owner, name, publicId, systemId); + makeReadonly(); + } + + /** + * The base URI of an external entity is its system ID. + * The base URI of an internal entity is the parent document's base URI. + * @since DOM Level 3 Core + */ + public String getBaseURI() + { + String systemId = getSystemId(); + return (systemId == null) ? owner.getBaseURI() : systemId; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomNsNode.java b/libjava/classpath/gnu/xml/dom/DomNsNode.java new file mode 100644 index 000000000..55e351185 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomNsNode.java @@ -0,0 +1,226 @@ +/* DomNsNode.java -- + Copyright (C) 1999,2000,2001,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.xml.dom; + +import javax.xml.XMLConstants; +import org.w3c.dom.DOMException; + +/** + *

      Abstract implemention of namespace support. This facilitates + * sharing code for attribute and element nodes. + * + * @author David Brownell + * @author Chris Burdess + */ +public abstract class DomNsNode + extends DomNode +{ + + private String name; + private String namespace; + private String prefix; + private String localName; + + /** + * Constructs a node associated with the specified document, and + * with the specified namespace information. + * + * @param owner The document with which this entity is associated + * @param namespaceURI Combined with the local part of the name, + * this identifies a type of element or attribute; may be null. + * If this is the empty string, it is reassigned as null so that + * applications only need to test that case. + * @param name Name of this node, which may include a prefix + */ + // package private + DomNsNode(short nodeType, DomDocument owner, String namespaceURI, String name) + { + super(nodeType, owner); + setNodeName(name); + setNamespaceURI(namespaceURI); + } + + /** + * Constructs a node associated with the specified document, and + * with the specified namespace information. The prefix and local part + * are given explicitly rather than being computed. This allows them + * to be explicitly set to {@code null} as required by + * {@link Document#createElement(String)}. + * + * @param owner The document with which this entity is associated + * @param namespaceURI Combined with the local part of the name, + * this identifies a type of element or attribute; may be null. + * If this is the empty string, it is reassigned as null so that + * applications only need to test that case. + * @param name Name of this node, which may include a prefix + * @param prefix the namespace prefix of the name. May be {@code null}. + * @param localName the local part of the name. May be {@code null}. + */ + // package private + DomNsNode(short nodeType, DomDocument owner, String namespaceURI, String name, + String prefix, String localName) + { + super(nodeType, owner); + this.name = name.intern(); + this.prefix = prefix == null ? null : prefix.intern(); + this.localName = localName == null ? null : localName.intern(); + setNamespaceURI(namespaceURI); + } + + /** + * DOM L1 + * Returns the node's name, including any namespace prefix. + */ + public final String getNodeName() + { + return name; + } + + final void setNodeName(String name) + { + this.name = name.intern(); + int index = name.indexOf(':'); + if (index == -1) + { + prefix = null; + localName = this.name; + } + else + { + prefix = name.substring(0, index).intern(); + localName = name.substring(index + 1).intern(); + } + } + + /** + * DOM L2 + * Returns the node's namespace URI + * or null if the node name is not namespace scoped. + */ + public final String getNamespaceURI() + { + return namespace; + } + + final void setNamespaceURI(String namespaceURI) + { + if ("".equals(namespaceURI)) + { + namespaceURI = null; + } + namespace = (namespaceURI == null) ? null : namespaceURI.intern(); + } + + /** + * DOM L2 + * Returns any prefix part of the node's name (before any colon). + */ + public final String getPrefix() + { + return prefix; + } + + /** + * DOM L2 + * Assigns the prefix part of the node's name (before any colon). + */ + public final void setPrefix(String prefix) + { + if (readonly) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + + if (prefix == null) + { + name = localName; + return; + } + else if (namespace == null) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "can't set prefix, node has no namespace URI", + this, 0); + } + + DomDocument.checkName(prefix, "1.1".equals(owner.getXmlVersion())); + if (prefix.indexOf (':') != -1) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "illegal prefix " + prefix, this, 0); + } + + if (XMLConstants.XML_NS_PREFIX.equals(prefix) + && !XMLConstants.XML_NS_URI.equals(namespace)) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "xml namespace is always " + + XMLConstants.XML_NS_URI, this, 0); + } + + if (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix)) + { + if (namespace != null || getNodeType() != ATTRIBUTE_NODE) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "xmlns attribute prefix is reserved", + this, 0); + } + } + else if (getNodeType () == ATTRIBUTE_NODE + && (XMLConstants.XMLNS_ATTRIBUTE.equals(name) || + name.startsWith("xmlns:"))) + { + throw new DomDOMException(DOMException.NAMESPACE_ERR, + "namespace declarations can't change names", + this, 0); + } + + this.prefix = prefix.intern(); + } + + /** + * DOM L2 + * Returns the local part of the node's name (after any colon). + */ + public final String getLocalName() + { + return localName; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomProcessingInstruction.java b/libjava/classpath/gnu/xml/dom/DomProcessingInstruction.java new file mode 100644 index 000000000..6d443a293 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomProcessingInstruction.java @@ -0,0 +1,146 @@ +/* DomProcessingInstruction.java -- + Copyright (C) 1999,2000,2001,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.xml.dom; + +import org.w3c.dom.DOMException; +import org.w3c.dom.ProcessingInstruction; + +/** + *

      "ProcessingInstruction" (PI) implementation. + * This is a non-core DOM class, supporting the "XML" feature.

      + * + *

      Unlike other DOM APIs in the "XML" feature, this one fully + * exposes the functionality it describes. So there is no reason + * inherent in DOM to avoid using this API, unless you want to rely + * on NOTATION declarations to associate meaning with your PIs; + * there is no vendor-neutal way to record those notations in DOM.

      + * + *

      Also of note is that PI support is part of SAX, so that XML + * systems using PIs can choose among multiple APIs.

      + * + * @see DomNotation + * + * @author David Brownell + * @author Chris Burdess + */ +public class DomProcessingInstruction + extends DomNode + implements ProcessingInstruction +{ + + private String target; + private String data; + + /** + * Constructs a ProcessingInstruction node associated with the + * specified document, with the specified data. + * + *

      This constructor should only be invoked by a Document object as + * part of its createProcessingInstruction functionality, or through + * a subclass which is similarly used in a "Sub-DOM" style layer. + */ + protected DomProcessingInstruction(DomDocument owner, + String target, String data) + { + super(PROCESSING_INSTRUCTION_NODE, owner); + this.target = target; + this.data = data; + } + + /** + * DOM L1 + * Returns the target of the processing instruction. + */ + public final String getTarget() + { + return target; + } + + /** + * DOM L1 + * Returns the target of the processing instruction + * (same as getTarget). + */ + public final String getNodeName() + { + return target; + } + + /** + * DOM L1 + * Returns the data associated with the processing instruction. + */ + public final String getData() + { + return data; + } + + /** + * DOM L1 + * Returns the data associated with the processing instruction + * (same as getData). + */ + public final String getNodeValue() + { + return data; + } + + /** + * DOM L1 + * Assigns the data associated with the processing instruction; + * same as setNodeValue. + */ + public final void setData(String data) + { + setNodeValue(data); + } + + /** + * DOM L1 + * Assigns the data associated with the processing instruction. + */ + public final void setNodeValue(String data) + { + if (isReadonly()) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + this.data = data; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomText.java b/libjava/classpath/gnu/xml/dom/DomText.java new file mode 100644 index 000000000..b74c5b4c2 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomText.java @@ -0,0 +1,222 @@ +/* DomText.java -- + Copyright (C) 1999, 2000, 2001, 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.xml.dom; + +import gnu.java.lang.CPStringBuilder; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Text; + +/** + *

      "Text" implementation.

      + * + * @author David Brownell + * @author Chris Burdess + */ +public class DomText + extends DomCharacterData + implements Text +{ + + // NOTE: deleted unused per-instance "isIgnorable" + // support to reclaim its space. + + /** + * Constructs a text node associated with the specified + * document and holding the specified data. + * + *

      This constructor should only be invoked by a Document object + * as part of its createTextNode functionality, or through a subclass + * which is similarly used in a "Sub-DOM" style layer. + */ + protected DomText(DomDocument owner, String value) + { + super(TEXT_NODE, owner, value); + } + + protected DomText(DomDocument owner, char[] buf, int off, int len) + { + super(TEXT_NODE, owner, buf, off, len); + } + + // Used by DomCDATA + DomText(short nodeType, DomDocument owner, String value) + { + super(nodeType, owner, value); + } + + DomText(short nodeType, DomDocument owner, char[] buf, int off, int len) + { + super(nodeType, owner, buf, off, len); + } + + /** + * DOM L1 + * Returns the string "#text". + */ + // can't be 'final' with CDATA subclassing + public String getNodeName() + { + return "#text"; + } + + /** + * DOM L1 + * Splits this text node in two parts at the offset, returning + * the new text node (the sibling with the second part). + */ + public Text splitText(int offset) + { + if (isReadonly()) + { + throw new DomDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR); + } + try + { + String text = getNodeValue(); + String before = text.substring(0, offset); + String after = text.substring(offset); + Text next; + + if (getNodeType() == TEXT_NODE) + { + next = owner.createTextNode(after); + } + else // CDATA_SECTION_NODE + { + next = owner.createCDATASection(after); + } + + if (this.next != null) + { + parent.insertBefore(next, this.next); + } + else + { + parent.appendChild(next); + } + setNodeValue(before); + return next; + + } + catch (IndexOutOfBoundsException x) + { + throw new DomDOMException(DOMException.INDEX_SIZE_ERR); + } + } + + // DOM Level 3 + + public boolean isElementContentWhitespace() + { + if (parent != null) + { + DomDoctype doctype = (DomDoctype) owner.getDoctype(); + if (doctype != null) + { + DTDElementTypeInfo info = + doctype.getElementTypeInfo(parent.getNodeName()); + if (info != null) + { + if (info.model == null && info.model.indexOf("#PCDATA") != -1) + { + return false; + } + return getNodeValue().trim().length() == 0; + } + } + } + return false; + } + + public String getWholeText() + { + DomNode ref = this; + DomNode ctx; + for (ctx = previous; ctx != null && + (ctx.nodeType == TEXT_NODE || ctx.nodeType == CDATA_SECTION_NODE); + ctx = ctx.previous) + { + ref = ctx; + } + CPStringBuilder buf = new CPStringBuilder(ref.getNodeValue()); + for (ctx = ref.next; ctx != null && + (ctx.nodeType == TEXT_NODE || ctx.nodeType == CDATA_SECTION_NODE); + ctx = ctx.next) + { + buf.append(ctx.getNodeValue()); + } + return buf.toString (); + } + + public Text replaceWholeText(String content) + throws DOMException + { + boolean isEmpty = (content == null || content.length () == 0); + if (!isEmpty) + { + setNodeValue(content); + } + + DomNode ref = this; + DomNode ctx; + for (ctx = previous; ctx != null && + (ctx.nodeType == TEXT_NODE || ctx.nodeType == CDATA_SECTION_NODE); + ctx = ctx.previous) + { + ref = ctx; + } + ctx = ref.next; + if ((isEmpty || ref != this) && parent != null) + { + parent.removeChild(ref); + } + for (; ctx != null && + (ctx.nodeType == TEXT_NODE || ctx.nodeType == CDATA_SECTION_NODE); + ctx = ref) + { + ref = ctx.next; + if ((isEmpty || ctx != this) && parent != null) + { + parent.removeChild(ctx); + } + } + return (isEmpty) ? null : this; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomXPathExpression.java b/libjava/classpath/gnu/xml/dom/DomXPathExpression.java new file mode 100644 index 000000000..0b6962930 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomXPathExpression.java @@ -0,0 +1,147 @@ +/* DomXPathExpression.java -- + 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.xml.dom; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import javax.xml.namespace.QName; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpression; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.xpath.XPathException; +import org.w3c.dom.xpath.XPathNSResolver; +import org.w3c.dom.xpath.XPathResult; +import gnu.xml.xpath.DocumentOrderComparator; + +/** + * An XPath expression. + * + * @author Chris Burdess + */ +class DomXPathExpression +implements org.w3c.dom.xpath.XPathExpression +{ + + final DomDocument doc; + final XPathExpression expression; + final XPathNSResolver resolver; + + DomXPathExpression(DomDocument doc, String expression, + XPathNSResolver resolver) + throws XPathException + { + this.doc = doc; + this.resolver = resolver; + + XPathFactory factory = XPathFactory.newInstance(); + XPath xpath = factory.newXPath(); + if (resolver != null) + { + xpath.setNamespaceContext(new DomNSResolverContext(resolver)); + } + try + { + this.expression = xpath.compile(expression); + } + catch (XPathExpressionException e) + { + throw new XPathException(XPathException.INVALID_EXPRESSION_ERR, + e.getMessage ()); + } + } + + public Object evaluate(Node contextNode, short type, Object result) + throws XPathException, DOMException + { + try + { + QName typeName = null; + switch (type) + { + case XPathResult.BOOLEAN_TYPE: + typeName = XPathConstants.BOOLEAN; + break; + case XPathResult.NUMBER_TYPE: + typeName = XPathConstants.NUMBER; + break; + case XPathResult.STRING_TYPE: + typeName = XPathConstants.STRING; + break; + case XPathResult.ANY_UNORDERED_NODE_TYPE: + case XPathResult.FIRST_ORDERED_NODE_TYPE: + typeName = XPathConstants.NODE; + break; + case XPathResult.UNORDERED_NODE_ITERATOR_TYPE: + case XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE: + case XPathResult.ORDERED_NODE_ITERATOR_TYPE: + case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE: + typeName = XPathConstants.NODESET; + break; + default: + throw new XPathException(XPathException.TYPE_ERR, null); + } + Object val = expression.evaluate(contextNode, typeName); + switch (type) + { + case XPathResult.ORDERED_NODE_ITERATOR_TYPE: + case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE: + // Sort the nodes + List ns = new ArrayList((Collection) val); + Collections.sort(ns, new DocumentOrderComparator()); + val = ns; + } + return new DomXPathResult(val, type); + } + catch (javax.xml.xpath.XPathException e) + { + throw new XPathException(XPathException.TYPE_ERR, e.getMessage()); + } + } + + public String toString () + { + return getClass ().getName () + "[expression=" + expression + "]"; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomXPathNSResolver.java b/libjava/classpath/gnu/xml/dom/DomXPathNSResolver.java new file mode 100644 index 000000000..fb0719a4e --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomXPathNSResolver.java @@ -0,0 +1,64 @@ +/* DomXPathNSResolver.java -- + 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.xml.dom; + +import org.w3c.dom.Node; +import org.w3c.dom.xpath.XPathNSResolver; + +/** + * Generic XPath namespace resolver using a DOM Node. + * + * @author Chris Burdess + */ +class DomXPathNSResolver +implements XPathNSResolver +{ + + Node node; + + DomXPathNSResolver (Node node) + { + this.node = node; + } + + public String lookupNamespaceURI (String prefix) + { + return node.lookupNamespaceURI (prefix); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/DomXPathResult.java b/libjava/classpath/gnu/xml/dom/DomXPathResult.java new file mode 100644 index 000000000..da8fcf513 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/DomXPathResult.java @@ -0,0 +1,233 @@ +/* DomXPathResult.java -- + 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.xml.dom; + +import java.util.Collection; +import java.util.Iterator; +import org.w3c.dom.Node; +import org.w3c.dom.xpath.XPathException; +import org.w3c.dom.xpath.XPathResult; + +/** + * An XPath result object. + * + * @author Chris Burdess + */ +class DomXPathResult +implements XPathResult +{ + + final Object value; + final short type; + Iterator iterator; + + DomXPathResult (Object value, short requestedType) + { + this.value = value; + if (value instanceof Boolean) + { + type = XPathResult.BOOLEAN_TYPE; + } + else if (value instanceof Double) + { + type = XPathResult.NUMBER_TYPE; + } + else if (value instanceof String) + { + type = XPathResult.STRING_TYPE; + } + else if (value instanceof Collection) + { + Collection ns = (Collection) value; + switch (requestedType) + { + case XPathResult.ANY_TYPE: + case XPathResult.ANY_UNORDERED_NODE_TYPE: + type = (ns.size () == 1) ? XPathResult.FIRST_ORDERED_NODE_TYPE : + XPathResult.ORDERED_NODE_ITERATOR_TYPE; + break; + default: + type = requestedType; + } + iterator = ns.iterator (); + } + else + { + throw new IllegalArgumentException (); + } + } + + public boolean getBooleanValue() + { + if (type == XPathResult.BOOLEAN_TYPE) + { + return ((Boolean) value).booleanValue (); + } + throw new XPathException (XPathException.TYPE_ERR, value.toString ()); + } + + public boolean getInvalidIteratorState() + { + return iterator == null; + } + + public double getNumberValue() + { + if (type == XPathResult.NUMBER_TYPE) + { + return ((Double) value).doubleValue (); + } + throw new XPathException (XPathException.TYPE_ERR, value.toString ()); + } + + public short getResultType() + { + return type; + } + + public Node getSingleNodeValue() + { + switch (type) + { + case XPathResult.FIRST_ORDERED_NODE_TYPE: + case XPathResult.ORDERED_NODE_ITERATOR_TYPE: + case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE: + case XPathResult.UNORDERED_NODE_ITERATOR_TYPE: + case XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE: + Collection ns = (Collection) value; + if (ns.isEmpty ()) + { + return null; + } + else + { + return (Node) ns.iterator ().next (); + } + } + throw new XPathException (XPathException.TYPE_ERR, value.toString ()); + } + + public int getSnapshotLength() + { + switch (type) + { + case XPathResult.FIRST_ORDERED_NODE_TYPE: + case XPathResult.ORDERED_NODE_ITERATOR_TYPE: + case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE: + case XPathResult.UNORDERED_NODE_ITERATOR_TYPE: + case XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE: + return ((Collection) value).size (); + } + throw new XPathException (XPathException.TYPE_ERR, value.toString ()); + } + + public String getStringValue() + { + if (type == XPathResult.STRING_TYPE) + { + return (String) value; + } + throw new XPathException (XPathException.TYPE_ERR, value.toString ()); + } + + public Node iterateNext() + { + if (iterator != null) + { + if (iterator.hasNext ()) + { + return (Node) iterator.next (); + } + else + { + iterator = null; + return null; + } + } + throw new XPathException (XPathException.TYPE_ERR, value.toString ()); + } + + public Node snapshotItem(int index) + { + switch (type) + { + case XPathResult.FIRST_ORDERED_NODE_TYPE: + case XPathResult.ORDERED_NODE_ITERATOR_TYPE: + case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE: + case XPathResult.UNORDERED_NODE_ITERATOR_TYPE: + case XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE: + Collection ns = (Collection) value; + Node[] nodes = new Node[ns.size ()]; + ns.toArray (nodes); + return nodes[index]; + } + throw new XPathException (XPathException.TYPE_ERR, value.toString ()); + } + + public String toString () + { + return getClass ().getName () + "[type=" + typeName (type) + ",value=" + + value + ']'; + } + + private String typeName (short type) + { + switch (type) + { + case XPathResult.BOOLEAN_TYPE: + return "BOOLEAN_TYPE"; + case XPathResult.NUMBER_TYPE: + return "NUMBER_TYPE"; + case XPathResult.STRING_TYPE: + return "STRING_TYPE"; + case XPathResult.FIRST_ORDERED_NODE_TYPE: + return "FIRST_ORDERED_NODE_TYPE"; + case XPathResult.ORDERED_NODE_ITERATOR_TYPE: + return "ORDERED_NODE_ITERATOR_TYPE"; + case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE: + return "ORDERED_NODE_SNAPSHOT_TYPE"; + case XPathResult.UNORDERED_NODE_ITERATOR_TYPE: + return "UNORDERED_NODE_ITERATOR_TYPE"; + case XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE: + return "UNORDERED_NODE_SNAPSHOT_TYPE"; + default: + return "(unknown)"; + } + } + +} diff --git a/libjava/classpath/gnu/xml/dom/ImplementationList.java b/libjava/classpath/gnu/xml/dom/ImplementationList.java new file mode 100644 index 000000000..c99f55d0d --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/ImplementationList.java @@ -0,0 +1,70 @@ +/* ImplementationList.java -- + 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.xml.dom; + +import java.util.List; + +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.DOMImplementationList; + +/** + * Implementation list for GNU JAXP. + * + * @author Chris Burdess + */ +public class ImplementationList + implements DOMImplementationList +{ + + private List list; + + ImplementationList(List list) + { + this.list = list; + } + + public int getLength() + { + return list.size(); + } + + public DOMImplementation item(int index) + { + return (DOMImplementation) list.get(index); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/ImplementationSource.java b/libjava/classpath/gnu/xml/dom/ImplementationSource.java new file mode 100644 index 000000000..5f404423a --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/ImplementationSource.java @@ -0,0 +1,167 @@ +/* ImplementationSource.java -- + 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.xml.dom; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.DOMImplementationList; +import org.w3c.dom.DOMImplementationSource; + +/** + * Implementation source for GNU JAXP. + * + * @author Chris Burdess + */ +public class ImplementationSource + implements DOMImplementationSource +{ + + private static final String DIGITS = "1234567890"; + + /* + * GNU DOM implementations. + */ + private static final DOMImplementation[] implementations; + + static + { + List acc = new ArrayList(); + acc.add(new gnu.xml.dom.DomImpl()); + try + { + Class t = Class.forName("gnu.xml.libxmlj.dom.GnomeDocumentBuilder"); + acc.add(t.newInstance()); + } + catch (Exception e) + { + // libxmlj not available + } + catch (UnsatisfiedLinkError e) + { + // libxmlj not available + } + implementations = new DOMImplementation[acc.size()]; + acc.toArray(implementations); + } + + public DOMImplementation getDOMImplementation(String features) + { + List available = getImplementations(features); + if (available.isEmpty()) + { + return null; + } + return (DOMImplementation) available.get(0); + } + + public DOMImplementationList getDOMImplementationList(String features) + { + List available = getImplementations(features); + return new ImplementationList(available); + } + + /** + * Returns a list of the implementations that support the specified + * features. + */ + private final List getImplementations(String features) + { + List available = new ArrayList(Arrays.asList(implementations)); + for (Iterator i = parseFeatures(features).iterator(); i.hasNext(); ) + { + String feature = (String) i.next(); + String version = null; + int si = feature.indexOf(' '); + if (si != -1) + { + version = feature.substring(si + 1); + feature = feature.substring(0, si); + } + for (Iterator j = available.iterator(); j.hasNext(); ) + { + DOMImplementation impl = (DOMImplementation) j.next(); + if (!impl.hasFeature(feature, version)) + { + j.remove(); + } + } + } + return available; + } + + /** + * Parses the feature list into feature tokens. + */ + final List parseFeatures(String features) + { + List list = new ArrayList(); + int pos = 0, start = 0; + int len = features.length(); + for (; pos < len; pos++) + { + char c = features.charAt(pos); + if (c == ' ') + { + if (pos + 1 < len && + DIGITS.indexOf(features.charAt(pos + 1)) == -1) + { + list.add(getFeature(features, start, pos)); + start = pos + 1; + } + } + } + if (pos > start) + { + list.add(getFeature(features, start, len)); + } + return list; + } + + final String getFeature(String features, int start, int end) + { + if (features.length() > 0 && features.charAt(start) == '+') + { + return features.substring(start + 1, end); + } + return features.substring(start, end); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/JAXPFactory.java b/libjava/classpath/gnu/xml/dom/JAXPFactory.java new file mode 100644 index 000000000..d7d399b5b --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/JAXPFactory.java @@ -0,0 +1,308 @@ +/* JAXPFactory.java -- + Copyright (C) 2001 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.dom; + +import java.io.IOException; + +import org.w3c.dom.Document; +import org.w3c.dom.DOMImplementation; + +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +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; +import javax.xml.parsers.SAXParserFactory; + + +/** + * DOM bootstrapping API, for use with JAXP. + * + * @see Consumer + * + * @author David Brownell + */ +public final class JAXPFactory + extends DocumentBuilderFactory +{ + + private static final String PROPERTY = "http://xml.org/sax/properties/"; + private static final String FEATURE = "http://xml.org/sax/features/"; + + private SAXParserFactory pf; + private boolean secureProcessing; + + /** + * Default constructor. + */ + public JAXPFactory() + { + } + + /** + * Constructs a JAXP document builder which uses the default + * JAXP SAX2 parser and the DOM implementation in this package. + */ + public DocumentBuilder newDocumentBuilder() + throws ParserConfigurationException + { + if (pf == null) + { + // Force use of AElfred2 since not all JAXP parsers + // conform very well to the SAX2 API spec ... + pf = new gnu.xml.aelfred2.JAXPFactory(); + // pf = SAXParserFactory.newInstance (); + } + + // JAXP default: false + pf.setValidating(isValidating()); + + // FIXME: this namespace setup may cause errors in some + // conformant SAX2 parsers, which we CAN patch up by + // splicing a "NSFilter" stage up front ... + + // JAXP default: false + pf.setNamespaceAware(isNamespaceAware()); + + try + { + // undo rude "namespace-prefixes=false" default + pf.setFeature(FEATURE + "namespace-prefixes", true); + + return new JAXPBuilder(pf.newSAXParser().getXMLReader(), this); + } + catch (SAXException e) + { + String msg = "can't create JAXP DocumentBuilder: " + e.getMessage(); + throw new ParserConfigurationException(msg); + } + } + + /** There seems to be no useful specification for attribute names */ + public void setAttribute(String name, Object value) + throws IllegalArgumentException + { + if ("http://java.sun.com/xml/jaxp/properties/schemaLanguage".equals(name)) + { + // TODO + } + else + { + throw new IllegalArgumentException(name); + } + } + + /** There seems to be no useful specification for attribute names */ + public Object getAttribute(String name) + throws IllegalArgumentException + { + 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 + { + + private Consumer consumer; + private XMLReader producer; + private DomImpl impl; + + JAXPBuilder(XMLReader parser, JAXPFactory factory) + throws ParserConfigurationException + { + impl = new DomImpl(); + + // set up consumer side + try + { + consumer = new Consumer(); + } + catch (SAXException e) + { + throw new ParserConfigurationException(e.getMessage()); + } + + // JAXP defaults: true, noise nodes are good (bleech) + consumer.setHidingReferences(factory.isExpandEntityReferences()); + consumer.setHidingComments(factory.isIgnoringComments()); + consumer.setHidingWhitespace(factory.isIgnoringElementContentWhitespace()); + consumer.setHidingCDATA(factory.isCoalescing()); + + // set up producer side + producer = parser; + producer.setContentHandler(consumer.getContentHandler()); + producer.setDTDHandler(consumer.getDTDHandler()); + + try + { + String id; + + // if validating, report validity errors, and default + // to treating them as fatal + if (factory.isValidating ()) + { + producer.setFeature(FEATURE + "validation", true); + producer.setErrorHandler(this); + } + + // always save prefix info, maybe do namespace processing + producer.setFeature(FEATURE + "namespace-prefixes", true); + producer.setFeature(FEATURE + "namespaces", + factory.isNamespaceAware()); + + // set important handlers + id = PROPERTY + "lexical-handler"; + producer.setProperty(id, consumer.getProperty(id)); + + id = PROPERTY + "declaration-handler"; + producer.setProperty(id, consumer.getProperty(id)); + + } + catch (SAXException e) + { + throw new ParserConfigurationException(e.getMessage()); + } + } + + public Document parse(InputSource source) + throws SAXException, IOException + { + producer.parse(source); + Document doc = consumer.getDocument(); + // TODO inputEncoding + doc.setDocumentURI(source.getSystemId()); + return doc; + } + + public boolean isNamespaceAware() + { + try + { + return producer.getFeature(FEATURE + "namespaces"); + } + catch (SAXException e) + { + // "can't happen" + throw new RuntimeException(e.getMessage()); + } + } + + public boolean isValidating() + { + try + { + return producer.getFeature(FEATURE + "validation"); + } + catch (SAXException e) + { + // "can't happen" + throw new RuntimeException(e.getMessage()); + } + } + + public void setEntityResolver(EntityResolver resolver) + { + producer.setEntityResolver(resolver); + } + + public void setErrorHandler(ErrorHandler handler) + { + producer.setErrorHandler(handler); + consumer.setErrorHandler(handler); + } + + public DOMImplementation getDOMImplementation() + { + return impl; + } + + public Document newDocument() + { + return new DomDocument(); + } + + // implementation of error handler that's used when validating + public void fatalError(SAXParseException e) + throws SAXException + { + throw e; + } + + public void error(SAXParseException e) + throws SAXException + { + throw e; + } + + public void warning(SAXParseException e) + throws SAXException + { + /* ignore */ + } + + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLAnchorElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLAnchorElement.java new file mode 100644 index 000000000..4448dd580 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLAnchorElement.java @@ -0,0 +1,188 @@ +/* DomHTMLAnchorElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLAnchorElement; + +/** + * An HTML 'A' element node. + * + * @author Chris Burdess + */ +public class DomHTMLAnchorElement + extends DomHTMLElement + implements HTMLAnchorElement +{ + + protected DomHTMLAnchorElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getAccessKey() + { + return getHTMLAttribute("accesskey"); + } + + public void setAccessKey(String accessKey) + { + setHTMLAttribute("accesskey", accessKey); + } + + public String getCharset() + { + return getHTMLAttribute("charset"); + } + + public void setCharset(String charset) + { + setHTMLAttribute("charset", charset); + } + + public String getCoords() + { + return getHTMLAttribute("coords"); + } + + public void setCoords(String coords) + { + setHTMLAttribute("coords", coords); + } + + public String getHref() + { + return getHTMLAttribute("href"); + } + + public void setHref(String href) + { + setHTMLAttribute("href", href); + } + + public String getHreflang() + { + return getHTMLAttribute("hreflang"); + } + + public void setHreflang(String hreflang) + { + setHTMLAttribute("hreflang", hreflang); + } + + public String getName() + { + return getHTMLAttribute("name"); + } + + public void setName(String name) + { + setHTMLAttribute("name", name); + } + + public String getRel() + { + return getHTMLAttribute("rel"); + } + + public void setRel(String rel) + { + setHTMLAttribute("rel", rel); + } + + public String getRev() + { + return getHTMLAttribute("rev"); + } + + public void setRev(String rev) + { + setHTMLAttribute("rev", rev); + } + + public String getShape() + { + return getHTMLAttribute("shape"); + } + + public void setShape(String shape) + { + setHTMLAttribute("shape", shape); + } + + public int getTabIndex() + { + return getIntHTMLAttribute("tabindex"); + } + + public void setTabIndex(int tabIndex) + { + setIntHTMLAttribute("tabindex", tabIndex); + } + + public String getTarget() + { + return getHTMLAttribute("target"); + } + + public void setTarget(String target) + { + setHTMLAttribute("target", target); + } + + public String getType() + { + return getHTMLAttribute("type"); + } + + public void setType(String type) + { + setHTMLAttribute("type", type); + } + + public void blur() + { + dispatchUIEvent("blur"); + } + + public void focus() + { + dispatchUIEvent("focus"); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLAppletElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLAppletElement.java new file mode 100644 index 000000000..429fb0038 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLAppletElement.java @@ -0,0 +1,187 @@ +/* DomHTMLAppletElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLAppletElement; + +/** + * An HTML 'APPLET' element node. + * + * @author Chris Burdess + */ +public class DomHTMLAppletElement + extends DomHTMLElement + implements HTMLAppletElement +{ + + protected DomHTMLAppletElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getAlign() + { + return getHTMLAttribute("align"); + } + + public void setAlign(String align) + { + setHTMLAttribute("align", align); + } + + public String getCls() + { + return getHTMLAttribute("class"); + } + + public void setCls(String cls) + { + setHTMLAttribute("class", cls); + } + + public String getSrc() + { + return getHTMLAttribute("src"); + } + + public void setSrc(String src) + { + setHTMLAttribute("src", src); + } + + public String getAlt() + { + return getHTMLAttribute("alt"); + } + + public void setAlt(String alt) + { + setHTMLAttribute("alt", alt); + } + + public String getArchive() + { + return getHTMLAttribute("archive"); + } + + public void setArchive(String archive) + { + setHTMLAttribute("archive", archive); + } + + public String getCode() + { + return getHTMLAttribute("code"); + } + + public void setCode(String code) + { + setHTMLAttribute("code", code); + } + + public String getCodeBase() + { + return getHTMLAttribute("codebase"); + } + + public void setCodeBase(String codeBase) + { + setHTMLAttribute("codebase", codeBase); + } + + public String getHeight() + { + return getHTMLAttribute("height"); + } + + public void setHeight(String height) + { + setHTMLAttribute("height", height); + } + + public int getHspace() + { + return getIntHTMLAttribute("hspace"); + } + + public void setHspace(int hspace) + { + setIntHTMLAttribute("hspace", hspace); + } + + public String getName() + { + return getHTMLAttribute("name"); + } + + public void setName(String name) + { + setHTMLAttribute("name", name); + } + + public String getObject() + { + return getHTMLAttribute("object"); + } + + public void setObject(String object) + { + setHTMLAttribute("object", object); + } + + public int getVspace() + { + return getIntHTMLAttribute("vspace"); + } + + public void setVspace(int vspace) + { + setIntHTMLAttribute("vspace", vspace); + } + + public String getWidth() + { + return getHTMLAttribute("width"); + } + + public void setWidth(String width) + { + setHTMLAttribute("width", width); + } +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLAreaElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLAreaElement.java new file mode 100644 index 000000000..728b3fdfc --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLAreaElement.java @@ -0,0 +1,138 @@ +/* DomHTMLAreaElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLAreaElement; + +/** + * An HTML 'AREA' element node. + * + * @author Chris Burdess + */ +public class DomHTMLAreaElement + extends DomHTMLElement + implements HTMLAreaElement +{ + + protected DomHTMLAreaElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getAccessKey() + { + return getHTMLAttribute("accesskey"); + } + + public void setAccessKey(String accessKey) + { + setHTMLAttribute("accesskey", accessKey); + } + + public String getAlt() + { + return getHTMLAttribute("alt"); + } + + public void setAlt(String alt) + { + setHTMLAttribute("alt", alt); + } + + public String getCoords() + { + return getHTMLAttribute("coords"); + } + + public void setCoords(String coords) + { + setHTMLAttribute("coords", coords); + } + + public String getHref() + { + return getHTMLAttribute("href"); + } + + public void setHref(String href) + { + setHTMLAttribute("href", href); + } + + public boolean getNoHref() + { + return getBooleanHTMLAttribute("nohref"); + } + + public void setNoHref(boolean nohref) + { + setBooleanHTMLAttribute("nohref", nohref); + } + + public String getShape() + { + return getHTMLAttribute("shape"); + } + + public void setShape(String shape) + { + setHTMLAttribute("shape", shape); + } + + public int getTabIndex() + { + return getIntHTMLAttribute("tabindex"); + } + + public void setTabIndex(int tabIndex) + { + setIntHTMLAttribute("tabindex", tabIndex); + } + + public String getTarget() + { + return getHTMLAttribute("target"); + } + + public void setTarget(String target) + { + setHTMLAttribute("target", target); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLBRElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLBRElement.java new file mode 100644 index 000000000..5ad49c549 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLBRElement.java @@ -0,0 +1,68 @@ +/* DomHTMLBRElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLBRElement; + +/** + * An HTML 'BR' element node. + * + * @author Chris Burdess + */ +public class DomHTMLBRElement + extends DomHTMLElement + implements HTMLBRElement +{ + + protected DomHTMLBRElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getClear() + { + return getHTMLAttribute("clear"); + } + + public void setClear(String clear) + { + setHTMLAttribute("clear", clear); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLBaseElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLBaseElement.java new file mode 100644 index 000000000..99a0993ba --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLBaseElement.java @@ -0,0 +1,78 @@ +/* DomHTMLBaseElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLBaseElement; + +/** + * An HTML 'BASE' element node. + * + * @author Chris Burdess + */ +public class DomHTMLBaseElement + extends DomHTMLElement + implements HTMLBaseElement +{ + + protected DomHTMLBaseElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getHref() + { + return getHTMLAttribute("href"); + } + + public void setHref(String href) + { + setHTMLAttribute("href", href); + } + + public String getTarget() + { + return getHTMLAttribute("target"); + } + + public void setTarget(String target) + { + setHTMLAttribute("target", target); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLBaseFontElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLBaseFontElement.java new file mode 100644 index 000000000..73ec96dbd --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLBaseFontElement.java @@ -0,0 +1,88 @@ +/* DomHTMLBaseFontElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLBaseFontElement; + +/** + * An HTML 'BASEFONT' element node. + * + * @author Chris Burdess + */ +public class DomHTMLBaseFontElement + extends DomHTMLElement + implements HTMLBaseFontElement +{ + + protected DomHTMLBaseFontElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getColor() + { + return getHTMLAttribute("color"); + } + + public void setColor(String color) + { + setHTMLAttribute("color", color); + } + + public String getFace() + { + return getHTMLAttribute("face"); + } + + public void setFace(String face) + { + setHTMLAttribute("face", face); + } + + public int getSize() + { + return getIntHTMLAttribute("size"); + } + + public void setSize(int size) + { + setIntHTMLAttribute("size", size); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLBodyElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLBodyElement.java new file mode 100644 index 000000000..d4528625b --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLBodyElement.java @@ -0,0 +1,118 @@ +/* DomHTMLBodyElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLBodyElement; + +/** + * An HTML 'BODY' element node. + * + * @author Chris Burdess + */ +public class DomHTMLBodyElement + extends DomHTMLElement + implements HTMLBodyElement +{ + + protected DomHTMLBodyElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getALink() + { + return getHTMLAttribute("alink"); + } + + public void setALink(String alink) + { + setHTMLAttribute("alink", alink); + } + + public String getBackground() + { + return getHTMLAttribute("background"); + } + + public void setBackground(String background) + { + setHTMLAttribute("background", background); + } + + public String getBgColor() + { + return getHTMLAttribute("bgcolor"); + } + + public void setBgColor(String bgcolor) + { + setHTMLAttribute("bgcolor", bgcolor); + } + + public String getLink() + { + return getHTMLAttribute("link"); + } + + public void setLink(String link) + { + setHTMLAttribute("link", link); + } + + public String getText() + { + return getHTMLAttribute("text"); + } + + public void setText(String text) + { + setHTMLAttribute("text", text); + } + + public String getVLink() + { + return getHTMLAttribute("vlink"); + } + + public void setVLink(String vlink) + { + setHTMLAttribute("vlink", vlink); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLButtonElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLButtonElement.java new file mode 100644 index 000000000..696169ac2 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLButtonElement.java @@ -0,0 +1,119 @@ +/* DomHTMLButtonElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLButtonElement; +import org.w3c.dom.html2.HTMLFormElement; + +/** + * An HTML 'BUTTON' element node. + * + * @author Chris Burdess + */ +public class DomHTMLButtonElement + extends DomHTMLElement + implements HTMLButtonElement +{ + + protected DomHTMLButtonElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public HTMLFormElement getForm() + { + return (HTMLFormElement) getParentElement("form"); + } + + public String getAccessKey() + { + return getHTMLAttribute("accesskey"); + } + + public void setAccessKey(String accessKey) + { + setHTMLAttribute("accesskey", accessKey); + } + + public boolean getDisabled() + { + return getBooleanHTMLAttribute("disabled"); + } + + public void setDisabled(boolean disabled) + { + setBooleanHTMLAttribute("disabled", disabled); + } + + public String getName() + { + return getHTMLAttribute("name"); + } + + public void setName(String name) + { + setHTMLAttribute("name", name); + } + + public int getTabIndex() + { + return getIntHTMLAttribute("tabindex"); + } + + public void setTabIndex(int tabIndex) + { + setIntHTMLAttribute("tabindex", tabIndex); + } + + public String getType() + { + return getHTMLAttribute("type"); + } + + public String getValue() + { + return getHTMLAttribute("value"); + } + + public void setValue(String value) + { + setHTMLAttribute("value", value); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLCollection.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLCollection.java new file mode 100644 index 000000000..830028753 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLCollection.java @@ -0,0 +1,225 @@ +/* DomHTMLCollection.java -- + 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.xml.dom.html2; + +import gnu.xml.dom.DomDOMException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import org.w3c.dom.DOMException; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.html2.HTMLCollection; +import org.w3c.dom.html2.HTMLOptionsCollection; +import org.w3c.dom.traversal.NodeFilter; +import org.w3c.dom.traversal.NodeIterator; + +/** + * An HTML element collection. + * + * @author Chris Burdess + */ +class DomHTMLCollection + implements HTMLCollection, HTMLOptionsCollection, NodeList, NodeFilter +{ + + final DomHTMLDocument doc; + final Node root; + List nodeNames; + List attributeNames; + List results; + + DomHTMLCollection(DomHTMLDocument doc, Node root) + { + this.doc = doc; + this.root = root; + } + + // -- Node name and attribute filtering -- + + void addNodeName(String name) + { + if (nodeNames == null) + { + nodeNames = new LinkedList(); + } + nodeNames.add(name); + } + + void addAttributeName(String name) + { + if (attributeNames == null) + { + attributeNames = new LinkedList(); + } + attributeNames.add(name); + } + + public short acceptNode(Node n) + { + if (n.getNodeType() != Node.ELEMENT_NODE) + { + return NodeFilter.FILTER_SKIP; + } + String localName = n.getLocalName(); + if (localName == null) + { + localName = n.getNodeName(); + } + if (nodeNames != null && !acceptName(localName)) + { + return NodeFilter.FILTER_SKIP; + } + if (attributeNames != null && !acceptAttributes(n.getAttributes())) + { + return NodeFilter.FILTER_SKIP; + } + return NodeFilter.FILTER_ACCEPT; + } + + private boolean acceptName(String name) + { + for (Iterator i = nodeNames.iterator(); i.hasNext(); ) + { + String nodeName = (String) i.next(); + if (nodeName.equalsIgnoreCase(name)) + { + return true; + } + } + return false; + } + + private boolean acceptAttributes(NamedNodeMap attrs) + { + for (Iterator i = attributeNames.iterator(); i.hasNext(); ) + { + String attributeName = (String) i.next(); + Node attr = getNamedItem(attrs, attributeName); + if (attr != null) + { + // Check that attribute has a non-null value + String nodeValue = attr.getNodeValue(); + if (nodeValue != null && nodeValue.length() > 0) + { + return true; + } + } + } + return false; + } + + /** + * Case-insensitive version of getNamedItem. + */ + private Node getNamedItem(NamedNodeMap attrs, String name) + { + int len = attrs.getLength(); + for (int i = 0; i < len; i++) + { + Node attr = attrs.item(i); + String attrName = attr.getLocalName(); + if (attrName == null) + { + attrName = attr.getNodeName(); + } + if (name.equalsIgnoreCase(attrName)) + { + return attr; + } + } + return null; + } + + // -- Perform query -- + + void evaluate() + { + NodeIterator i = doc.createNodeIterator(root, NodeFilter.SHOW_ELEMENT, + this, true); + results = new ArrayList(); + for (Node node = i.nextNode(); node != null; node = i.nextNode()) + { + results.add(node); + } + } + + // -- HTMLCollection/NodeList interface -- + + public int getLength() + { + return results.size(); + } + + public void setLength(int length) + { + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR); + } + + public Node item(int index) + { + return (Node) results.get(index); + } + + public Node namedItem(String name) + { + boolean xhtml = false; // FIXME detect XHTML document + for (Iterator i = results.iterator(); i.hasNext(); ) + { + Node node = (Node) i.next(); + NamedNodeMap attrs = node.getAttributes(); + Node attr = getNamedItem(attrs, "id"); + if (name.equals(attr.getTextContent())) + { + return node; + } + if (!xhtml) + { + attr = getNamedItem(attrs, "name"); + if (name.equals(attr.getTextContent())) + { + return node; + } + } + } + return null; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLDListElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLDListElement.java new file mode 100644 index 000000000..9acce856a --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLDListElement.java @@ -0,0 +1,68 @@ +/* DomHTMLDListElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLDListElement; + +/** + * An HTML 'DL' element node. + * + * @author Chris Burdess + */ +public class DomHTMLDListElement + extends DomHTMLElement + implements HTMLDListElement +{ + + protected DomHTMLDListElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public boolean getCompact() + { + return getBooleanHTMLAttribute("compact"); + } + + public void setCompact(boolean compact) + { + setBooleanHTMLAttribute("compact", compact); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLDirectoryElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLDirectoryElement.java new file mode 100644 index 000000000..e0f94a1ed --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLDirectoryElement.java @@ -0,0 +1,68 @@ +/* DomHTMLDirectoryElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLDirectoryElement; + +/** + * An HTML 'DIR' element node. + * + * @author Chris Burdess + */ +public class DomHTMLDirectoryElement + extends DomHTMLElement + implements HTMLDirectoryElement +{ + + protected DomHTMLDirectoryElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public boolean getCompact() + { + return getBooleanHTMLAttribute("compact"); + } + + public void setCompact(boolean compact) + { + setBooleanHTMLAttribute("compact", compact); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLDivElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLDivElement.java new file mode 100644 index 000000000..66b3ac743 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLDivElement.java @@ -0,0 +1,68 @@ +/* DomHTMLDivElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLDivElement; + +/** + * An HTML 'DIV' element node. + * + * @author Chris Burdess + */ +public class DomHTMLDivElement + extends DomHTMLElement + implements HTMLDivElement +{ + + protected DomHTMLDivElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getAlign() + { + return getHTMLAttribute("align"); + } + + public void setAlign(String align) + { + setHTMLAttribute("align", align); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLDocument.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLDocument.java new file mode 100644 index 000000000..1afed7beb --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLDocument.java @@ -0,0 +1,426 @@ +/* DomHTMLDocument.java -- + 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.xml.dom.html2; + +import gnu.xml.dom.DomDocument; +import gnu.xml.dom.DomDOMException; +import java.lang.reflect.Constructor; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import org.w3c.dom.DOMException; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.html2.HTMLCollection; +import org.w3c.dom.html2.HTMLDocument; +import org.w3c.dom.html2.HTMLElement; + +/** + * An HTML document. + * This is the factory object used to create HTML elements. + * + * @author Chris Burdess + */ +public class DomHTMLDocument + extends DomDocument + implements HTMLDocument +{ + + private static final Class[] ELEMENT_PT = new Class[] { + DomHTMLDocument.class, + String.class, + String.class + }; + + private static Map ELEMENT_CLASSES; + static + { + Map map = new HashMap(); + map.put("a", DomHTMLAnchorElement.class); + map.put("applet", DomHTMLAppletElement.class); + map.put("area", DomHTMLAreaElement.class); + map.put("base", DomHTMLBaseElement.class); + map.put("basefont", DomHTMLBaseFontElement.class); + map.put("body", DomHTMLBodyElement.class); + map.put("br", DomHTMLBRElement.class); + map.put("button", DomHTMLButtonElement.class); + map.put("dir", DomHTMLDirectoryElement.class); + map.put("div", DomHTMLDivElement.class); + map.put("dlist", DomHTMLDListElement.class); + map.put("embed", DomHTMLEmbedElement.class); + map.put("fieldset", DomHTMLFieldSetElement.class); + map.put("font", DomHTMLFontElement.class); + map.put("form", DomHTMLFormElement.class); + map.put("frame", DomHTMLFrameElement.class); + map.put("frameset", DomHTMLFrameSetElement.class); + map.put("head", DomHTMLHeadElement.class); + map.put("h1", DomHTMLHeadingElement.class); + map.put("h2", DomHTMLHeadingElement.class); + map.put("h3", DomHTMLHeadingElement.class); + map.put("h4", DomHTMLHeadingElement.class); + map.put("h5", DomHTMLHeadingElement.class); + map.put("h6", DomHTMLHeadingElement.class); + map.put("html", DomHTMLHtmlElement.class); + map.put("iframe", DomHTMLIFrameElement.class); + map.put("img", DomHTMLImageElement.class); + map.put("input", DomHTMLInputElement.class); + map.put("isindex", DomHTMLIsIndexElement.class); + map.put("label", DomHTMLLabelElement.class); + map.put("legend", DomHTMLLegendElement.class); + map.put("li", DomHTMLLIElement.class); + map.put("link", DomHTMLLinkElement.class); + map.put("map", DomHTMLMapElement.class); + map.put("menu", DomHTMLMenuElement.class); + map.put("meta", DomHTMLMetaElement.class); + map.put("ins", DomHTMLModElement.class); + map.put("del", DomHTMLModElement.class); + map.put("object", DomHTMLObjectElement.class); + map.put("ol", DomHTMLOListElement.class); + map.put("optgroup", DomHTMLOptGroupElement.class); + map.put("option", DomHTMLOptionElement.class); + map.put("p", DomHTMLParagraphElement.class); + map.put("param", DomHTMLParamElement.class); + map.put("pre", DomHTMLPreElement.class); + map.put("q", DomHTMLQuoteElement.class); + map.put("blockquote", DomHTMLQuoteElement.class); + map.put("script", DomHTMLScriptElement.class); + map.put("select", DomHTMLSelectElement.class); + map.put("style", DomHTMLStyleElement.class); + map.put("caption", DomHTMLTableCaptionElement.class); + map.put("th", DomHTMLTableCellElement.class); + map.put("td", DomHTMLTableCellElement.class); + map.put("col", DomHTMLTableColElement.class); + map.put("colgroup", DomHTMLTableColElement.class); + map.put("table", DomHTMLTableElement.class); + map.put("tr", DomHTMLTableRowElement.class); + map.put("thead", DomHTMLTableSectionElement.class); + map.put("tfoot", DomHTMLTableSectionElement.class); + map.put("tbody", DomHTMLTableSectionElement.class); + map.put("textarea", DomHTMLTextAreaElement.class); + map.put("title", DomHTMLTitleElement.class); + map.put("ul", DomHTMLUListElement.class); + ELEMENT_CLASSES = Collections.unmodifiableMap(map); + } + + private static Set HTML_NS_URIS; + static + { + Set set = new HashSet(); + set.add("http://www.w3.org/TR/html4/strict"); + set.add("http://www.w3.org/TR/html4/loose"); + set.add("http://www.w3.org/TR/html4/frameset"); + set.add("http://www.w3.org/1999/xhtml"); + set.add("http://www.w3.org/TR/xhtml1/strict"); + set.add("http://www.w3.org/TR/xhtml1/loose"); + set.add("http://www.w3.org/TR/xhtml1/frameset"); + HTML_NS_URIS = Collections.unmodifiableSet(set); + } + + /** + * Convenience constructor. + */ + public DomHTMLDocument() + { + this(new DomHTMLImpl()); + } + + /** + * Constructor. + * This is called by the DOMImplementation. + */ + public DomHTMLDocument(DomHTMLImpl impl) + { + super(impl); + } + + private Node getChildNodeByName(Node parent, String name) + { + for (Node ctx = parent.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + if (name.equalsIgnoreCase(ctx.getNodeName())) + { + return ctx; + } + } + return null; + } + + public String getTitle() + { + Node html = getDocumentElement(); + if (html != null) + { + Node head = getChildNodeByName(html, "head"); + if (head != null) + { + Node title = getChildNodeByName(head, "title"); + if (title != null) + { + return title.getTextContent(); + } + } + } + return null; + } + + public void setTitle(String title) + { + Node html = getDocumentElement(); + if (html == null) + { + html = createElement("html"); + appendChild(html); + } + Node head = getChildNodeByName(html, "head"); + if (head == null) + { + head = createElement("head"); + Node first = html.getFirstChild(); + if (first != null) + { + html.insertBefore(first, head); + } + else + { + html.appendChild(head); + } + } + Node titleNode = getChildNodeByName(head, "title"); + if (titleNode == null) + { + titleNode = createElement("title"); + Node first = head.getFirstChild(); + if (first != null) + { + head.insertBefore(first, titleNode); + } + else + { + head.appendChild(titleNode); + } + } + titleNode.setTextContent(title); + } + + public String getReferrer() + { + // TODO getReferrer + return null; + } + + public String getDomain() + { + try + { + URL url = new URL(getDocumentURI()); + return url.getHost(); + } + catch (MalformedURLException e) + { + return null; + } + } + + public String getURL() + { + return getDocumentURI(); + } + + public HTMLElement getBody() + { + Node html = getDocumentElement(); + if (html != null) + { + Node body = getChildNodeByName(html, "body"); + if (body == null) + { + body = getChildNodeByName(html, "frameset"); + } + return (HTMLElement) body; + } + return null; + } + + public void setBody(HTMLElement body) + { + Node html = getDocumentElement(); + if (html == null) + { + html = createElement("html"); + appendChild(html); + } + Node ref = getBody(); + if (ref == null) + { + html.appendChild(body); + } + else + { + html.replaceChild(body, ref); + } + } + + public HTMLCollection getImages() + { + DomHTMLCollection ret = new DomHTMLCollection(this, this); + ret.addNodeName("img"); + ret.evaluate(); + return ret; + } + + public HTMLCollection getApplets() + { + DomHTMLCollection ret = new DomHTMLCollection(this, this); + ret.addNodeName("embed"); + ret.addNodeName("object"); + ret.addNodeName("applet"); + ret.evaluate(); + return ret; + } + + public HTMLCollection getLinks() + { + DomHTMLCollection ret = new DomHTMLCollection(this, this); + ret.addNodeName("area"); + ret.addNodeName("a"); + ret.evaluate(); + return ret; + } + + public HTMLCollection getForms() + { + DomHTMLCollection ret = new DomHTMLCollection(this, this); + ret.addNodeName("form"); + ret.evaluate(); + return ret; + } + + public HTMLCollection getAnchors() + { + DomHTMLCollection ret = new DomHTMLCollection(this, this); + ret.addNodeName("a"); + ret.addAttributeName("name"); + ret.evaluate(); + return ret; + } + + public String getCookie() + { + // TODO getCookie + return null; + } + + public void setCookie(String cookie) + { + // TODO setCookie + } + + public void open() + { + // TODO open + } + + public void close() + { + // TODO close + } + + public void write(String text) + { + // TODO write + } + + public void writeln(String text) + { + // TODO write + } + + public NodeList getElementsByName(String name) + { + DomHTMLCollection ret = new DomHTMLCollection(this, this); + ret.addNodeName(name); + ret.evaluate(); + return ret; + // TODO xhtml: return only form controls (?) + } + + public Element createElement(String tagName) + { + return createElementNS(null, tagName); + } + + public Element createElementNS(String uri, String qName) + { + /* If a non-HTML element, use the default implementation. */ + if (uri != null && !HTML_NS_URIS.contains(uri)) + { + return super.createElementNS(uri, qName); + } + String localName = qName.toLowerCase(); + int ci = qName.indexOf(':'); + if (ci != -1) + { + localName = qName.substring(ci + 1); + } + Class t = (Class) ELEMENT_CLASSES.get(localName); + /* If a non-HTML element, use the default implementation. */ + if (t == null) + { + return super.createElementNS(uri, qName); + } + try + { + Constructor c = t.getDeclaredConstructor(ELEMENT_PT); + Object[] args = new Object[] { this, uri, qName }; + return (Element) c.newInstance(args); + } + catch (Exception e) + { + DOMException e2 = new DomDOMException(DOMException.TYPE_MISMATCH_ERR); + e2.initCause(e); + throw e2; + } + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLElement.java new file mode 100644 index 000000000..deeefec60 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLElement.java @@ -0,0 +1,286 @@ +/* DomHTMLElement.java -- + 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.xml.dom.html2; + +import gnu.xml.dom.DomDOMException; +import gnu.xml.dom.DomElement; +import gnu.xml.dom.DomEvent; +import org.w3c.dom.DOMException; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.events.UIEvent; +import org.w3c.dom.html2.HTMLElement; + +/** + * Abstract implementation of an HTML element node. + * + * @author Chris Burdess + */ +public abstract class DomHTMLElement + extends DomElement + implements HTMLElement +{ + + protected DomHTMLElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + /** + * Returns the value of the specified attribute. + * The attribute name is case insensitive. + */ + protected String getHTMLAttribute(String name) + { + if (hasAttributes()) + { + NamedNodeMap attrs = getAttributes(); + int len = attrs.getLength(); + for (int i = 0; i < len; i++) + { + Node attr = attrs.item(i); + String attrName = attr.getLocalName(); + if (attrName == null) + { + attrName = attr.getNodeName(); + } + if (attrName.equalsIgnoreCase(name)) + { + return attr.getNodeValue(); + } + } + } + return ""; + } + + protected int getIntHTMLAttribute(String name) + { + String value = getHTMLAttribute(name); + if (value == null) + { + return -1; + } + try + { + return Integer.parseInt(value); + } + catch (NumberFormatException e) + { + return -1; + } + } + + protected boolean getBooleanHTMLAttribute(String name) + { + String value = getHTMLAttribute(name); + return value != null; + } + + /** + * Sets the value of the specified attribute. + * The attribute name is case insensitive. + */ + protected void setHTMLAttribute(String name, String value) + { + Node attr; + NamedNodeMap attrs = getAttributes(); + int len = attrs.getLength(); + for (int i = 0; i < len; i++) + { + attr = attrs.item(i); + String attrName = attr.getLocalName(); + if (attrName == null) + { + attrName = attr.getNodeName(); + } + if (attrName.equalsIgnoreCase(name)) + { + if (value != null) + { + attr.setNodeValue(value); + } + else + { + attrs.removeNamedItem(attr.getNodeName()); + } + return; + } + } + if (value != null) + { + // Create a new attribute + DomHTMLDocument doc = (DomHTMLDocument) getOwnerDocument(); + // XXX namespace URI for attribute? + attr = doc.createAttribute(name); + attr.setNodeValue(value); + } + } + + protected void setIntHTMLAttribute(String name, int value) + { + setHTMLAttribute(name, Integer.toString(value)); + } + + protected void setBooleanHTMLAttribute(String name, boolean value) + { + setHTMLAttribute(name, value ? name : null); + } + + /** + * Returns the first parent element with the specified name. + */ + protected Node getParentElement(String name) + { + for (Node parent = getParentNode(); parent != null; + parent = parent.getParentNode()) + { + String parentName = parent.getLocalName(); + if (parentName == null) + { + parentName = parent.getNodeName(); + } + if (name.equalsIgnoreCase(parentName)) + { + return parent; + } + } + return null; + } + + /** + * Returns the first child element with the specified name. + */ + protected Node getChildElement(String name) + { + for (Node child = getFirstChild(); child != null; + child = child.getNextSibling()) + { + String childName = child.getLocalName(); + if (childName == null) + { + childName = child.getLocalName(); + } + if (name.equalsIgnoreCase(childName)) + { + return child; + } + } + return null; + } + + /** + * Returns the index of this element among elements of the same name, + * relative to its parent. + */ + protected int getIndex() + { + int index = 0; + Node parent = getParentNode(); + if (parent != null) + { + for (Node ctx = parent.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + if (ctx == this) + { + return index; + } + index++; + } + } + throw new DomDOMException(DOMException.NOT_FOUND_ERR); + } + + protected void dispatchUIEvent(String name) + { + UIEvent event = new DomEvent.DomUIEvent(name); + dispatchEvent(event); + } + + public String getId() + { + return getHTMLAttribute("id"); + } + + public void setId(String id) + { + setHTMLAttribute("id", id); + } + + public String getTitle() + { + return getHTMLAttribute("title"); + } + + public void setTitle(String title) + { + setHTMLAttribute("title", title); + } + + public String getLang() + { + return getHTMLAttribute("lang"); + } + + public void setLang(String lang) + { + setHTMLAttribute("lang", lang); + } + + public String getDir() + { + return getHTMLAttribute("dir"); + } + + public void setDir(String dir) + { + setHTMLAttribute("dir", dir); + } + + public String getClassName() + { + return getHTMLAttribute("class"); + } + + public void setClassName(String className) + { + setHTMLAttribute("class", className); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLEmbedElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLEmbedElement.java new file mode 100644 index 000000000..221131533 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLEmbedElement.java @@ -0,0 +1,129 @@ +/* DomHTMLEmbedElement.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.dom.html2; + +public class DomHTMLEmbedElement + extends DomHTMLAppletElement +{ + protected DomHTMLEmbedElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getJavaObject() + { + return getHTMLAttribute("java_object"); + } + + public void setJavaObject(String object) + { + setHTMLAttribute("java_object", object); + } + + public String getJavaCodeBase() + { + return getHTMLAttribute("java_codebase"); + } + + public void setJavaCodeBase(String codeBase) + { + setHTMLAttribute("java_codebase", codeBase); + } + + public String getJavaArchive() + { + return getHTMLAttribute("java_archive"); + } + + public void setJavaArchive(String archive) + { + setHTMLAttribute("java_archive", archive); + } + + public void setJavaCode(String code) + { + setHTMLAttribute("java_code", code); + } + + public String getJavaCode() + { + return getHTMLAttribute("java_code"); + } + + public void setJavaType(String type) + { + setHTMLAttribute("java_type", type); + } + + public String getJavaType() + { + return getHTMLAttribute("java_type"); + } + + public void setType(String type) + { + setHTMLAttribute("type", type); + } + + public String getType() + { + return getHTMLAttribute("type"); + } + + public String getPluginsPage() + { + return getHTMLAttribute("pluginspage"); + } + + public void setPluginsPage(String pluginspage) + { + setHTMLAttribute("pluginspage", pluginspage); + } + + public String getMayscript() + { + return getHTMLAttribute("mayscript"); + } + + public void setMayscript(String mayscript) + { + setHTMLAttribute("mayscript", mayscript); + } +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLFieldSetElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLFieldSetElement.java new file mode 100644 index 000000000..252cd3d2b --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLFieldSetElement.java @@ -0,0 +1,64 @@ +/* DomHTMLFieldSetElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLFieldSetElement; +import org.w3c.dom.html2.HTMLFormElement; + +/** + * An HTML 'FIELDSET' element node. + * + * @author Chris Burdess + */ +public class DomHTMLFieldSetElement + extends DomHTMLElement + implements HTMLFieldSetElement +{ + + protected DomHTMLFieldSetElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public HTMLFormElement getForm() + { + return (HTMLFormElement) getParentElement("form"); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLFontElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLFontElement.java new file mode 100644 index 000000000..5bfbb6f36 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLFontElement.java @@ -0,0 +1,88 @@ +/* DomHTMLFontElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLFontElement; + +/** + * An HTML 'FONT' element node. + * + * @author Chris Burdess + */ +public class DomHTMLFontElement + extends DomHTMLElement + implements HTMLFontElement +{ + + protected DomHTMLFontElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getColor() + { + return getHTMLAttribute("color"); + } + + public void setColor(String color) + { + setHTMLAttribute("color", color); + } + + public String getFace() + { + return getHTMLAttribute("face"); + } + + public void setFace(String face) + { + setHTMLAttribute("face", face); + } + + public String getSize() + { + return getHTMLAttribute("size"); + } + + public void setSize(String size) + { + setHTMLAttribute("size", size); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLFormElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLFormElement.java new file mode 100644 index 000000000..9fe2ae802 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLFormElement.java @@ -0,0 +1,149 @@ +/* DomHTMLFormElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLCollection; +import org.w3c.dom.html2.HTMLFormElement; + +/** + * An HTML 'FORM' element node. + * + * @author Chris Burdess + */ +public class DomHTMLFormElement + extends DomHTMLElement + implements HTMLFormElement +{ + + protected DomHTMLFormElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public HTMLCollection getElements() + { + DomHTMLCollection ret = + new DomHTMLCollection((DomHTMLDocument) getOwnerDocument(), this); + ret.addNodeName("input"); + ret.addNodeName("button"); + ret.addNodeName("select"); + ret.addNodeName("textarea"); + ret.addNodeName("isindex"); + ret.addNodeName("label"); + ret.addNodeName("option"); + ret.evaluate(); + return ret; + } + + public int getLength() + { + return getElements().getLength(); + } + + public String getName() + { + return getHTMLAttribute("name"); + } + + public void setName(String name) + { + setHTMLAttribute("name", name); + } + + public String getAcceptCharset() + { + return getHTMLAttribute("accept-charset"); + } + + public void setAcceptCharset(String acceptCharset) + { + setHTMLAttribute("accept-charset", acceptCharset); + } + + public String getAction() + { + return getHTMLAttribute("action"); + } + + public void setAction(String action) + { + setHTMLAttribute("action", action); + } + + public String getEnctype() + { + return getHTMLAttribute("enctype"); + } + + public void setEnctype(String enctype) + { + setHTMLAttribute("enctype", enctype); + } + + public String getMethod() + { + return getHTMLAttribute("method"); + } + + public void setMethod(String method) + { + setHTMLAttribute("method", method); + } + + public String getTarget() + { + return getHTMLAttribute("target"); + } + + public void setTarget(String target) + { + setHTMLAttribute("target", target); + } + + public void submit() + { + dispatchUIEvent("submit"); + } + + public void reset() + { + dispatchUIEvent("reset"); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLFrameElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLFrameElement.java new file mode 100644 index 000000000..2465c4b89 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLFrameElement.java @@ -0,0 +1,145 @@ +/* DomHTMLFrameElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.Document; +import org.w3c.dom.html2.HTMLFrameElement; + +/** + * An HTML 'FRAME' element node. + * + * @author Chris Burdess + */ +public class DomHTMLFrameElement + extends DomHTMLElement + implements HTMLFrameElement +{ + + protected DomHTMLFrameElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getFrameBorder() + { + return getHTMLAttribute("frameborder"); + } + + public void setFrameBorder(String frameBorder) + { + setHTMLAttribute("frameborder", frameBorder); + } + + public String getLongDesc() + { + return getHTMLAttribute("longdesc"); + } + + public void setLongDesc(String longDesc) + { + setHTMLAttribute("longdesc", longDesc); + } + + public String getMarginHeight() + { + return getHTMLAttribute("marginheight"); + } + + public void setMarginHeight(String marginHeight) + { + setHTMLAttribute("marginheight", marginHeight); + } + + public String getMarginWidth() + { + return getHTMLAttribute("marginwidth"); + } + + public void setMarginWidth(String marginWidth) + { + setHTMLAttribute("marginwidth", marginWidth); + } + + public String getName() + { + return getHTMLAttribute("name"); + } + + public void setName(String name) + { + setHTMLAttribute("name", name); + } + + public boolean getNoResize() + { + return getBooleanHTMLAttribute("noresize"); + } + + public void setNoResize(boolean noResize) + { + setBooleanHTMLAttribute("noresize", noResize); + } + + public String getScrolling() + { + return getHTMLAttribute("scrolling"); + } + + public void setScrolling(String scrolling) + { + setHTMLAttribute("scrolling", scrolling); + } + + public String getSrc() + { + return getHTMLAttribute("src"); + } + + public void setSrc(String src) + { + setHTMLAttribute("src", src); + } + + public Document getContentDocument() + { + // TODO getContentDocument + return null; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLFrameSetElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLFrameSetElement.java new file mode 100644 index 000000000..dae9430fb --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLFrameSetElement.java @@ -0,0 +1,78 @@ +/* DomHTMLFrameSetElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLFrameSetElement; + +/** + * An HTML 'FRAMESET' element node. + * + * @author Chris Burdess + */ +public class DomHTMLFrameSetElement + extends DomHTMLElement + implements HTMLFrameSetElement +{ + + protected DomHTMLFrameSetElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getCols() + { + return getHTMLAttribute("cols"); + } + + public void setCols(String cols) + { + setHTMLAttribute("cols", cols); + } + + public String getRows() + { + return getHTMLAttribute("rows"); + } + + public void setRows(String rows) + { + setHTMLAttribute("rows", rows); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLHRElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLHRElement.java new file mode 100644 index 000000000..e27ef5595 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLHRElement.java @@ -0,0 +1,98 @@ +/* DomHTMLHRElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLHRElement; + +/** + * An HTML 'HR' element node. + * + * @author Chris Burdess + */ +public class DomHTMLHRElement + extends DomHTMLElement + implements HTMLHRElement +{ + + protected DomHTMLHRElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getAlign() + { + return getHTMLAttribute("align"); + } + + public void setAlign(String align) + { + setHTMLAttribute("align", align); + } + + public boolean getNoShade() + { + return getBooleanHTMLAttribute("noshade"); + } + + public void setNoShade(boolean noShade) + { + setBooleanHTMLAttribute("noshade", noShade); + } + + public String getSize() + { + return getHTMLAttribute("size"); + } + + public void setSize(String size) + { + setHTMLAttribute("size", size); + } + + public String getWidth() + { + return getHTMLAttribute("width"); + } + + public void setWidth(String width) + { + setHTMLAttribute("width", width); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLHeadElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLHeadElement.java new file mode 100644 index 000000000..4a8ef995b --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLHeadElement.java @@ -0,0 +1,68 @@ +/* DomHTMLHeadElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLHeadElement; + +/** + * An HTML 'HEAD' element node. + * + * @author Chris Burdess + */ +public class DomHTMLHeadElement + extends DomHTMLElement + implements HTMLHeadElement +{ + + protected DomHTMLHeadElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getProfile() + { + return getHTMLAttribute("profile"); + } + + public void setProfile(String profile) + { + setHTMLAttribute("profile", profile); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLHeadingElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLHeadingElement.java new file mode 100644 index 000000000..6e78e9004 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLHeadingElement.java @@ -0,0 +1,68 @@ +/* DomHTMLHeadingElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLHeadingElement; + +/** + * An HTML 'H1', 'H2', 'H3', 'H4', 'H5', or 'H6' element node. + * + * @author Chris Burdess + */ +public class DomHTMLHeadingElement + extends DomHTMLElement + implements HTMLHeadingElement +{ + + protected DomHTMLHeadingElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getAlign() + { + return getHTMLAttribute("align"); + } + + public void setAlign(String align) + { + setHTMLAttribute("align", align); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLHtmlElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLHtmlElement.java new file mode 100644 index 000000000..73f7243ed --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLHtmlElement.java @@ -0,0 +1,68 @@ +/* DomHTMLHtmlElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLHtmlElement; + +/** + * An HTML 'HTML' top-level element node. + * + * @author Chris Burdess + */ +public class DomHTMLHtmlElement + extends DomHTMLElement + implements HTMLHtmlElement +{ + + protected DomHTMLHtmlElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getVersion() + { + return getHTMLAttribute("version"); + } + + public void setVersion(String version) + { + setHTMLAttribute("version", version); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLIFrameElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLIFrameElement.java new file mode 100644 index 000000000..1a58fb73e --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLIFrameElement.java @@ -0,0 +1,165 @@ +/* DomHTMLIFrameElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.Document; +import org.w3c.dom.html2.HTMLIFrameElement; + +/** + * An HTML 'IFRAME' element node. + * + * @author Chris Burdess + */ +public class DomHTMLIFrameElement + extends DomHTMLElement + implements HTMLIFrameElement +{ + + protected DomHTMLIFrameElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getAlign() + { + return getHTMLAttribute("align"); + } + + public void setAlign(String align) + { + setHTMLAttribute("align", align); + } + + public String getFrameBorder() + { + return getHTMLAttribute("frameborder"); + } + + public void setFrameBorder(String frameBorder) + { + setHTMLAttribute("frameborder", frameBorder); + } + + public String getHeight() + { + return getHTMLAttribute("height"); + } + + public void setHeight(String height) + { + setHTMLAttribute("height", height); + } + + public String getLongDesc() + { + return getHTMLAttribute("longdesc"); + } + + public void setLongDesc(String longDesc) + { + setHTMLAttribute("longdesc", longDesc); + } + + public String getMarginHeight() + { + return getHTMLAttribute("marginheight"); + } + + public void setMarginHeight(String marginHeight) + { + setHTMLAttribute("marginheight", marginHeight); + } + + public String getMarginWidth() + { + return getHTMLAttribute("marginwidth"); + } + + public void setMarginWidth(String marginWidth) + { + setHTMLAttribute("marginwidth", marginWidth); + } + + public String getName() + { + return getHTMLAttribute("name"); + } + + public void setName(String name) + { + setHTMLAttribute("name", name); + } + + public String getScrolling() + { + return getHTMLAttribute("scrolling"); + } + + public void setScrolling(String scrolling) + { + setHTMLAttribute("scrolling", scrolling); + } + + public String getSrc() + { + return getHTMLAttribute("src"); + } + + public void setSrc(String src) + { + setHTMLAttribute("src", src); + } + + public String getWidth() + { + return getHTMLAttribute("width"); + } + + public void setWidth(String width) + { + setHTMLAttribute("width", width); + } + + public Document getContentDocument() + { + // TODO getContentDocument + return null; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLImageElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLImageElement.java new file mode 100644 index 000000000..c5d294c6f --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLImageElement.java @@ -0,0 +1,178 @@ +/* DomHTMLImageElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLImageElement; + +/** + * An HTML 'IMG' element node. + * + * @author Chris Burdess + */ +public class DomHTMLImageElement + extends DomHTMLElement + implements HTMLImageElement +{ + + protected DomHTMLImageElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getName() + { + return getHTMLAttribute("name"); + } + + public void setName(String name) + { + setHTMLAttribute("name", name); + } + + public String getAlign() + { + return getHTMLAttribute("align"); + } + + public void setAlign(String align) + { + setHTMLAttribute("align", align); + } + + public String getAlt() + { + return getHTMLAttribute("alt"); + } + + public void setAlt(String alt) + { + setHTMLAttribute("alt", alt); + } + + public String getBorder() + { + return getHTMLAttribute("border"); + } + + public void setBorder(String border) + { + setHTMLAttribute("border", border); + } + + public int getHeight() + { + return getIntHTMLAttribute("height"); + } + + public void setHeight(int height) + { + setIntHTMLAttribute("height", height); + } + + public int getHspace() + { + return getIntHTMLAttribute("hspace"); + } + + public void setHspace(int hspace) + { + setIntHTMLAttribute("hspace", hspace); + } + + public boolean getIsMap() + { + return getBooleanHTMLAttribute("ismap"); + } + + public void setIsMap(boolean isMap) + { + setBooleanHTMLAttribute("ismap", isMap); + } + + public String getLongDesc() + { + return getHTMLAttribute("longdesc"); + } + + public void setLongDesc(String longDesc) + { + setHTMLAttribute("longdesc", longDesc); + } + + public String getSrc() + { + return getHTMLAttribute("src"); + } + + public void setSrc(String src) + { + setHTMLAttribute("src", src); + } + + public String getUseMap() + { + return getHTMLAttribute("usemap"); + } + + public void setUseMap(String useMap) + { + setHTMLAttribute("usemap", useMap); + } + + public int getVspace() + { + return getIntHTMLAttribute("vspace"); + } + + public void setVspace(int vspace) + { + setIntHTMLAttribute("vspace", vspace); + } + + public int getWidth() + { + return getIntHTMLAttribute("width"); + } + + public void setWidth(int width) + { + setIntHTMLAttribute("width", width); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLImpl.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLImpl.java new file mode 100644 index 000000000..a5faee5ce --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLImpl.java @@ -0,0 +1,66 @@ +/* DomHTMLImpl.java -- + 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.xml.dom.html2; + +import gnu.xml.dom.DomImpl; +import org.w3c.dom.Document; + +/** + * Specialised DOMImplementation for creating HTML documents. + * + * @author Chris Burdess + */ +public class DomHTMLImpl + extends DomImpl +{ + + protected Document createDocument() + { + return new DomHTMLDocument(this); + } + + public Object getFeature(String feature, String version) + { + if (hasFeature(feature, version)) + { + return this; + } + return null; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLInputElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLInputElement.java new file mode 100644 index 000000000..21201889d --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLInputElement.java @@ -0,0 +1,265 @@ +/* DomHTMLInputElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLFormElement; +import org.w3c.dom.html2.HTMLInputElement; + +/** + * An HTML 'INPUT' element node. + * + * @author Chris Burdess + */ +public class DomHTMLInputElement + extends DomHTMLElement + implements HTMLInputElement +{ + + protected String value; + protected Boolean checked; + + protected DomHTMLInputElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getDefaultValue() + { + return getHTMLAttribute("value"); + } + + public void setDefaultValue(String defaultValue) + { + setHTMLAttribute("value", defaultValue); + } + + public boolean getDefaultChecked() + { + return getBooleanHTMLAttribute("checked"); + } + + public void setDefaultChecked(boolean defaultChecked) + { + setBooleanHTMLAttribute("checked", defaultChecked); + } + + public HTMLFormElement getForm() + { + return (HTMLFormElement) getParentElement("form"); + } + + public String getAccept() + { + return getHTMLAttribute("accept"); + } + + public void setAccept(String accept) + { + setHTMLAttribute("accept", accept); + } + + public String getAccessKey() + { + return getHTMLAttribute("accesskey"); + } + + public void setAccessKey(String accessKey) + { + setHTMLAttribute("accesskey", accessKey); + } + + public String getAlign() + { + return getHTMLAttribute("align"); + } + + public void setAlign(String align) + { + setHTMLAttribute("align", align); + } + + public String getAlt() + { + return getHTMLAttribute("alt"); + } + + public void setAlt(String alt) + { + setHTMLAttribute("alt", alt); + } + + public boolean getChecked() + { + if (checked == null) + { + checked = Boolean.valueOf(getDefaultChecked()); + } + return checked.booleanValue(); + } + + public void setChecked(boolean checked) + { + this.checked = Boolean.valueOf(checked); + } + + public boolean getDisabled() + { + return getBooleanHTMLAttribute("disabled"); + } + + public void setDisabled(boolean disabled) + { + setBooleanHTMLAttribute("disabled", disabled); + } + + public int getMaxLength() + { + return getIntHTMLAttribute("maxLength"); + } + + public void setMaxLength(int maxLength) + { + setIntHTMLAttribute("maxLength", maxLength); + } + + public String getName() + { + return getHTMLAttribute("name"); + } + + public void setName(String name) + { + setHTMLAttribute("name", name); + } + + public boolean getReadOnly() + { + return getBooleanHTMLAttribute("readonly"); + } + + public void setReadOnly(boolean readOnly) + { + setBooleanHTMLAttribute("readonly", readOnly); + } + + public int getSize() + { + return getIntHTMLAttribute("size"); + } + + public void setSize(int size) + { + setIntHTMLAttribute("size", size); + } + + public String getSrc() + { + return getHTMLAttribute("src"); + } + + public void setSrc(String src) + { + setHTMLAttribute("src", src); + } + + public int getTabIndex() + { + return getIntHTMLAttribute("tabindex"); + } + + public void setTabIndex(int tabIndex) + { + setIntHTMLAttribute("tabindex", tabIndex); + } + + public String getType() + { + return getHTMLAttribute("type"); + } + + public void setType(String type) + { + setHTMLAttribute("type", type); + } + + public String getUseMap() + { + return getHTMLAttribute("usemap"); + } + + public void setUseMap(String useMap) + { + setHTMLAttribute("usemap", useMap); + } + + public String getValue() + { + if (value == null) + { + value = getDefaultValue(); + } + return value; + } + + public void setValue(String value) + { + this.value = value; + } + + public void blur() + { + dispatchUIEvent("blur"); + } + + public void focus() + { + dispatchUIEvent("focus"); + } + + public void select() + { + dispatchUIEvent("select"); + } + + public void click() + { + dispatchUIEvent("click"); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLIsIndexElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLIsIndexElement.java new file mode 100644 index 000000000..8578cb6c0 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLIsIndexElement.java @@ -0,0 +1,74 @@ +/* DomHTMLIsIndexElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLFormElement; +import org.w3c.dom.html2.HTMLIsIndexElement; + +/** + * An HTML 'ISINDEX' element node. + * + * @author Chris Burdess + */ +public class DomHTMLIsIndexElement + extends DomHTMLElement + implements HTMLIsIndexElement +{ + + protected DomHTMLIsIndexElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public HTMLFormElement getForm() + { + return (HTMLFormElement) getParentElement("form"); + } + + public String getPrompt() + { + return getHTMLAttribute("prompt"); + } + + public void setPrompt(String prompt) + { + setHTMLAttribute("prompt", prompt); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLLIElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLLIElement.java new file mode 100644 index 000000000..cab1412dd --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLLIElement.java @@ -0,0 +1,78 @@ +/* DomHTMLLIElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLLIElement; + +/** + * An HTML 'LI' element node. + * + * @author Chris Burdess + */ +public class DomHTMLLIElement + extends DomHTMLElement + implements HTMLLIElement +{ + + protected DomHTMLLIElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getType() + { + return getHTMLAttribute("type"); + } + + public void setType(String type) + { + setHTMLAttribute("type", type); + } + + public int getValue() + { + return getIntHTMLAttribute("value"); + } + + public void setValue(int value) + { + setIntHTMLAttribute("value", value); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLLabelElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLLabelElement.java new file mode 100644 index 000000000..96cfbaab5 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLLabelElement.java @@ -0,0 +1,84 @@ +/* DomHTMLLabelElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLFormElement; +import org.w3c.dom.html2.HTMLLabelElement; + +/** + * An HTML 'LABEL' element node. + * + * @author Chris Burdess + */ +public class DomHTMLLabelElement + extends DomHTMLElement + implements HTMLLabelElement +{ + + protected DomHTMLLabelElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public HTMLFormElement getForm() + { + return (HTMLFormElement) getParentElement("form"); + } + + public String getAccessKey() + { + return getHTMLAttribute("accesskey"); + } + + public void setAccessKey(String accessKey) + { + setHTMLAttribute("accesskey", accessKey); + } + + public String getHtmlFor() + { + return getHTMLAttribute("for"); + } + + public void setHtmlFor(String htmlFor) + { + setHTMLAttribute("for", htmlFor); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLLegendElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLLegendElement.java new file mode 100644 index 000000000..045861cae --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLLegendElement.java @@ -0,0 +1,84 @@ +/* DomHTMLLegendElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLFormElement; +import org.w3c.dom.html2.HTMLLegendElement; + +/** + * An HTML 'LEGEND' element node. + * + * @author Chris Burdess + */ +public class DomHTMLLegendElement + extends DomHTMLElement + implements HTMLLegendElement +{ + + protected DomHTMLLegendElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public HTMLFormElement getForm() + { + return (HTMLFormElement) getParentElement("form"); + } + + public String getAccessKey() + { + return getHTMLAttribute("accesskey"); + } + + public void setAccessKey(String accessKey) + { + setHTMLAttribute("accesskey", accessKey); + } + + public String getAlign() + { + return getHTMLAttribute("align"); + } + + public void setAlign(String align) + { + setHTMLAttribute("align", align); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLLinkElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLLinkElement.java new file mode 100644 index 000000000..292ec9305 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLLinkElement.java @@ -0,0 +1,148 @@ +/* DomHTMLLinkElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLLinkElement; + +/** + * An HTML 'LINK' element node. + * + * @author Chris Burdess + */ +public class DomHTMLLinkElement + extends DomHTMLElement + implements HTMLLinkElement +{ + + protected DomHTMLLinkElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public boolean getDisabled() + { + return getBooleanHTMLAttribute("disabled"); + } + + public void setDisabled(boolean disabled) + { + setBooleanHTMLAttribute("disabled", disabled); + } + + public String getCharset() + { + return getHTMLAttribute("charset"); + } + + public void setCharset(String charset) + { + setHTMLAttribute("charset", charset); + } + + public String getHref() + { + return getHTMLAttribute("href"); + } + + public void setHref(String href) + { + setHTMLAttribute("href", href); + } + + public String getHreflang() + { + return getHTMLAttribute("hreflang"); + } + + public void setHreflang(String hreflang) + { + setHTMLAttribute("hreflang", hreflang); + } + + public String getMedia() + { + return getHTMLAttribute("media"); + } + + public void setMedia(String media) + { + setHTMLAttribute("media", media); + } + + public String getRel() + { + return getHTMLAttribute("rel"); + } + + public void setRel(String rel) + { + setHTMLAttribute("rel", rel); + } + + public String getRev() + { + return getHTMLAttribute("rev"); + } + + public void setRev(String rev) + { + setHTMLAttribute("rev", rev); + } + + public String getTarget() + { + return getHTMLAttribute("target"); + } + + public void setTarget(String target) + { + setHTMLAttribute("target", target); + } + + public String getType() + { + return getHTMLAttribute("type"); + } + + public void setType(String type) + { + setHTMLAttribute("type", type); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLMapElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLMapElement.java new file mode 100644 index 000000000..4497b00e2 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLMapElement.java @@ -0,0 +1,78 @@ +/* DomHTMLMapElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLCollection; +import org.w3c.dom.html2.HTMLMapElement; + +/** + * An HTML 'MAP' element node. + * + * @author Chris Burdess + */ +public class DomHTMLMapElement + extends DomHTMLElement + implements HTMLMapElement +{ + + protected DomHTMLMapElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public HTMLCollection getAreas() + { + DomHTMLCollection ret = + new DomHTMLCollection((DomHTMLDocument) getOwnerDocument(), this); + ret.addNodeName("area"); + ret.evaluate(); + return ret; + } + + public String getName() + { + return getHTMLAttribute("name"); + } + + public void setName(String name) + { + setHTMLAttribute("name", name); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLMenuElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLMenuElement.java new file mode 100644 index 000000000..2a6ff08f1 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLMenuElement.java @@ -0,0 +1,68 @@ +/* DomHTMLMenuElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLMenuElement; + +/** + * An HTML 'MENU' element node. + * + * @author Chris Burdess + */ +public class DomHTMLMenuElement + extends DomHTMLElement + implements HTMLMenuElement +{ + + protected DomHTMLMenuElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public boolean getCompact() + { + return getBooleanHTMLAttribute("compact"); + } + + public void setCompact(boolean compact) + { + setBooleanHTMLAttribute("compact", compact); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLMetaElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLMetaElement.java new file mode 100644 index 000000000..e555a4273 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLMetaElement.java @@ -0,0 +1,98 @@ +/* DomHTMLMetaElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLMetaElement; + +/** + * An HTML 'META' element node. + * + * @author Chris Burdess + */ +public class DomHTMLMetaElement + extends DomHTMLElement + implements HTMLMetaElement +{ + + protected DomHTMLMetaElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getContent() + { + return getHTMLAttribute("content"); + } + + public void setContent(String content) + { + setHTMLAttribute("content", content); + } + + public String getHttpEquiv() + { + return getHTMLAttribute("http-equiv"); + } + + public void setHttpEquiv(String httpEquiv) + { + setHTMLAttribute("http-equiv", httpEquiv); + } + + public String getName() + { + return getHTMLAttribute("name"); + } + + public void setName(String name) + { + setHTMLAttribute("name", name); + } + + public String getScheme() + { + return getHTMLAttribute("scheme"); + } + + public void setScheme(String scheme) + { + setHTMLAttribute("scheme", scheme); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLModElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLModElement.java new file mode 100644 index 000000000..8c158f48a --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLModElement.java @@ -0,0 +1,78 @@ +/* DomHTMLModElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLModElement; + +/** + * An HTML 'INS' or 'DEL' element node. + * + * @author Chris Burdess + */ +public class DomHTMLModElement + extends DomHTMLElement + implements HTMLModElement +{ + + protected DomHTMLModElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getCite() + { + return getHTMLAttribute("cite"); + } + + public void setCite(String cite) + { + setHTMLAttribute("cite", cite); + } + + public String getDateTime() + { + return getHTMLAttribute("datetime"); + } + + public void setDateTime(String dateTime) + { + setHTMLAttribute("datetime", dateTime); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLOListElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLOListElement.java new file mode 100644 index 000000000..54f7fd46b --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLOListElement.java @@ -0,0 +1,88 @@ +/* DomHTMLOListElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLOListElement; + +/** + * An HTML 'OL' element node. + * + * @author Chris Burdess + */ +public class DomHTMLOListElement + extends DomHTMLElement + implements HTMLOListElement +{ + + protected DomHTMLOListElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public boolean getCompact() + { + return getBooleanHTMLAttribute("compact"); + } + + public void setCompact(boolean compact) + { + setBooleanHTMLAttribute("compact", compact); + } + + public int getStart() + { + return getIntHTMLAttribute("start"); + } + + public void setStart(int start) + { + setIntHTMLAttribute("start", start); + } + + public String getType() + { + return getHTMLAttribute("type"); + } + + public void setType(String type) + { + setHTMLAttribute("type", type); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLObjectElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLObjectElement.java new file mode 100644 index 000000000..2ce5f45c3 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLObjectElement.java @@ -0,0 +1,320 @@ +/* DomHTMLObjectElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.Document; +import org.w3c.dom.html2.HTMLFormElement; +import org.w3c.dom.html2.HTMLObjectElement; + +/** + * An HTML 'OBJECT' element node. + * + * @author Chris Burdess + */ +public class DomHTMLObjectElement + extends DomHTMLElement + implements HTMLObjectElement +{ + + protected DomHTMLObjectElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public HTMLFormElement getForm() + { + return (HTMLFormElement) getParentElement("form"); + } + + public String getCode() + { + return getHTMLAttribute("code"); + } + + public void setCode(String code) + { + setHTMLAttribute("code", code); + } + + public String getJavaCode() + { + return getHTMLAttribute("java_code"); + } + + public void setJavaCode(String code) + { + setHTMLAttribute("java_code", code); + } + + public String getObject() + { + return getHTMLAttribute("object"); + } + + public void setObject(String obj) + { + setHTMLAttribute("object", obj); + } + + public String getJavaObject() + { + return getHTMLAttribute("java_object"); + } + + public void setJavaObject(String obj) + { + setHTMLAttribute("java_object", obj); + } + + public String getAlign() + { + return getHTMLAttribute("align"); + } + + public void setAlign(String align) + { + setHTMLAttribute("align", align); + } + + public String getArchive() + { + return getHTMLAttribute("archive"); + } + + public void setArchive(String archive) + { + setHTMLAttribute("archive", archive); + } + + public String getJavaArchive() + { + return getHTMLAttribute("java_archive"); + } + + public void setJavaArchive(String archive) + { + setHTMLAttribute("java_archive", archive); + } + + public String getBorder() + { + return getHTMLAttribute("border"); + } + + public void setBorder(String border) + { + setHTMLAttribute("border", border); + } + + public String getCodeBase() + { + return getHTMLAttribute("codebase"); + } + + public void setCodeBase(String codeBase) + { + setHTMLAttribute("codebase", codeBase); + } + + public String getJavaCodeBase() + { + return getHTMLAttribute("java_codebase"); + } + + public void setJavaCodeBase(String codeBase) + { + setHTMLAttribute("java_codebase", codeBase); + } + + public String getCodeType() + { + return getHTMLAttribute("codetype"); + } + + public void setCodeType(String codeType) + { + setHTMLAttribute("codetype", codeType); + } + + public String getData() + { + return getHTMLAttribute("data"); + } + + public void setData(String data) + { + setHTMLAttribute("data", data); + } + + public boolean getDeclare() + { + return getBooleanHTMLAttribute("declare"); + } + + public void setDeclare(boolean declare) + { + setBooleanHTMLAttribute("declare", declare); + } + + public String getHeight() + { + return getHTMLAttribute("height"); + } + + public void setHeight(String height) + { + setHTMLAttribute("height", height); + } + + public int getHspace() + { + return getIntHTMLAttribute("hspace"); + } + + public void setHspace(int hspace) + { + setIntHTMLAttribute("hspace", hspace); + } + + public String getName() + { + return getHTMLAttribute("name"); + } + + public void setName(String name) + { + setHTMLAttribute("name", name); + } + + public String getStandby() + { + return getHTMLAttribute("standby"); + } + + public void setStandby(String standby) + { + setHTMLAttribute("standby", standby); + } + + public int getTabIndex() + { + return getIntHTMLAttribute("tabindex"); + } + + public void setTabIndex(int tabIndex) + { + setIntHTMLAttribute("tabindex", tabIndex); + } + + public String getType() + { + return getHTMLAttribute("type"); + } + + public void setType(String type) + { + setHTMLAttribute("type", type); + } + + public String getJavaType() + { + return getHTMLAttribute("java_type"); + } + + public void setJavaType(String type) + { + setHTMLAttribute("java_type", type); + } + + public String getUseMap() + { + return getHTMLAttribute("usemap"); + } + + public void setUseMap(String useMap) + { + setHTMLAttribute("usemap", useMap); + } + + public int getVspace() + { + return getIntHTMLAttribute("vspace"); + } + + public void setVspace(int vspace) + { + setIntHTMLAttribute("vspace", vspace); + } + + public String getWidth() + { + return getHTMLAttribute("width"); + } + + public void setWidth(String width) + { + setHTMLAttribute("width", width); + } + + public Document getContentDocument() + { + // TODO getContentDocument + return null; + } + + public void setMayscript(String may) + { + setHTMLAttribute("mayscript", may); + } + + public String getMayscript() + { + return getHTMLAttribute("mayscript"); + } + + public void setScriptable(String scr) + { + setHTMLAttribute("scriptable", scr); + } + + public String getScriptable() + { + return getHTMLAttribute("scriptable"); + } +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLOptGroupElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLOptGroupElement.java new file mode 100644 index 000000000..acb948484 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLOptGroupElement.java @@ -0,0 +1,78 @@ +/* DomHTMLOptGroupElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLOptGroupElement; + +/** + * An HTML 'OPTGROUP' element node. + * + * @author Chris Burdess + */ +public class DomHTMLOptGroupElement + extends DomHTMLElement + implements HTMLOptGroupElement +{ + + protected DomHTMLOptGroupElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public boolean getDisabled() + { + return getBooleanHTMLAttribute("disabled"); + } + + public void setDisabled(boolean disabled) + { + setBooleanHTMLAttribute("disabled", disabled); + } + + public String getLabel() + { + return getHTMLAttribute("label"); + } + + public void setLabel(String label) + { + setHTMLAttribute("label", label); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLOptionElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLOptionElement.java new file mode 100644 index 000000000..f775c138a --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLOptionElement.java @@ -0,0 +1,130 @@ +/* DomHTMLOptionElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLFormElement; +import org.w3c.dom.html2.HTMLOptionElement; + +/** + * An HTML 'OPTION' element node. + * + * @author Chris Burdess + */ +public class DomHTMLOptionElement + extends DomHTMLElement + implements HTMLOptionElement +{ + + protected Boolean selected; + + protected DomHTMLOptionElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public HTMLFormElement getForm() + { + return (HTMLFormElement) getParentElement("form"); + } + + public boolean getDefaultSelected() + { + return getBooleanHTMLAttribute("selected"); + } + + public void setDefaultSelected(boolean defaultSelected) + { + setBooleanHTMLAttribute("selected", defaultSelected); + } + + public String getText() + { + return getTextContent(); + } + + public int getIndex() + { + return super.getIndex(); + } + + public boolean getDisabled() + { + return getBooleanHTMLAttribute("disabled"); + } + + public void setDisabled(boolean disabled) + { + setBooleanHTMLAttribute("disabled", disabled); + } + + public String getLabel() + { + return getHTMLAttribute("label"); + } + + public void setLabel(String label) + { + setHTMLAttribute("label", label); + } + + public boolean getSelected() + { + if (selected == null) + { + selected = Boolean.valueOf(getDefaultSelected()); + } + return selected.booleanValue(); + } + + public void setSelected(boolean selected) + { + this.selected = Boolean.valueOf(selected); + } + + public String getValue() + { + return getHTMLAttribute("value"); + } + + public void setValue(String value) + { + setHTMLAttribute("value", value); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLParagraphElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLParagraphElement.java new file mode 100644 index 000000000..4c867fdc1 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLParagraphElement.java @@ -0,0 +1,68 @@ +/* DomHTMLParagraphElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLParagraphElement; + +/** + * An HTML 'P' element node. + * + * @author Chris Burdess + */ +public class DomHTMLParagraphElement + extends DomHTMLElement + implements HTMLParagraphElement +{ + + protected DomHTMLParagraphElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getAlign() + { + return getHTMLAttribute("align"); + } + + public void setAlign(String align) + { + setHTMLAttribute("align", align); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLParamElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLParamElement.java new file mode 100644 index 000000000..cdd74ad4a --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLParamElement.java @@ -0,0 +1,98 @@ +/* DomHTMLParamElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLParamElement; + +/** + * An HTML 'PARAM' element node. + * + * @author Chris Burdess + */ +public class DomHTMLParamElement + extends DomHTMLElement + implements HTMLParamElement +{ + + protected DomHTMLParamElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getName() + { + return getHTMLAttribute("name"); + } + + public void setName(String name) + { + setHTMLAttribute("name", name); + } + + public String getType() + { + return getHTMLAttribute("type"); + } + + public void setType(String type) + { + setHTMLAttribute("type", type); + } + + public String getValue() + { + return getHTMLAttribute("value"); + } + + public void setValue(String value) + { + setHTMLAttribute("value", value); + } + + public String getValueType() + { + return getHTMLAttribute("valuetype"); + } + + public void setValueType(String valueType) + { + setHTMLAttribute("valuetype", valueType); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLParser.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLParser.java new file mode 100644 index 000000000..88656d2d3 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLParser.java @@ -0,0 +1,264 @@ +/* DomHTMLParser.java -- + 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.xml.dom.html2; + +import java.io.IOException; +import java.io.Reader; + +import java.util.Enumeration; +import java.util.Iterator; +import java.util.LinkedList; + +import javax.swing.text.AttributeSet; +import javax.swing.text.html.HTML; +import javax.swing.text.html.parser.DTD; +import javax.swing.text.html.parser.TagElement; + +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.html2.HTMLDocument; + +/** + * This parser reads HTML from the given stream and stores into + * {@link HTMLDocument}. The HTML tag becomes the {@link Node}. + * The tag attributes become the node attributes. The text inside + * HTML tag is inserted as one or several text nodes. The nested + * HTML tags are inserted as child nodes. + * + * If the strict tree structure, closing the tag means closing all + * nested tags. To work around this, this parser closes the nested + * tags and immediately reopens them after the closed tag. + * In this way, <b><i>c</b>d + * is parsed as <b><i>c</i></b><i>d . + * + * @author Audrius Meskauskas (AudriusA@Bioinformatics.org) + */ +public class DomHTMLParser + extends gnu.javax.swing.text.html.parser.support.Parser +{ + /** + * The target where HTML document will be inserted. + */ + protected DomHTMLDocument document; + + /** + * The subsequently created new nodes will be inserted as the + * childs of this cursor. + */ + protected Node cursor; + + /** + * Create parser using the given DTD. + * + * @param dtd the DTD (for example, + * {@link gnu.javax.swing.text.html.parser.HTML_401F}). + */ + public DomHTMLParser(DTD dtd) + { + super(dtd); + } + + /** + * Parse SGML insertion ( <! ... > ). + * Currently just treats it as comment. + */ + public boolean parseMarkupDeclarations(StringBuffer strBuff) + throws java.io.IOException + { + Node c = document.createComment(strBuff.toString()); + cursor.appendChild(c); + return false; + } + + /** + * Read the document, present in the given stream, and + * return the corresponding {@link HTMLDocument}. + * + * @param input a stream to read from. + * @return a document, reflecting the structure of the provided HTML + * text. + * + * @throws IOException if the reader throws one. + */ + public HTMLDocument parseDocument(Reader input) + throws IOException + { + try + { + document = new DomHTMLDocument(); + document.setCheckWellformedness(false); + document.setCheckingCharacters(false); + + cursor = document; + + parse(input); + + DomHTMLDocument h = document; + document = null; + return h; + } + catch (Exception ex) + { + ex.printStackTrace(); + throw new IOException("Exception: " + ex.getMessage()); + } + } + + /** + * Create a new node. + * @param name the name of node, case insensitive. + * @return the created node. + */ + protected Node createNode(String name) + { + Node new_node = document.createElement(name.toLowerCase()); + AttributeSet hatts = getAttributes(); + NamedNodeMap natts = new_node.getAttributes(); + + Enumeration enumeration = hatts.getAttributeNames(); + Object key; + Node attribute; + + while (hatts != null) + { + while (enumeration.hasMoreElements()) + { + key = enumeration.nextElement(); + attribute = document.createAttribute(key.toString()); + attribute.setNodeValue(hatts.getAttribute(key).toString()); + natts.setNamedItem(attribute); + } + + // The default values are stored in a parent node. + hatts = hatts.getResolveParent(); + } + + return new_node; + } + + /** + * Handle comment by inserting the comment node. + * @param text the comment text. + */ + protected void handleComment(char[] text) + { + Node c = document.createComment(new String(text)); + cursor.appendChild(c); + } + + /** + * Handle the tag with no content. + * @param tag the tag to handle. + */ + protected void handleEmptyTag(TagElement tag) + { + String name = tag.getHTMLTag().toString(); + + if (name.equalsIgnoreCase("#pcdata")) + return; + + Node c = createNode(name); + cursor.appendChild(c); + } + + /** + * Close the given tag. Close and reopen all nested tags. + * @param tag the tag to close. + */ + protected void handleEndTag(TagElement tag) + { + String name = tag.getHTMLTag().toString(); + String nname = cursor.getNodeName(); + + // Closing the current tag. + if (nname != null && nname.equalsIgnoreCase(name)) + { + cursor = cursor.getParentNode(); + } + else + { + Node nCursor = cursor.getParentNode(); + + // Remember the opened nodes. + LinkedList open = new LinkedList(); + Node close = cursor; + while (close != null && !close.getNodeName().equalsIgnoreCase(name)) + { + if (close != document) + open.addFirst(close); + close = close.getParentNode(); + } + if (close == null) + cursor = document; + else + cursor = close.getParentNode(); + + // Insert the copies of the opened nodes. + Iterator iter = open.iterator(); + while (iter.hasNext()) + { + Node item = (Node) iter.next(); + cursor.appendChild(item); + cursor = item; + } + } + } + + /** + * Handle the start tag by inserting the HTML element. + * @param tag the tag to handle. + */ + protected void handleStartTag(TagElement tag) + { + HTML.Tag h = tag.getHTMLTag(); + Node c = createNode(h.toString()); + cursor.appendChild(c); + cursor = c; + } + + /** + * Handle text by inserting the text node. + * @param text the text to insert. + */ + protected void handleText(char[] text) + { + Node c = document.createTextNode(text, 0, text.length); + cursor.appendChild(c); + } +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLPreElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLPreElement.java new file mode 100644 index 000000000..9a51aaeeb --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLPreElement.java @@ -0,0 +1,68 @@ +/* DomHTMLPreElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLPreElement; + +/** + * An HTML 'PRE' element node. + * + * @author Chris Burdess + */ +public class DomHTMLPreElement + extends DomHTMLElement + implements HTMLPreElement +{ + + protected DomHTMLPreElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public int getWidth() + { + return getIntHTMLAttribute("width"); + } + + public void setWidth(int width) + { + setIntHTMLAttribute("width", width); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLQuoteElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLQuoteElement.java new file mode 100644 index 000000000..811aed58b --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLQuoteElement.java @@ -0,0 +1,68 @@ +/* DomHTMLQuoteElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLQuoteElement; + +/** + * An HTML 'Q' or 'BLOCKQUOTE' element node. + * + * @author Chris Burdess + */ +public class DomHTMLQuoteElement + extends DomHTMLElement + implements HTMLQuoteElement +{ + + protected DomHTMLQuoteElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getCite() + { + return getHTMLAttribute("cite"); + } + + public void setCite(String cite) + { + setHTMLAttribute("cite", cite); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLScriptElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLScriptElement.java new file mode 100644 index 000000000..1bd7b3417 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLScriptElement.java @@ -0,0 +1,128 @@ +/* DomHTMLScriptElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLScriptElement; + +/** + * An HTML 'SCRIPT' element node. + * + * @author Chris Burdess + */ +public class DomHTMLScriptElement + extends DomHTMLElement + implements HTMLScriptElement +{ + + protected DomHTMLScriptElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getText() + { + return getTextContent(); + } + + public void setText(String text) + { + setTextContent(text); + } + + public String getHtmlFor() + { + return getHTMLAttribute("for"); + } + + public void setHtmlFor(String htmlFor) + { + setHTMLAttribute("for", htmlFor); + } + + public String getEvent() + { + return getHTMLAttribute("event"); + } + + public void setEvent(String event) + { + setHTMLAttribute("event", event); + } + + public String getCharset() + { + return getHTMLAttribute("charset"); + } + + public void setCharset(String charset) + { + setHTMLAttribute("charset", charset); + } + + public boolean getDefer() + { + return getBooleanHTMLAttribute("defer"); + } + + public void setDefer(boolean defer) + { + setBooleanHTMLAttribute("defer", defer); + } + + public String getSrc() + { + return getHTMLAttribute("src"); + } + + public void setSrc(String src) + { + setHTMLAttribute("src", src); + } + + public String getType() + { + return getHTMLAttribute("type"); + } + + public void setType(String type) + { + setHTMLAttribute("type", type); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLSelectElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLSelectElement.java new file mode 100644 index 000000000..fc1debbd6 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLSelectElement.java @@ -0,0 +1,210 @@ +/* DomHTMLSelectElement.java -- + 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.xml.dom.html2; + +import gnu.xml.dom.DomDOMException; +import org.w3c.dom.DOMException; +import org.w3c.dom.html2.HTMLElement; +import org.w3c.dom.html2.HTMLFormElement; +import org.w3c.dom.html2.HTMLOptionElement; +import org.w3c.dom.html2.HTMLOptionsCollection; +import org.w3c.dom.html2.HTMLSelectElement; + +/** + * An HTML 'SELECT' element node. + * + * @author Chris Burdess + */ +public class DomHTMLSelectElement + extends DomHTMLElement + implements HTMLSelectElement +{ + + protected DomHTMLSelectElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getType() + { + return getHTMLAttribute("type"); + } + + public int getSelectedIndex() + { + HTMLOptionsCollection options = getOptions(); + int len = options.getLength(); + for (int i = 0; i < len; i++) + { + HTMLOptionElement option = (HTMLOptionElement) options.item(i); + if (option.getSelected()) + { + return i; + } + } + return -1; + } + + public void setSelectedIndex(int selectedIndex) + { + HTMLOptionsCollection options = getOptions(); + int len = options.getLength(); + if (selectedIndex < 0 || selectedIndex >= len) + { + throw new DomDOMException(DOMException.INDEX_SIZE_ERR); + } + for (int i = 0; i < len; i++) + { + HTMLOptionElement option = (HTMLOptionElement) options.item(i); + option.setSelected(i == selectedIndex); + } + } + + public String getValue() + { + return getHTMLAttribute("value"); + } + + public void setValue(String value) + { + setHTMLAttribute("value", value); + } + + public int getLength() + { + return getIntHTMLAttribute("length"); + } + + public void setLength(int length) + { + setIntHTMLAttribute("length", length); + } + + public HTMLFormElement getForm() + { + return (HTMLFormElement) getParentElement("form"); + } + + public HTMLOptionsCollection getOptions() + { + DomHTMLCollection ret = + new DomHTMLCollection((DomHTMLDocument) getOwnerDocument(), this); + ret.addNodeName("option"); + ret.evaluate(); + return ret; + } + + public boolean getDisabled() + { + return getBooleanHTMLAttribute("disabled"); + } + + public void setDisabled(boolean disabled) + { + setBooleanHTMLAttribute("disabled", disabled); + } + + public boolean getMultiple() + { + return getBooleanHTMLAttribute("multiple"); + } + + public void setMultiple(boolean multiple) + { + setBooleanHTMLAttribute("multiple", multiple); + } + + public String getName() + { + return getHTMLAttribute("name"); + } + + public void setName(String name) + { + setHTMLAttribute("name", name); + } + + public int getSize() + { + return getIntHTMLAttribute("size"); + } + + public void setSize(int size) + { + setIntHTMLAttribute("size", size); + } + + public int getTabIndex() + { + return getIntHTMLAttribute("tabindex"); + } + + public void setTabIndex(int tabIndex) + { + setIntHTMLAttribute("tabindex", tabIndex); + } + + public void add(HTMLElement element, HTMLElement before) + { + insertBefore(before, element); + } + + public void remove(int index) + { + HTMLOptionsCollection options = getOptions(); + int len = options.getLength(); + if (index < 0 || index >= len) + { + throw new DomDOMException(DOMException.INDEX_SIZE_ERR); + } + HTMLOptionElement option = (HTMLOptionElement) options.item(index); + option.getParentNode().removeChild(option); + } + + public void blur() + { + dispatchUIEvent("blur"); + } + + public void focus() + { + dispatchUIEvent("focus"); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLStyleElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLStyleElement.java new file mode 100644 index 000000000..78cef3b18 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLStyleElement.java @@ -0,0 +1,88 @@ +/* DomHTMLStyleElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLStyleElement; + +/** + * An HTML 'STYLE' element node. + * + * @author Chris Burdess + */ +public class DomHTMLStyleElement + extends DomHTMLElement + implements HTMLStyleElement +{ + + protected DomHTMLStyleElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public boolean getDisabled() + { + return getBooleanHTMLAttribute("disabled"); + } + + public void setDisabled(boolean disabled) + { + setBooleanHTMLAttribute("disabled", disabled); + } + + public String getMedia() + { + return getHTMLAttribute("media"); + } + + public void setMedia(String media) + { + setHTMLAttribute("media", media); + } + + public String getType() + { + return getHTMLAttribute("type"); + } + + public void setType(String type) + { + setHTMLAttribute("type", type); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableCaptionElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableCaptionElement.java new file mode 100644 index 000000000..2133b1412 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableCaptionElement.java @@ -0,0 +1,69 @@ +/* DomHTMLTableCaptionElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLTableCaptionElement; + +/** + * An HTML 'CAPTION' element node. + * + * @author Chris Burdess + */ +public class DomHTMLTableCaptionElement + extends DomHTMLElement + implements HTMLTableCaptionElement +{ + + protected DomHTMLTableCaptionElement(DomHTMLDocument owner, + String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getAlign() + { + return getHTMLAttribute("align"); + } + + public void setAlign(String align) + { + setHTMLAttribute("align", align); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableCellElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableCellElement.java new file mode 100644 index 000000000..350f0bf42 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableCellElement.java @@ -0,0 +1,204 @@ +/* DomHTMLTableCellElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLTableCellElement; + +/** + * An HTML 'TH' or 'TD' element node. + * + * @author Chris Burdess + */ +public class DomHTMLTableCellElement + extends DomHTMLElement + implements HTMLTableCellElement +{ + + protected DomHTMLTableCellElement(DomHTMLDocument owner, + String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public int getCellIndex() + { + return getIndex(); + } + + public String getAbbr() + { + return getHTMLAttribute("abbr"); + } + + public void setAbbr(String abbr) + { + setHTMLAttribute("abbr", abbr); + } + + public String getAlign() + { + return getHTMLAttribute("align"); + } + + public void setAlign(String align) + { + setHTMLAttribute("align", align); + } + + public String getAxis() + { + return getHTMLAttribute("axis"); + } + + public void setAxis(String axis) + { + setHTMLAttribute("axis", axis); + } + + public String getBgColor() + { + return getHTMLAttribute("bgcolor"); + } + + public void setBgColor(String bgColor) + { + setHTMLAttribute("bgcolor", bgColor); + } + + public String getCh() + { + return getHTMLAttribute("char"); + } + + public void setCh(String ch) + { + setHTMLAttribute("char", ch); + } + + public String getChOff() + { + return getHTMLAttribute("charoff"); + } + + public void setChOff(String chOff) + { + setHTMLAttribute("charoff", chOff); + } + + public int getColSpan() + { + return getIntHTMLAttribute("colspan"); + } + + public void setColSpan(int colSpan) + { + setIntHTMLAttribute("colspan", colSpan); + } + + public String getHeaders() + { + return getHTMLAttribute("headers"); + } + + public void setHeaders(String headers) + { + setHTMLAttribute("headers", headers); + } + + public String getHeight() + { + return getHTMLAttribute("height"); + } + + public void setHeight(String height) + { + setHTMLAttribute("height", height); + } + + public boolean getNoWrap() + { + return getBooleanHTMLAttribute("nowrap"); + } + + public void setNoWrap(boolean noWrap) + { + setBooleanHTMLAttribute("nowrap", noWrap); + } + + public int getRowSpan() + { + return getIntHTMLAttribute("rowspan"); + } + + public void setRowSpan(int rowSpan) + { + setIntHTMLAttribute("rowspan", rowSpan); + } + + public String getScope() + { + return getHTMLAttribute("scope"); + } + + public void setScope(String scope) + { + setHTMLAttribute("scope", scope); + } + + public String getVAlign() + { + return getHTMLAttribute("valign"); + } + + public void setVAlign(String vAlign) + { + setHTMLAttribute("valign", vAlign); + } + + public String getWidth() + { + return getHTMLAttribute("width"); + } + + public void setWidth(String width) + { + setHTMLAttribute("width", width); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableColElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableColElement.java new file mode 100644 index 000000000..c7cef31eb --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableColElement.java @@ -0,0 +1,119 @@ +/* DomHTMLTableColElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLTableColElement; + +/** + * An HTML 'COL' or 'COLGROUP' element node. + * + * @author Chris Burdess + */ +public class DomHTMLTableColElement + extends DomHTMLElement + implements HTMLTableColElement +{ + + protected DomHTMLTableColElement(DomHTMLDocument owner, + String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getAlign() + { + return getHTMLAttribute("align"); + } + + public void setAlign(String align) + { + setHTMLAttribute("align", align); + } + + public String getCh() + { + return getHTMLAttribute("char"); + } + + public void setCh(String ch) + { + setHTMLAttribute("char", ch); + } + + public String getChOff() + { + return getHTMLAttribute("charoff"); + } + + public void setChOff(String chOff) + { + setHTMLAttribute("charoff", chOff); + } + + public int getSpan() + { + return getIntHTMLAttribute("span"); + } + + public void setSpan(int span) + { + setIntHTMLAttribute("span", span); + } + + public String getVAlign() + { + return getHTMLAttribute("valign"); + } + + public void setVAlign(String vAlign) + { + setHTMLAttribute("valign", vAlign); + } + + public String getWidth() + { + return getHTMLAttribute("width"); + } + + public void setWidth(String width) + { + setHTMLAttribute("width", width); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableElement.java new file mode 100644 index 000000000..ade463ef7 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableElement.java @@ -0,0 +1,397 @@ +/* DomHTMLTableElement.java -- + 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.xml.dom.html2; + +import gnu.xml.dom.DomDOMException; +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.html2.HTMLCollection; +import org.w3c.dom.html2.HTMLElement; +import org.w3c.dom.html2.HTMLTableCaptionElement; +import org.w3c.dom.html2.HTMLTableElement; +import org.w3c.dom.html2.HTMLTableSectionElement; + +/** + * An HTML 'TABLE' element node. + * + * @author Chris Burdess + */ +public class DomHTMLTableElement + extends DomHTMLElement + implements HTMLTableElement +{ + + protected DomHTMLTableElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public HTMLTableCaptionElement getCaption() + { + return (HTMLTableCaptionElement) getChildElement("caption"); + } + + public void setCaption(HTMLTableCaptionElement caption) + { + HTMLTableCaptionElement ref = getCaption(); + if (ref == null) + { + appendChild(caption); + } + else + { + replaceChild(caption, ref); + } + } + + public HTMLTableSectionElement getTHead() + { + return (HTMLTableSectionElement) getChildElement("thead"); + } + + public void setTHead(HTMLTableSectionElement tHead) + { + HTMLTableSectionElement ref = getTHead(); + if (ref == null) + { + appendChild(tHead); + } + else + { + replaceChild(tHead, ref); + } + } + + public HTMLTableSectionElement getTFoot() + { + return (HTMLTableSectionElement) getChildElement("tfoot"); + } + + public void setTFoot(HTMLTableSectionElement tFoot) + { + HTMLTableSectionElement ref = getTFoot(); + if (ref == null) + { + appendChild(tFoot); + } + else + { + replaceChild(tFoot, ref); + } + } + + public HTMLCollection getRows() + { + DomHTMLCollection ret = + new DomHTMLCollection((DomHTMLDocument) getOwnerDocument(), this); + ret.addNodeName("tr"); + ret.evaluate(); + return ret; + } + + public HTMLCollection getTBodies() + { + DomHTMLCollection ret = + new DomHTMLCollection((DomHTMLDocument) getOwnerDocument(), this); + ret.addNodeName("tbody"); + ret.evaluate(); + return ret; + } + + public String getAlign() + { + return getHTMLAttribute("align"); + } + + public void setAlign(String align) + { + setHTMLAttribute("align", align); + } + + public String getBgColor() + { + return getHTMLAttribute("bgcolor"); + } + + public void setBgColor(String bgColor) + { + setHTMLAttribute("bgcolor", bgColor); + } + + public String getBorder() + { + return getHTMLAttribute("border"); + } + + public void setBorder(String border) + { + setHTMLAttribute("border", border); + } + + public String getCellPadding() + { + return getHTMLAttribute("cellpadding"); + } + + public void setCellPadding(String cellPadding) + { + setHTMLAttribute("cellpadding", cellPadding); + } + + public String getCellSpacing() + { + return getHTMLAttribute("cellspacing"); + } + + public void setCellSpacing(String cellSpacing) + { + setHTMLAttribute("cellspacing", cellSpacing); + } + + public String getFrame() + { + return getHTMLAttribute("frame"); + } + + public void setFrame(String frame) + { + setHTMLAttribute("frame", frame); + } + + public String getRules() + { + return getHTMLAttribute("rules"); + } + + public void setRules(String rules) + { + setHTMLAttribute("rules", rules); + } + + public String getSummary() + { + return getHTMLAttribute("summary"); + } + + public void setSummary(String summary) + { + setHTMLAttribute("summary", summary); + } + + public String getWidth() + { + return getHTMLAttribute("width"); + } + + public void setWidth(String width) + { + setHTMLAttribute("width", width); + } + + public HTMLElement createTHead() + { + HTMLTableSectionElement ref = getTHead(); + if (ref == null) + { + return (HTMLElement) getOwnerDocument().createElement("thead"); + } + else + { + return ref; + } + } + + public void deleteTHead() + { + HTMLTableSectionElement ref = getTHead(); + if (ref != null) + { + removeChild(ref); + } + } + + public HTMLElement createTFoot() + { + HTMLTableSectionElement ref = getTFoot(); + if (ref == null) + { + return (HTMLElement) getOwnerDocument().createElement("tfoot"); + } + else + { + return ref; + } + } + + public void deleteTFoot() + { + HTMLTableSectionElement ref = getTFoot(); + if (ref != null) + { + removeChild(ref); + } + } + + public HTMLElement createCaption() + { + HTMLTableCaptionElement ref = getCaption(); + if (ref == null) + { + return (HTMLElement) getOwnerDocument().createElement("caption"); + } + else + { + return ref; + } + } + + public void deleteCaption() + { + HTMLTableCaptionElement ref = getCaption(); + if (ref != null) + { + removeChild(ref); + } + } + + public HTMLElement insertRow(int index) + { + Node ref = getRow(index); + Node row = getOwnerDocument().createElement("tr"); + if (ref == null) + { + Node tbody = getChildElement("tbody"); + if (tbody == null) + { + tbody = getOwnerDocument().createElement("tfoot"); + appendChild(tbody); + } + tbody.appendChild(row); + } + else + { + ref.getParentNode().insertBefore(row, ref); + } + return (HTMLElement) row; + } + + public void deleteRow(int index) + { + Node ref = getRow(index); + if (ref == null) + { + throw new DomDOMException(DOMException.INDEX_SIZE_ERR); + } + ref.getParentNode().removeChild(ref); + } + + Node getRow(final int index) + { + int i = 0; + Node thead = getChildElement("thead"); + if (thead != null) + { + for (Node ctx = thead.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + String ctxName = ctx.getLocalName(); + if (ctxName == null) + { + ctxName = ctx.getNodeName(); + } + if (!"tr".equalsIgnoreCase(ctxName)) + { + continue; + } + if (index == i) + { + return ctx; + } + i++; + } + } + Node tbody = getChildElement("tbody"); + if (tbody == null) + { + tbody = this; + } + for (Node ctx = tbody.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + String ctxName = ctx.getLocalName(); + if (ctxName == null) + { + ctxName = ctx.getNodeName(); + } + if (!"tr".equalsIgnoreCase(ctxName)) + { + continue; + } + if (index == i) + { + return ctx; + } + i++; + } + Node tfoot = getChildElement("tfoot"); + if (tfoot != null) + { + for (Node ctx = tfoot.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + String ctxName = ctx.getLocalName(); + if (ctxName == null) + { + ctxName = ctx.getNodeName(); + } + if (!"tr".equalsIgnoreCase(ctxName)) + { + continue; + } + if (index == i) + { + return ctx; + } + i++; + } + } + return null; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableRowElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableRowElement.java new file mode 100644 index 000000000..9943585f4 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableRowElement.java @@ -0,0 +1,228 @@ +/* DomHTMLTableRowElement.java -- + 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.xml.dom.html2; + +import gnu.xml.dom.DomDOMException; +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.html2.HTMLCollection; +import org.w3c.dom.html2.HTMLElement; +import org.w3c.dom.html2.HTMLTableRowElement; + +/** + * An HTML 'TR' element node. + * + * @author Chris Burdess + */ +public class DomHTMLTableRowElement + extends DomHTMLElement + implements HTMLTableRowElement +{ + + protected DomHTMLTableRowElement(DomHTMLDocument owner, + String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public int getRowIndex() + { + return getIndex(); + } + + public int getSectionRowIndex() + { + int index = 0; + DomHTMLElement parent = (DomHTMLElement) getParentElement("table"); + if (parent != null) + { + Node thead = parent.getChildElement("thead"); + if (thead != null) + { + for (Node ctx = thead.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + if (ctx == this) + { + return index; + } + index++; + } + } + Node tbody = parent.getChildElement("tbody"); + if (tbody != null) + { + for (Node ctx = tbody.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + if (ctx == this) + { + return index; + } + index++; + } + } + Node tfoot = parent.getChildElement("tfoot"); + if (tfoot != null) + { + for (Node ctx = tfoot.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + if (ctx == this) + { + return index; + } + index++; + } + } + } + throw new DomDOMException(DOMException.NOT_FOUND_ERR); + } + + public HTMLCollection getCells() + { + DomHTMLCollection ret = + new DomHTMLCollection((DomHTMLDocument) getOwnerDocument(), this); + ret.addNodeName("th"); + ret.addNodeName("td"); + ret.evaluate(); + return ret; + } + + public String getAlign() + { + return getHTMLAttribute("align"); + } + + public void setAlign(String align) + { + setHTMLAttribute("align", align); + } + + public String getBgColor() + { + return getHTMLAttribute("bgcolor"); + } + + public void setBgColor(String bgColor) + { + setHTMLAttribute("bgcolor", bgColor); + } + + public String getCh() + { + return getHTMLAttribute("char"); + } + + public void setCh(String ch) + { + setHTMLAttribute("char", ch); + } + + public String getChOff() + { + return getHTMLAttribute("charoff"); + } + + public void setChOff(String chOff) + { + setHTMLAttribute("charoff", chOff); + } + + public String getVAlign() + { + return getHTMLAttribute("valign"); + } + + public void setVAlign(String vAlign) + { + setHTMLAttribute("valign", vAlign); + } + + public HTMLElement insertCell(int index) + { + Node ref = getCell(index); + Node cell = getOwnerDocument().createElement("td"); + if (ref == null) + { + appendChild(cell); + } + else + { + insertBefore(cell, ref); + } + return (HTMLElement) cell; + } + + public void deleteCell(int index) + { + Node ref = getCell(index); + if (ref == null) + { + throw new DomDOMException(DOMException.INDEX_SIZE_ERR); + } + removeChild(ref); + } + + Node getCell(final int index) + { + int i = 0; + for (Node ctx = getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + String name = ctx.getLocalName(); + if (name == null) + { + name = ctx.getNodeName(); + } + if (!"td".equalsIgnoreCase(name) && + !"th".equalsIgnoreCase(name)) + { + continue; + } + if (index == i) + { + return ctx; + } + i++; + } + return null; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableSectionElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableSectionElement.java new file mode 100644 index 000000000..389eb591b --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTableSectionElement.java @@ -0,0 +1,162 @@ +/* DomHTMLTableSectionElement.java -- + 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.xml.dom.html2; + +import gnu.xml.dom.DomDOMException; +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.html2.HTMLCollection; +import org.w3c.dom.html2.HTMLElement; +import org.w3c.dom.html2.HTMLTableSectionElement; + +/** + * An HTML 'THEAD', 'TFOOT', or 'TBODY' element node. + * + * @author Chris Burdess + */ +public class DomHTMLTableSectionElement + extends DomHTMLElement + implements HTMLTableSectionElement +{ + + protected DomHTMLTableSectionElement(DomHTMLDocument owner, + String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getAlign() + { + return getHTMLAttribute("align"); + } + + public void setAlign(String align) + { + setHTMLAttribute("align", align); + } + + public String getCh() + { + return getHTMLAttribute("char"); + } + + public void setCh(String ch) + { + setHTMLAttribute("char", ch); + } + + public String getChOff() + { + return getHTMLAttribute("charoff"); + } + + public void setChOff(String chOff) + { + setHTMLAttribute("charoff", chOff); + } + + public String getVAlign() + { + return getHTMLAttribute("valign"); + } + + public void setVAlign(String vAlign) + { + setHTMLAttribute("valign", vAlign); + } + + public HTMLCollection getRows() + { + DomHTMLCollection ret = + new DomHTMLCollection((DomHTMLDocument) getOwnerDocument(), this); + ret.addNodeName("tr"); + ret.evaluate(); + return ret; + } + + public HTMLElement insertRow(int index) + { + Node ref = getRow(index); + Node row = getOwnerDocument().createElement("tr"); + if (ref == null) + { + appendChild(row); + } + else + { + insertBefore(row, ref); + } + return (HTMLElement) row; + } + + public void deleteRow(int index) + { + Node ref = getRow(index); + if (ref == null) + { + throw new DomDOMException(DOMException.INDEX_SIZE_ERR); + } + removeChild(ref); + } + + Node getRow(final int index) + { + int i = 0; + for (Node ctx = getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + String name = ctx.getLocalName(); + if (name == null) + { + name = ctx.getNodeName(); + } + if (!"tr".equalsIgnoreCase(name)) + { + continue; + } + if (index == i) + { + return ctx; + } + i++; + } + return null; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLTextAreaElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTextAreaElement.java new file mode 100644 index 000000000..9acfab134 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTextAreaElement.java @@ -0,0 +1,181 @@ +/* DomHTMLTextAreaElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLFormElement; +import org.w3c.dom.html2.HTMLTextAreaElement; + +/** + * An HTML 'TEXTAREA' element node. + * + * @author Chris Burdess + */ +public class DomHTMLTextAreaElement + extends DomHTMLElement + implements HTMLTextAreaElement +{ + + protected String value; + + protected DomHTMLTextAreaElement(DomHTMLDocument owner, + String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getDefaultValue() + { + return getHTMLAttribute("value"); + } + + public void setDefaultValue(String defaultValue) + { + setHTMLAttribute("value", defaultValue); + } + + public HTMLFormElement getForm() + { + return (HTMLFormElement) getParentElement("form"); + } + + public String getAccessKey() + { + return getHTMLAttribute("accesskey"); + } + + public void setAccessKey(String accessKey) + { + setHTMLAttribute("accesskey", accessKey); + } + + public int getCols() + { + return getIntHTMLAttribute("cols"); + } + + public void setCols(int cols) + { + setIntHTMLAttribute("cols", cols); + } + + public boolean getDisabled() + { + return getBooleanHTMLAttribute("disabled"); + } + + public void setDisabled(boolean disabled) + { + setBooleanHTMLAttribute("disabled", disabled); + } + + public String getName() + { + return getHTMLAttribute("name"); + } + + public void setName(String name) + { + setHTMLAttribute("name", name); + } + + public boolean getReadOnly() + { + return getBooleanHTMLAttribute("readOnly"); + } + + public void setReadOnly(boolean readOnly) + { + setBooleanHTMLAttribute("readonly", readOnly); + } + + public int getRows() + { + return getIntHTMLAttribute("rows"); + } + + public void setRows(int rows) + { + setIntHTMLAttribute("rows", rows); + } + + public int getTabIndex() + { + return getIntHTMLAttribute("tabindex"); + } + + public void setTabIndex(int tabIndex) + { + setIntHTMLAttribute("tabindex", tabIndex); + } + + public String getType() + { + return "textarea"; + } + + public String getValue() + { + if (value == null) + { + value = getDefaultValue(); + } + return value; + } + + public void setValue(String value) + { + this.value = value; + } + + public void blur() + { + dispatchUIEvent("blur"); + } + + public void focus() + { + dispatchUIEvent("focus"); + } + + public void select() + { + dispatchUIEvent("select"); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLTitleElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTitleElement.java new file mode 100644 index 000000000..4f581061b --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLTitleElement.java @@ -0,0 +1,68 @@ +/* DomHTMLTitleElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLTitleElement; + +/** + * An HTML 'TITLE' element node. + * + * @author Chris Burdess + */ +public class DomHTMLTitleElement + extends DomHTMLElement + implements HTMLTitleElement +{ + + protected DomHTMLTitleElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public String getText() + { + return getTextContent(); + } + + public void setText(String text) + { + setTextContent(text); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/html2/DomHTMLUListElement.java b/libjava/classpath/gnu/xml/dom/html2/DomHTMLUListElement.java new file mode 100644 index 000000000..39cdce7d3 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/html2/DomHTMLUListElement.java @@ -0,0 +1,78 @@ +/* DomHTMLUListElement.java -- + 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.xml.dom.html2; + +import org.w3c.dom.html2.HTMLUListElement; + +/** + * An HTML 'UL' element node. + * + * @author Chris Burdess + */ +public class DomHTMLUListElement + extends DomHTMLElement + implements HTMLUListElement +{ + + protected DomHTMLUListElement(DomHTMLDocument owner, String namespaceURI, + String name) + { + super(owner, namespaceURI, name); + } + + public boolean getCompact() + { + return getBooleanHTMLAttribute("compact"); + } + + public void setCompact(boolean compact) + { + setBooleanHTMLAttribute("compact", compact); + } + + public String getType() + { + return getHTMLAttribute("type"); + } + + public void setType(String type) + { + setHTMLAttribute("type", type); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/ls/DomLSException.java b/libjava/classpath/gnu/xml/dom/ls/DomLSException.java new file mode 100644 index 000000000..31efc845f --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/ls/DomLSException.java @@ -0,0 +1,57 @@ +/* DomLSException.java -- + 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.xml.dom.ls; + +import org.w3c.dom.ls.LSException; + +/** + * A DOM LS exception incorporating a cause. + * + * @author Chris Burdess + */ +public class DomLSException + extends LSException +{ + + public DomLSException(short type, Exception cause) + { + super(type, (cause == null) ? null : cause.getMessage()); + initCause(cause); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/ls/DomLSInput.java b/libjava/classpath/gnu/xml/dom/ls/DomLSInput.java new file mode 100644 index 000000000..39b17694f --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/ls/DomLSInput.java @@ -0,0 +1,159 @@ +/* DomLSInput.java -- + Copyright (C) 1999,2000,2001 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.dom.ls; + +import gnu.java.lang.CPStringBuilder; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import org.w3c.dom.ls.LSInput; + +/** + * Specification of XML input to parse. + * + * @author Chris Burdess + */ +public class DomLSInput + implements LSInput +{ + + private InputStream in; + private String systemId; + private String publicId; + private String baseURI; + private String encoding; + private boolean certifiedText; + + public Reader getCharacterStream() + { + return new InputStreamReader(in); + } + + public void setCharacterStream(Reader characterStream) + { + in = new ReaderInputStream(characterStream); + } + + public InputStream getByteStream() + { + return in; + } + + public void setByteStream(InputStream byteStream) + { + in = byteStream; + } + + public String getStringData() + { + CPStringBuilder acc = new CPStringBuilder(); + Reader reader = getCharacterStream(); + try + { + char[] buf = new char[4096]; + for (int len = reader.read(buf); len != -1; len = reader.read(buf)) + { + acc.append(buf, 0, len); + } + } + catch (IOException e) + { + return null; // ? + } + return acc.toString(); + } + + public void setStringData(String stringData) + { + in = new ReaderInputStream(new StringReader(stringData)); + } + + public String getSystemId() + { + return systemId; + } + + public void setSystemId(String systemId) + { + this.systemId = systemId; + } + + public String getPublicId() + { + return publicId; + } + + public void setPublicId(String publicId) + { + this.publicId = publicId; + } + + public String getBaseURI() + { + return baseURI; + } + + public void setBaseURI(String baseURI) + { + this.baseURI = baseURI; + } + + public String getEncoding() + { + return encoding; + } + + public void setEncoding(String encoding) + { + this.encoding = encoding; + } + + public boolean getCertifiedText() + { + return certifiedText; + } + + public void setCertifiedText(boolean certifiedText) + { + this.certifiedText = certifiedText; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/ls/DomLSOutput.java b/libjava/classpath/gnu/xml/dom/ls/DomLSOutput.java new file mode 100644 index 000000000..e8bec2ec1 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/ls/DomLSOutput.java @@ -0,0 +1,98 @@ +/* DomLSOutput.java -- + Copyright (C) 1999,2000,2001 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.dom.ls; + +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import org.w3c.dom.ls.LSOutput; + +/** + * Specification of XML output to produce. + * + * @author Chris Burdess + */ +public class DomLSOutput + implements LSOutput +{ + + private OutputStream out; + private String systemId; + private String encoding; + + public Writer getCharacterStream() + { + return new OutputStreamWriter(out); + } + + public void setCharacterStream(Writer characterStream) + { + out = new WriterOutputStream(characterStream); + } + + public OutputStream getByteStream() + { + return out; + } + + public void setByteStream(OutputStream out) + { + this.out = out; + } + + public String getSystemId() + { + return systemId; + } + + public void setSystemId(String systemId) + { + this.systemId = systemId; + } + + public String getEncoding() + { + return encoding; + } + + public void setEncoding(String encoding) + { + this.encoding = encoding; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/ls/DomLSParser.java b/libjava/classpath/gnu/xml/dom/ls/DomLSParser.java new file mode 100644 index 000000000..99db79d64 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/ls/DomLSParser.java @@ -0,0 +1,567 @@ +/* DomLSParser.java -- + Copyright (C) 1999,2000,2001,2007 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.dom.ls; + +import java.io.File; +import java.io.InputStream; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Arrays; +import java.util.List; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import org.w3c.dom.Document; +import org.w3c.dom.DOMConfiguration; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMStringList; +import org.w3c.dom.Node; +import org.w3c.dom.ls.DOMImplementationLS; +import org.w3c.dom.ls.LSException; +import org.w3c.dom.ls.LSInput; +import org.w3c.dom.ls.LSParser; +import org.w3c.dom.ls.LSParserFilter; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXParseException; +import org.xml.sax.XMLReader; +import gnu.xml.dom.DomDocument; +import gnu.xml.dom.DomDOMException; + +/** + * Parser implementation for GNU DOM. + * + * @author Chris Burdess + */ +public class DomLSParser + implements LSParser, DOMConfiguration, DOMStringList, ErrorHandler +{ + + private static final List SUPPORTED_PARAMETERS + = Arrays.asList(new String[] { "cdata-sections", + "comments", + "element-content-whitespace", + "namespaces", + "expand-entity-references", + "coalescing", + "validating", + "xinclude-aware", + "entity-resolver", + "error-handler" }); + + private LSParserFilter filter; + private final boolean async; + private String schemaType; + private SAXEventSink eventSink; + private SAXParserFactory factory; + private XMLReader reader; + + private boolean namespaceAware = true; + private boolean ignoreWhitespace; + private boolean expandEntityReferences; + private boolean ignoreComments; + private boolean coalescing; + private boolean validating; + private boolean xIncludeAware; + private EntityResolver entityResolver; + private ErrorHandler errorHandler; + + public DomLSParser(short mode, String schemaType) + throws DOMException + { + switch (mode) + { + case DOMImplementationLS.MODE_ASYNCHRONOUS: + async = true; + break; + case DOMImplementationLS.MODE_SYNCHRONOUS: + async = false; + break; + default: + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR); + } + // TODO schemaType + this.schemaType = schemaType; + factory = SAXParserFactory.newInstance(); + } + + // -- LSParser -- + + public DOMConfiguration getDomConfig() + { + return this; + } + + public LSParserFilter getFilter() + { + return filter; + } + + public void setFilter(LSParserFilter filter) + { + this.filter = filter; + } + + public boolean getAsync() + { + return async; + } + + public boolean getBusy() + { + return eventSink != null; + } + + public Document parse(LSInput input) + throws DOMException, LSException + { + if (async) + { + return doParse(input); + } + else + { + synchronized (this) + { + return doParse(input); + } + } + } + + public Document parseURI(String uri) + throws DOMException, LSException + { + LSInput input = new DomLSInput(); + input.setSystemId(uri); + return parse(input); + } + + public Node parseWithContext(LSInput input, Node context, short action) + throws DOMException, LSException + { + Document doc = (context.getNodeType() == Node.DOCUMENT_NODE) ? + (Document) context : context.getOwnerDocument(); + input.setBaseURI(doc.getDocumentURI()); + // TODO use namespaces defined on context node + Document ret = parse(input); + Node root = ret.getDocumentElement(); + root = doc.adoptNode(root); + switch (action) + { + case ACTION_APPEND_AS_CHILDREN: + context.appendChild(root); + break; + case ACTION_REPLACE_CHILDREN: + Node c1 = context.getFirstChild(); + while (c1 != null) + { + Node next = c1.getNextSibling(); + context.removeChild(c1); + c1 = next; + } + context.appendChild(root); + break; + case ACTION_INSERT_BEFORE: + Node p1 = context.getParentNode(); + p1.insertBefore(root, context); + break; + case ACTION_INSERT_AFTER: + Node p2 = context.getParentNode(); + Node r1 = context.getNextSibling(); + if (r1 == null) + { + p2.appendChild(root); + } + else + { + p2.insertBefore(root, r1); + } + break; + case ACTION_REPLACE: + Node p3 = context.getParentNode(); + Node r2 = context.getNextSibling(); + p3.removeChild(context); + if (r2 == null) + { + p3.appendChild(root); + } + else + { + p3.insertBefore(root, r2); + } + break; + } + return root; + } + + public void abort() + { + if (eventSink != null) + { + eventSink.interrupt(); + } + } + + private Document doParse(LSInput input) + throws DOMException, LSException + { + // create event sink + if (eventSink != null) + { + throw new LSException(LSException.PARSE_ERR, "parse in progress"); + } + InputSource source = getInputSource(input); + eventSink = (filter == null) ? new SAXEventSink() : + new FilteredSAXEventSink(filter); + // configure sink + eventSink.setNamespaceAware(namespaceAware); + eventSink.ignoreWhitespace = ignoreWhitespace; + eventSink.expandEntityReferences = expandEntityReferences; + eventSink.ignoreComments = ignoreComments; + eventSink.coalescing = coalescing; + // get and configure reader + XMLReader reader = getXMLReader(); + eventSink.reader = reader; + try + { + reader.setContentHandler(eventSink); + reader.setDTDHandler(eventSink); + reader.setProperty("http://xml.org/sax/properties/lexical-handler", + eventSink); + reader.setProperty("http://xml.org/sax/properties/declaration-handler", + eventSink); + reader.setFeature("http://xml.org/sax/features/namespaces", + namespaceAware); + reader.setFeature("http://xml.org/sax/features/namespace-prefixes", + true); + reader.setFeature("http://xml.org/sax/features/validation", + validating); + try + { + reader.setFeature("http://gnu.org/sax/features/coalescing", + coalescing); + } + catch (SAXNotRecognizedException e) + { + // ignore + } + try + { + reader.setFeature("http://xml.org/sax/features/use-attributes2", + true); + } + catch (SAXNotRecognizedException e) + { + // ignore + } + try + { + reader.setFeature("http://xml.org/sax/features/external-general-entities", + true); + } + catch (SAXNotRecognizedException e) + { + // ignore + } + reader.setEntityResolver(entityResolver); + reader.setErrorHandler(errorHandler); + // parse + reader.parse(source); + } + catch (DOMException e) + { + reader = null; + eventSink = null; + throw e; + } + catch (SAXException e) + { + reader = null; + eventSink = null; + throw new DomLSException(LSException.PARSE_ERR, e); + } + catch (IOException e) + { + reader = null; + eventSink = null; + throw new DomLSException(LSException.PARSE_ERR, e); + } + // return document + Document ret = eventSink.doc; + String systemId = input.getSystemId(); + if (systemId != null && ret instanceof DomDocument) + { + ((DomDocument) ret).setDocumentURI(systemId); + } + eventSink = null; + return ret; + } + + private XMLReader getXMLReader() + throws LSException + { + if (reader == null) + { + factory.setNamespaceAware(namespaceAware); + factory.setValidating(validating); + factory.setXIncludeAware(xIncludeAware); + try + { + SAXParser parser = factory.newSAXParser(); + reader = parser.getXMLReader(); + } + catch (ParserConfigurationException e) + { + throw new DomLSException(LSException.PARSE_ERR, e); + } + catch (SAXException e) + { + throw new DomLSException(LSException.PARSE_ERR, e); + } + } + return reader; + } + + private InputSource getInputSource(LSInput input) + throws LSException + { + InputSource source = null; + String systemId = input.getSystemId(); + InputStream in = input.getByteStream(); + if (in != null) + { + source = new InputSource(in); + source.setSystemId(systemId); + } + if (source == null) + { + URL url = null; + String base = input.getBaseURI(); + try + { + try + { + URL baseURL = (base == null) ? null : new URL(base); + url = (baseURL == null) ? new URL(systemId) : + new URL(baseURL, systemId); + } + catch (MalformedURLException e) + { + File baseFile = (base == null) ? null : new File(base); + url = (baseFile == null) ? new File(systemId).toURL() : + new File(baseFile, systemId).toURL(); + } + in = url.openStream(); + systemId = url.toString(); + source = new InputSource(in); + source.setSystemId(systemId); + } + catch (IOException e) + { + throw new DomLSException(LSException.PARSE_ERR, e); + } + } + return source; + } + + // -- DOMConfiguration -- + + public void setParameter(String name, Object value) + throws DOMException + { + name = name.toLowerCase(); + if ("cdata-sections".equals(name)) + { + coalescing = !((Boolean) value).booleanValue(); + } + else if ("comments".equals(name)) + { + ignoreComments = !((Boolean) value).booleanValue(); + } + else if ("element-content-whitespace".equals(name)) + { + ignoreWhitespace = !((Boolean) value).booleanValue(); + } + else if ("namespaces".equals(name)) + { + namespaceAware = ((Boolean) value).booleanValue(); + } + else if ("expand-entity-references".equals(name)) + { + expandEntityReferences = ((Boolean) value).booleanValue(); + } + else if ("coalescing".equals(name)) + { + coalescing = ((Boolean) value).booleanValue(); + } + else if ("validating".equals(name)) + { + validating = ((Boolean) value).booleanValue(); + } + else if ("xinclude-aware".equals(name)) + { + xIncludeAware = ((Boolean) value).booleanValue(); + } + else if ("entity-resolver".equals(name)) + { + entityResolver = (EntityResolver) value; + } + else if ("error-handler".equals(name)) + { + errorHandler = (ErrorHandler) value; + } + else + { + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR); + } + // invalidate reader, a new one will be created + reader = null; + } + + public Object getParameter(String name) + throws DOMException + { + name = name.toLowerCase(); + if ("cdata-sections".equals(name)) + { + return coalescing ? Boolean.FALSE : Boolean.TRUE; + } + else if ("comments".equals(name)) + { + return ignoreComments ? Boolean.FALSE : Boolean.TRUE; + } + else if ("element-content-whitespace".equals(name)) + { + return ignoreWhitespace ? Boolean.FALSE : Boolean.TRUE; + } + else if ("namespaces".equals(name)) + { + return namespaceAware ? Boolean.TRUE : Boolean.FALSE; + } + else if ("expand-entity-references".equals(name)) + { + return expandEntityReferences ? Boolean.TRUE : Boolean.FALSE; + } + else if ("coalescing".equals(name)) + { + return coalescing ? Boolean.TRUE : Boolean.FALSE; + } + else if ("validating".equals(name)) + { + return validating ? Boolean.TRUE : Boolean.FALSE; + } + else if ("xinclude-aware".equals(name)) + { + return xIncludeAware ? Boolean.TRUE : Boolean.FALSE; + } + else if ("entity-resolver".equals(name)) + { + return entityResolver; + } + else if ("error-handler".equals(name)) + { + return errorHandler; + } + else + { + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR); + } + } + + public boolean canSetParameter(String name, Object value) + { + return contains(name); + } + + public DOMStringList getParameterNames() + { + return this; + } + + // -- DOMStringList -- + + public String item(int i) + { + return (String) SUPPORTED_PARAMETERS.get(i); + } + + public int getLength() + { + return SUPPORTED_PARAMETERS.size(); + } + + public boolean contains(String str) + { + return SUPPORTED_PARAMETERS.contains(str); + } + + // -- ErrorHandler -- + + public void warning(SAXParseException e) + throws SAXException + { + if (errorHandler != null) + { + errorHandler.warning(e); + } + } + + public void error(SAXParseException e) + throws SAXException + { + if (errorHandler != null) + { + errorHandler.error(e); + } + } + + public void fatalError(SAXParseException e) + throws SAXException + { + if (errorHandler != null) + { + errorHandler.fatalError(e); + } + abort(); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/ls/DomLSSerializer.java b/libjava/classpath/gnu/xml/dom/ls/DomLSSerializer.java new file mode 100644 index 000000000..c282b0b9f --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/ls/DomLSSerializer.java @@ -0,0 +1,353 @@ +/* DomLSSerializer.java -- + Copyright (C) 1999,2000,2001 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.dom.ls; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.StringWriter; +import java.io.Writer; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.util.Arrays; +import java.util.List; +import org.w3c.dom.DOMConfiguration; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMStringList; +import org.w3c.dom.Node; +import org.w3c.dom.ls.LSException; +import org.w3c.dom.ls.LSOutput; +import org.w3c.dom.ls.LSSerializer; +import org.w3c.dom.ls.LSSerializerFilter; +import org.w3c.dom.traversal.NodeFilter; +import gnu.xml.dom.DomDOMException; +import gnu.xml.transform.StreamSerializer; + +/** + * Serialize a DOM node to a stream. + * + * @author Chris Burdess + */ +public class DomLSSerializer + extends StreamSerializer + implements LSSerializer, DOMConfiguration, DOMStringList +{ + + private static final List SUPPORTED_PARAMETERS = + Arrays.asList(new String[] {"discard-default-content", + "xml-declaration"}); + + private LSSerializerFilter filter; + private StreamSerializer serializer; + + public DomLSSerializer() + { + super(); + discardDefaultContent = true; + } + + // -- LSSerializer -- + + public DOMConfiguration getDomConfig() + { + return this; + } + + public String getNewLine() + { + return eol; + } + + public void setNewLine(String newLine) + { + if (newLine == null) + { + newLine = System.getProperty("line.separator"); + } + eol = newLine; + } + + public LSSerializerFilter getFilter() + { + return filter; + } + + public void setFilter(LSSerializerFilter filter) + { + this.filter = filter; + } + + public boolean write(Node node, LSOutput output) + throws LSException + { + OutputStream out = output.getByteStream(); + try + { + if (out == null) + { + String systemId = output.getSystemId(); + try + { + URL url = new URL(systemId); + URLConnection connection = url.openConnection(); + connection.setDoOutput(true); + if (connection instanceof HttpURLConnection) + { + ((HttpURLConnection) connection).setRequestMethod("PUT"); + } + out = connection.getOutputStream(); + } + catch (MalformedURLException e) + { + File file = new File(systemId); + out = new FileOutputStream(file); + } + } + serialize(node, out); + out.flush(); + return true; + } + catch (IOException e) + { + throw new DomLSException(LSException.SERIALIZE_ERR, e); + } + } + + public boolean writeToURI(Node node, String uri) + throws LSException + { + LSOutput output = new DomLSOutput(); + output.setSystemId(uri); + return write(node, output); + } + + public String writeToString(Node node) + throws DOMException, LSException + { + Writer writer = new StringWriter(); + LSOutput output = new DomLSOutput(); + output.setCharacterStream(writer); + write(node, output); + return writer.toString(); + } + + public void serialize(Node node, OutputStream out) + throws IOException + { + if (filter == null) + { + super.serialize(node, out); + } + else + { + int wts = filter.getWhatToShow(); + if (wts != NodeFilter.SHOW_ALL) + { + switch (node.getNodeType()) + { + case Node.ATTRIBUTE_NODE: + if ((wts & NodeFilter.SHOW_ATTRIBUTE) == 0) + { + super.serialize(node, out); + return; + } + break; + case Node.TEXT_NODE: + if ((wts & NodeFilter.SHOW_TEXT) == 0) + { + super.serialize(node, out); + return; + } + break; + case Node.ELEMENT_NODE: + if ((wts & NodeFilter.SHOW_ELEMENT) == 0) + { + super.serialize(node, out); + return; + } + break; + case Node.CDATA_SECTION_NODE: + if ((wts & NodeFilter.SHOW_CDATA_SECTION) == 0) + { + super.serialize(node, out); + return; + } + break; + case Node.COMMENT_NODE: + if ((wts & NodeFilter.SHOW_COMMENT) == 0) + { + super.serialize(node, out); + return; + } + break; + case Node.DOCUMENT_NODE: + if ((wts & NodeFilter.SHOW_DOCUMENT) == 0) + { + super.serialize(node, out); + return; + } + break; + case Node.DOCUMENT_TYPE_NODE: + if ((wts & NodeFilter.SHOW_DOCUMENT_TYPE) == 0) + { + super.serialize(node, out); + return; + } + break; + case Node.PROCESSING_INSTRUCTION_NODE: + if ((wts & NodeFilter.SHOW_PROCESSING_INSTRUCTION) == 0) + { + super.serialize(node, out); + return; + } + break; + case Node.DOCUMENT_FRAGMENT_NODE: + if ((wts & NodeFilter.SHOW_DOCUMENT_FRAGMENT) == 0) + { + super.serialize(node, out); + return; + } + break; + case Node.ENTITY_NODE: + if ((wts & NodeFilter.SHOW_ENTITY) == 0) + { + super.serialize(node, out); + return; + } + break; + case Node.ENTITY_REFERENCE_NODE: + if ((wts & NodeFilter.SHOW_ENTITY_REFERENCE) == 0) + { + super.serialize(node, out); + return; + } + break; + case Node.NOTATION_NODE: + if ((wts & NodeFilter.SHOW_NOTATION) == 0) + { + super.serialize(node, out); + return; + } + break; + } + } + switch (filter.acceptNode(node)) + { + case NodeFilter.FILTER_ACCEPT: + super.serialize(node, out); + break; + case NodeFilter.FILTER_REJECT: + break; + case NodeFilter.FILTER_SKIP: + Node first = node.getFirstChild(); + if (first != null) + { + serialize(first, out); + } + break; + } + } + } + + // -- DOMConfiguration -- + + public void setParameter(String name, Object value) + throws DOMException + { + if ("discard-default-content".equals(name)) + { + discardDefaultContent = "true".equals(value.toString()); + } + else if ("xml-declaration".equals(name)) + { + xmlDeclaration = "false".equals(value.toString()); + } + else + { + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR); + } + } + + public Object getParameter(String name) + throws DOMException + { + if ("discard-default-content".equals(name)) + { + return discardDefaultContent ? "true" : "false"; + } + else if ("xml-declaration".equals(name)) + { + return xmlDeclaration ? "true" : "false"; + } + else + { + throw new DomDOMException(DOMException.NOT_SUPPORTED_ERR); + } + } + + public boolean canSetParameter(String name, Object value) + { + return contains(name); + } + + public DOMStringList getParameterNames() + { + return this; + } + + // -- DOMStringList -- + + public String item(int i) + { + return (String) SUPPORTED_PARAMETERS.get(i); + } + + public int getLength() + { + return SUPPORTED_PARAMETERS.size(); + } + + public boolean contains(String str) + { + return SUPPORTED_PARAMETERS.contains(str); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/ls/FilteredSAXEventSink.java b/libjava/classpath/gnu/xml/dom/ls/FilteredSAXEventSink.java new file mode 100644 index 000000000..65c1d37a4 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/ls/FilteredSAXEventSink.java @@ -0,0 +1,353 @@ +/* FilteredSAXEventSink.java -- + Copyright (C) 1999,2000,2001 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.dom.ls; + +import java.util.LinkedList; +import org.w3c.dom.Attr; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.Text; +import org.w3c.dom.ls.LSParserFilter; +import org.w3c.dom.traversal.NodeFilter; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; + +/** + * A SAX event sink that calls out to a parser filter in order to decide + * whether to insert nodes into the tree. + * + * @author Chris Burdess + */ +class FilteredSAXEventSink + extends SAXEventSink +{ + + final LSParserFilter filter; + final int whatToShow; + + /** + * Stack of elements to insert. + */ + LinkedList nodes; + + /** + * Corresponding stack of filter decisions about the nodes. + */ + LinkedList decisions; + + /** + * True when rejecting child nodes. + */ + boolean rejecting; + + FilteredSAXEventSink(LSParserFilter filter) + { + this.filter = filter; + whatToShow = filter.getWhatToShow(); + } + + public void startDocument() + throws SAXException + { + if (interrupted) + { + return; + } + nodes = new LinkedList(); + decisions = new LinkedList(); + + super.startDocument(); + } + + public void endDocument() + throws SAXException + { + if (interrupted) + { + return; + } + super.endDocument(); + + switch (getDecision(ctx, false)) + { + case LSParserFilter.FILTER_REJECT: + ctx = null; + doc = null; + break; + } + + nodes = null; + decisions = null; + } + + public void startElement(String uri, String localName, String qName, + Attributes atts) + throws SAXException + { + if (rejecting || interrupted) + { + return; + } + Element element = createElement(uri, localName, qName, atts); + ctx = element; + + short decision = getDecision(element, true); + nodes.addLast(element); + decisions.addLast(new Short(decision)); + + switch (decision) + { + case LSParserFilter.FILTER_REJECT: + rejecting = true; + break; + case LSParserFilter.FILTER_INTERRUPT: + interrupted = true; + break; + } + } + + protected Attr createAttr(Attributes atts, int index) + { + Attr attr = super.createAttr(atts, index); + short decision = getDecision(attr, false); + switch (decision) + { + case LSParserFilter.FILTER_REJECT: + return null; + case LSParserFilter.FILTER_INTERRUPT: + interrupted = true; + return null; + } + return attr; + } + + public void endElement(String uri, String localName, String qName) + throws SAXException + { + if (rejecting || interrupted) + { + return; + } + super.endElement(uri, localName, qName); + + Element element = (Element) nodes.removeLast(); + Node parent = nodes.isEmpty() ? doc : (Node) nodes.getLast(); + ctx = parent; + short decision = ((Short) decisions.removeLast()).shortValue(); + switch (decision) + { + case LSParserFilter.FILTER_SKIP: + // Add all children of element to parent + for (Node child = element.getFirstChild(); child != null; + child = child.getNextSibling()) + { + parent.insertBefore(child, element); + } + return; + case LSParserFilter.FILTER_REJECT: + rejecting = false; + break; + } + decision = getDecision(element, false); + switch (decision) + { + case LSParserFilter.FILTER_ACCEPT: + parent.appendChild(element); + break; + case LSParserFilter.FILTER_INTERRUPT: + interrupted = true; + break; + } + } + + public void characters(char[] c, int off, int len) + throws SAXException + { + if (rejecting || interrupted) + { + return; + } + Text text = createText(c, off, len); + short decision = getDecision(text, false); + switch (decision) + { + case LSParserFilter.FILTER_ACCEPT: + ctx.appendChild(text); + break; + case LSParserFilter.FILTER_INTERRUPT: + interrupted = true; + break; + } + } + + public void processingInstruction(String target, String data) + throws SAXException + { + if (rejecting || interrupted || inDTD) + { + return; + } + Node pi = createProcessingInstruction(target, data); + short decision = getDecision(pi, false); + switch (decision) + { + case LSParserFilter.FILTER_ACCEPT: + ctx.appendChild(pi); + break; + case LSParserFilter.FILTER_INTERRUPT: + interrupted = true; + break; + } + } + + public void startDTD(String name, String publicId, String systemId) + throws SAXException + { + if (interrupted) + { + return; + } + Node doctype = createDocumentType(name, publicId, systemId); + ctx = doctype; + inDTD = true; + nodes.addLast(doctype); + decisions.addLast(new Short(LSParserFilter.FILTER_ACCEPT)); + } + + public void endDTD() + throws SAXException + { + if (interrupted) + { + return; + } + Node doctype = (Node) nodes.removeLast(); + decisions.removeLast(); + inDTD = false; + ctx = doc; + short decision = getDecision(doctype, false); + switch (decision) + { + case LSParserFilter.FILTER_ACCEPT: + ctx.appendChild(doctype); + break; + case LSParserFilter.FILTER_INTERRUPT: + interrupted = true; + break; + } + } + + public void comment(char[] c, int off, int len) + throws SAXException + { + if (rejecting || interrupted || inDTD) + { + return; + } + Node comment = createComment(c, off, len); + short decision = getDecision(comment, false); + switch (decision) + { + case LSParserFilter.FILTER_ACCEPT: + ctx.appendChild(comment); + break; + case LSParserFilter.FILTER_INTERRUPT: + interrupted = true; + break; + } + } + + // TODO declarations + + short getDecision(Node node, boolean start) + { + boolean show = (whatToShow == NodeFilter.SHOW_ALL); + if (!show) + { + switch (node.getNodeType()) + { + case Node.ATTRIBUTE_NODE: + show = ((whatToShow & NodeFilter.SHOW_ATTRIBUTE) != 0); + break; + case Node.TEXT_NODE: + show = ((whatToShow & NodeFilter.SHOW_TEXT) != 0); + break; + case Node.CDATA_SECTION_NODE: + show = ((whatToShow & NodeFilter.SHOW_CDATA_SECTION) != 0); + break; + case Node.ELEMENT_NODE: + show = ((whatToShow & NodeFilter.SHOW_ELEMENT) != 0); + break; + case Node.COMMENT_NODE: + show = ((whatToShow & NodeFilter.SHOW_COMMENT) != 0); + break; + case Node.DOCUMENT_NODE: + show = ((whatToShow & NodeFilter.SHOW_DOCUMENT) != 0); + break; + case Node.PROCESSING_INSTRUCTION_NODE: + show = ((whatToShow & NodeFilter.SHOW_PROCESSING_INSTRUCTION) != 0); + break; + case Node.DOCUMENT_FRAGMENT_NODE: + show = ((whatToShow & NodeFilter.SHOW_DOCUMENT_FRAGMENT) != 0); + break; + case Node.DOCUMENT_TYPE_NODE: + show = ((whatToShow & NodeFilter.SHOW_DOCUMENT_TYPE) != 0); + break; + case Node.ENTITY_REFERENCE_NODE: + show = ((whatToShow & NodeFilter.SHOW_ENTITY_REFERENCE) != 0); + break; + case Node.ENTITY_NODE: + show = ((whatToShow & NodeFilter.SHOW_ENTITY) != 0); + break; + case Node.NOTATION_NODE: + show = ((whatToShow & NodeFilter.SHOW_NOTATION) != 0); + break; + } + } + if (!show) + { + return LSParserFilter.FILTER_ACCEPT; + } + if (start) + { + return filter.startElement((Element) node); + } + return filter.acceptNode(node); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/ls/ReaderInputStream.java b/libjava/classpath/gnu/xml/dom/ls/ReaderInputStream.java new file mode 100644 index 000000000..cf279ab39 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/ls/ReaderInputStream.java @@ -0,0 +1,236 @@ +/* ReaderInputStream.java -- + Copyright (C) 1999, 2000, 2001, 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.xml.dom.ls; + +import java.io.InputStream; +import java.io.IOException; +import java.io.Reader; + +/** + * Character stream wrapper. + * + * @author Chris Burdess + * @author Mark Wielaard + */ +public class ReaderInputStream + extends InputStream +{ + + private Reader reader; + private String encoding; + + // Holds extra spillover data if necessary + private byte extra[]; + private int pos; + + private byte extra_marked[]; + private int pos_marked; + + public ReaderInputStream(Reader reader) + { + this.reader = reader; + this.encoding = "UTF-8"; + } + + void setEncoding(String encoding) + { + this.encoding = encoding; + } + + public int read() + throws IOException + { + if (extra != null) + { + int result = extra[pos]; + pos++; + if (pos >= extra.length) + { + extra = null; + } + return result; + } + return reader.read(); + } + + public int read(byte[] b) + throws IOException + { + return read(b, 0, b.length); + } + + public int read(byte[] b, int off, int len) + throws IOException + { + if (len == 0) + { + return 0; + } + + if (extra != null) + { + int available = extra.length - pos; + int l = available < len ? available : len; + System.arraycopy(extra, 0, b, off, l); + pos += l; + if (pos >= extra.length) + { + extra = null; + } + return l; + } + + char[] c = new char[len]; + int l = reader.read(c, 0, len); + if (l == -1) + { + return -1; + } + + String s = new String(c, 0, l); + byte[] d = s.getBytes(encoding); + + int available = d.length; + int more = d.length - len; + if (more > 0) + { + extra = new byte[more]; + pos = 0; + System.arraycopy(d, len, extra, 0, more); + available -= more; + } + + System.arraycopy(d, 0, b, off, available); + return available; + } + + public void close() + throws IOException + { + reader.close(); + } + + public boolean markSupported() + { + return reader.markSupported(); + } + + public void mark(int limit) + { + if (extra != null) + { + extra_marked = new byte[extra.length]; + System.arraycopy(extra, 0, extra_marked, 0, extra.length); + pos_marked = pos; + } + else + { + extra_marked = null; + } + + try + { + // Note that this might be a bit more than asked for. + // Because we might also have the extra_marked bytes. + // That is fine (and necessary for reset() to work). + reader.mark(limit); + } + catch (IOException ioe) + { + throw new RuntimeException(ioe); + } + } + + public void reset() + throws IOException + { + extra = extra_marked; + pos = pos_marked; + extra_marked = null; + + reader.reset(); + } + + public long skip(long n) + throws IOException + { + long done = 0; + if (extra != null) + { + int available = extra.length - pos; + done = available < n ? available : n; + pos += done; + if (pos >= extra.length) + { + extra = null; + } + } + + n -= done; + if (n > 0) + { + return reader.skip(n) + done; + } + else + { + return done; + } + } + + /** + * Returns conservative number of bytes available without blocking. + * Actual number of bytes that can be read without blocking might + * be (much) bigger. + */ + public int available() + throws IOException + { + if (extra != null) + { + return pos - extra.length; + } + + return reader.ready() ? 1 : 0; + } + + public String toString() + { + return getClass().getName() + "[" + reader + ", " + encoding + "]"; + } + +} diff --git a/libjava/classpath/gnu/xml/dom/ls/SAXEventSink.java b/libjava/classpath/gnu/xml/dom/ls/SAXEventSink.java new file mode 100644 index 000000000..06333dd7e --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/ls/SAXEventSink.java @@ -0,0 +1,603 @@ +/* SAXEventSink.java -- + Copyright (C) 1999,2000,2001 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.dom.ls; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import javax.xml.XMLConstants; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.Element; +import org.w3c.dom.Entity; +import org.w3c.dom.EntityReference; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.Text; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.DTDHandler; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.XMLReader; +import org.xml.sax.ext.Attributes2; +import org.xml.sax.ext.DeclHandler; +import org.xml.sax.ext.LexicalHandler; +import org.xml.sax.ext.Locator2; +import gnu.xml.dom.DomAttr; +import gnu.xml.dom.DomDocument; +import gnu.xml.dom.DomDoctype; +import gnu.xml.dom.DomNode; + +/** + * A SAX content and lexical handler used to construct a DOM document. + * + * @author Chris Burdess + */ +public class SAXEventSink + implements ContentHandler, LexicalHandler, DTDHandler, DeclHandler +{ + + private static final String XMLNS_URI = XMLConstants.XMLNS_ATTRIBUTE_NS_URI; + private static final String XMLNS_PREFIX = XMLConstants.XMLNS_ATTRIBUTE; + private static final HashSet PREDEFINED_ENTITIES = new HashSet(); + static + { + PREDEFINED_ENTITIES.add("amp"); + PREDEFINED_ENTITIES.add("lt"); + PREDEFINED_ENTITIES.add("gt"); + PREDEFINED_ENTITIES.add("quot"); + PREDEFINED_ENTITIES.add("apos"); + } + + private boolean namespaceAware; + boolean ignoreWhitespace; + boolean expandEntityReferences; + boolean ignoreComments; + boolean coalescing; + + XMLReader reader; // reference back to the parser to get features + + DomDocument doc; // document being constructed + Node ctx; // current context (parent node) + LinkedList entityCtx; // entity context + List pending; // namespace nodes waiting for a declaring element + Locator locator; + boolean inCDATA; + boolean inDTD; + boolean interrupted; + + void interrupt() + { + interrupted = true; + } + + public Document getDocument() + { + return doc; + } + + public void setReader(XMLReader reader) + { + this.reader = reader; + } + + // -- ContentHandler2 -- + + public void setDocumentLocator(Locator locator) + { + this.locator = locator; + } + + public void setNamespaceAware(boolean namespaceAware) + { + this.namespaceAware = namespaceAware; + } + + public void startDocument() + throws SAXException + { + if (namespaceAware) + { + pending = new LinkedList(); + } + doc = new DomDocument(); + doc.setStrictErrorChecking(false); + doc.setBuilding(true); + doc.setDefaultAttributes(false); + ctx = doc; + + final String FEATURES = "http://xml.org/sax/features/"; + final String PROPERTIES = "http://xml.org/sax/properties/"; + final String GNU_PROPERTIES = "http://gnu.org/sax/properties/"; + + if (reader != null) + { + boolean standalone = reader.getFeature(FEATURES + "is-standalone"); + doc.setXmlStandalone(standalone); + try + { + String version = (String) reader.getProperty(PROPERTIES + + "document-xml-version"); + doc.setXmlVersion(version); + } + catch (SAXNotRecognizedException e) + { + } + catch (SAXNotSupportedException e) + { + } + try + { + String encoding = (String) reader.getProperty(GNU_PROPERTIES + + "document-xml-encoding"); + doc.setXmlEncoding(encoding); + } + catch (SAXNotRecognizedException e) + { + } + catch (SAXNotSupportedException e) + { + } + } + if (locator != null && locator instanceof Locator2) + { + String encoding = ((Locator2) locator).getEncoding(); + doc.setInputEncoding(encoding); + } + } + + public void endDocument() + throws SAXException + { + doc.setStrictErrorChecking(true); + doc.setBuilding(false); + doc.setDefaultAttributes(true); + DomDoctype doctype = (DomDoctype) doc.getDoctype(); + if (doctype != null) + { + doctype.makeReadonly(); + } + ctx = null; + locator = null; + } + + public void startPrefixMapping(String prefix, String uri) + throws SAXException + { + if (namespaceAware) + { + String nsName = (prefix != null && prefix.length() > 0) ? + XMLNS_PREFIX + ":" + prefix : XMLNS_PREFIX; + DomAttr ns = (DomAttr) doc.createAttributeNS(XMLNS_URI, nsName); + ns.setNodeValue(uri); + if (ctx.getNodeType() == Node.ATTRIBUTE_NODE) + { + // Add to owner element + Node target = ((Attr) ctx).getOwnerElement(); + target.getAttributes().setNamedItemNS(ns); + } + else + { + // Add to pending list; namespace node will be inserted when + // element is seen + pending.add(ns); + } + } + } + + public void endPrefixMapping(String prefix) + throws SAXException + { + } + + public void startElement(String uri, String localName, String qName, + Attributes atts) + throws SAXException + { + if (interrupted) + { + return; + } + Element element = createElement(uri, localName, qName, atts); + // add element to context + ctx.appendChild(element); + ctx = element; + } + + protected Element createElement(String uri, String localName, String qName, + Attributes atts) + throws SAXException + { + // create element node + Element element = namespaceAware ? + doc.createElementNS(uri, qName) : + doc.createElement(qName); + NamedNodeMap attrs = element.getAttributes(); + if (namespaceAware && !pending.isEmpty()) + { + // add pending namespace nodes + for (Iterator i = pending.iterator(); i.hasNext(); ) + { + Node ns = (Node) i.next(); + attrs.setNamedItemNS(ns); + } + pending.clear(); + } + // add attributes + int len = atts.getLength(); + for (int i = 0; i < len; i++) + { + // create attribute + Attr attr = createAttr(atts, i); + if (attr != null) + { + // add attribute to element + if (namespaceAware) + { + attrs.setNamedItemNS(attr); + } + else + { + attrs.setNamedItem(attr); + } + } + } + return element; + } + + protected Attr createAttr(Attributes atts, int index) + { + DomAttr attr; + if (namespaceAware) + { + String a_uri = atts.getURI(index); + String a_qName = atts.getQName(index); + attr = (DomAttr) doc.createAttributeNS(a_uri, a_qName); + } + else + { + String a_qName = atts.getQName(index); + attr = (DomAttr) doc.createAttribute(a_qName); + } + attr.setNodeValue(atts.getValue(index)); + if (atts instanceof Attributes2) + { + Attributes2 atts2 = (Attributes2) atts; + // TODO attr.setDeclared(atts2.isDeclared(index)); + attr.setSpecified(atts2.isSpecified(index)); + } + return attr; + } + + public void endElement(String uri, String localName, String qName) + throws SAXException + { + if (interrupted) + { + return; + } + if (namespaceAware) + { + pending.clear(); + } + ctx = ctx.getParentNode(); + } + + public void characters(char[] c, int off, int len) + throws SAXException + { + if (interrupted || len < 1) + { + return; + } + ctx.appendChild(createText(c, off, len)); + } + + protected Text createText(char[] c, int off, int len) + throws SAXException + { + Text text = (inCDATA && !coalescing) ? + doc.createCDATASection(new String(c, off, len)) : + doc.createTextNode(new String(c, off, len)); + return text; + } + + public void ignorableWhitespace(char[] c, int off, int len) + throws SAXException + { + if (interrupted) + { + return; + } + if (!ignoreWhitespace) + { + characters(c, off, len); + } + } + + public void processingInstruction(String target, String data) + throws SAXException + { + if (interrupted) + { + return; + } + Node pi = createProcessingInstruction(target, data); + ctx.appendChild(pi); + } + + protected Node createProcessingInstruction(String target, String data) + { + return doc.createProcessingInstruction(target, data); + } + + public void skippedEntity(String name) + throws SAXException + { + // This callback is totally pointless + } + + // -- LexicalHandler -- + + public void startDTD(String name, String publicId, String systemId) + throws SAXException + { + if (interrupted) + { + return; + } + Node doctype = createDocumentType(name, publicId, systemId); + doc.appendChild(doctype); + ctx = doctype; + inDTD = true; + } + + protected Node createDocumentType(String name, String publicId, + String systemId) + { + return new DomDoctype(doc, name, publicId, systemId); + } + + public void endDTD() + throws SAXException + { + if (interrupted) + { + return; + } + inDTD = false; + ctx = ctx.getParentNode(); + } + + public void startEntity(String name) + throws SAXException + { + if (interrupted) + return; + DocumentType doctype = doc.getDoctype(); + if (doctype == null) + { + throw new SAXException("SAX parser error: " + + "reference to entity in undeclared doctype"); + } + if ("[dtd]".equals(name) || name.charAt(0) == '%') + return; + if (PREDEFINED_ENTITIES.contains(name)) + return; + // Get entity + NamedNodeMap entities = doctype.getEntities(); + Entity entity = (Entity) entities.getNamedItem(name); + if (entity == null) + { + throw new SAXException("SAX parser error: " + + "reference to undeclared entity: " + name); + } + EntityReference ref = doc.createEntityReference(name); + // DomDocument populates with the entity replacement text, remove this + Node child = ref.getFirstChild(); + while (child != null) + { + Node nextChild = child.getNextSibling(); + ref.removeChild(child); + child = nextChild; + } + ctx.appendChild(ref); + ctx = ref; + } + + public void endEntity(String name) + throws SAXException + { + if (interrupted) + return; + if ("[dtd]".equals(name) || name.charAt(0) == '%') + return; + if (PREDEFINED_ENTITIES.contains(name)) + return; + // Get entity reference + EntityReference ref = (EntityReference) ctx; + if (!ref.getNodeName().equals(name)) + throw new SAXException("expecting end of "+ref.getNodeName()+" entity"); + ctx = ctx.getParentNode(); + if (ref instanceof DomNode) + ((DomNode) ref).makeReadonly(); + if (expandEntityReferences) + { + // Move entity content from reference node onto context + Node child = ref.getFirstChild(); + while (child != null) + { + Node nextChild = child.getNextSibling(); + ctx.appendChild(child); + child = nextChild; + } + ctx.removeChild(ref); + } + } + + public void startCDATA() + throws SAXException + { + inCDATA = true; + } + + public void endCDATA() + throws SAXException + { + inCDATA = false; + } + + public void comment(char[] c, int off, int len) + throws SAXException + { + if (interrupted) + { + return; + } + Node comment = createComment(c, off, len); + ctx.appendChild(comment); + } + + protected Node createComment(char[] c, int off, int len) + { + return doc.createComment(new String(c, off, len)); + } + + // -- DTDHandler -- + + public void notationDecl(String name, String publicId, String systemId) + throws SAXException + { + if (interrupted) + { + return; + } + if (!inDTD) + throw new SAXException("notation decl outside DTD"); + DomDoctype doctype = (DomDoctype) ctx; + doctype.declareNotation(name, publicId, systemId); + } + + public void unparsedEntityDecl(String name, String publicId, String systemId, + String notationName) + throws SAXException + { + if (interrupted) + { + return; + } + if (!inDTD) + throw new SAXException("unparsed entity decl outside DTD"); + DomDoctype doctype = (DomDoctype) ctx; + Entity entity = doctype.declareEntity(name, publicId, systemId, + notationName); + } + + // -- DeclHandler -- + + public void elementDecl(String name, String model) + throws SAXException + { + if (interrupted) + { + return; + } + if (!inDTD) + throw new SAXException("element decl outside DTD"); + // Ignore fake element declarations generated by ValidationConsumer. + // If an element is not really declared in the DTD it will not be + // declared in the document model. + if (!(ctx instanceof DomDoctype)) + { + return; + } + DomDoctype doctype = (DomDoctype) ctx; + doctype.elementDecl(name, model); + } + + public void attributeDecl(String eName, String aName, String type, + String mode, String value) + throws SAXException + { + if (interrupted) + { + return; + } + if (!inDTD) + throw new SAXException("attribute decl outside DTD"); + DomDoctype doctype = (DomDoctype) ctx; + doctype.attributeDecl(eName, aName, type, mode, value); + } + + public void internalEntityDecl(String name, String value) + throws SAXException + { + if (interrupted) + { + return; + } + if (!inDTD) + throw new SAXException("internal entity decl outside DTD"); + DomDoctype doctype = (DomDoctype) ctx; + Entity entity = doctype.declareEntity(name, null, null, null); + if (entity != null) + { + Node text = doc.createTextNode(value); + entity.appendChild(text); + } + } + + public void externalEntityDecl(String name, String publicId, String systemId) + throws SAXException + { + if (interrupted) + { + return; + } + if (!inDTD) + throw new SAXException("external entity decl outside DTD"); + DomDoctype doctype = (DomDoctype) ctx; + Entity entity = doctype.declareEntity(name, publicId, systemId, null); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/ls/WriterOutputStream.java b/libjava/classpath/gnu/xml/dom/ls/WriterOutputStream.java new file mode 100644 index 000000000..f1ae344f4 --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/ls/WriterOutputStream.java @@ -0,0 +1,97 @@ +/* WriterOutputStream.java -- + Copyright (C) 1999,2000,2001 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.dom.ls; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.Writer; + +/** + * Character stream wrapper. + * + * @author Chris Burdess + */ +public class WriterOutputStream + extends OutputStream +{ + + private Writer writer; + private String encoding; + + public WriterOutputStream(Writer writer) + { + this.writer = writer; + this.encoding = "UTF-8"; + } + + void setEncoding(String encoding) + { + this.encoding = encoding; + } + + public void write(int c) + throws IOException + { + writer.write(c); + } + + public void write(byte[] b) + throws IOException + { + write(b, 0, b.length); + } + + public void write(byte[] b, int off, int len) + throws IOException + { + writer.write(new String(b, off, len, encoding)); + } + + public void close() + throws IOException + { + writer.close(); + } + + public void flush() + throws IOException + { + writer.flush(); + } + +} diff --git a/libjava/classpath/gnu/xml/dom/package.html b/libjava/classpath/gnu/xml/dom/package.html new file mode 100644 index 000000000..fbc864a4d --- /dev/null +++ b/libjava/classpath/gnu/xml/dom/package.html @@ -0,0 +1,273 @@ + + + +

      +This is a Free Software DOM Level 3 implementation, supporting these features: +

        +
      • "XML"
      • +
      • "Events"
      • +
      • "MutationEvents"
      • +
      • "HTMLEvents" (won't generate them though)
      • +
      • "UIEvents" (also won't generate them)
      • +
      • "USER-Events" (a conformant extension)
      • +
      • "Traversal" (optional)
      • +
      • "XPath"
      • +
      • "LS" and "LS-Async"
      • +
      +It is intended to be a reasonable base both for +experimentation and supporting additional DOM modules as clean layers. +

      + +

      +Note that while DOM does not specify its behavior in the +face of concurrent access, this implementation does. +Specifically: +

        +
      • If only one thread at a time accesses a Document, +of if several threads cooperate for read-only access, +then no concurrency conflicts will occur.
      • +
      • If several threads mutate a given document +(or send events using it) at the same time, +there is currently no guarantee that +they won't interfere with each other.
      • +
      +

      + +

      Design Goals

      + +

      +A number of DOM implementations are available in Java, including +commercial ones from Sun, IBM, Oracle, and DataChannel as well as +noncommercial ones from Docuverse, OpenXML, and Silfide. Why have +another? Some of the goals of this version: +

      + +
        +
      • Advanced DOM support. This was the first generally available +implementation of DOM Level 2 in Java, and one of the first Level 3 +and XPath implementations.
      • + +
      • Free Software. This one is distributed under the GPL (with +"library exception") so it can be used with a different class of +application.
      • + +
      • Second implementation syndrome. I can do it simpler this time +around ... and heck, writing it only takes a bit over a day once you +know your way around.
      • + +
      • Sanity check the then-current Last Call DOM draft. Best to find +bugs early, when they're relatively fixable. Yes, bugs were found.
      • + +
      • Modularity. Most of the implementations mentioned above are part +of huge packages; take all (including bugs, of which some have far +too many), or take nothing. I prefer a menu approach, when possible. +This code is standalone, not beholden to any particular parser or XSL +or XPath code.
      • + +
      • OK, I'm a hacker, I like to write code.
      • +
      + +

      +This also works with the GNU Compiler for Java (GCJ). GCJ promises +to be quite the environment for programming Java, both directly and from +C++ using the new CNI interfaces (which really use C++, unlike JNI).

      + + +

      Open Issues

      + +

      At this writing:

      +
        +
      • See below for some restrictions on the mutation event +support ... some events aren't reported (and likely won't be).
      • + +
      • More testing and conformance work is needed.
      • + +
      • We need an XML Schema validator (actually we need validation in the DOM +full stop).
      • +
      + +

      +I ran a profiler a few times and remove some of the performance hotspots, +but it's not tuned. Reporting mutation events, in particular, is +rather costly -- it started at about a 40% penalty for appendNode calls, +I've got it down around 12%, but it'll be hard to shrink it much further. +The overall code size is relatively small, though you may want to be rid of +many of the unused DOM interface classes (HTML, CSS, and so on). +

      + + +

      Features of this Package

      + +

      Starting with DOM Level 2, you can really see that DOM is constructed +as a bunch of optional modules around a core of either XML or HTML +functionality. Different implementations will support different optional +modules. This implementation provides a set of features that should be +useful if you're not depending on the HTML functionality (lots of convenience +functions that mostly don't buy much except API surface area) and user +interface support. That is, browsers will want more -- but what they +need should be cleanly layered over what's already here.

      + +

      Core Feature Set: "XML"

      + +

      This DOM implementation supports the "XML" feature set, which basically +gets you four things over the bare core (which you're officially not supposed +to implement except in conjunction with the "XML" or "HTML" feature). In +order of decreasing utility, those four things are:

        + +
      1. ProcessingInstruction nodes. These are probably the most + valuable thing. Handy little buggers, in part because all the APIs + you need to use them are provided, and they're designed to let you + escape XML document structure rules in controlled ways.
      2. + +
      3. CDATASection nodes. These are of of limited utility since CDATA + is just text that prints funny. These are of use to some sorts of + applications, though I encourage folk to not use them.
      4. + +
      5. DocumentType nodes, and associated Notation and Entity nodes. + These appear to be useless. Briefly, these "Type" nodes expose no + typing information. They're only really usable to expose some lexical + structure that almost every application needs to ignore. (XML editors + might like to see them, but they need true typing information much more.) + I strongly encourage people not to use these.
      6. + +
      7. EntityReference nodes can show up. These are actively annoying, + since they add an extra level of hierarchy, are the cause of most of + the complexity in attribute values, and their contents are immutable. + Avoid these.
      8. + +
      + +

      Optional Feature Sets: "Events", and friends

      + +

      Events may be one of the more interesting new features in Level 2. +This package provides the core feature set and exposes mutation events. +No gooey events though; if you want that, write a layered implementation!

      + +

      Three mutation events aren't currently generated:

        + +
      • DOMSubtreeModified is poorly specified. Think of this + as generating one such event around the time of finalization, which + is a fully conformant implementation. This implementation is exactly + as useful as that one.
      • + +
      • DOMNodeRemovedFromDocument and + DOMNodeInsertedIntoDocument are supposed to get sent to + every node in a subtree that gets removed or inserted (respectively). + This can be extremely costly, and the removal and insertion + processing is already significantly slower due to event reporting. + It's much easier, and more efficient, to have a listener higher in the + tree watch removal and insertion events through the bubbling or capture + mechanisms, than it is to watch for these two events.
      • + +
      + +

      In addition, certain kinds of attribute modification aren't reported. +A fix is known, but it couldn't report the previous value of the attribute. +More work could fix all of this (as well as reduce the generally high cost +of childful attributes), but that's not been done yet.

      + +

      Also, note that it is a Bad Thing™ to have the listener +for a mutation event change the ancestry for the target of that event. +Or to prevent mutation events from bubbling to where they're needed. +Just don't do those, OK?

      + +

      As an experimental feature (named "USER-Events"), you can provide +your own "user" events. Just name them anything starting with "USER-" +and you're set. Dispatch them through, bubbling, capturing, or what +ever takes your fancy. One important thing you can't currently do is +pass any data (like an object) with those events. Maybe later there +will be a "UserEvent" interface letting you get some substantial use +out of this mechanism even if you're not "inside" of a DOM package.

      + +

      You can create and send HTML events. Ditto UIEvents. Since DOM +doesn't require a UI, it's the UI's job to send them; perhaps that's +part of your application.

      + +

      This package may be built without the ability to report mutation +events, gaining a significant speedup in DOM construction time. However, +if that is done then certain other features -- notably node iterators +and getElementsByTagname -- will not be available. + + +

      Optional Feature: "Traversal"

      + +

      Each DOM node has all you need to walk to everything connected +to that node. Lightweight, efficient utilities are easily layered on +top of just the core APIs.

      + +

      Traversal APIs are an optional part of DOM Level 2, providing +a not-so-lightweight way to walk over DOM trees, if your application +didn't already have such utilities for use with data represented via +DOM. Implementing this helped debug the (optional) event and mutation +event subsystems, so it's provided here.

      + +

      At this writing, the "TreeWalker" interface isn't implemented.

      + + + +

      DOM Functionality to Avoid

      + +

      For what appear to be a combination of historical and "committee +logic" reasons, DOM has a number of features which I strongly advise +you to avoid using in your library and application code. These +include the following types of DOM nodes; see the documentation for the +implementation class for more information:

        + +
      • CDATASection + (DomCDATA class) + ... use normal Text nodes instead, so you don't have to make + every algorithm recognize multiple types of character data + +
      • DocumentType + (DomDocType class) + ... if this held actual typing information, it might be useful + +
      • Entity + (DomEntity class) + ... neither parsed nor unparsed entities work well in DOM; it + won't even tell you which attributes identify unparsed entities + +
      • EntityReference + (DomEntityReference class) + ... permitted implementation variances are extreme, all children + are readonly, and these can interact poorly with namespaces + +
      • Notation + (DomNotation class) + ... only really usable with unparsed entities (which aren't well + supported; see above) or perhaps with PIs after the DTD, not with + NOTATION attributes + +
      + +

      If you really need to use unparsed entities or notations, use SAX; +it offers better support for all DTD-related functionality. +It also exposes actual +document typing information (such as element content models).

      + +

      Also, when accessing attribute values, use methods that provide their +values as single strings, rather than those which expose value substructure +(Text and EntityReference nodes). (See the DomAttr +documentation for more information.)

      + +

      Note that many of these features were provided as partial support for +editor functionality (including the incomplete DTD access). Full editor +functionality requires access to potentially malformed lexical structure, +at the level of unparsed tokens and below. Access at such levels is so +complex that using it in non-editor applications sacrifices all the +benefits of XML; editor aplications need extremely specialized APIs.

      + +

      (This isn't a slam against DTDs, note; only against the broken support +for them in DOM. Even despite inclusion of some dubious SGML legacy features +such as notations and unparsed entities, +and the ongoing proliferation of alternative schema and validation tools, +DTDs are still the most widely adopted tool +to constrain XML document structure. +Alternative schemes generally focus on data transfer style +applications; open document architectures comparable to +DocBook 4.0 don't yet exist in the schema world. +Feel free to use DTDs; just don't expect DOM to help you.)

      + + + + diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeAttr.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeAttr.java new file mode 100644 index 000000000..da9c62c9d --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeAttr.java @@ -0,0 +1,117 @@ +/* GnomeAttr.java - + 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.xml.libxmlj.dom; + +import gnu.java.lang.CPStringBuilder; + +import org.w3c.dom.Attr; +import org.w3c.dom.DOMException; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.TypeInfo; + +/** + * A DOM attribute node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeAttr + extends GnomeNode + implements Attr +{ + + GnomeAttr(Object id) + { + super(id); + } + + public String getName() + { + return getNodeName(); + } + + public native boolean getSpecified(); + + public native String getValue(); + + public native void setValue(String value) + throws DOMException; + + public Node getParentNode() + { + return null; + } + + public Element getOwnerElement() + { + return (Element) super.getParentNode(); + } + + // DOM Level 3 methods + + public TypeInfo getSchemaTypeInfo() + { + return new GnomeTypeInfo(id); + } + + public boolean isId() + { + if (xmljIsId()) + { + return true; + } + GnomeElement element = (GnomeElement) getOwnerElement(); + return (element != null && + element.userIdAttrs != null && + element.userIdAttrs.contains(this)); + } + + private native boolean xmljIsId(); + + public String toString() + { + CPStringBuilder buffer = new CPStringBuilder(getClass().getName()); + buffer.append("[name="); + buffer.append(getName()); + buffer.append(",value="); + buffer.append(getValue()); + buffer.append("]"); + return buffer.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeCDATASection.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeCDATASection.java new file mode 100644 index 000000000..3e408e653 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeCDATASection.java @@ -0,0 +1,57 @@ +/* GnomeCDATASection.java - + 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.xml.libxmlj.dom; + +import org.w3c.dom.CDATASection; + +/** + * A DOM CDATA section node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeCDATASection + extends GnomeText + implements CDATASection +{ + + GnomeCDATASection(Object id) + { + super(id); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeCharacterData.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeCharacterData.java new file mode 100644 index 000000000..3f3d6ecb5 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeCharacterData.java @@ -0,0 +1,119 @@ +/* GnomeCharacterData.java - + 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.xml.libxmlj.dom; + +import gnu.java.lang.CPStringBuilder; + +import org.w3c.dom.CharacterData; +import org.w3c.dom.DOMException; + +/** + * A DOM character data node implemented in libxml2. + * + * @author Chris Burdess + */ +abstract class GnomeCharacterData + extends GnomeNode + implements CharacterData +{ + + GnomeCharacterData(Object id) + { + super(id); + } + + public String getData() + throws DOMException + { + return getNodeValue(); + } + + public void setData(String data) + throws DOMException + { + setNodeValue(data); + } + + public int getLength() + { + return getData().length(); + } + + public String substringData(int offset, int count) + throws DOMException + { + return getData().substring(offset, offset + count); + } + + public void appendData(String arg) + throws DOMException + { + setData(getData() + arg); + } + + public void insertData(int offset, String arg) + throws DOMException + { + String data = getData(); + setData(data.substring(0, offset) + arg + data.substring(offset)); + } + + public void deleteData(int offset, int count) + throws DOMException + { + String data = getData(); + setData(data.substring(0, offset) + data.substring(offset + count)); + } + + public void replaceData(int offset, int count, String arg) + { + String data = getData(); + setData(data.substring(0, offset) + arg + + data.substring(offset + count)); + } + + public String toString() + { + CPStringBuilder buffer = new CPStringBuilder(getClass().getName()); + buffer.append("[data="); + buffer.append(getData()); + buffer.append("]"); + return buffer.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeComment.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeComment.java new file mode 100644 index 000000000..b6985c4a4 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeComment.java @@ -0,0 +1,57 @@ +/* GnomeComment.java - + 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.xml.libxmlj.dom; + +import org.w3c.dom.Comment; + +/** + * A DOM comment node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeComment + extends GnomeCharacterData + implements Comment +{ + + GnomeComment(Object id) + { + super(id); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDOMException.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDOMException.java new file mode 100644 index 000000000..a1af82335 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDOMException.java @@ -0,0 +1,98 @@ +/* GnomeDOMException.java - + 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.xml.libxmlj.dom; + +import org.w3c.dom.DOMException; + +class GnomeDOMException + extends DOMException +{ + + GnomeDOMException(short code, String message) + { + super(code, createMessage(code, message)); + } + + private static String createMessage(int code, String message) + { + if (message != null) + { + return message; + } + switch (code) + { + case INDEX_SIZE_ERR: + return "INDEX_SIZE_ERR"; + case DOMSTRING_SIZE_ERR: + return "DOMSTRING_SIZE_ERR"; + case HIERARCHY_REQUEST_ERR: + return "HIERARCHY_REQUEST_ERR"; + case WRONG_DOCUMENT_ERR: + return "WRONG_DOCUMENT_ERR"; + case INVALID_CHARACTER_ERR: + return "INVALID_CHARACTER_ERR"; + case NO_DATA_ALLOWED_ERR: + return "NO_DATA_ALLOWED_ERR"; + case NO_MODIFICATION_ALLOWED_ERR: + return "NO_MODIFICATION_ALLOWED_ERR"; + case NOT_FOUND_ERR: + return "NOT_FOUND_ERR"; + case NOT_SUPPORTED_ERR: + return "NOT_SUPPORTED_ERR"; + case INUSE_ATTRIBUTE_ERR: + return "INUSE_ATTRIBUTE_ERR"; + case INVALID_STATE_ERR: + return "INVALID_STATE_ERR"; + case SYNTAX_ERR: + return "SYNTAX_ERR"; + case INVALID_MODIFICATION_ERR: + return "INVALID_MODIFICATION_ERR"; + case NAMESPACE_ERR: + return "NAMESPACE_ERR"; + case INVALID_ACCESS_ERR: + return "INVALID_ACCESS_ERR"; + case VALIDATION_ERR: + return "VALIDATION_ERR"; + case TYPE_MISMATCH_ERR: + return "TYPE_MISMATCH_ERR"; + default: + return null; + } + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDOMStringList.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDOMStringList.java new file mode 100644 index 000000000..c415ec782 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDOMStringList.java @@ -0,0 +1,84 @@ +/* GnomeDOMStringList.java - + 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.xml.libxmlj.dom; + +import org.w3c.dom.DOMStringList; + +/** + * Implementation of a string list using an array of strings. + * + * @author Chris Burdess + */ +class GnomeDOMStringList + implements DOMStringList +{ + + final String[] values; + + GnomeDOMStringList(String[] values) + { + this.values = values; + } + + public int getLength() + { + return values.length; + } + + public String item(int index) + { + if (index < 0 || index >= values.length) + { + return null; + } + return values[index]; + } + + public boolean contains(String value) + { + for (int i = 0; i < values.length; i++) + { + if (values[i].equalsIgnoreCase(value)) + { + return true; + } + } + return false; + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocument.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocument.java new file mode 100644 index 000000000..0d1b487d8 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocument.java @@ -0,0 +1,562 @@ +/* GnomeDocument.java - + 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.xml.libxmlj.dom; + +import gnu.java.lang.CPStringBuilder; +import gnu.xml.dom.DomNodeIterator; + +import java.util.Iterator; + +import org.w3c.dom.Attr; +import org.w3c.dom.CDATASection; +import org.w3c.dom.Comment; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.DocumentType; +import org.w3c.dom.DOMConfiguration; +import org.w3c.dom.DOMErrorHandler; +import org.w3c.dom.DOMException; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.DOMStringList; +import org.w3c.dom.Element; +import org.w3c.dom.EntityReference; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.ProcessingInstruction; +import org.w3c.dom.Text; +import org.w3c.dom.UserDataHandler; +import org.w3c.dom.traversal.DocumentTraversal; +import org.w3c.dom.traversal.NodeFilter; +import org.w3c.dom.traversal.NodeIterator; +import org.w3c.dom.traversal.TreeWalker; +import org.w3c.dom.xpath.XPathEvaluator; +import org.w3c.dom.xpath.XPathException; +import org.w3c.dom.xpath.XPathExpression; +import org.w3c.dom.xpath.XPathNSResolver; + +/** + * A DOM document node implemented in libxml2. + * + * @author Chris Burdess + */ +public class GnomeDocument + extends GnomeNode + implements Document, DOMConfiguration, XPathEvaluator, DocumentTraversal +{ + + DOMImplementation dom; + + /** + * Not currently used. + */ + boolean strictErrorChecking; + + /* DOMConfiguration */ + boolean canonicalForm = false; + boolean cdataSections = true; + boolean checkCharacterNormalization = false; + boolean comments = true; + boolean datatypeNormalization = false; + boolean elementContentWhitespace = true; + boolean entities = true; + DOMErrorHandler errorHandler; + boolean namespaces = true; + boolean namespaceDeclarations = true; + boolean normalizeCharacters = false; + boolean splitCdataSections = true; + boolean validate = false; + boolean validateIfSchema = false; + boolean wellFormed = true; + + GnomeDocument(Object id) + { + super(id); + strictErrorChecking = true; + } + + protected void finalize() + { + free(id); + } + + private native void free(Object id); + + public native DocumentType getDoctype(); + + public DOMImplementation getImplementation() + { + return dom; + } + + public native Element getDocumentElement(); + + public Element createElement(String tagName) + throws DOMException + { + return createElementNS(null, tagName); + } + + public native DocumentType createDocumentType(String name, String publicId, + String systemId); + + public native DocumentFragment createDocumentFragment(); + + public native Text createTextNode(String data); + + public native Comment createComment(String data); + + public native CDATASection createCDATASection(String data) + throws DOMException; + + public native ProcessingInstruction createProcessingInstruction(String target, + String data) + throws DOMException; + + public Attr createAttribute(String name) + throws DOMException + { + return createAttributeNS(null, name); + } + + public native EntityReference createEntityReference(String name) + throws DOMException; + + public native NodeList getElementsByTagName(String tagName); + + public Node importNode(Node importedNode, boolean deep) + throws DOMException + { + Node ret = xmljImportNode(importedNode, deep); + if (importedNode instanceof GnomeNode) + { + ((GnomeNode) importedNode) + .notifyUserDataHandlers(UserDataHandler.NODE_IMPORTED, + importedNode, ret); + } + return ret; + } + + private native Node xmljImportNode(Node importedNode, boolean deep) + throws DOMException; + + public native Element createElementNS(String namespaceURI, String + qualifiedName) + throws DOMException; + + public native Attr createAttributeNS(String namespaceURI, String + qualifiedName) + throws DOMException; + + public native NodeList getElementsByTagNameNS(String namespaceURI, + String localName); + + public Element getElementById(String elementId) + { + Element element = xmljGetElementById(elementId); + if (element == null) + { + TreeWalker walker = createTreeWalker(this, NodeFilter.SHOW_ELEMENT, + null, false); + for (Node node = walker.nextNode(); node != null; + node = walker.nextNode()) + { + GnomeElement e = (GnomeElement) node; + if (e.userIdAttrs != null) + { + for (Iterator i = e.userIdAttrs.iterator(); i.hasNext(); ) + { + Attr attr = (Attr) i.next(); + if (attr.getNodeValue().equals(elementId)) + { + return e; + } + } + } + } + } + return element; + } + + private native Element xmljGetElementById(String elementId); + + // DOM Level 3 methods + + public native String getInputEncoding(); + + public native String getXmlEncoding(); + + public native boolean getXmlStandalone(); + + public native void setXmlStandalone(boolean xmlStandalone); + + public native String getXmlVersion(); + + public native void setXmlVersion(String xmlVersion); + + public boolean getStrictErrorChecking() + { + return strictErrorChecking; + } + + public void setStrictErrorChecking(boolean strictErrorChecking) + { + this.strictErrorChecking = strictErrorChecking; + } + + public native String getDocumentURI(); + + public native void setDocumentURI(String documentURI); + + public Node adoptNode(Node source) + throws DOMException + { + if (source == null || !(source instanceof GnomeNode)) + { + return null; + } + Node ret = xmljAdoptNode(source); + if (source instanceof GnomeNode) + { + ((GnomeNode) source). + notifyUserDataHandlers(UserDataHandler.NODE_ADOPTED, + source, ret); + } + return ret; + } + + private native Node xmljAdoptNode(Node source) + throws DOMException; + + public DOMConfiguration getDomConfig() + { + return this; + } + + public void normalizeDocument() + { + normalize(); + } + + public native Node renameNode(Node n, String namespaceURI, + String qualifiedName); + + // -- DOMConfiguration methods -- + + public void setParameter(String name, Object value) + throws DOMException + { + name = name.toLowerCase(); + if ("canonical-form".equals(name)) + { + /* optional + canonicalForm = getBooleanValue(value);*/ + } + else if ("cdata-sections".equals(name)) + { + cdataSections = getBooleanValue(value); + } + else if ("check-character-normalization".equals(name)) + { + /* optional + checkCharacterNormalization = getBooleanValue(value);*/ + } + else if ("comments".equals(name)) + { + comments = getBooleanValue(value); + } + else if ("datatype-normalization".equals(name)) + { + /* optional + datatypeNormalization = getBooleanValue(value);*/ + } + else if ("element-content-whitespace".equals(name)) + { + /* optional + elementContentWhitespace = getBooleanValue(value);*/ + } + else if ("entities".equals(name)) + { + entities = getBooleanValue(value); + } + else if ("error-handler".equals(name)) + { + errorHandler = (DOMErrorHandler) value; + } + else if ("infoset".equals(name)) + { + if (getBooleanValue(value)) + { + validateIfSchema = false; + entities = false; + datatypeNormalization = false; + cdataSections = false; + namespaceDeclarations = true; + wellFormed = true; + elementContentWhitespace = true; + comments = true; + namespaces = true; + } + } + else if ("namespaces".equals(name)) + { + /* optional + namespaces = getBooleanValue(value);*/ + } + else if ("namespace-declarations".equals(name)) + { + namespaceDeclarations = getBooleanValue(value); + } + else if ("normalize-characters".equals(name)) + { + /* optional + normalizeCharacters = getBooleanValue(value);*/ + } + else if ("split-cdata-sections".equals(name)) + { + splitCdataSections = getBooleanValue(value); + } + else if ("validate".equals(name)) + { + /* optional + validate = getBooleanValue(value);*/ + } + else if ("validate-if-schema".equals(name)) + { + /* optional + validateIfSchema = getBooleanValue(value);*/ + } + else if ("well-formed".equals(name)) + { + /* optional + wellFormed = getBooleanValue(value);*/ + } + else + { + throw new GnomeDOMException(DOMException.NOT_FOUND_ERR, name); + } + } + + public Object getParameter(String name) + throws DOMException + { + name = name.toLowerCase(); + if ("canonical-form".equals(name)) + { + return Boolean.valueOf(canonicalForm); + } + else if ("cdata-sections".equals(name)) + { + return Boolean.valueOf(cdataSections); + } + else if ("check-character-normalization".equals(name)) + { + return Boolean.valueOf(checkCharacterNormalization); + } + else if ("comments".equals(name)) + { + return Boolean.valueOf(comments); + } + else if ("datatype-normalization".equals(name)) + { + return Boolean.valueOf(datatypeNormalization); + } + else if ("element-content-whitespace".equals(name)) + { + return Boolean.valueOf(elementContentWhitespace); + } + else if ("entities".equals(name)) + { + return Boolean.valueOf(entities); + } + else if ("error-handler".equals(name)) + { + return errorHandler; + } + else if ("infoset".equals(name)) + { + return Boolean.valueOf(!validateIfSchema && + !entities && + !datatypeNormalization && + !cdataSections && + namespaceDeclarations && + wellFormed && + elementContentWhitespace && + comments && + namespaces); + } + else if ("namespaces".equals(name)) + { + return Boolean.valueOf(namespaces); + } + else if ("namespace-declarations".equals(name)) + { + return Boolean.valueOf(namespaceDeclarations); + } + else if ("normalize-characters".equals(name)) + { + return Boolean.valueOf(normalizeCharacters); + } + else if ("split-cdata-sections".equals(name)) + { + return Boolean.valueOf(splitCdataSections); + } + else if ("validate".equals(name)) + { + return Boolean.valueOf(validate); + } + else if ("validate-if-schema".equals(name)) + { + return Boolean.valueOf(validateIfSchema); + } + else if ("well-formed".equals(name)) + { + return Boolean.valueOf(wellFormed); + } + else + { + throw new GnomeDOMException(DOMException.NOT_FOUND_ERR, name); + } + } + + public boolean canSetParameter(String name, Object value) + { + name = name.toLowerCase(); + if ("error-handler".equals(name)) + { + return (value == null || value instanceof DOMErrorHandler); + } + return ("cdata-sections".equals(name) || + "comments".equals(name) || + "entities".equals(name) || + "namespace-declarations".equals(name) || + "split-cdata-sections".equals(name)); + } + + public DOMStringList getParameterNames() + { + String[] names = new String[] { + "canonical-form", + "cdata-sections", + "check-character-normalization", + "comments", + "datatype-normalization", + "element-content-whitespace", + "entities", + "error-handler", + "infoset", + "namespaces", + "namespace-declarations", + "normalize-characters", + "split-cdata-sections", + "validate", + "validate-if-schema", + "well-formed" + }; + return new GnomeDOMStringList(names); + } + + private boolean getBooleanValue(Object value) + { + if (value instanceof Boolean) + { + return ((Boolean) value).booleanValue(); + } + else if (value instanceof String) + { + return Boolean.valueOf ((String) value).booleanValue(); + } + return false; + } + + // -- XPathEvaluator methods -- + + public XPathExpression createExpression(String expression, + XPathNSResolver resolver) + throws XPathException, DOMException + { + return new GnomeXPathExpression(this, expression, resolver); + } + + public XPathNSResolver createNSResolver(Node nodeResolver) + { + return new GnomeXPathNSResolver(nodeResolver); + } + + public native Object evaluate(String expression, + Node contextNode, + XPathNSResolver resolver, + short type, + Object result) + throws XPathException, DOMException; + + // -- DocumentTraversal methods -- + + public NodeIterator createNodeIterator(Node root, + int whatToShow, + NodeFilter filter, + boolean entityReferenceExpansion) + throws DOMException + { + return new DomNodeIterator(root, whatToShow, filter, + entityReferenceExpansion, false); + } + + public TreeWalker createTreeWalker(Node root, + int whatToShow, + NodeFilter filter, + boolean entityReferenceExpansion) + throws DOMException + { + return new DomNodeIterator(root, whatToShow, filter, + entityReferenceExpansion, true); + } + + // -- Debugging -- + + public String toString() + { + CPStringBuilder buffer = new CPStringBuilder(getClass().getName()); + buffer.append("[version="); + buffer.append(getXmlVersion()); + buffer.append(",standalone="); + buffer.append(getXmlStandalone()); + buffer.append("]"); + return buffer.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentBuilder.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentBuilder.java new file mode 100644 index 000000000..6dea87226 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentBuilder.java @@ -0,0 +1,326 @@ +/* GnomeDocumentBuilder.java - + 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.xml.libxmlj.dom; + +import java.io.InputStream; +import java.io.IOException; +import java.net.URL; +import javax.xml.parsers.DocumentBuilder; + +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.DOMImplementation; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +import gnu.xml.libxmlj.util.NamedInputStream; +import gnu.xml.libxmlj.util.StandaloneDocumentType; +import gnu.xml.libxmlj.util.StandaloneLocator; +import gnu.xml.libxmlj.util.XMLJ; + +/** + * A JAXP DOM implementation that uses Gnome libxml2 as the underlying + * parser and node representation. + * + * @author Chris Burdess + */ +public class GnomeDocumentBuilder + extends DocumentBuilder + implements DOMImplementation +{ + + static + { + XMLJ.init(); + } + + // -- DocumentBuilder -- + + private boolean validate; + private boolean coalesce; + private boolean expandEntities; + private EntityResolver entityResolver; + private ErrorHandler errorHandler; + private boolean seenFatalError; + + /** + * Constructs a new validating document builder. + */ + public GnomeDocumentBuilder() + { + this(true, false, false); + } + + /** + * Constructs a new document builder. + * @param validate whether to validate during parsing + * @param coalesce whether to merge CDATA as text nodes + * @param expandEntities whether to expand entity references + */ + public GnomeDocumentBuilder(boolean validate, + boolean coalesce, + boolean expandEntities) + { + this.validate = validate; + this.coalesce = coalesce; + this.expandEntities = expandEntities; + } + + public DOMImplementation getDOMImplementation() + { + return this; + } + + public boolean isNamespaceAware() + { + return true; + } + + public boolean isValidating() + { + return validate; + } + + public Document newDocument() + { + return createDocument(null, null, null); + } + + public Document parse(InputSource input) + throws SAXException, IOException + { + NamedInputStream in = XMLJ.getInputStream(input); + byte[] detectBuffer = in.getDetectBuffer(); + String publicId = input.getPublicId(); + String systemId = input.getSystemId(); + String base = XMLJ.getBaseURI(systemId); + // Handle zero-length document + if (detectBuffer == null) + { + throw new SAXParseException("No document element", publicId, + systemId, 0, 0); + } + seenFatalError = false; + return parseStream(in, + detectBuffer, + publicId, + systemId, + base, + validate, + coalesce, + expandEntities, + true, //entityResolver != null, + errorHandler != null); + } + + private native Document parseStream(InputStream in, + byte[] detectBuffer, + String publicId, + String systemId, + String base, + boolean validate, + boolean coalesce, + boolean expandEntities, + boolean entityResolver, + boolean errorHandler); + + public void setEntityResolver(EntityResolver resolver) + { + entityResolver = resolver; + } + + public void setErrorHandler(ErrorHandler handler) + { + errorHandler = handler; + } + + // -- DOMImplementation -- + + public boolean hasFeature(String name, String version) + { + if (name.length() == 0) + { + return false; + } + name = name.toLowerCase(); + if (name.charAt(0) == '+') + { + name = name.substring(1); + } + + if ("xml".equals(name) || "core".equals(name)) + { + return (version == null || + "".equals(version) || + "1.0".equals(version) || + "2.0".equals(version) || + "3.0".equals(version)); + + } + else if ("ls".equals(name) || "ls-async".equals(name)) + { + // TODO + /* + return (version == null || + "".equals(version) || + "3.0".equals(version)); + */ + return false; + } + else if ("traversal".equals(name)) + { + return (version == null || + "".equals(version) || + "2.0".equals(version)); + } + else if ("xpath".equals(name)) + { + return (version == null || + "".equals(version) || + "3.0".equals(version)); + } + return false; + } + + // DOM Level 3 + + public Object getFeature(String feature, String version) + { + if (hasFeature(feature, version)) + { + return this; + } + return null; + } + + public native Document createDocument(String namespaceURI, + String qualifiedName, + DocumentType doctype); + + public DocumentType createDocumentType(String qualifiedName, + String publicId, + String systemId) + { + return new StandaloneDocumentType(qualifiedName, publicId, systemId); + } + + // Callback hooks from JNI + + private void setDocumentLocator(Object ctx, Object loc) + { + // ignore + } + + private InputStream resolveEntity(String publicId, String systemId, + String base) + throws SAXException, IOException + { + String url = XMLJ.getAbsoluteURI(base, systemId); + InputStream in = null; + if (entityResolver != null) + { + InputSource source = entityResolver.resolveEntity(publicId, url); + if (source != null) + { + in = XMLJ.getInputStream(source); + } + } + if (in == null) + { + in = XMLJ.getInputStream(new URL(url)); + } + return in; + } + + private void warning(String message, + int lineNumber, + int columnNumber, + String publicId, + String systemId) + throws SAXException + { + if (!seenFatalError && errorHandler != null) + { + Locator l = new StandaloneLocator(lineNumber, + columnNumber, + publicId, + systemId); + errorHandler.warning(new SAXParseException(message, l)); + } + } + + private void error(String message, + int lineNumber, + int columnNumber, + String publicId, + String systemId) + throws SAXException + { + if (!seenFatalError && errorHandler != null) + { + Locator l = new StandaloneLocator(lineNumber, + columnNumber, + publicId, + systemId); + errorHandler.error(new SAXParseException(message, l)); + } + } + + private void fatalError(String message, + int lineNumber, + int columnNumber, + String publicId, + String systemId) + throws SAXException + { + if (!seenFatalError && errorHandler != null) + { + seenFatalError = true; + Locator l = new StandaloneLocator(lineNumber, + columnNumber, + publicId, + systemId); + errorHandler.fatalError(new SAXParseException(message, l)); + } + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentBuilderFactory.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentBuilderFactory.java new file mode 100644 index 000000000..448e12351 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentBuilderFactory.java @@ -0,0 +1,118 @@ +/* GnomeDocumentBuilderFactory.java - + 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.xml.libxmlj.dom; + +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +/** + * Factory for JAXP document builders using the libxml2 implementation. + * + * @author Chris Burdess + */ +public class GnomeDocumentBuilderFactory + extends DocumentBuilderFactory +{ + + private boolean secureProcessing; + + public GnomeDocumentBuilderFactory () + { + setNamespaceAware (true); + } + + public Object getAttribute (String name) + { + // TODO + return null; + } + + public DocumentBuilder newDocumentBuilder () + throws ParserConfigurationException + { + /* + if (!isNamespaceAware ()) + { + String msg = "Parser must be namespace-aware"; + throw new ParserConfigurationException (msg); + } + if (isIgnoringComments ()) + { + String msg = "Ignoring comments not supported"; + throw new ParserConfigurationException (msg); + } + if (isIgnoringElementContentWhitespace ()) + { + String msg = "Ignoring element content whitespace not supported"; + throw new ParserConfigurationException (msg); + } + */ + return new GnomeDocumentBuilder (isValidating (), + isCoalescing (), + isExpandEntityReferences ()); + } + + public void setAttribute (String name, Object value) + { + // 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/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentFragment.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentFragment.java new file mode 100644 index 000000000..3623eb6cf --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentFragment.java @@ -0,0 +1,57 @@ +/* GnomeDocumentFragment.java - + 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.xml.libxmlj.dom; + +import org.w3c.dom.DocumentFragment; + +/** + * A DOM document fragment node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeDocumentFragment +extends GnomeNode +implements DocumentFragment +{ + + GnomeDocumentFragment (Object id) + { + super (id); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentType.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentType.java new file mode 100644 index 000000000..7649b7339 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentType.java @@ -0,0 +1,98 @@ +/* GnomeDocumentType.java - + 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.xml.libxmlj.dom; + +import gnu.java.lang.CPStringBuilder; + +import org.w3c.dom.DocumentType; +import org.w3c.dom.NamedNodeMap; + +/** + * A DOM document type node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeDocumentType +extends GnomeNode +implements DocumentType +{ + + GnomeDocumentType (Object id) + { + super (id); + } + + public String getName () + { + return getNodeName (); + } + + public NamedNodeMap getEntities () + { + return new GnomeNamedNodeMap (id, 1); + } + + public NamedNodeMap getNotations () + { + return new GnomeNamedNodeMap (id, 2); + } + + public native String getPublicId (); + + public native String getSystemId (); + + public native String getInternalSubset (); + + public String toString () + { + String publicId = getPublicId (); + CPStringBuilder buffer = new CPStringBuilder (getClass ().getName ()); + buffer.append ("["); + if (publicId != null) + { + buffer.append ("publicId="); + buffer.append (publicId); + buffer.append (","); + } + buffer.append ("systemId="); + buffer.append (getSystemId ()); + buffer.append ("]"); + return buffer.toString (); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeElement.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeElement.java new file mode 100644 index 000000000..19889d663 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeElement.java @@ -0,0 +1,184 @@ +/* GnomeElement.java - + 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.xml.libxmlj.dom; + +import gnu.java.lang.CPStringBuilder; + +import java.util.HashSet; +import java.util.Set; + +import org.w3c.dom.Attr; +import org.w3c.dom.DOMException; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.w3c.dom.TypeInfo; + +/** + * A DOM element node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeElement + extends GnomeNode + implements Element +{ + + /** + * User-defined ID attributes. + */ + Set userIdAttrs; + + GnomeElement(Object id) + { + super(id); + } + + public String getTagName() + { + return getNodeName(); + } + + public native String getAttribute(String name); + + public native void setAttribute(String name, String value) + throws DOMException; + + public void removeAttribute(String name) + throws DOMException + { + Attr attr = getAttributeNode(name); + if (attr != null) + { + removeAttributeNode(attr); + } + } + + public native Attr getAttributeNode(String name); + + public native Attr setAttributeNode(Attr newAttr) + throws DOMException; + + public native Attr removeAttributeNode(Attr oldAttr) + throws DOMException; + + public native NodeList getElementsByTagName(String name); + + public native String getAttributeNS(String namespaceURI, String localName); + + public native void setAttributeNS(String namespaceURI, String + qualifiedName, String value) + throws DOMException; + + public void removeAttributeNS(String namespaceURI, String localName) + throws DOMException + { + Attr attr = getAttributeNodeNS(namespaceURI, localName); + if (attr != null) + { + removeAttributeNode(attr); + } + } + + public native Attr getAttributeNodeNS(String namespaceURI, + String localName); + + public native Attr setAttributeNodeNS(Attr newAttr) + throws DOMException; + + public native NodeList getElementsByTagNameNS(String namespaceURI, + String localName); + + public native boolean hasAttribute(String name); + + public native boolean hasAttributeNS(String namespaceURI, + String localName); + + // DOM Level 3 methods + + public TypeInfo getSchemaTypeInfo() + { + return new GnomeTypeInfo(id); + } + + public void setIdAttribute(String name, boolean isId) + { + Attr attr = getAttributeNode(name); + setIdAttributeNode(attr, isId); + } + + public void setIdAttributeNode(Attr attr, boolean isId) + { + if (attr == null)// FIXME || !attr.getOwnerElement().equals(this)) + { + throw new GnomeDOMException(DOMException.NOT_FOUND_ERR, null); + } + if (isId) + { + if (userIdAttrs == null) + { + userIdAttrs = new HashSet(); + } + userIdAttrs.add(attr); + } + else if (userIdAttrs != null) + { + userIdAttrs.remove(attr); + if (userIdAttrs.isEmpty()) + { + userIdAttrs = null; + } + } + } + + public void setIdAttributeNS(String namespaceURI, String localName, + boolean isId) + { + Attr attr = getAttributeNodeNS(namespaceURI, localName); + setIdAttributeNode(attr, isId); + } + + public String toString() + { + CPStringBuilder buffer = new CPStringBuilder(getClass().getName()); + buffer.append("[tagName="); + buffer.append(getTagName()); + buffer.append("]"); + return buffer.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeEntity.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeEntity.java new file mode 100644 index 000000000..a05217473 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeEntity.java @@ -0,0 +1,104 @@ +/* GnomeEntity.java - + 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.xml.libxmlj.dom; + +import gnu.java.lang.CPStringBuilder; + +import org.w3c.dom.Entity; + +/** + * A DOM entity node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeEntity +extends GnomeNode +implements Entity +{ + + GnomeEntity (Object id) + { + super (id); + } + + public native String getPublicId (); + + public native String getSystemId (); + + public native String getNotationName (); + + // DOM Level 3 methods + + public String getInputEncoding () + { + // TODO + return null; + } + + public String getXmlEncoding () + { + // TODO + return null; + } + + public String getXmlVersion () + { + // TODO + return null; + } + + public String toString () + { + String publicId = getPublicId (); + CPStringBuilder buffer = new CPStringBuilder (getClass ().getName ()); + buffer.append ("["); + if (publicId != null) + { + buffer.append ("publicId="); + buffer.append (publicId); + buffer.append (","); + } + buffer.append ("systemId="); + buffer.append (getSystemId ()); + buffer.append (",notationName="); + buffer.append (getNotationName ()); + buffer.append ("]"); + return buffer.toString (); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeEntityReference.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeEntityReference.java new file mode 100644 index 000000000..aa2fcf1e5 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeEntityReference.java @@ -0,0 +1,57 @@ +/* GnomeEntityReference.java - + 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.xml.libxmlj.dom; + +import org.w3c.dom.EntityReference; + +/** + * A DOM entity reference node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeEntityReference +extends GnomeNode +implements EntityReference +{ + + GnomeEntityReference (Object id) + { + super (id); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNamedNodeMap.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNamedNodeMap.java new file mode 100644 index 000000000..b8df4fede --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNamedNodeMap.java @@ -0,0 +1,92 @@ +/* GnomeNamedNodeMap.java - + 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.xml.libxmlj.dom; + +import org.w3c.dom.DOMException; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +/** + * A DOM named node map implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeNamedNodeMap +implements NamedNodeMap +{ + + /** + * The node id. + */ + private final Object id; + + /** + * The map type. + * 0=attributes + * 1=entities + * 2=notations + */ + private final int type; + + GnomeNamedNodeMap (Object id, int type) + { + this.id = id; + this.type = type; + } + + public native Node getNamedItem (String name); + + public native Node setNamedItem (Node arg) + throws DOMException; + + public native Node removeNamedItem (String name) + throws DOMException; + + public native Node item (int index); + + public native int getLength (); + + public native Node getNamedItemNS (String namespaceURI, String localName); + + public native Node setNamedItemNS (Node arg) + throws DOMException; + + public native Node removeNamedItemNS (String namespaceURI, + String localName); + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNode.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNode.java new file mode 100644 index 000000000..5874916e5 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNode.java @@ -0,0 +1,501 @@ +/* GnomeNode.java - + 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.xml.libxmlj.dom; + +import gnu.java.lang.CPStringBuilder; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.DOMException; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; +import org.w3c.dom.UserDataHandler; + +import gnu.xml.libxmlj.util.StandaloneDocumentType; + +/** + * A DOM node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeNode + implements Node, Comparable +{ + + /** + * Maps document pointers to a map of node pointers to node instances. + */ + static Map instances; + + /** + * Retrieves the node instance for the specified node pointer. + * This creates a new instance and adds it to the cache if required. + * @param doc the document pointer + * @param node the node pointer + * @param type the node type + */ + static GnomeNode newInstance(final Object doc, final Object node, + final int type) + { + if (doc == null) + { + throw new NullPointerException("doc"); + } + if (node == null) + { + throw new NullPointerException("node"); + } + if (instances == null) + { + instances = new HashMap(); + } + Map docNodes = (Map) instances.get(doc); + if (docNodes == null) + { + docNodes = new HashMap(1024); // TODO review optimal initial capacity + instances.put(doc, docNodes); + } + GnomeNode nodeInstance = (GnomeNode) docNodes.get(node); + if (nodeInstance != null) + { + return nodeInstance; // Return cached version + } + switch (type) + { + case ELEMENT_NODE: + nodeInstance = new GnomeElement(node); + break; + case ATTRIBUTE_NODE: + nodeInstance = new GnomeAttr(node); + break; + case TEXT_NODE: + nodeInstance = new GnomeText(node); + break; + case CDATA_SECTION_NODE: + nodeInstance = new GnomeCDATASection(node); + break; + case ENTITY_REFERENCE_NODE: + nodeInstance = new GnomeEntityReference(node); + break; + case ENTITY_NODE: + nodeInstance = new GnomeEntity(node); + break; + case PROCESSING_INSTRUCTION_NODE: + nodeInstance = new GnomeProcessingInstruction(node); + break; + case COMMENT_NODE: + nodeInstance = new GnomeComment(node); + break; + case DOCUMENT_NODE: + nodeInstance = new GnomeDocument(node); + break; + case DOCUMENT_TYPE_NODE: + nodeInstance = new GnomeDocumentType(node); + break; + case DOCUMENT_FRAGMENT_NODE: + nodeInstance = new GnomeDocumentFragment(node); + break; + case NOTATION_NODE: + nodeInstance = new GnomeNotation(node); + break; + default: + throw new IllegalArgumentException("Unknown node type: " + type); + } + docNodes.put(node, nodeInstance); + return nodeInstance; + } + + /** + * Frees the specified document. + * This removes all its nodes from the cache. + */ + static void freeDocument(final Object doc) + { + if (instances == null || doc == null) + { + return; + } + instances.remove(doc); + //System.out.println("Freed "+instances.remove(doc)); + } + + /** + * xmlNodePtr + */ + final Object id; + + Map userData; + Map userDataHandlers; + + GnomeNode(final Object id) + { + this.id = id; + } + + public native String getNodeName(); + + public native String getNodeValue() + throws DOMException; + + public native void setNodeValue(String nodeValue) + throws DOMException; + + public native short getNodeType(); + + public native Node getParentNode(); + + public NodeList getChildNodes() + { + return new GnomeNodeList(id); + } + + public native Node getFirstChild(); + + public native Node getLastChild(); + + public native Node getPreviousSibling(); + + public native Node getNextSibling(); + + public NamedNodeMap getAttributes() + { + return new GnomeNamedNodeMap(id, 0); + } + + public native Document getOwnerDocument(); + + public Node insertBefore(Node newChild, Node refChild) + throws DOMException + { + if (newChild instanceof StandaloneDocumentType) + { + DocumentType dt = (DocumentType) newChild; + newChild = ((GnomeDocument) getOwnerDocument()) + .createDocumentType(dt.getName(), dt.getPublicId(), + dt.getSystemId()); + } + if (newChild == null) + { + throw new GnomeDOMException(DOMException.NOT_FOUND_ERR, null); + } + if (!(newChild instanceof GnomeNode)) + { + throw new GnomeDOMException(DOMException.WRONG_DOCUMENT_ERR, null); + } + if (refChild == null || !(refChild instanceof GnomeNode)) + { + throw new GnomeDOMException(DOMException.NOT_FOUND_ERR, null); + } + return xmljInsertBefore(newChild, refChild); + } + + private native Node xmljInsertBefore(Node newChild, Node refChild) + throws DOMException; + + public Node replaceChild(Node newChild, Node oldChild) + throws DOMException + { + if (newChild instanceof StandaloneDocumentType) + { + DocumentType dt = (DocumentType) newChild; + newChild = ((GnomeDocument) getOwnerDocument()) + .createDocumentType(dt.getName(), dt.getPublicId(), + dt.getSystemId()); + } + if (newChild == null) + { + throw new GnomeDOMException(DOMException.NOT_FOUND_ERR, null); + } + if (!(newChild instanceof GnomeNode)) + { + throw new GnomeDOMException(DOMException.WRONG_DOCUMENT_ERR, newChild.toString()); + } + if (oldChild == null || !(oldChild instanceof GnomeNode)) + { + throw new GnomeDOMException(DOMException.NOT_FOUND_ERR, null); + } + return xmljReplaceChild(newChild, oldChild); + } + + private native Node xmljReplaceChild(Node newChild, Node oldChild) + throws DOMException; + + public Node removeChild(Node oldChild) + throws DOMException + { + if (!(oldChild instanceof GnomeNode)) + { + throw new GnomeDOMException(DOMException.WRONG_DOCUMENT_ERR, null); + } + return xmljRemoveChild(oldChild); + } + + private native Node xmljRemoveChild(Node oldChild) + throws DOMException; + + public Node appendChild(Node newChild) + throws DOMException + { + if (newChild instanceof StandaloneDocumentType) + { + DocumentType dt = (DocumentType) newChild; + newChild = ((GnomeDocument) getOwnerDocument()) + .createDocumentType(dt.getName(), dt.getPublicId(), + dt.getSystemId()); + } + if (!(newChild instanceof GnomeNode)) + { + throw new GnomeDOMException(DOMException.WRONG_DOCUMENT_ERR, null); + } + return xmljAppendChild(newChild); + } + + private native Node xmljAppendChild(Node newChild) + throws DOMException; + + public native boolean hasChildNodes(); + + public Node cloneNode(boolean deep) + { + Node ret = xmljCloneNode(deep); + notifyUserDataHandlers(UserDataHandler.NODE_CLONED, this, ret); + return ret; + } + + private native Node xmljCloneNode(boolean deep); + + public native void normalize(); + + public boolean isSupported(String feature, String version) + { + return getOwnerDocument().getImplementation() + .hasFeature(feature, version); + } + + public native String getNamespaceURI(); + + public native String getPrefix(); + + public native void setPrefix(String prefix) + throws DOMException; + + public native String getLocalName(); + + public native boolean hasAttributes(); + + public int hashCode() + { + return id.hashCode(); + } + + public boolean equals(Object other) + { + if (other == this) + { + return true; + } + return (other instanceof GnomeNode && + ((GnomeNode) other).id == id); + } + + // DOM Level 3 methods + + public native String getBaseURI(); + + public short compareDocumentPosition(Node other) + throws DOMException + { + return (short) compareTo(other); + } + + public final int compareTo(Object other) + { + if (other instanceof GnomeNode) + { + return xmljCompareTo(other); + } + return 0; + } + + private native int xmljCompareTo(Object other); + + public String getTextContent() + throws DOMException + { + switch (getNodeType()) + { + case ELEMENT_NODE: + case ATTRIBUTE_NODE: + case ENTITY_NODE: + case ENTITY_REFERENCE_NODE: + case DOCUMENT_FRAGMENT_NODE: + CPStringBuilder buffer = new CPStringBuilder(); + NodeList children = getChildNodes(); + int len = children.getLength(); + for (int i = 0; i < len; i++) + { + Node child = children.item(i); + String textContent = child.getTextContent(); + if (textContent != null) + { + buffer.append(textContent); + } + } + return buffer.toString(); + case TEXT_NODE: + case CDATA_SECTION_NODE: + case COMMENT_NODE: + case PROCESSING_INSTRUCTION_NODE: + return getNodeValue(); + default: + return null; + } + } + + public void setTextContent(String textContent) + throws DOMException + { + switch (getNodeType()) + { + case ENTITY_REFERENCE_NODE: + // entity references are read only + throw new GnomeDOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, + null); + case ELEMENT_NODE: + case ATTRIBUTE_NODE: + case ENTITY_NODE: + case DOCUMENT_FRAGMENT_NODE: + NodeList children = getChildNodes(); + int len = children.getLength(); + for (int i = 0; i < len; i++) + { + Node child = children.item(i); + removeChild(child); + } + if (textContent != null) + { + Text text = getOwnerDocument().createTextNode(textContent); + appendChild(text); + } + break; + case TEXT_NODE: + case CDATA_SECTION_NODE: + case COMMENT_NODE: + case PROCESSING_INSTRUCTION_NODE: + setNodeValue(textContent); + break; + } + } + + public boolean isSameNode(Node other) + { + return equals(other); + } + + public native String lookupPrefix(String namespaceURI); + + public native boolean isDefaultNamespace(String namespaceURI); + + public native String lookupNamespaceURI(String prefix); + + public native boolean isEqualNode(Node arg); + + public Object getFeature(String feature, String version) + { + return getOwnerDocument().getImplementation() + .getFeature(feature, version); + } + + public Object setUserData(String key, Object data, UserDataHandler handler) + { + // TODO handler + if (userData == null) + { + userData = new HashMap(); + } + if (handler != null) + { + if (userDataHandlers == null) + { + userDataHandlers = new HashMap(); + } + userDataHandlers.put(key, handler); + } + return userData.put(key, data); + } + + public Object getUserData(String key) + { + if (userData == null) + { + return null; + } + return userData.get(key); + } + + void notifyUserDataHandlers(short op, Node src, Node dst) + { + if (userDataHandlers != null) + { + for (Iterator i = userDataHandlers.entrySet().iterator(); i.hasNext(); ) + { + Map.Entry entry = (Map.Entry) i.next(); + String key = (String) entry.getKey(); + UserDataHandler handler = (UserDataHandler) entry.getValue(); + Object data = userData.get(key); + handler.handle(op, key, data, src, dst); + } + } + } + + public String toString() + { + CPStringBuilder buffer = new CPStringBuilder(getClass().getName()); + buffer.append("[nodeName="); + buffer.append(getNodeName()); + buffer.append("]"); + return buffer.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNodeList.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNodeList.java new file mode 100644 index 000000000..51a6d0bfa --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNodeList.java @@ -0,0 +1,66 @@ +/* GnomeNodeList.java - + 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.xml.libxmlj.dom; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * A DOM node list implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeNodeList +implements NodeList +{ + + /** + * The node id. + */ + private final Object id; + + GnomeNodeList (Object id) + { + this.id = id; + } + + public native Node item (int index); + + public native int getLength (); + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNotation.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNotation.java new file mode 100644 index 000000000..50e48e2a3 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeNotation.java @@ -0,0 +1,80 @@ +/* GnomeNotation.java - + 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.xml.libxmlj.dom; + +import gnu.java.lang.CPStringBuilder; + +import org.w3c.dom.Notation; + +/** + * A DOM notation node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeNotation +extends GnomeNode +implements Notation +{ + + GnomeNotation (Object id) + { + super (id); + } + + public native String getPublicId (); + + public native String getSystemId (); + + public String toString () + { + String publicId = getPublicId (); + CPStringBuilder buffer = new CPStringBuilder (getClass ().getName ()); + buffer.append ("["); + if (publicId != null) + { + buffer.append ("publicId="); + buffer.append (publicId); + buffer.append (","); + } + buffer.append ("systemId="); + buffer.append (getSystemId ()); + buffer.append ("]"); + return buffer.toString (); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeProcessingInstruction.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeProcessingInstruction.java new file mode 100644 index 000000000..fad6e108a --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeProcessingInstruction.java @@ -0,0 +1,79 @@ +/* GnomeProcessingInstruction.java - + 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.xml.libxmlj.dom; + +import gnu.java.lang.CPStringBuilder; + +import org.w3c.dom.DOMException; +import org.w3c.dom.ProcessingInstruction; + +/** + * A DOM processing instruction node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeProcessingInstruction +extends GnomeNode +implements ProcessingInstruction +{ + + GnomeProcessingInstruction (Object id) + { + super (id); + } + + public String getTarget () + { + return getNodeName (); + } + + public native String getData (); + + public native void setData (String data) + throws DOMException; + + public String toString () + { + CPStringBuilder buffer = new CPStringBuilder (getClass ().getName ()); + buffer.append ("[data="); + buffer.append (getData ()); + buffer.append ("]"); + return buffer.toString (); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeText.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeText.java new file mode 100644 index 000000000..e00be18a9 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeText.java @@ -0,0 +1,132 @@ +/* GnomeText.java - + 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.xml.libxmlj.dom; + +import gnu.java.lang.CPStringBuilder; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.Text; + +/** + * A DOM text node implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeText +extends GnomeCharacterData +implements Text +{ + + GnomeText (Object id) + { + super (id); + } + + public Text splitText (int offset) + throws DOMException + { + String value = getNodeValue (); + String part1 = value.substring (0, offset); + String part2 = value.substring (offset); + Text text = getOwnerDocument ().createTextNode (part1); + getParentNode ().insertBefore (text, this); + setNodeValue (part2); + return text; + } + + // DOM Level 3 + + public boolean isElementContentWhitespace () + { + return getTextContent ().trim ().length () == 0; + } + + public String getWholeText () + { + Node first = this; + Node node = getPreviousSibling (); + while (node != null && node instanceof Text) + { + first = node; + node = node.getPreviousSibling (); + } + CPStringBuilder buf = new CPStringBuilder (first.getNodeValue ()); + node = first.getNextSibling (); + while (node != null && node instanceof Text) + { + buf.append (node.getNodeValue ()); + node = node.getNextSibling (); + } + return buf.toString (); + } + + public Text replaceWholeText (String content) throws DOMException + { + boolean isEmpty = (content == null || content.length () == 0); + if (!isEmpty) + { + setNodeValue (content); + } + + Node first = this; + Node node = getPreviousSibling (); + while (node != null && node instanceof Text) + { + first = node; + node = node.getPreviousSibling (); + } + node = first.getNextSibling (); + Node parent = getParentNode (); + if (first != this || isEmpty) + { + parent.removeChild (first); + } + while (node != null && node instanceof Text) + { + Node tmp = node; + node = node.getNextSibling (); + if (tmp != this || isEmpty) + { + parent.removeChild (tmp); + } + } + return (isEmpty) ? null : this; + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeTypeInfo.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeTypeInfo.java new file mode 100644 index 000000000..5517e8a99 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeTypeInfo.java @@ -0,0 +1,65 @@ +/* GnomeTypeInfo.java - + 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.xml.libxmlj.dom; + +import org.w3c.dom.TypeInfo; + +/** + * Provides XML Schema information about an element or attribute. + * + * @author Chris Burdess + */ +class GnomeTypeInfo implements TypeInfo +{ + + final Object id; + + GnomeTypeInfo(Object id) + { + this.id = id; + } + + public native String getTypeName (); + + public native String getTypeNamespace (); + + public native boolean isDerivedFrom (String typeNamespaceArg, + String typeNameArg, + int derivationMethod); + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathExpression.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathExpression.java new file mode 100644 index 000000000..52f4daa21 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathExpression.java @@ -0,0 +1,86 @@ +/* GnomeXPathExpression.java - + 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.xml.libxmlj.dom; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.xpath.XPathException; +import org.w3c.dom.xpath.XPathExpression; +import org.w3c.dom.xpath.XPathNSResolver; + +/** + * A compiled XPath expression implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeXPathExpression +implements XPathExpression +{ + + /** + * xmlXPathCompExprPtr + */ + final Object expr; + + GnomeXPathExpression (GnomeDocument doc, String expression, + XPathNSResolver resolver) + { + expr = init (expression); + // TODO resolver + } + + protected void finalize () + { + free (expr); + } + + private native Object init (String expression); + + private native void free (Object expr); + + public Object evaluate (Node contextNode, short type, Object result) + throws XPathException, DOMException + { + return doEvaluate (expr, contextNode, type, result); + } + + private native Object doEvaluate (Object expr, Node contextNode, + short type, Object result) + throws XPathException, DOMException; + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathNSResolver.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathNSResolver.java new file mode 100644 index 000000000..039a79a03 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathNSResolver.java @@ -0,0 +1,64 @@ +/* GnomeXPathNSResolver.java - + 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.xml.libxmlj.dom; + +import org.w3c.dom.Node; +import org.w3c.dom.xpath.XPathNSResolver; + +/** + * XPath namespace URI resolver implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeXPathNSResolver + implements XPathNSResolver +{ + + Node node; + + GnomeXPathNSResolver(Node node) + { + this.node = node; + } + + public String lookupNamespaceURI(String prefix) + { + return node.lookupNamespaceURI(prefix); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathNodeList.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathNodeList.java new file mode 100644 index 000000000..b8d0a3d0a --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathNodeList.java @@ -0,0 +1,73 @@ +/* GnomeXPathNodeList.java - + 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.xml.libxmlj.dom; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * A node list that uses an XPath result object. + * + * @author Chris Burdess + */ +class GnomeXPathNodeList +implements NodeList +{ + + /** + * xmlXPathObjectPtr + */ + final Object obj; + + GnomeXPathNodeList (Object obj) + { + this.obj = obj; + } + + protected void finalize () + { + free(obj); + } + + private native void free (Object obj); + + public native int getLength (); + + public native Node item (int index); + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathResult.java b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathResult.java new file mode 100644 index 000000000..b2c706f65 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathResult.java @@ -0,0 +1,134 @@ +/* GnomeXPathResult.java - + 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.xml.libxmlj.dom; + +import gnu.java.lang.CPStringBuilder; + +import org.w3c.dom.DOMException; +import org.w3c.dom.Node; +import org.w3c.dom.xpath.XPathException; +import org.w3c.dom.xpath.XPathResult; + +/** + * An XPath result object implemented in libxml2. + * + * @author Chris Burdess + */ +class GnomeXPathResult +implements XPathResult +{ + + /** + * xmlXPathObjectPtr + */ + final Object obj; + + GnomeXPathResult (Object obj) + { + this.obj = obj; + } + + protected void finalize () + { + free (obj); + } + + private native void free (Object obj); + + public native short getResultType (); + + public native double getNumberValue () + throws XPathException; + + public native String getStringValue () + throws XPathException; + + public native boolean getBooleanValue () + throws XPathException; + + public native Node getSingleNodeValue () + throws XPathException; + + public native boolean getInvalidIteratorState(); + + public native int getSnapshotLength () + throws XPathException; + + public native Node iterateNext () + throws XPathException, DOMException; + + public native Node snapshotItem (int index) + throws XPathException; + + public String toString () + { + short type = getResultType (); + switch (type) + { + case STRING_TYPE: + return getStringValue (); + case NUMBER_TYPE: + return Double.toString (getNumberValue ()); + case BOOLEAN_TYPE: + return Boolean.valueOf (getBooleanValue ()).toString (); + case UNORDERED_NODE_SNAPSHOT_TYPE: + int len = getSnapshotLength (); + switch (len) { + case 0: + return "[no matches]"; + case 1: + return getSingleNodeValue ().toString (); + default: + CPStringBuilder buffer = new CPStringBuilder (); + for (int i = 0; i < len; i++) + { + if (i > 0) + { + buffer.append (','); + } + buffer.append (snapshotItem (i)); + } + return buffer.toString (); + } + default: + return getClass ().getName () + "[type=" + type + ",length=" + + getSnapshotLength () + ']'; + } + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/sax/GnomeLocator.java b/libjava/classpath/gnu/xml/libxmlj/sax/GnomeLocator.java new file mode 100644 index 000000000..dba0a72c0 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/sax/GnomeLocator.java @@ -0,0 +1,99 @@ +/* GnomeLocator.java - + 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.xml.libxmlj.sax; + +import org.xml.sax.Locator; + +/** + * SAX Locator implementation that uses libxml2. + * + * @author Chris Burdess + */ +class GnomeLocator +implements Locator +{ + + // An xmlParserCtxtPtr + private final Object ctx; + + // An xmlSAXLocatorPtr + private final Object loc; + + GnomeLocator (Object ctx, Object loc) + { + this.ctx = ctx; + this.loc = loc; + if (ctx == null) + { + throw new NullPointerException ("ctx"); + } + if (loc == null) + { + throw new NullPointerException ("loc"); + } + } + + public String getPublicId () + { + return publicId (ctx, loc); + } + + private native String publicId (Object ctx, Object loc); + + public String getSystemId () + { + return systemId (ctx, loc); + } + + private native String systemId (Object ctx, Object loc); + + public int getLineNumber () + { + return lineNumber (ctx, loc); + } + + private native int lineNumber (Object ctx, Object loc); + + public int getColumnNumber () + { + return columnNumber (ctx, loc); + } + + private native int columnNumber (Object ctx, Object loc); + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/sax/GnomeSAXParser.java b/libjava/classpath/gnu/xml/libxmlj/sax/GnomeSAXParser.java new file mode 100644 index 000000000..86d326b7c --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/sax/GnomeSAXParser.java @@ -0,0 +1,105 @@ +/* GnomeSAXParser.java - + 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.xml.libxmlj.sax; + +import javax.xml.parsers.SAXParser; + +import org.xml.sax.Parser; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.XMLReader; + +/** + * JAXP SAX parser implementation that uses libxml2. + * + * @author Chris Burdess + */ +class GnomeSAXParser +extends SAXParser +{ + + private boolean namespaceAware; + private boolean validating; + + /** + * Creates a new SAX parser. + */ + GnomeSAXParser (boolean namespaceAware, boolean validating) + { + this.namespaceAware = namespaceAware; + this.validating = validating; + } + + public Parser getParser () + throws SAXException + { + throw new SAXNotSupportedException ("SAX version 1 not supported"); + } + + public XMLReader getXMLReader () + throws SAXException + { + return new GnomeXMLReader (namespaceAware, validating); + } + + public Object getProperty (String name) + throws SAXNotRecognizedException, SAXNotSupportedException + { + GnomeXMLReader.checkPropertyName (name); + throw new SAXNotSupportedException (name); + } + + public void setProperty (String name, Object value) + throws SAXNotRecognizedException, SAXNotSupportedException + { + GnomeXMLReader.checkPropertyName (name); + throw new SAXNotSupportedException (name); + } + + public boolean isNamespaceAware () + { + return namespaceAware; + } + + public boolean isValidating () + { + return validating; + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/sax/GnomeSAXParserFactory.java b/libjava/classpath/gnu/xml/libxmlj/sax/GnomeSAXParserFactory.java new file mode 100644 index 000000000..0c2881240 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/sax/GnomeSAXParserFactory.java @@ -0,0 +1,92 @@ +/* GnomeSAXParserFactory.java - + 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.xml.libxmlj.sax; + +import java.util.Map; +import java.util.HashMap; + +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; + +/** + * JAXP SAX parser factory implementation that uses libxml2. + * + * @author Chris Burdess + */ +public class GnomeSAXParserFactory +extends SAXParserFactory +{ + + private Map features; + + /** + * Creates a new SAX parser factory. + */ + public GnomeSAXParserFactory () + { + features = new HashMap (); + } + + public SAXParser newSAXParser () + throws ParserConfigurationException, SAXException + { + // TODO features + return new GnomeSAXParser (isNamespaceAware (), isValidating ()); + } + + public boolean getFeature (String name) + throws ParserConfigurationException, SAXNotRecognizedException, SAXNotSupportedException + { + GnomeXMLReader.checkFeatureName (name); + Boolean val = (Boolean) features.get (name); + return (val == null) ? false : val.booleanValue (); + } + + public void setFeature (String name, boolean flag) + throws ParserConfigurationException, SAXNotRecognizedException, SAXNotSupportedException + { + GnomeXMLReader.checkFeatureName (name); + features.put (name, flag ? Boolean.TRUE : Boolean.FALSE); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/sax/GnomeXMLReader.java b/libjava/classpath/gnu/xml/libxmlj/sax/GnomeXMLReader.java new file mode 100644 index 000000000..3a34bc934 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/sax/GnomeXMLReader.java @@ -0,0 +1,1065 @@ +/* GnomeXMLReader.java - + 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.xml.libxmlj.sax; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.DTDHandler; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.SAXParseException; +import org.xml.sax.XMLReader; +import org.xml.sax.ext.DeclHandler; +import org.xml.sax.ext.LexicalHandler; + +import gnu.xml.libxmlj.util.NamedInputStream; +import gnu.xml.libxmlj.util.StandaloneLocator; +import gnu.xml.libxmlj.util.XMLJ; + +/** + * A SAX2 parser that uses libxml2. + * + * @author Chris Burdess + */ +public class GnomeXMLReader +implements XMLReader +{ + + static + { + XMLJ.init (); + } + + private static final String FEATURES_PREFIX = + "http://xml.org/sax/features/"; + + private static final List RECOGNIZED_FEATURES = + Arrays.asList (new String[] + { + "external-general-entities", + "external-parameter-entities", + "is-standalone", + "lexical-handler/parameter-entities", + "namespaces", + "namespace-prefixes", + "resolve-dtd-uris", + "string-interning", + "use-attributes2", + "use-locator2", + "use-entity-resolver2", + "validation" + }); + + private static final String PROPERTIES_PREFIX = + "http://xml.org/sax/properties/"; + + private static final List RECOGNIZED_PROPERTIES = + Arrays.asList (new String[] + { + "declaration-handler", + "dom-node", + "lexical-handler", + "xml-string" + }); + + // Features + + private transient boolean standalone; + private boolean namespaces; + private boolean namespacePrefixes; + private boolean validation; + + // Callback handlers + + private ContentHandler contentHandler; + + private DTDHandler dtdHandler; + + private EntityResolver entityResolver; + + private ErrorHandler errorHandler; + + private DeclHandler declarationHandler; + + private LexicalHandler lexicalHandler; + + private GnomeLocator locator; + + // Namespace helper for handling callbacks + private transient Namespaces ns; + + // If true, do not invoke callback methods except endDocument + private transient boolean seenFatalError; + + private transient boolean seenStartDocument; + + private transient String base; + + public GnomeXMLReader () + { + this (true, true); + } + + public GnomeXMLReader (boolean namespaces, boolean validation) + { + this.namespaces = namespaces; + this.validation = validation; + ns = new Namespaces (); + } + + public ContentHandler getContentHandler () + { + return contentHandler; + } + + public void setContentHandler (ContentHandler handler) + { + contentHandler = handler; + } + + public DTDHandler getDTDHandler () + { + return dtdHandler; + } + + public void setDTDHandler (DTDHandler handler) + { + dtdHandler = handler; + } + + public EntityResolver getEntityResolver () + { + return entityResolver; + } + + public void setEntityResolver (EntityResolver resolver) + { + entityResolver = resolver; + } + + public ErrorHandler getErrorHandler () + { + return errorHandler; + } + + public void setErrorHandler (ErrorHandler handler) + { + errorHandler = handler; + } + + // Features + + public boolean getFeature (String name) + throws SAXNotRecognizedException, SAXNotSupportedException + { + checkFeatureName (name); + String key = name.substring (FEATURES_PREFIX.length ()); + if ("external-general-entities".equals (key)) + { + return validation; // TODO check this + } + else if ("external-parameter-entities".equals (key)) + { + return validation; // TODO check this + } + else if ("is-standalone".equals (key)) + { + return standalone; + } + else if ("namespaces".equals (key)) + { + return namespaces; + } + else if ("namespace-prefixes".equals (key)) + { + return namespacePrefixes; + } + else if ("resolve-dtd-uris".equals (key)) + { + return true; + } + else if ("validation".equals (key)) + { + return validation; + } + else + { + return false; + } + } + + public void setFeature (String name, boolean value) + throws SAXNotRecognizedException, SAXNotSupportedException + { + checkFeatureName (name); + String key = name.substring (FEATURES_PREFIX.length ()); + if ("namespaces".equals (key)) + { + namespaces = value; + } + else if ("namespace-prefixes".equals (key)) + { + namespacePrefixes = value; + } + else if ("validation".equals (key)) + { + validation = value; + } + } + + /** + * Check that the specified feature name is recognized. + */ + static void checkFeatureName (String name) + throws SAXNotRecognizedException + { + if (name == null || !name.startsWith (FEATURES_PREFIX)) + { + throw new SAXNotRecognizedException (name); + } + String key = name.substring (FEATURES_PREFIX.length ()); + if (!RECOGNIZED_FEATURES.contains (key)) + { + throw new SAXNotRecognizedException (name); + } + } + + // Properties + + public Object getProperty (String name) + throws SAXNotRecognizedException, SAXNotSupportedException + { + checkPropertyName (name); + String key = name.substring (PROPERTIES_PREFIX.length ()); + if ("declaration-handler".equals (key)) + { + return getDeclarationHandler (); + } + else if ("lexical-handler".equals (key)) + { + return getLexicalHandler (); + } + else + { + throw new SAXNotSupportedException (name); + } + } + + public void setProperty (String name, Object value) + throws SAXNotRecognizedException, SAXNotSupportedException + { + checkPropertyName (name); + String key = name.substring (PROPERTIES_PREFIX.length ()); + if ("declaration-handler".equals (key)) + { + setDeclarationHandler ((DeclHandler) value); + } + else if ("lexical-handler".equals (key)) + { + setLexicalHandler ((LexicalHandler) value); + } + } + + public DeclHandler getDeclarationHandler () + { + return declarationHandler; + } + + public void setDeclarationHandler (DeclHandler declarationHandler) + { + this.declarationHandler = declarationHandler; + } + + public LexicalHandler getLexicalHandler () + { + return lexicalHandler; + } + + public void setLexicalHandler (LexicalHandler lexicalHandler) + { + this.lexicalHandler = lexicalHandler; + } + + /** + * Check that the specified property name is recognized. + */ + static void checkPropertyName (String name) + throws SAXNotRecognizedException + { + if (!name.startsWith (PROPERTIES_PREFIX)) + { + throw new SAXNotRecognizedException (name); + } + String key = name.substring (PROPERTIES_PREFIX.length ()); + if (!RECOGNIZED_PROPERTIES.contains (key)) + { + throw new SAXNotRecognizedException (name); + } + } + + // Parse + + public void parse (String systemId) + throws IOException, SAXException + { + URL url = null; + try + { + url = new URL (systemId); + } + catch (MalformedURLException e) + { + File file = new File(systemId); + if (!file.exists ()) + { + throw new FileNotFoundException (systemId); + } + String path = file.getAbsolutePath(); + if (File.separatorChar != '/') + { + path = path.replace (File.separatorChar, '/'); + } + if (!path.startsWith ("/")) + { + path = "/" + path; + } + if (!path.endsWith ("/") && file.isDirectory ()) + { + path = path + "/"; + } + url = new URL ("file:" + path); + } + InputSource source = new InputSource(url.toString ()); + source.setByteStream (url.openStream ()); + parse (source); + } + + public synchronized void parse (InputSource input) + throws IOException, SAXException + { + NamedInputStream in = XMLJ.getInputStream (input); + byte[] detectBuffer = in.getDetectBuffer (); + String publicId = input.getPublicId (); + String systemId = input.getSystemId (); + base = XMLJ.getBaseURI (systemId); + // Reset state + standalone = false; + seenFatalError = false; + seenStartDocument = false; + if (systemId != null) + { + int lsi = systemId.lastIndexOf ('/'); + if (lsi != -1) + { + base = systemId.substring (0, lsi + 1); + } + } + // Handle zero-length document + if (detectBuffer == null) + { + startDocument (true); + fatalError ("No document element", 0, 0, publicId, systemId); + endDocument (); + return; + } + // Parse + parseStream(in, + detectBuffer, + publicId, + systemId, + base, + validation, + contentHandler != null, + dtdHandler != null, + entityResolver != null, + errorHandler != null, + declarationHandler != null, + lexicalHandler != null); + in.close (); + } + + native void parseStream (InputStream in, + byte[] detectBuffer, + String publicId, + String systemId, + String base, + boolean validate, + boolean contentHandler, + boolean dtdHandler, + boolean entityResolver, + boolean errorHandler, + boolean declarationHandler, + boolean lexicalHandler) + throws IOException, SAXException; + + String getURI (String prefix) + { + if (!namespaces) + { + return null; + } + return ns.getURI (prefix); + } + + // Callbacks from libxmlj + + private void startDTD (String name, String publicId, String systemId) + throws SAXException + { + if (seenFatalError || lexicalHandler == null) + { + return; + } + try + { + systemId = XMLJ.getAbsoluteURI (base, systemId); + lexicalHandler.startDTD (name, publicId, systemId); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void externalEntityDecl (String name, String publicId, + String systemId) + throws SAXException + { + if (seenFatalError || declarationHandler == null) + { + return; + } + try + { + systemId = XMLJ.getAbsoluteURI (base, systemId); + declarationHandler.externalEntityDecl (name, publicId, systemId); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void internalEntityDecl (String name, String value) + throws SAXException + { + if (seenFatalError || declarationHandler == null) + { + return; + } + try + { + declarationHandler.internalEntityDecl (name, value); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private InputStream resolveEntity (String publicId, String systemId) + throws SAXException, IOException + { + if (entityResolver == null) + { + return null; + } + try + { + systemId = XMLJ.getAbsoluteURI (base, systemId); + InputSource source = entityResolver.resolveEntity (publicId, systemId); + return (source == null) ? null : XMLJ.getInputStream (source); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void notationDecl (String name, String publicId, String systemId) + throws SAXException + { + if (seenFatalError || dtdHandler == null) + { + return; + } + try + { + systemId = XMLJ.getAbsoluteURI (base, systemId); + dtdHandler.notationDecl (name, publicId, systemId); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void attributeDecl (String eName, String aName, String type, + String mode, String value) + throws SAXException + { + if (seenFatalError || declarationHandler == null) + { + return; + } + try + { + declarationHandler.attributeDecl (eName, aName, type, mode, value); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void elementDecl (String name, String model) + throws SAXException + { + if (seenFatalError || declarationHandler == null) + { + return; + } + try + { + declarationHandler.elementDecl (name, model); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void unparsedEntityDecl (String name, String publicId, + String systemId, String notationName) + throws SAXException + { + if (seenFatalError || dtdHandler == null) + { + return; + } + try + { + systemId = XMLJ.getAbsoluteURI (base, systemId); + dtdHandler.unparsedEntityDecl (name, publicId, systemId, + notationName); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void setDocumentLocator (Object ctx, Object loc) + { + locator = new GnomeLocator (ctx, loc); + if (seenFatalError || contentHandler == null) + { + return; + } + try + { + contentHandler.setDocumentLocator (locator); + } + catch (Exception e) + { + } + } + + private void startDocument (boolean standalone) + throws SAXException + { + this.standalone = standalone; + seenStartDocument = true; + if (contentHandler == null) + { + return; + } + try + { + contentHandler.startDocument (); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void endDocument () + throws SAXException + { + if (contentHandler == null) + { + return; + } + try + { + contentHandler.endDocument(); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void startElement(String name, String[] attrs) + throws SAXException + { + if (seenFatalError || contentHandler == null) + { + return; + } + try + { + XMLName xName = new XMLName (this, name); + if (namespaces) + { + // Handle defined namespaces + ns.push (); + int len = (attrs == null) ? 0 : attrs.length; + if (len > 0) + { + ArrayList filtered = new ArrayList (len); + for (int i = 0; i < len; i += 2) + { + String attName = attrs[i]; + String attValue = attrs[i + 1]; + if (attName.equals ("xmlns")) + { + startPrefixMapping ("", attValue); + } + else if (attName.startsWith ("xmlns:")) + { + startPrefixMapping (attName.substring (6), attValue); + } + else + { + filtered.add (attName); + filtered.add (attValue); + } + } + // Remove xmlns attributes + attrs = new String[filtered.size ()]; + filtered.toArray (attrs); + } + } + // Construct attributes + Attributes atts = new StringArrayAttributes (this, attrs); + contentHandler.startElement (xName.uri, xName.localName, xName.qName, + atts); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void endElement (String name) + throws SAXException + { + if (seenFatalError || contentHandler == null) + { + return; + } + try + { + XMLName xName = new XMLName (this, name); + String uri = (xName.uri == null) ? "" : xName.uri; + contentHandler.endElement (uri, xName.localName, xName.qName); + // Handle undefining namespaces + if (namespaces) + { + for (Iterator i = ns.currentPrefixes (); i.hasNext (); ) + { + endPrefixMapping ((String) i.next ()); + } + ns.pop (); // releases current depth + } + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void startPrefixMapping (String prefix, String uri) + throws SAXException + { + if (seenFatalError || contentHandler == null) + { + return; + } + ns.define (prefix, uri); + contentHandler.startPrefixMapping (prefix, uri); + } + + private void endPrefixMapping (String prefix) + throws SAXException + { + if (seenFatalError || contentHandler == null) + { + return; + } + contentHandler.endPrefixMapping (prefix); + } + + private void characters (String text) + throws SAXException + { + if (seenFatalError || contentHandler == null || text == null) + { + return; + } + try + { + char[] ch = text.toCharArray (); + contentHandler.characters (ch, 0, ch.length); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void ignorableWhitespace (String text) + throws SAXException + { + if (seenFatalError || contentHandler == null || text == null) + { + return; + } + try + { + char[] ch = text.toCharArray (); + contentHandler.ignorableWhitespace (ch, 0, ch.length); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void processingInstruction (String target, String data) + throws SAXException + { + if (seenFatalError || contentHandler == null) + { + return; + } + try + { + if (data == null) + { + data = ""; + } + contentHandler.processingInstruction (target, data); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void comment (String text) + throws SAXException + { + if (seenFatalError || lexicalHandler == null || text == null) + { + return; + } + try + { + char[] ch = text.toCharArray (); + lexicalHandler.comment (ch, 0, ch.length); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void cdataBlock (String text) + throws SAXException + { + if (seenFatalError || text == null) + { + return; + } + try + { + if (lexicalHandler == null) + { + characters(text); + } + else + { + lexicalHandler.startCDATA(); + characters(text); + lexicalHandler.endCDATA(); + } + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void warning (String message, + int lineNumber, int columnNumber, + String publicId, String systemId) + throws SAXException + { + if (seenFatalError || errorHandler == null) + { + return; + } + try + { + Locator l = new StandaloneLocator (lineNumber, columnNumber, + publicId, systemId); + errorHandler.warning (new SAXParseException (message, l)); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void error (String message, + int lineNumber, int columnNumber, + String publicId, String systemId) + throws SAXException + { + if (seenFatalError || errorHandler == null) + { + return; + } + try + { + Locator l = new StandaloneLocator (lineNumber, columnNumber, + publicId, systemId); + errorHandler.error (new SAXParseException (message, l)); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + + private void fatalError (String message, + int lineNumber, int columnNumber, + String publicId, String systemId) + throws SAXException + { + if (seenFatalError || errorHandler == null) + { + return; + } + try + { + if (!seenStartDocument) + { + startDocument (false); + } + seenFatalError = true; + Locator l = new StandaloneLocator (lineNumber, columnNumber, + publicId, systemId); + errorHandler.fatalError (new SAXParseException (message, l)); + } + catch (Exception e) + { + if (e instanceof SAXException) + { + throw (SAXException) e; + } + else + { + throw new SAXException (e); + } + } + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/sax/Namespaces.java b/libjava/classpath/gnu/xml/libxmlj/sax/Namespaces.java new file mode 100644 index 000000000..473d02028 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/sax/Namespaces.java @@ -0,0 +1,122 @@ +/* Namespaces.java - + 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.xml.libxmlj.sax; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; + +/** + * Helper class for managing namespaces. + * + * @author Chris Burdess + */ +class Namespaces +{ + + ArrayList stack = new ArrayList (); + + /** + * Increments the tree depth. + * This allocates a new potential namespace entry. + */ + void push () + { + stack.add (null); + } + + /** + * Decrements the tree depth. + * This removes namespaces defined at the extremity. + */ + void pop () + { + stack.remove (stack.size() - 1); + } + + /** + * Searches for the namespace URI corresponding to the specified prefix. + */ + String getURI (String prefix) + { + for (int i = stack.size () - 1; i >= 0; i--) + { + HashMap ns = (HashMap) stack.get (i); + if (ns != null && ns.containsKey (prefix)) + { + String ret = (String) ns.get (prefix); + return (ret == null) ? "" : ret; + } + } + return ""; + } + + /** + * Defines the specified prefix-URI mapping at the current depth in the + * tree. + */ + void define (String prefix, String uri) + { + int index = stack.size () - 1; + HashMap ns = (HashMap) stack.get (index); + if (ns == null) + { + ns = new HashMap (); + stack.set (index, ns); + } + ns.put (prefix, uri); + } + + /** + * Returns an iterator over the prefixes defined at the current depth. + */ + Iterator currentPrefixes () + { + HashMap ns = (HashMap) stack.get (stack.size () - 1); + if (ns == null) + { + return Collections.EMPTY_LIST.iterator (); + } + else + { + return ns.keySet ().iterator (); + } + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/sax/StringArrayAttributes.java b/libjava/classpath/gnu/xml/libxmlj/sax/StringArrayAttributes.java new file mode 100644 index 000000000..f5a753c56 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/sax/StringArrayAttributes.java @@ -0,0 +1,170 @@ +/* StringArrayAttributes.java - + 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.xml.libxmlj.sax; + +import org.xml.sax.Attributes; + +/** + * An implementation of Attributes that reads values from an array of + * strings, supplied by libxml2. + * Each pair of elements in the array represents a key followed by a value. + * + * @author Chris Burdess + */ +class StringArrayAttributes +implements Attributes +{ + + private int len; + private XMLName[] keys; + private String[] values; + + StringArrayAttributes (GnomeXMLReader parser, String[] pairs) + { + len = (pairs == null) ? 0 : pairs.length / 2; + keys = new XMLName[len]; + values = new String[len]; + for (int i = 0; i < len; i++) + { + int pairIndex = i * 2; + keys[i] = new XMLName (parser, pairs[pairIndex]); + values[i] = pairs[pairIndex + 1]; + } + } + + public int getLength () + { + return len; + } + + public String getURI (int index) + { + if (index < 0 || index >= len) + { + return null; + } + return keys[index].uri; + } + + public String getLocalName (int index) + { + if (index < 0 || index >= len) + { + return null; + } + return keys[index].localName; + } + + public String getQName (int index) + { + if (index < 0 || index >= len) + { + return null; + } + return keys[index].qName; + } + + public String getType (int index) + { + if (index < 0 || index >= len) + { + return null; + } + // TODO can we get this information from libxml2? + return "CDATA"; + } + + public String getValue (int index) + { + if (index < 0 || index >= len) + { + return null; + } + return values[index]; + } + + public int getIndex (String uri, String localName) + { + for (int i = 0; i < len; i++) + { + XMLName key = keys[i]; + if (key.localName.equals (localName)) + { + if ((key.uri == null && uri == null) || + (key.uri != null && key.uri.equals(uri))) + { + return i; + } + } + } + return -1; + } + + public int getIndex (String qName) + { + for (int i = 0; i < len; i++) + { + if (keys[i].qName.equals (qName)) + { + return i; + } + } + return -1; + } + + public String getType (String uri, String localName) + { + return getType (getIndex (uri, localName)); + } + + public String getType (String qName) + { + return getType (getIndex (qName)); + } + + public String getValue (String uri, String localName) + { + return getValue (getIndex (uri, localName)); + } + + public String getValue (String qName) + { + return getValue (getIndex (qName)); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/sax/XMLName.java b/libjava/classpath/gnu/xml/libxmlj/sax/XMLName.java new file mode 100644 index 000000000..b9bdf9159 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/sax/XMLName.java @@ -0,0 +1,92 @@ +/* XMLName.java - + 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.xml.libxmlj.sax; + +/** + * Structure containing the components of an XML element/attribute name. + * + * @author Chris Burdess + */ +class XMLName +{ + + private static final String XML_URI = "http://www.w3.org/XML/1998/namespace"; + + final String uri; + final String localName; + final String qName; + final String prefix; + + XMLName (GnomeXMLReader parser, String qName) + { + this.qName = qName; + int ci = qName.lastIndexOf (':'); + if (ci < 1) + { + localName = qName; + prefix = null; + uri = ""; + } + else + { + localName = qName.substring (ci + 1); + prefix = qName.substring (0, ci); + if ("xml".equals (prefix)) + { + if ("lang".equals (localName) || "space".equals (localName)) + { + uri = XML_URI; + } + else + { + uri = parser.getURI (prefix); + } + } + else + { + uri = parser.getURI (prefix); + } + } + } + + public String toString () + { + return qName; + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/transform/ErrorListenerErrorHandler.java b/libjava/classpath/gnu/xml/libxmlj/transform/ErrorListenerErrorHandler.java new file mode 100644 index 000000000..398a0ba2e --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/transform/ErrorListenerErrorHandler.java @@ -0,0 +1,111 @@ +/* ErrorListenerErrorHandler.java - + 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.xml.libxmlj.transform; + +import javax.xml.transform.ErrorListener; +import javax.xml.transform.TransformerException; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +/** + * Provides a SAX ErrorHandler interface to an ErrorListener. + * + * @author Chris Burdess + */ +class ErrorListenerErrorHandler +implements ErrorHandler +{ + + private ErrorListener listener; + + ErrorListenerErrorHandler (ErrorListener listener) + { + this.listener = listener; + } + + public void warning (SAXParseException e) + throws SAXException + { + try + { + listener.warning (new TransformerException (e)); + } + catch (TransformerException te) + { + throw getSAXException (te); + } + } + + public void error (SAXParseException e) + throws SAXException + { + try + { + listener.error (new TransformerException (e)); + } + catch (TransformerException te) + { + throw getSAXException (te); + } + } + + public void fatalError (SAXParseException e) + throws SAXException + { + try + { + listener.fatalError (new TransformerException (e)); + } + catch (TransformerException te) + { + throw getSAXException (te); + } + } + + private SAXException getSAXException (TransformerException e) + { + Throwable cause = e.getCause (); + if (cause instanceof SAXException) + { + return (SAXException) cause; + } + return new SAXException (e); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/transform/GnomeTransformer.java b/libjava/classpath/gnu/xml/libxmlj/transform/GnomeTransformer.java new file mode 100755 index 000000000..5f31cb898 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/transform/GnomeTransformer.java @@ -0,0 +1,572 @@ +/* GnomeTransformer.java - + 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.xml.libxmlj.transform; + +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; + +import java.net.URL; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; + +import javax.xml.transform.ErrorListener; +import javax.xml.transform.Source; +import javax.xml.transform.SourceLocator; +import javax.xml.transform.Result; +import javax.xml.transform.Templates; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.URIResolver; + +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.sax.SAXResult; +import javax.xml.transform.stream.StreamSource; +import javax.xml.transform.stream.StreamResult; + +import org.w3c.dom.Node; + +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; + +import gnu.xml.libxmlj.dom.GnomeDocument; +import gnu.xml.libxmlj.sax.GnomeXMLReader; +import gnu.xml.libxmlj.util.NamedInputStream; +import gnu.xml.libxmlj.util.StandaloneLocator; +import gnu.xml.libxmlj.util.XMLJ; + +/** + * An implementation of {@link javax.xml.transform.Transformer} which + * performs XSLT transformation using libxslt. + * + * @author Julian Scheid + * @author Chris Burdess + */ +public class GnomeTransformer + extends Transformer + implements Templates +{ + + /** + * The parameters added by the user via {@link setParameter()}. + */ + private Map parameters; + + /** + * The output properties set by the user. + */ + private Properties outputProperties; + + /** + * The URI resolver to use during transformation. + */ + private URIResolver resolver; + + /** + * The error listener for transformation errors. + */ + private ErrorListener errorListener; + + /** + * Handle to the source stylesheet. + * This is a native pointer of type xsltStylesheetPtr. + */ + private Object stylesheet; + + /** + * Constructor. + * @param source the XSLT stylesheet document source + * @param resolver the resolver to use during transformation + * @param errorListener the error listener for transformation errors + */ + GnomeTransformer (Source source, + URIResolver resolver, + ErrorListener errorListener) + throws TransformerConfigurationException + { + this.resolver = resolver; + this.errorListener = errorListener; + parameters = new HashMap (); + outputProperties = new Properties (); + + if (source == null) + { + stylesheet = newStylesheet (); + } + else if (source instanceof StreamSource) + { + try + { + StreamSource ss = (StreamSource) source; + NamedInputStream in = XMLJ.getInputStream (ss); + String systemId = ss.getSystemId (); + String publicId = ss.getPublicId (); + String base = XMLJ.getBaseURI (systemId); + byte[] detectBuffer = in.getDetectBuffer (); + if (detectBuffer == null) + { + String msg = "No document element"; + throw new TransformerConfigurationException (msg); + } + stylesheet = newStylesheetFromStream (in, detectBuffer, publicId, + systemId, base, + (resolver != null), + (errorListener != null)); + } + catch (IOException e) + { + throw new TransformerConfigurationException (e); + } + } + else if (source instanceof DOMSource) + { + DOMSource ds = (DOMSource) source; + Node node = ds.getNode (); + if (!(node instanceof GnomeDocument)) + { + String msg = "Node is not a GnomeDocument"; + throw new TransformerConfigurationException (msg); + } + GnomeDocument doc = (GnomeDocument) node; + stylesheet = newStylesheetFromDoc (doc); + } + else + { + String msg = "Source type not supported (" + source + ")"; + throw new TransformerConfigurationException (msg); + } + } + + /** + * Copy constructor. + */ + private GnomeTransformer (Object stylesheet, + URIResolver resolver, + ErrorListener errorListener, + Map parameters, + Properties outputProperties) + { + this.stylesheet = stylesheet; + this.resolver = resolver; + this.errorListener = errorListener; + this.parameters = parameters; + this.outputProperties = outputProperties; + } + + private native Object newStylesheet () + throws TransformerConfigurationException; + + private native Object newStylesheetFromStream (InputStream in, + byte[] detectBuffer, + String publicId, + String systemId, + String base, + boolean entityResolver, + boolean errorHandler) + throws TransformerConfigurationException; + + private native Object newStylesheetFromDoc (GnomeDocument doc) + throws TransformerConfigurationException; + + //--- Implementation of javax.xml.transform.Transformer follows. + + // Set, get and clear the parameters to use on transformation + + public synchronized void setParameter (String parameter, Object value) + { + parameters.put (parameter, value); + } + + public synchronized Object getParameter (String name) + { + return parameters.get (name); + } + + public synchronized void clearParameters () + { + parameters.clear (); + } + + // Set and get the ErrorListener to use on transformation + + public void setErrorListener (ErrorListener listener) + { + this.errorListener = listener; + } + + public ErrorListener getErrorListener () + { + return errorListener; + } + + // Set and get the URIResolver to use on transformation + + public void setURIResolver (URIResolver resolver) + { + this.resolver = resolver; + } + + public URIResolver getURIResolver () + { + return resolver; + } + + // Set the output properties to use on transformation; get default + // output properties and output properties specified in the + // stylesheet or by the user. + + public void setOutputProperties (Properties outputProperties) + { + // Note: defensive copying + this.outputProperties = new Properties (outputProperties); + } + + public void setOutputProperty (String name, String value) + { + outputProperties.setProperty (name, value); + } + + public Properties getOutputProperties () + { + // Note: defensive copying + return new Properties (this.outputProperties); + } + + public String getOutputProperty (String name) + { + return outputProperties.getProperty (name); + } + + // -- Templates -- + + public Transformer newTransformer () + { + return new GnomeTransformer (stylesheet, resolver, errorListener, + new HashMap (parameters), + new Properties (outputProperties)); + } + + // -- transform -- + + /** + * Transforms the given source and writes the result to the + * given target. + */ + public void transform (Source source, Result result) + throws TransformerException + { + if (source instanceof StreamSource) + { + try + { + StreamSource ss = (StreamSource) source; + NamedInputStream in = XMLJ.getInputStream (ss); + String publicId = ss.getPublicId (); + String systemId = ss.getSystemId (); + String base = XMLJ.getBaseURI (systemId); + byte[] detectBuffer = in.getDetectBuffer (); + if (detectBuffer == null) + { + throw new TransformerException ("No document element"); + } + if (result instanceof StreamResult) + { + OutputStream out = XMLJ.getOutputStream ((StreamResult) result); + transformStreamToStream (in, detectBuffer, publicId, systemId, + base, (resolver != null), + (errorListener != null), out); + } + else if (result instanceof DOMResult) + { + DOMResult dr = (DOMResult) result; + GnomeDocument ret = + transformStreamToDoc (in, detectBuffer, publicId, systemId, + base, (resolver != null), + (errorListener != null)); + dr.setNode (ret); + dr.setSystemId (null); + } + else if (result instanceof SAXResult) + { + SAXResult sr = (SAXResult) result; + transformStreamToSAX (in, detectBuffer, publicId, systemId, + base, (resolver != null), + (errorListener != null), + getSAXContext (sr)); + } + else + { + String msg = "Result type not supported (" + result + ")"; + throw new TransformerConfigurationException (msg); + } + } + catch (IOException e) + { + throw new TransformerException (e); + } + } + else if (source instanceof DOMSource) + { + DOMSource ds = (DOMSource) source; + Node node = ds.getNode (); + if (!(node instanceof GnomeDocument)) + { + String msg = "Node is not a GnomeDocument (" + node + ")"; + throw new TransformerException (msg); + } + GnomeDocument doc = (GnomeDocument) node; + if (result instanceof StreamResult) + { + try + { + OutputStream out = XMLJ.getOutputStream ((StreamResult) result); + transformDocToStream (doc, out); + } + catch (IOException e) + { + throw new TransformerException (e); + } + } + else if (result instanceof DOMResult) + { + DOMResult dr = (DOMResult) result; + GnomeDocument ret = transformDocToDoc (doc); + dr.setNode (ret); + dr.setSystemId (null); + } + else if (result instanceof SAXResult) + { + SAXResult sr = (SAXResult) result; + transformDocToSAX (doc, getSAXContext (sr)); + } + else + { + String msg = "Result type not supported"; + throw new TransformerConfigurationException (msg); + } + } + else + { + String msg = "Source type not supported"; + throw new TransformerConfigurationException (msg); + } + } + + private GnomeXMLReader getSAXContext (SAXResult result) + { + GnomeXMLReader ctx = new GnomeXMLReader (); + ctx.setContentHandler (result.getHandler ()); + ctx.setLexicalHandler (result.getLexicalHandler ()); + if (errorListener != null) + { + ErrorHandler errorHandler = + new ErrorListenerErrorHandler (errorListener); + ctx.setErrorHandler (errorHandler); + } + if (resolver != null) + { + EntityResolver entityResolver = + new URIResolverEntityResolver (resolver); + ctx.setEntityResolver (entityResolver); + } + return ctx; + } + + private native void transformStreamToStream (InputStream in, + byte[] detectBuffer, + String publicId, + String systemId, + String base, + boolean entityResolver, + boolean errorHandler, + OutputStream out) + throws TransformerException; + + private native GnomeDocument transformStreamToDoc (InputStream in, + byte[] detectBuffer, + String publicId, + String systemId, + String base, + boolean entityResolver, + boolean errorHandler) + throws TransformerException; + + private native void transformStreamToSAX (InputStream in, + byte[] detectBuffer, + String publicId, + String systemId, + String base, + boolean entityResolver, + boolean errorHandler, + GnomeXMLReader out) + throws TransformerException; + + private native void transformDocToStream (GnomeDocument in, + OutputStream out) + throws TransformerException; + + private native GnomeDocument transformDocToDoc (GnomeDocument in) + throws TransformerException; + + private native void transformDocToSAX (GnomeDocument in, + GnomeXMLReader out) + throws TransformerException; + + /* + * Retrieve parameters as a string array. + * This is a convenience method called from native code. + */ + private String[] getParameterArray () + { + String[] parameterArray = new String[parameters.size () * 2]; + int index = 0; + for (Iterator it = parameters.keySet ().iterator (); + it.hasNext (); + ++index) + { + String parameterKey = (String) it.next (); + String parameterValue = (String) parameters.get (parameterKey); + parameterArray[index * 2 + 0] = parameterKey; + parameterArray[index * 2 + 1] = + "'" + ((parameterValue != null) ? parameterValue : "") + "'"; + // FIXME encode parameter value correctly for XPath + } + return parameterArray; + } + + // -- Free xsltStylesheet handle -- + + public void finalize () + { + if (stylesheet != null) + { + free (); + stylesheet = null; + } + } + + private native void free (); + + // -- Callbacks -- + + private InputStream resolveEntity (String publicId, String systemId) + throws TransformerException + { + if (resolver != null) + { + systemId = resolver.resolve (null, systemId).getSystemId (); + } + if (systemId == null) + { + return null; + } + try + { + URL url = new URL (systemId); + return XMLJ.getInputStream (url); + } + catch (IOException e) + { + throw new TransformerException (e); + } + } + + private void setDocumentLocator (Object ctx, Object loc) + { + } + + private void warning (String message, + int lineNumber, + int columnNumber, + String publicId, + String systemId) + throws TransformerException + { + if (errorListener == null) + { + return; + } + SourceLocator l = new StandaloneLocator (lineNumber, + columnNumber, + publicId, + systemId); + errorListener.warning (new TransformerException (message, l)); + } + + private void error (String message, + int lineNumber, + int columnNumber, + String publicId, + String systemId) + throws TransformerException + { + if (errorListener == null) + { + return; + } + SourceLocator l = new StandaloneLocator (lineNumber, + columnNumber, + publicId, + systemId); + errorListener.error (new TransformerException (message, l)); + } + + private void fatalError (String message, + int lineNumber, + int columnNumber, + String publicId, + String systemId) + throws TransformerException + { + if (errorListener == null) + { + return; + } + SourceLocator l = new StandaloneLocator (lineNumber, + columnNumber, + publicId, + systemId); + errorListener.fatalError (new TransformerException (message, l)); + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/transform/GnomeTransformerFactory.java b/libjava/classpath/gnu/xml/libxmlj/transform/GnomeTransformerFactory.java new file mode 100755 index 000000000..4a0100a21 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/transform/GnomeTransformerFactory.java @@ -0,0 +1,349 @@ +/* GnomeTransformerFactory.java - + 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.xml.libxmlj.transform; + +import java.io.InputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import javax.xml.parsers.FactoryConfigurationError; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import javax.xml.transform.ErrorListener; +import javax.xml.transform.Source; +import javax.xml.transform.Templates; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.URIResolver; + +import javax.xml.transform.dom.DOMResult; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.DefaultHandler; + +import gnu.xml.libxmlj.util.XMLJ; + +/** + * An implementation of TransformerFactory producing + * Transformer objects which use libxslt + * for transformation. + * + * @author Julian Scheid + * @author Chris Burdess + */ +public class GnomeTransformerFactory + extends TransformerFactory +{ + + static + { + XMLJ.init (); + } + + /** + * URIResolver set by user, or default implementation. + */ + private URIResolver uriResolver; + + /** + * ErrorListener set by user, or default implementation. + */ + private ErrorListener errorListener; + + /** + * Attributes set by user. + */ + private Map attributes = new HashMap (); + + //--- Implementation of javax.xml.transform.TransformerFactory + //--- follows. + + // -- begin getAssociatedStylesheet implementation -- + + /** + * Returns the stylesheet associated with the specified XML source, or + * null if no associated stylesheet could be found. + */ + public Source getAssociatedStylesheet(Source source, String media, + String title, String charset) + throws TransformerConfigurationException + { + String href= null; + String base = source.getSystemId(); + if (source instanceof DOMSource) + { + Node node = ((DOMSource) source).getNode(); + Document doc = (node.getNodeType() == Node.DOCUMENT_NODE) ? + (Document) node : node.getOwnerDocument(); + if (base == null) + { + base = doc.getDocumentURI(); + } + for (node = doc.getFirstChild(); node != null; + node = node.getNextSibling()) + { + if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE && + "xml-stylesheet".equals(node.getNodeName())) + { + String data = node.getNodeValue(); + if (media != null && + !media.equals(parseParameter(data, "type"))) + { + continue; + } + if (title != null && + !title.equals(parseParameter(data, "title"))) + { + continue; + } + href = parseParameter(data, "href"); + } + } + } + else + { + InputSource input; + XMLReader parser = null; + try + { + if (source instanceof SAXSource) + { + SAXSource sax = (SAXSource) source; + input = sax.getInputSource(); + parser = sax.getXMLReader(); + } + else + { + StreamSource stream = (StreamSource) source; + InputStream in = stream.getInputStream(); + input = new InputSource(in); + } + input.setSystemId(base); + if (parser == null) + { + parser = createXMLReader(); + } + AssociatedStylesheetHandler ash = + new AssociatedStylesheetHandler(); + ash.media = media; + ash.title = title; + parser.setContentHandler(ash); + parser.parse(input); + href = ash.href; + } + catch (SAXException e) + { + throw new TransformerConfigurationException(e); + } + catch (IOException e) + { + throw new TransformerConfigurationException(e); + } + } + if (href == null) + { + return null; + } + if (base != null) + { + base = XMLJ.getBaseURI(base); + } + href = XMLJ.getAbsoluteURI(base, href); + return new StreamSource(href); + } + + private XMLReader createXMLReader() + throws TransformerConfigurationException + { + try + { + SAXParserFactory factory = SAXParserFactory.newInstance(); + SAXParser parser = factory.newSAXParser(); + return parser.getXMLReader(); + } + catch (FactoryConfigurationError e) + { + throw new TransformerConfigurationException(e); + } + catch (ParserConfigurationException e) + { + throw new TransformerConfigurationException(e); + } + catch (SAXException e) + { + throw new TransformerConfigurationException(e); + } + } + + class AssociatedStylesheetHandler + extends DefaultHandler + { + + String media; + String title; + String href; + + public void processingInstruction(String target, String data) + throws SAXException + { + if ("xml-stylesheet".equals(target)) + { + if (media != null && !media.equals(parseParameter(data, "type"))) + { + return; + } + if (title != null && !title.equals(parseParameter(data, "title"))) + { + return; + } + href = parseParameter(data, "href"); + } + } + + } + + String parseParameter(String data, String name) + { + int start = data.indexOf(name + "="); + if (start != -1) + { + start += name.length() + 2; + char delim = data.charAt(start - 1); + int end = data.indexOf(delim, start); + if (end != -1) + { + return data.substring(start, end); + } + } + return null; + } + + // -- end getAssociatedStylesheet implementation -- + + public synchronized void setAttribute (String name, Object value) + { + this.attributes.put (name, value); + } + + public synchronized Object getAttribute (String name) + { + return attributes.get (name); + } + + public void setErrorListener (ErrorListener errorListener) + { + this.errorListener = errorListener; + } + + public ErrorListener getErrorListener () + { + return errorListener; + } + + public void setURIResolver (URIResolver uriResolver) + { + this.uriResolver = uriResolver; + } + + public URIResolver getURIResolver () + { + return uriResolver; + } + + public boolean getFeature (String name) + { + return (StreamSource.FEATURE.equals (name) || + StreamResult.FEATURE.equals (name) || + DOMSource.FEATURE.equals (name) || + DOMResult.FEATURE.equals (name)); + } + + public void setFeature(String name, boolean value) + throws TransformerConfigurationException + { + throw new TransformerConfigurationException(name); + } + + /** + * Returns a new instance of class {@link Transformer} for a + * null souce. + */ + public Transformer newTransformer () + throws TransformerConfigurationException + { + return newTransformer (null); + } + + /** + * Returns a new instance of class {@link Transformer} for + * the given souce. + */ + public Transformer newTransformer (Source source) + throws TransformerConfigurationException + { + return new GnomeTransformer (source, uriResolver, errorListener); + } + + /** + * Returns a new instance of class {@link Templates} for + * the given souce. + */ + public Templates newTemplates (Source source) + throws TransformerConfigurationException + { + return new GnomeTransformer (source, uriResolver, errorListener); + } + + /** + * Perform native cleanup. + */ + public static native void freeLibxsltGlobal (); + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/transform/URIResolverEntityResolver.java b/libjava/classpath/gnu/xml/libxmlj/transform/URIResolverEntityResolver.java new file mode 100644 index 000000000..0ce71d0ef --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/transform/URIResolverEntityResolver.java @@ -0,0 +1,87 @@ +/* URIResolverEntityResolver.java - + 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.xml.libxmlj.transform; + +import java.io.IOException; +import javax.xml.transform.URIResolver; +import javax.xml.transform.TransformerException; +import javax.xml.transform.sax.SAXSource; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/** + * Provides an EntityResolver interface to a URIResolver. + * + * @author Chris Burdess + */ +class URIResolverEntityResolver +implements EntityResolver +{ + + private URIResolver resolver; + + URIResolverEntityResolver (URIResolver resolver) + { + this.resolver = resolver; + } + + public InputSource resolveEntity (String publicId, String systemId) + throws SAXException, IOException + { + try + { + return SAXSource.sourceToInputSource (resolver.resolve (systemId, + null)); + } + catch (TransformerException e) + { + Throwable cause = e.getCause (); + if (cause instanceof SAXException) + { + throw (SAXException) cause; + } + else if (cause instanceof IOException) + { + throw (IOException) cause; + } + throw new SAXException (e); + } + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/transform/package.html b/libjava/classpath/gnu/xml/libxmlj/transform/package.html new file mode 100755 index 000000000..dac1027ff --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/transform/package.html @@ -0,0 +1,14 @@ + +

      + A JAXP-compliant wrapper for the XSLT C library for Gnome, also + known as libxslt. Allows to use libxslt via the Java API for XML + processing. +

      + +

      + Usage: +

    • Set the system property javax.xml.transform.TransformerFactory + to gnu.xml.libxmlj.GnomeTransformerFactory.
    • + +

      + diff --git a/libjava/classpath/gnu/xml/libxmlj/util/EmptyNodeList.java b/libjava/classpath/gnu/xml/libxmlj/util/EmptyNodeList.java new file mode 100644 index 000000000..60019ddd4 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/util/EmptyNodeList.java @@ -0,0 +1,62 @@ +/* EmptyNodeList.java - + 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.xml.libxmlj.util; + +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * An empty node list. + * + * @author Chris Burdess + */ +class EmptyNodeList +implements NodeList +{ + + public Node item (int index) + { + return null; + } + + public int getLength () + { + return 0; + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/util/NamedInputStream.java b/libjava/classpath/gnu/xml/libxmlj/util/NamedInputStream.java new file mode 100644 index 000000000..01b3af90d --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/util/NamedInputStream.java @@ -0,0 +1,99 @@ +/* NamedInputStream.java - + 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.xml.libxmlj.util; + +import java.io.FilterInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.PushbackInputStream; + +/** + * An input stream associated with an XML system ID. + * It can report the system ID and the first few bytes of the stream + * in order to detect the character encoding of the stream. + * + * @author Chris Burdess + */ +public class NamedInputStream +extends FilterInputStream +{ + + private static int DETECT_BUFFER_SIZE = 50; + + private String name; + + NamedInputStream (String name, InputStream in, int size) + { + super (new PushbackInputStream (in, size)); + this.name = name; + } + + /** + * Returns the name of the stream (the XML system ID). + */ + public String getName () + { + return name; + } + + /** + * Returns the first few bytes of the stream for character encoding + * purposes. The entire stream can thereafter be read normally from the + * beginning. This method is only valid if no bytes have yet been read + * from the stream. + */ + public byte[] getDetectBuffer () + throws IOException + { + PushbackInputStream p = (PushbackInputStream) in; + byte[] buffer = new byte[DETECT_BUFFER_SIZE]; + int len = p.read (buffer); + if (len < 0) + { + return null; + } + else + { + p.unread (buffer, 0, len); + byte[] ret = new byte[len]; + System.arraycopy (buffer, 0, ret, 0, len); + return ret; + } + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/util/StandaloneDocumentType.java b/libjava/classpath/gnu/xml/libxmlj/util/StandaloneDocumentType.java new file mode 100644 index 000000000..5c3316611 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/util/StandaloneDocumentType.java @@ -0,0 +1,294 @@ +/* StandaloneDocumentType.java - + 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.xml.libxmlj.util; + +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.DOMException; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.UserDataHandler; + +/** + * A "standalone" document type, i.e. one that isn't attached to a document + * node. + * This can be used to create new documents. + */ +public final class StandaloneDocumentType +implements DocumentType +{ + + private final String name; + private final String publicId; + private final String systemId; + + public StandaloneDocumentType (String name, String publicId, String systemId) + { + this.name = name; + this.publicId = publicId; + this.systemId = systemId; + } + + public String getName () + { + return name; + } + + public NamedNodeMap getEntities () + { + // TODO + return null; + } + + public NamedNodeMap getNotations () + { + // TODO + return null; + } + + public String getPublicId () + { + return publicId; + } + + public String getSystemId () + { + return systemId; + } + + public String getInternalSubset () + { + return null; + } + + // -- Node -- + + public String getNodeName () + { + return getName (); + } + + public String getNodeValue () + throws DOMException + { + return null; + } + + public void setNodeValue (String nodeValue) + throws DOMException + { + } + + public short getNodeType () + { + return DOCUMENT_TYPE_NODE; + } + + public Node getParentNode () + { + return null; + } + + public NodeList getChildNodes () + { + return new EmptyNodeList (); + } + + public Node getFirstChild () + { + return null; + } + + public Node getLastChild () + { + return null; + } + + public Node getPreviousSibling () + { + return null; + } + + public Node getNextSibling () + { + return null; + } + + public NamedNodeMap getAttributes () + { + return null; + } + + public Document getOwnerDocument () + { + return null; + } + + public Node insertBefore (Node newChild, Node refChild) + throws DOMException + { + throw new DOMException (DOMException.NO_MODIFICATION_ALLOWED_ERR, null); + } + + public Node replaceChild (Node newChild, Node oldChild) + throws DOMException + { + throw new DOMException (DOMException.NO_MODIFICATION_ALLOWED_ERR, null); + } + + public Node removeChild (Node oldChild) + throws DOMException + { + throw new DOMException (DOMException.NO_MODIFICATION_ALLOWED_ERR, null); + } + + public Node appendChild (Node oldChild) + throws DOMException + { + throw new DOMException (DOMException.NO_MODIFICATION_ALLOWED_ERR, null); + } + + public boolean hasChildNodes () + { + return false; + } + + public Node cloneNode (boolean deep) + { + return new StandaloneDocumentType (name, publicId, systemId); + } + + public void normalize () + { + } + + public boolean isSupported (String feature, String version) + { + return false; + } + + public String getNamespaceURI () + { + return null; + } + + public String getPrefix () + { + return null; + } + + public void setPrefix (String prefix) + { + throw new DOMException (DOMException.NO_MODIFICATION_ALLOWED_ERR, null); + } + + public String getLocalName () + { + return getName (); + } + + public boolean hasAttributes () + { + return false; + } + + // DOM Level 3 + + public String getBaseURI () + { + return null; + } + + public short compareDocumentPosition (Node node) + { + return -1; + } + + public String getTextContent () + { + return null; + } + + public void setTextContent (String content) + { + throw new DOMException(DOMException.NO_MODIFICATION_ALLOWED_ERR, null); + } + + public boolean isSameNode (Node other) + { + return equals (other); + } + + public String lookupPrefix (String namespace) + { + return null; + } + + public boolean isDefaultNamespace (String namespace) + { + return false; + } + + public String lookupNamespaceURI (String prefix) + { + return null; + } + + public boolean isEqualNode (Node other) + { + return equals (other); + } + + public Object getFeature (String feature, String version) + { + return null; + } + + public Object setUserData (String name, Object value, + UserDataHandler handler) + { + return null; + } + + public Object getUserData (String name) + { + return null; + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/util/StandaloneLocator.java b/libjava/classpath/gnu/xml/libxmlj/util/StandaloneLocator.java new file mode 100644 index 000000000..75b40bdf1 --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/util/StandaloneLocator.java @@ -0,0 +1,89 @@ +/* StandaloneLocator.java - + 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.xml.libxmlj.util; + +import javax.xml.transform.SourceLocator; +import org.xml.sax.Locator; + +/** + * SAX Locator implementation that uses the specified values. + * + * @author Chris Burdess + */ +public final class StandaloneLocator +implements Locator, SourceLocator +{ + + private final int lineNumber; + + private final int columnNumber; + + private final String publicId; + + private final String systemId; + + public StandaloneLocator (int lineNumber, int columnNumber, + String publicId, String systemId) + { + this.lineNumber = lineNumber; + this.columnNumber = columnNumber; + this.publicId = publicId; + this.systemId = systemId; + } + + public String getPublicId () + { + return publicId; + } + + public String getSystemId () + { + return systemId; + } + + public int getLineNumber () + { + return lineNumber; + } + + public int getColumnNumber () + { + return columnNumber; + } + +} diff --git a/libjava/classpath/gnu/xml/libxmlj/util/XMLJ.java b/libjava/classpath/gnu/xml/libxmlj/util/XMLJ.java new file mode 100644 index 000000000..8d954d0be --- /dev/null +++ b/libjava/classpath/gnu/xml/libxmlj/util/XMLJ.java @@ -0,0 +1,280 @@ +/* XMLJ.java - + 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.xml.libxmlj.util; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; + +import javax.xml.transform.Result; +import javax.xml.transform.Source; +import javax.xml.transform.sax.SAXSource; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +import org.xml.sax.InputSource; + +import gnu.xml.libxmlj.transform.GnomeTransformerFactory; + +import gnu.xml.dom.ls.ReaderInputStream; +import gnu.xml.dom.ls.WriterOutputStream; + +/** + * Utility functions for libxmlj. + */ +public final class XMLJ +{ + + static class XMLJShutdownHook + implements Runnable + { + + public void run () + { + // Make sure finalizers are run + System.gc (); + Runtime.getRuntime ().runFinalization (); + + // Perform global cleanup on the native level + GnomeTransformerFactory.freeLibxsltGlobal (); + } + + } + + private static boolean initialised = false; + + public static void init () + { + if (!initialised) + { + System.loadLibrary ("xmlj"); + + XMLJShutdownHook hook = new XMLJShutdownHook (); + Runtime.getRuntime ().addShutdownHook (new Thread (hook)); + } + initialised = true; + } + + private static final int LOOKAHEAD = 50; + + /** + * Returns an input stream for the specified input source. + * This returns a pushback stream that libxmlj can use to detect the + * character encoding of the stream. + */ + public static NamedInputStream getInputStream (InputSource input) + throws IOException + { + InputStream in = input.getByteStream (); + String systemId = input.getSystemId (); + if (in == null) + { + Reader r = input.getCharacterStream(); + if (r != null) + in = new ReaderInputStream(r); + } + if (in == null) + { + in = getInputStream(systemId); + } + return new NamedInputStream (systemId, in, LOOKAHEAD); + } + + /** + * Returns an input stream for the specified transformer source. + * This returns a pushback stream that libxmlj can use to detect the + * character encoding of the stream. + */ + public static NamedInputStream getInputStream (Source source) + throws IOException + { + if (source instanceof SAXSource) + { + return getInputStream (((SAXSource) source).getInputSource ()); + } + InputStream in = null; + String systemId = source.getSystemId (); + if (source instanceof StreamSource) + { + in = ((StreamSource) source).getInputStream (); + } + if (in == null) + { + in = getInputStream(systemId); + } + return new NamedInputStream (systemId, in, LOOKAHEAD); + } + + private static InputStream getInputStream(String systemId) + throws IOException + { + if (systemId == null) + { + throw new IOException("no system ID"); + } + try + { + return new URL(systemId).openStream(); + } + catch (MalformedURLException e) + { + return new FileInputStream(systemId); + } + } + + /** + * Returns an input stream for the specified URL. + * This returns a pushback stream that libxmlj can use to detect the + * character encoding of the stream. + */ + public static NamedInputStream getInputStream (URL url) + throws IOException + { + return new NamedInputStream (url.toString (), url.openStream(), + LOOKAHEAD); + } + + /** + * Convenience method for xmljDocLoader + */ + static NamedInputStream xmljGetInputStream(String base, String url) + throws IOException + { + try + { + if (base != null) + { + url = new URL(new URL(base), url).toString(); + } + } + catch (MalformedURLException e) + { + } + InputStream in = getInputStream(url); + return new NamedInputStream(url, in, LOOKAHEAD); + } + + /** + * Returns an output stream for the specified transformer result. + */ + public static OutputStream getOutputStream (Result result) + throws IOException + { + OutputStream out = null; + if (result instanceof StreamResult) + { + out = ((StreamResult) result).getOutputStream (); + } + if (out == null) + { + Writer w = ((StreamResult) result).getWriter (); + if (w != null) + out = new WriterOutputStream (w); + } + if (out == null) + { + String systemId = result.getSystemId (); + if (systemId == null) + { + throw new IOException ("no system ID"); + } + try + { + URL url = new URL (systemId); + URLConnection connection = url.openConnection (); + connection.setDoOutput (true); + out = connection.getOutputStream (); + } + catch (MalformedURLException e) + { + out = new FileOutputStream (systemId); + } + } + + return out; + } + + /** + * Returns the absolute form of the specified URI. + * If the URI is already absolute, returns it as-is. + * Otherwise returns a new URI relative to the given base URI. + */ + public static String getAbsoluteURI (String base, String uri) + { + if (uri != null && + base != null && + (uri.length() > 0) && + (uri.indexOf(':') == -1) && + (uri.charAt(0) != '/')) + { + // URI is relative + if (base.charAt(base.length() - 1) != '/') + { + int i = base.lastIndexOf('/'); + base = base.substring(0, i + 1); + } + return base + uri; + } + else + { + // URI is absolute or no base specified + return uri; + } + } + + public static String getBaseURI(String uri) + { + if (uri != null) + { + int si = uri.lastIndexOf('/'); + if (si != -1) + { + uri = uri.substring(0, si + 1); + } + } + return uri; + } + +} diff --git a/libjava/classpath/gnu/xml/pipeline/CallFilter.java b/libjava/classpath/gnu/xml/pipeline/CallFilter.java new file mode 100644 index 000000000..2398b8685 --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/CallFilter.java @@ -0,0 +1,257 @@ +/* CallFilter.java -- + Copyright (C) 1999,2000,2001 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.pipeline; + +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.net.URL; +import java.net.URLConnection; +import java.io.Writer; + +import org.xml.sax.DTDHandler; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.XMLReaderFactory; + +import gnu.xml.util.Resolver; +import gnu.xml.util.XMLWriter; + + +/** + * Input is sent as an XML request to given URI, and the output of this + * filter is the parsed response to that request. + * A connection is opened to the remote URI when the startDocument call is + * issued through this filter, and the request is finished when the + * endDocument call is issued. Events should be written quickly enough to + * prevent the remote HTTP server from aborting the connection due to + * inactivity; you may want to buffer text in an earlier pipeline stage. + * If your application requires validity checking of such + * outputs, have the output pipeline include a validation stage. + * + *

      In effect, this makes a remote procedure call to the URI, with the + * request and response document syntax as chosen by the application. + * Note that all the input events must be seen, and sent to the URI, + * before the first output event can be seen. Clients are delayed + * at least by waiting for the server to respond, constraining concurrency. + * Services can thus be used to synchronize concurrent activities, and + * even to prioritize service among different clients. + * + *

      You are advised to avoid restricting yourself to an "RPC" model + * for distributed computation. With a World Wide Web, network latencies + * and failures (e.g. non-availability) + * are significant; adopting a "procedure" model, rather than a workflow + * model where bulk requests are sent and worked on asynchronously, is not + * generally an optimal system-wide architecture. When the messages may + * need authentication, such as with an OpenPGP signature, or when server + * loads don't argue in favor of immediate responses, non-RPC models can + * be advantageous. (So-called "peer to peer" computing models are one + * additional type of model, though too often that term is applied to + * systems that still have a centralized control structure.) + * + *

      Be strict in what you send, liberal in what you accept, as + * the Internet tradition goes. Strictly conformant data should never cause + * problems to its receiver; make your request pipeline be very strict, and + * don't compromise on that. Make your response pipeline strict as well, + * but be ready to tolerate specific mild, temporary, and well-documented + * variations from specific communications peers. + * + * @see XmlServlet + * + * @author David Brownell + */ +final public class CallFilter implements EventConsumer +{ + private Requestor req; + private EventConsumer next; + private URL target; + private URLConnection conn; + private ErrorHandler errHandler; + + + /** + * Initializes a call filter so that its inputs are sent to the + * specified URI, and its outputs are sent to the next consumer + * provided. + * + * @exception IOException if the URI isn't accepted as a URL + */ + // constructor used by PipelineFactory + public CallFilter (String uri, EventConsumer next) + throws IOException + { + this.next = next; + req = new Requestor (); + setCallTarget (uri); + } + + /** + * Assigns the URI of the call target to be used. + * Does not affect calls currently being made. + */ + final public void setCallTarget (String uri) + throws IOException + { + target = new URL (uri); + } + + /** + * Assigns the error handler to be used to present most fatal + * errors. + */ + public void setErrorHandler (ErrorHandler handler) + { + req.setErrorHandler (handler); + } + + + /** + * Returns the call target's URI. + */ + final public String getCallTarget () + { + return target.toString (); + } + + /** Returns the content handler currently in use. */ + final public org.xml.sax.ContentHandler getContentHandler () + { + return req; + } + + /** Returns the DTD handler currently in use. */ + final public DTDHandler getDTDHandler () + { + return req; + } + + + /** + * Returns the declaration or lexical handler currently in + * use, or throws an exception for other properties. + */ + final public Object getProperty (String id) + throws SAXNotRecognizedException + { + if (EventFilter.DECL_HANDLER.equals (id)) + return req; + if (EventFilter.LEXICAL_HANDLER.equals (id)) + return req; + throw new SAXNotRecognizedException (id); + } + + + // JDK 1.1 seems to need it to be done this way, sigh + ErrorHandler getErrorHandler () { return errHandler; } + + // + // Takes input and echoes to server as POST input. + // Then sends the POST reply to the next pipeline element. + // + final class Requestor extends XMLWriter + { + Requestor () + { + super ((Writer)null); + } + + public synchronized void startDocument () throws SAXException + { + // Connect to remote object and set up to send it XML text + try { + if (conn != null) + throw new IllegalStateException ("call is being made"); + + conn = target.openConnection (); + conn.setDoOutput (true); + conn.setRequestProperty ("Content-Type", + "application/xml;charset=UTF-8"); + + setWriter (new OutputStreamWriter ( + conn.getOutputStream (), + "UTF8"), "UTF-8"); + + } catch (IOException e) { + fatal ("can't write (POST) to URI: " + target, e); + } + + // NOW base class can safely write that text! + super.startDocument (); + } + + public void endDocument () throws SAXException + { + // + // Finish writing the request (for HTTP, a POST); + // this closes the output stream. + // + super.endDocument (); + + // + // Receive the response. + // Produce events for the next stage. + // + InputSource source; + XMLReader producer; + String encoding; + + try { + + source = new InputSource (conn.getInputStream ()); + +// FIXME if status is anything but success, report it!! It'd be good to +// save the request data just in case we need to deal with a forward. + + encoding = Resolver.getEncoding (conn.getContentType ()); + if (encoding != null) + source.setEncoding (encoding); + + producer = XMLReaderFactory.createXMLReader (); + producer.setErrorHandler (getErrorHandler ()); + EventFilter.bind (producer, next); + producer.parse (source); + conn = null; + + } catch (IOException e) { + fatal ("I/O Exception reading response, " + e.getMessage (), e); + } + } + } +} diff --git a/libjava/classpath/gnu/xml/pipeline/DomConsumer.java b/libjava/classpath/gnu/xml/pipeline/DomConsumer.java new file mode 100644 index 000000000..141f36eca --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/DomConsumer.java @@ -0,0 +1,967 @@ +/* DomConsumer.java -- + Copyright (C) 1999,2000,2001 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.pipeline; + +import gnu.xml.util.DomParser; + +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.DTDHandler; +import org.xml.sax.ErrorHandler; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXParseException; +import org.xml.sax.ext.DeclHandler; +import org.xml.sax.ext.LexicalHandler; +import org.xml.sax.helpers.AttributesImpl; +import org.w3c.dom.Attr; +import org.w3c.dom.CDATASection; +import org.w3c.dom.CharacterData; +import org.w3c.dom.Document; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.Element; +import org.w3c.dom.EntityReference; +import org.w3c.dom.Node; +import org.w3c.dom.ProcessingInstruction; +import org.w3c.dom.Text; + +/** + * This consumer builds a DOM Document from its input, acting either as a + * pipeline terminus or as an intermediate buffer. When a document's worth + * of events has been delivered to this consumer, that document is read with + * a {@link DomParser} and sent to the next consumer. It is also available + * as a read-once property. + * + *

      The DOM tree is constructed as faithfully as possible. There are some + * complications since a DOM should expose behaviors that can't be implemented + * without API backdoors into that DOM, and because some SAX parsers don't + * report all the information that DOM permits to be exposed. The general + * problem areas involve information from the Document Type Declaration (DTD). + * DOM only represents a limited subset, but has some behaviors that depend + * on much deeper knowledge of a document's DTD. You shouldn't have much to + * worry about unless you change handling of "noise" nodes from its default + * setting (which ignores them all); note if you use JAXP to populate your + * DOM trees, it wants to save "noise" nodes by default. (Such nodes include + * ignorable whitespace, comments, entity references and CDATA boundaries.) + * Otherwise, your + * main worry will be if you use a SAX parser that doesn't flag ignorable + * whitespace unless it's validating (few don't). + * + *

      The SAX2 events used as input must contain XML Names for elements + * and attributes, with original prefixes. In SAX2, + * this is optional unless the "namespace-prefixes" parser feature is set. + * Moreover, many application components won't provide completely correct + * structures anyway. Before you convert a DOM to an output document, + * you should plan to postprocess it to create or repair such namespace + * information. The {@link NSFilter} pipeline stage does such work. + * + *

      Note: changes late in DOM L2 process made it impractical to + * attempt to create the DocumentType node in any implementation-neutral way, + * much less to populate it (L1 didn't support even creating such nodes). + * To create and populate such a node, subclass the inner + * {@link DomConsumer.Handler} class and teach it about the backdoors into + * whatever DOM implementation you want. It's possible that some revised + * DOM API (L3?) will make this problem solvable again. + * + * @see DomParser + * + * @author David Brownell + */ +public class DomConsumer implements EventConsumer +{ + private Class domImpl; + + private boolean hidingCDATA = true; + private boolean hidingComments = true; + private boolean hidingWhitespace = true; + private boolean hidingReferences = true; + + private Handler handler; + private ErrorHandler errHandler; + + private EventConsumer next; + + // FIXME: this can't be a generic pipeline stage just now, + // since its input became a Class not a String (to be turned + // into a class, using the right class loader) + + + /** + * Configures this pipeline terminus to use the specified implementation + * of DOM when constructing its result value. + * + * @param impl class implementing {@link org.w3c.dom.Document Document} + * which publicly exposes a default constructor + * + * @exception SAXException when there is a problem creating an + * empty DOM document using the specified implementation + */ + public DomConsumer (Class impl) + throws SAXException + { + domImpl = impl; + handler = new Handler (this); + } + + /** + * This is the hook through which a subclass provides a handler + * which knows how to access DOM extensions, specific to some + * implementation, to record additional data in a DOM. + * Treat this as part of construction; don't call it except + * before (or between) parses. + */ + protected void setHandler (Handler h) + { + handler = h; + } + + + private Document emptyDocument () + throws SAXException + { + try { + return (Document) domImpl.newInstance (); + } catch (IllegalAccessException e) { + throw new SAXException ("can't access constructor: " + + e.getMessage ()); + } catch (InstantiationException e) { + throw new SAXException ("can't instantiate Document: " + + e.getMessage ()); + } + } + + + /** + * Configures this consumer as a buffer/filter, using the specified + * DOM implementation when constructing its result value. + * + *

      This event consumer acts as a buffer and filter, in that it + * builds a DOM tree and then writes it out when endDocument + * is invoked. Because of the limitations of DOM, much information + * will as a rule not be seen in that replay. To get a full fidelity + * copy of the input event stream, use a {@link TeeConsumer}. + * + * @param impl class implementing {@link org.w3c.dom.Document Document} + * which publicly exposes a default constructor + * @param next receives a "replayed" sequence of parse events when + * the endDocument method is invoked. + * + * @exception SAXException when there is a problem creating an + * empty DOM document using the specified DOM implementation + */ + public DomConsumer (Class impl, EventConsumer n) + throws SAXException + { + this (impl); + next = n; + } + + + /** + * Returns the document constructed from the preceding + * sequence of events. This method should not be + * used again until another sequence of events has been + * given to this EventConsumer. + */ + final public Document getDocument () + { + return handler.clearDocument (); + } + + public void setErrorHandler (ErrorHandler handler) + { + errHandler = handler; + } + + + /** + * Returns true if the consumer is hiding entity references nodes + * (the default), and false if EntityReference nodes should + * instead be created. Such EntityReference nodes will normally be + * empty, unless an implementation arranges to populate them and then + * turn them back into readonly objects. + * + * @see #setHidingReferences + */ + final public boolean isHidingReferences () + { return hidingReferences; } + + /** + * Controls whether the consumer will hide entity expansions, + * or will instead mark them with entity reference nodes. + * + * @see #isHidingReferences + * @param flag False if entity reference nodes will appear + */ + final public void setHidingReferences (boolean flag) + { hidingReferences = flag; } + + + /** + * Returns true if the consumer is hiding comments (the default), + * and false if they should be placed into the output document. + * + * @see #setHidingComments + */ + public final boolean isHidingComments () + { return hidingComments; } + + /** + * Controls whether the consumer is hiding comments. + * + * @see #isHidingComments + */ + public final void setHidingComments (boolean flag) + { hidingComments = flag; } + + + /** + * Returns true if the consumer is hiding ignorable whitespace + * (the default), and false if such whitespace should be placed + * into the output document as children of element nodes. + * + * @see #setHidingWhitespace + */ + public final boolean isHidingWhitespace () + { return hidingWhitespace; } + + /** + * Controls whether the consumer hides ignorable whitespace + * + * @see #isHidingComments + */ + public final void setHidingWhitespace (boolean flag) + { hidingWhitespace = flag; } + + + /** + * Returns true if the consumer is saving CDATA boundaries, or + * false (the default) otherwise. + * + * @see #setHidingCDATA + */ + final public boolean isHidingCDATA () + { return hidingCDATA; } + + /** + * Controls whether the consumer will save CDATA boundaries. + * + * @see #isHidingCDATA + * @param flag True to treat CDATA text differently from other + * text nodes + */ + final public void setHidingCDATA (boolean flag) + { hidingCDATA = flag; } + + + + /** Returns the document handler being used. */ + final public ContentHandler getContentHandler () + { return handler; } + + /** Returns the DTD handler being used. */ + final public DTDHandler getDTDHandler () + { return handler; } + + /** + * Returns the lexical handler being used. + * (DOM construction can't really use declaration handlers.) + */ + final public Object getProperty (String id) + throws SAXNotRecognizedException + { + if ("http://xml.org/sax/properties/lexical-handler".equals (id)) + return handler; + if ("http://xml.org/sax/properties/declaration-handler".equals (id)) + return handler; + throw new SAXNotRecognizedException (id); + } + + EventConsumer getNext () { return next; } + + ErrorHandler getErrorHandler () { return errHandler; } + + /** + * Class used to intercept various parsing events and use them to + * populate a DOM document. Subclasses would typically know and use + * backdoors into specific DOM implementations, used to implement + * DTD-related functionality. + * + *

      Note that if this ever throws a DOMException (runtime exception) + * that will indicate a bug in the DOM (e.g. doesn't support something + * per specification) or the parser (e.g. emitted an illegal name, or + * accepted illegal input data).

      + */ + public static class Handler + implements ContentHandler, LexicalHandler, + DTDHandler, DeclHandler + { + protected DomConsumer consumer; + + private DOMImplementation impl; + private Document document; + private boolean isL2; + + private Locator locator; + private Node top; + private boolean inCDATA; + private boolean mergeCDATA; + private boolean inDTD; + private String currentEntity; + + private boolean recreatedAttrs; + private AttributesImpl attributes = new AttributesImpl (); + + /** + * Subclasses may use SAX2 events to provide additional + * behaviors in the resulting DOM. + */ + protected Handler (DomConsumer consumer) + throws SAXException + { + this.consumer = consumer; + document = consumer.emptyDocument (); + impl = document.getImplementation (); + isL2 = impl.hasFeature ("XML", "2.0"); + } + + private void fatal (String message, Exception x) + throws SAXException + { + SAXParseException e; + ErrorHandler errHandler = consumer.getErrorHandler (); + + if (locator == null) + e = new SAXParseException (message, null, null, -1, -1, x); + else + e = new SAXParseException (message, locator, x); + if (errHandler != null) + errHandler.fatalError (e); + throw e; + } + + /** + * Returns and forgets the document produced. If the handler is + * reused, a new document may be created. + */ + Document clearDocument () + { + Document retval = document; + document = null; + locator = null; + return retval; + } + + /** + * Returns the document under construction. + */ + protected Document getDocument () + { return document; } + + /** + * Returns the current node being populated. This is usually + * an Element or Document, but it might be an EntityReference + * node if some implementation-specific code knows how to put + * those into the result tree and later mark them as readonly. + */ + protected Node getTop () + { return top; } + + + // SAX1 + public void setDocumentLocator (Locator locator) + { + this.locator = locator; + } + + // SAX1 + public void startDocument () + throws SAXException + { + if (document == null) + try { + if (isL2) { + // couple to original implementation + document = impl.createDocument (null, "foo", null); + document.removeChild (document.getFirstChild ()); + } else { + document = consumer.emptyDocument (); + } + } catch (Exception e) { + fatal ("DOM create document", e); + } + top = document; + } + + // SAX1 + public void endDocument () + throws SAXException + { + try { + if (consumer.getNext () != null && document != null) { + DomParser parser = new DomParser (document); + + EventFilter.bind (parser, consumer.getNext ()); + parser.parse ("ignored"); + } + } finally { + top = null; + } + } + + // SAX1 + public void processingInstruction (String target, String data) + throws SAXException + { + // we can't create populated entity ref nodes using + // only public DOM APIs (they've got to be readonly) + if (currentEntity != null) + return; + + ProcessingInstruction pi; + + if (isL2 + // && consumer.isUsingNamespaces () + && target.indexOf (':') != -1) + namespaceError ( + "PI target name is namespace nonconformant: " + + target); + if (inDTD) + return; + pi = document.createProcessingInstruction (target, data); + top.appendChild (pi); + } + + /** + * Subclasses may overrride this method to provide a more efficient + * way to construct text nodes. + * Typically, copying the text into a single character array will + * be more efficient than doing that as well as allocating other + * needed for a String, including an internal StringBuffer. + * Those additional memory and CPU costs can be incurred later, + * if ever needed. + * Unfortunately the standard DOM factory APIs encourage those costs + * to be incurred early. + */ + protected Text createText ( + boolean isCDATA, + char ch [], + int start, + int length + ) { + String value = new String (ch, start, length); + + if (isCDATA) + return document.createCDATASection (value); + else + return document.createTextNode (value); + } + + // SAX1 + public void characters (char ch [], int start, int length) + throws SAXException + { + // we can't create populated entity ref nodes using + // only public DOM APIs (they've got to be readonly + // at creation time) + if (currentEntity != null) + return; + + Node lastChild = top.getLastChild (); + + // merge consecutive text or CDATA nodes if appropriate. + if (lastChild instanceof Text) { + if (consumer.isHidingCDATA () + // consecutive Text content ... always merge + || (!inCDATA + && !(lastChild instanceof CDATASection)) + // consecutive CDATASection content ... don't + // merge between sections, only within them + || (inCDATA && mergeCDATA + && lastChild instanceof CDATASection) + ) { + CharacterData last = (CharacterData) lastChild; + String value = new String (ch, start, length); + + last.appendData (value); + return; + } + } + if (inCDATA && !consumer.isHidingCDATA ()) { + top.appendChild (createText (true, ch, start, length)); + mergeCDATA = true; + } else + top.appendChild (createText (false, ch, start, length)); + } + + // SAX2 + public void skippedEntity (String name) + throws SAXException + { + // this callback is useless except to report errors, since + // we can't know if the ref was in content, within an + // attribute, within a declaration ... only one of those + // cases supports more intelligent action than a panic. + fatal ("skipped entity: " + name, null); + } + + // SAX2 + public void startPrefixMapping (String prefix, String uri) + throws SAXException + { + // reconstruct "xmlns" attributes deleted by all + // SAX2 parsers without "namespace-prefixes" = true + if ("".equals (prefix)) + attributes.addAttribute ("", "", "xmlns", + "CDATA", uri); + else + attributes.addAttribute ("", "", "xmlns:" + prefix, + "CDATA", uri); + recreatedAttrs = true; + } + + // SAX2 + public void endPrefixMapping (String prefix) + throws SAXException + { } + + // SAX2 + public void startElement ( + String uri, + String localName, + String qName, + Attributes atts + ) throws SAXException + { + // we can't create populated entity ref nodes using + // only public DOM APIs (they've got to be readonly) + if (currentEntity != null) + return; + + // parser discarded basic information; DOM tree isn't writable + // without massaging to assign prefixes to all nodes. + // the "NSFilter" class does that massaging. + if (qName.length () == 0) + qName = localName; + + + Element element; + int length = atts.getLength (); + + if (!isL2) { + element = document.createElement (qName); + + // first the explicit attributes ... + length = atts.getLength (); + for (int i = 0; i < length; i++) + element.setAttribute (atts.getQName (i), + atts.getValue (i)); + // ... then any recreated ones (DOM deletes duplicates) + if (recreatedAttrs) { + recreatedAttrs = false; + length = attributes.getLength (); + for (int i = 0; i < length; i++) + element.setAttribute (attributes.getQName (i), + attributes.getValue (i)); + attributes.clear (); + } + + top.appendChild (element); + top = element; + return; + } + + // For an L2 DOM when namespace use is enabled, use + // createElementNS/createAttributeNS except when + // (a) it's an element in the default namespace, or + // (b) it's an attribute with no prefix + String namespace; + + if (localName.length () != 0) + namespace = (uri.length () == 0) ? null : uri; + else + namespace = getNamespace (getPrefix (qName), atts); + + if (namespace == null) + element = document.createElement (qName); + else + element = document.createElementNS (namespace, qName); + + populateAttributes (element, atts); + if (recreatedAttrs) { + recreatedAttrs = false; + // ... DOM deletes any duplicates + populateAttributes (element, attributes); + attributes.clear (); + } + + top.appendChild (element); + top = element; + } + + final static String xmlnsURI = "http://www.w3.org/2000/xmlns/"; + + private void populateAttributes (Element element, Attributes attrs) + throws SAXParseException + { + int length = attrs.getLength (); + + for (int i = 0; i < length; i++) { + String type = attrs.getType (i); + String value = attrs.getValue (i); + String name = attrs.getQName (i); + String local = attrs.getLocalName (i); + String uri = attrs.getURI (i); + + // parser discarded basic information, DOM tree isn't writable + if (name.length () == 0) + name = local; + + // all attribute types other than these three may not + // contain scoped names... enumerated attributes get + // reported as NMTOKEN, except for NOTATION values + if (!("CDATA".equals (type) + || "NMTOKEN".equals (type) + || "NMTOKENS".equals (type))) { + if (value.indexOf (':') != -1) { + namespaceError ( + "namespace nonconformant attribute value: " + + "<" + element.getNodeName () + + " " + name + "='" + value + "' ...>"); + } + } + + // xmlns="" is legal (undoes default NS) + // xmlns:foo="" is illegal + String prefix = getPrefix (name); + String namespace; + + if ("xmlns".equals (prefix)) { + if ("".equals (value)) + namespaceError ("illegal null namespace decl, " + name); + namespace = xmlnsURI; + } else if ("xmlns".equals (name)) + namespace = xmlnsURI; + + else if (prefix == null) + namespace = null; + else if (!"".equals(uri) && uri.length () != 0) + namespace = uri; + else + namespace = getNamespace (prefix, attrs); + + if (namespace == null) + element.setAttribute (name, value); + else + element.setAttributeNS (namespace, name, value); + } + } + + private String getPrefix (String name) + { + int temp; + + if ((temp = name.indexOf (':')) > 0) + return name.substring (0, temp); + return null; + } + + // used with SAX1-level parser output + private String getNamespace (String prefix, Attributes attrs) + throws SAXParseException + { + String namespace; + String decl; + + // defaulting + if (prefix == null) { + decl = "xmlns"; + namespace = attrs.getValue (decl); + if ("".equals (namespace)) + return null; + else if (namespace != null) + return namespace; + + // "xmlns" is like a keyword + // ... according to the Namespace REC, but DOM L2 CR2+ + // and Infoset violate that by assigning a namespace. + // that conflict is resolved elsewhere. + } else if ("xmlns".equals (prefix)) + return null; + + // "xml" prefix is fixed + else if ("xml".equals (prefix)) + return "http://www.w3.org/XML/1998/namespace"; + + // otherwise, expect a declaration + else { + decl = "xmlns:" + prefix; + namespace = attrs.getValue (decl); + } + + // if we found a local declaration, great + if (namespace != null) + return namespace; + + + // ELSE ... search up the tree we've been building + for (Node n = top; + n != null && n.getNodeType () != Node.DOCUMENT_NODE; + n = n.getParentNode ()) { + if (n.getNodeType () == Node.ENTITY_REFERENCE_NODE) + continue; + Element e = (Element) n; + Attr attr = e.getAttributeNode (decl); + if (attr != null) + return attr.getNodeValue (); + } + // see above re "xmlns" as keyword + if ("xmlns".equals (decl)) + return null; + + namespaceError ("Undeclared namespace prefix: " + prefix); + return null; + } + + // SAX2 + public void endElement (String uri, String localName, String qName) + throws SAXException + { + // we can't create populated entity ref nodes using + // only public DOM APIs (they've got to be readonly) + if (currentEntity != null) + return; + + top = top.getParentNode (); + } + + // SAX1 (mandatory reporting if validating) + public void ignorableWhitespace (char ch [], int start, int length) + throws SAXException + { + if (consumer.isHidingWhitespace ()) + return; + characters (ch, start, length); + } + + // SAX2 lexical event + public void startCDATA () + throws SAXException + { + inCDATA = true; + // true except for the first fragment of a cdata section + mergeCDATA = false; + } + + // SAX2 lexical event + public void endCDATA () + throws SAXException + { + inCDATA = false; + } + + // SAX2 lexical event + // + // this SAX2 callback merges two unrelated things: + // - Declaration of the root element type ... belongs with + // the other DTD declaration methods, NOT HERE. + // - IDs for the optional external subset ... belongs here + // with other lexical information. + // + // ...and it doesn't include the internal DTD subset, desired + // both to support DOM L2 and to enable "pass through" processing + // + public void startDTD (String name, String publicId, String SystemId) + throws SAXException + { + // need to filter out comments and PIs within the DTD + inDTD = true; + } + + // SAX2 lexical event + public void endDTD () + throws SAXException + { + inDTD = false; + } + + // SAX2 lexical event + public void comment (char ch [], int start, int length) + throws SAXException + { + Node comment; + + // we can't create populated entity ref nodes using + // only public DOM APIs (they've got to be readonly) + if (consumer.isHidingComments () + || inDTD + || currentEntity != null) + return; + comment = document.createComment (new String (ch, start, length)); + top.appendChild (comment); + } + + /** + * May be overridden by subclasses to return true, indicating + * that entity reference nodes can be populated and then made + * read-only. + */ + public boolean canPopulateEntityRefs () + { return false; } + + // SAX2 lexical event + public void startEntity (String name) + throws SAXException + { + // are we ignoring what would be contents of an + // entity ref, since we can't populate it? + if (currentEntity != null) + return; + + // Are we hiding all entity boundaries? + if (consumer.isHidingReferences ()) + return; + + // SAX2 shows parameter entities; DOM hides them + if (name.charAt (0) == '%' || "[dtd]".equals (name)) + return; + + // Since we can't create a populated entity ref node in any + // standard way, we create an unpopulated one. + EntityReference ref = document.createEntityReference (name); + top.appendChild (ref); + top = ref; + + // ... allowing subclasses to populate them + if (!canPopulateEntityRefs ()) + currentEntity = name; + } + + // SAX2 lexical event + public void endEntity (String name) + throws SAXException + { + if (name.charAt (0) == '%' || "[dtd]".equals (name)) + return; + if (name.equals (currentEntity)) + currentEntity = null; + if (!consumer.isHidingReferences ()) + top = top.getParentNode (); + } + + + // SAX1 DTD event + public void notationDecl ( + String name, + String publicId, String SystemId + ) throws SAXException + { + /* IGNORE -- no public DOM API lets us store these + * into the doctype node + */ + } + + // SAX1 DTD event + public void unparsedEntityDecl ( + String name, + String publicId, String SystemId, + String notationName + ) throws SAXException + { + /* IGNORE -- no public DOM API lets us store these + * into the doctype node + */ + } + + // SAX2 declaration event + public void elementDecl (String name, String model) + throws SAXException + { + /* IGNORE -- no content model support in DOM L2 */ + } + + // SAX2 declaration event + public void attributeDecl ( + String eName, + String aName, + String type, + String mode, + String value + ) throws SAXException + { + /* IGNORE -- no attribute model support in DOM L2 */ + } + + // SAX2 declaration event + public void internalEntityDecl (String name, String value) + throws SAXException + { + /* IGNORE -- no public DOM API lets us store these + * into the doctype node + */ + } + + // SAX2 declaration event + public void externalEntityDecl ( + String name, + String publicId, + String SystemId + ) throws SAXException + { + /* IGNORE -- no public DOM API lets us store these + * into the doctype node + */ + } + + // + // These really should offer the option of nonfatal handling, + // like other validity errors, though that would cause major + // chaos in the DOM data structures. DOM is already spec'd + // to treat many of these as fatal, so this is consistent. + // + private void namespaceError (String description) + throws SAXParseException + { + SAXParseException err; + + err = new SAXParseException (description, locator); + throw err; + } + } +} diff --git a/libjava/classpath/gnu/xml/pipeline/EventConsumer.java b/libjava/classpath/gnu/xml/pipeline/EventConsumer.java new file mode 100644 index 000000000..a0a8824f7 --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/EventConsumer.java @@ -0,0 +1,95 @@ +/* EventConsumer.java -- + Copyright (C) 1999,2000,2001 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.pipeline; + +import org.xml.sax.*; + + +/** + * Collects the event consumption apparatus of a SAX pipeline stage. + * Consumers which permit some handlers or other characteristics to be + * configured will provide methods to support that configuration. + * + *

      Two important categories of consumers include filters, which + * process events and pass them on to other consumers, and terminus + * (or terminal) stages, which don't pass events on. Filters are not + * necessarily derived from the {@link EventFilter} class, although that + * class can substantially simplify their construction by automating the + * most common activities. + * + *

      Event consumers which follow certain conventions for the signatures + * of their constructors can be automatically assembled into pipelines + * by the {@link PipelineFactory} class. + * + * @author David Brownell + */ +public interface EventConsumer +{ + /** Most stages process these core SAX callbacks. */ + public ContentHandler getContentHandler (); + + /** Few stages will use unparsed entities. */ + public DTDHandler getDTDHandler (); + + /** + * This method works like the SAX2 XMLReader method of the same name, + * and is used to retrieve the optional lexical and declaration handlers + * in a pipeline. + * + * @param id This is a URI identifying the type of property desired. + * @return The value of that property, if it is defined. + * + * @exception SAXNotRecognizedException Thrown if the particular + * pipeline stage does not understand the specified identifier. + */ + public Object getProperty (String id) + throws SAXNotRecognizedException; + + /** + * This method provides a filter stage with a handler that abstracts + * presentation of warnings and both recoverable and fatal errors. + * Most pipeline stages should share a single policy and mechanism + * for such reports, since application components require consistency + * in such activities. Accordingly, typical responses to this method + * invocation involve saving the handler for use; filters will pass + * it on to any other consumers they use. + * + * @param handler encapsulates error handling policy for this stage + */ + public void setErrorHandler (ErrorHandler handler); +} diff --git a/libjava/classpath/gnu/xml/pipeline/EventFilter.java b/libjava/classpath/gnu/xml/pipeline/EventFilter.java new file mode 100644 index 000000000..b3cc2d654 --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/EventFilter.java @@ -0,0 +1,796 @@ +/* EventFilter.java -- + Copyright (C) 1999,2000,2001 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.pipeline; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.xml.sax.*; +import org.xml.sax.ext.*; +import org.xml.sax.helpers.XMLFilterImpl; + +/** + * A customizable event consumer, used to assemble various kinds of filters + * using SAX handlers and an optional second consumer. It can be constructed + * in two ways:

        + * + *
      • To serve as a passthrough, sending all events to a second consumer. + * The second consumer may be identified through {@link #getNext}. + * + *
      • To serve as a dead end, with all handlers null; + * {@link #getNext} returns null. + * + *
      + * + *

      Additionally, SAX handlers may be assigned, which completely replace + * the "upstream" view (through {@link EventConsumer}) of handlers, initially + * null or the "next" consumer provided to the constructor. To make + * it easier to build specialized filter classes, this class implements + * all the standard SAX consumer handlers, and those implementations + * delegate "downstream" to the consumer accessed by {@link #getNext}. + * + *

      The simplest way to create a custom a filter class is to create a + * subclass which overrides one or more handler interface methods. The + * constructor for that subclass then registers itself as a handler for + * those interfaces using a call such as setContentHandler(this), + * so the "upstream" view of event delivery is modified from the state + * established in the base class constructor. That way, + * the overridden methods intercept those event callbacks + * as they go "downstream", and + * all other event callbacks will pass events to any next consumer. + * Overridden methods may invoke superclass methods (perhaps after modifying + * parameters) if they wish to delegate such calls. Such subclasses + * should use {@link #getErrorHandler} to report errors using the + * common error reporting mechanism. + * + *

      Another important technique is to construct a filter consisting + * of only a few specific types of handler. For example, one could easily + * prune out lexical events or various declarations by providing handlers + * which don't pass those events downstream, or by providing null handlers. + * + *


      + * + *

      This may be viewed as the consumer oriented analogue of the SAX2 + * {@link org.xml.sax.helpers.XMLFilterImpl XMLFilterImpl} class. + * Key differences include:

        + * + *
      • This fully separates consumer and producer roles: it + * does not implement the producer side XMLReader or + * EntityResolver interfaces, so it can only be used + * in "push" mode (it has no parse() methods). + * + *
      • "Extension" handlers are fully supported, enabling a + * richer set of application requirements. + * And it implements {@link EventConsumer}, which groups related + * consumer methods together, rather than leaving them separated. + * + *
      • The chaining which is visible is "downstream" to the next + * consumer, not "upstream" to the preceding producer. + * It supports "fan-in", where + * a consumer can be fed by several producers. (For "fan-out", + * see the {@link TeeConsumer} class.) + * + *
      • Event chaining is set up differently. It is intended to + * work "upstream" from terminus towards producer, during filter + * construction, as described above. + * This is part of an early binding model: + * events don't need to pass through stages which ignore them. + * + *
      • ErrorHandler support is separated, on the grounds that + * pipeline stages need to share the same error handling policy. + * For the same reason, error handler setup goes "downstream": + * when error handlers get set, they are passed to subsequent + * consumers. + * + *
      + * + *

      The {@link #chainTo chainTo()} convenience routine supports chaining to + * an XMLFilterImpl, in its role as a limited functionality event + * consumer. Its event producer role ({@link XMLFilter}) is ignored. + * + *


      + * + *

      The {@link #bind bind()} routine may be used associate event pipelines + * with any kind of {@link XMLReader} that will produce the events. + * Such pipelines don't necessarily need to have any members which are + * implemented using this class. That routine has some intelligence + * which supports automatic changes to parser feature flags, letting + * event piplines become largely independent of the particular feature + * sets of parsers. + * + * @author David Brownell + */ +public class EventFilter + implements EventConsumer, ContentHandler, DTDHandler, + LexicalHandler, DeclHandler +{ + // SAX handlers + private ContentHandler docHandler, docNext; + private DTDHandler dtdHandler, dtdNext; + private LexicalHandler lexHandler, lexNext; + private DeclHandler declHandler, declNext; + // and ideally, one more for the stuff SAX2 doesn't show + + private Locator locator; + private EventConsumer next; + private ErrorHandler errHandler; + + + /** SAX2 URI prefix for standard feature flags. */ + public static final String FEATURE_URI + = "http://xml.org/sax/features/"; + /** SAX2 URI prefix for standard properties (mostly for handlers). */ + public static final String PROPERTY_URI + = "http://xml.org/sax/properties/"; + + /** SAX2 property identifier for {@link DeclHandler} events */ + public static final String DECL_HANDLER + = PROPERTY_URI + "declaration-handler"; + /** SAX2 property identifier for {@link LexicalHandler} events */ + public static final String LEXICAL_HANDLER + = PROPERTY_URI + "lexical-handler"; + + // + // These class objects will be null if the relevant class isn't linked. + // Small configurations (pJava and some kinds of embedded systems) need + // to facilitate smaller executables. So "instanceof" is undesirable + // when bind() sees if it can remove some stages. + // + // SECURITY NOTE: assuming all these classes are part of the same sealed + // package, there's no problem saving these in the instance of this class + // that's associated with "this" class loader. But that wouldn't be true + // for classes in another package. + // + private static boolean loaded; + private static Class nsClass; + private static Class validClass; + private static Class wfClass; + private static Class xincClass; + + static ClassLoader getClassLoader () + { + Method m = null; + + try { + m = Thread.class.getMethod("getContextClassLoader"); + } catch (NoSuchMethodException e) { + // Assume that we are running JDK 1.1, use the current ClassLoader + return EventFilter.class.getClassLoader(); + } + + try { + return (ClassLoader) m.invoke(Thread.currentThread()); + } catch (IllegalAccessException e) { + // assert(false) + throw new UnknownError(e.getMessage()); + } catch (InvocationTargetException e) { + // assert(e.getTargetException() instanceof SecurityException) + throw new UnknownError(e.getMessage()); + } + } + + static Class loadClass (ClassLoader classLoader, String className) + { + try { + if (classLoader == null) + return Class.forName(className); + else + return classLoader.loadClass(className); + } catch (Exception e) { + return null; + } + } + + static private void loadClasses () + { + ClassLoader loader = getClassLoader (); + + nsClass = loadClass (loader, "gnu.xml.pipeline.NSFilter"); + validClass = loadClass (loader, "gnu.xml.pipeline.ValidationConsumer"); + wfClass = loadClass (loader, "gnu.xml.pipeline.WellFormednessFilter"); + xincClass = loadClass (loader, "gnu.xml.pipeline.XIncludeFilter"); + loaded = true; + } + + + /** + * Binds the standard SAX2 handlers from the specified consumer + * pipeline to the specified producer. These handlers include the core + * {@link ContentHandler} and {@link DTDHandler}, plus the extension + * {@link DeclHandler} and {@link LexicalHandler}. Any additional + * application-specific handlers need to be bound separately. + * The {@link ErrorHandler} is handled differently: the producer's + * error handler is passed through to the consumer pipeline. + * The producer is told to include namespace prefix information if it + * can, since many pipeline stages need that Infoset information to + * work well. + * + *

      At the head of the pipeline, certain standard event filters are + * recognized and handled specially. This facilitates construction + * of processing pipelines that work regardless of the capabilities + * of the XMLReader implementation in use; for example, it permits + * validating output of a {@link gnu.xml.util.DomParser}.

        + * + *
      • {@link NSFilter} will be removed if the producer can be + * told not to discard namespace data, using the "namespace-prefixes" + * feature flag. + * + *
      • {@link ValidationConsumer} will be removed if the producer + * can be told to validate, using the "validation" feature flag. + * + *
      • {@link WellFormednessFilter} is always removed, on the + * grounds that no XMLReader is permitted to producee malformed + * event streams and this would just be processing overhead. + * + *
      • {@link XIncludeFilter} stops the special handling, except + * that it's told about the "namespace-prefixes" feature of the + * event producer so that the event stream is internally consistent. + * + *
      • The first consumer which is not one of those classes stops + * such special handling. This means that if you want to force + * one of those filters to be used, you could just precede it with + * an instance of {@link EventFilter} configured as a pass-through. + * You might need to do that if you are using an {@link NSFilter} + * subclass to fix names found in attributes or character data. + * + *
      + * + *

      Other than that, this method works with any kind of event consumer, + * not just event filters. Note that in all cases, the standard handlers + * are assigned; any previous handler assignments for the handler will + * be overridden. + * + * @param producer will deliver events to the specified consumer + * @param consumer pipeline supplying event handlers to be associated + * with the producer (may not be null) + */ + public static void bind (XMLReader producer, EventConsumer consumer) + { + Class klass = null; + boolean prefixes; + + if (!loaded) + loadClasses (); + + // DOM building, printing, layered validation, and other + // things don't work well when prefix info is discarded. + // Include it by default, whenever possible. + try { + producer.setFeature (FEATURE_URI + "namespace-prefixes", + true); + prefixes = true; + } catch (SAXException e) { + prefixes = false; + } + + // NOTE: This loop doesn't use "instanceof", since that + // would prevent compiling/linking without those classes + // being present. + while (consumer != null) { + klass = consumer.getClass (); + + // we might have already changed this problematic SAX2 default. + if (nsClass != null && nsClass.isAssignableFrom (klass)) { + if (!prefixes) + break; + consumer = ((EventFilter)consumer).getNext (); + + // the parser _might_ do DTD validation by default ... + // if not, maybe we can change this setting. + } else if (validClass != null + && validClass.isAssignableFrom (klass)) { + try { + producer.setFeature (FEATURE_URI + "validation", + true); + consumer = ((ValidationConsumer)consumer).getNext (); + } catch (SAXException e) { + break; + } + + // parsers are required not to have such bugs + } else if (wfClass != null && wfClass.isAssignableFrom (klass)) { + consumer = ((WellFormednessFilter)consumer).getNext (); + + // stop on the first pipeline stage we can't remove + } else + break; + + if (consumer == null) + klass = null; + } + + // the actual setting here doesn't matter as much + // as that producer and consumer agree + if (xincClass != null && klass != null + && xincClass.isAssignableFrom (klass)) + ((XIncludeFilter)consumer).setSavingPrefixes (prefixes); + + // Some SAX parsers can't handle null handlers -- bleech + DefaultHandler2 h = new DefaultHandler2 (); + + if (consumer != null && consumer.getContentHandler () != null) + producer.setContentHandler (consumer.getContentHandler ()); + else + producer.setContentHandler (h); + if (consumer != null && consumer.getDTDHandler () != null) + producer.setDTDHandler (consumer.getDTDHandler ()); + else + producer.setDTDHandler (h); + + try { + Object dh; + + if (consumer != null) + dh = consumer.getProperty (DECL_HANDLER); + else + dh = null; + if (dh == null) + dh = h; + producer.setProperty (DECL_HANDLER, dh); + } catch (Exception e) { /* ignore */ } + try { + Object lh; + + if (consumer != null) + lh = consumer.getProperty (LEXICAL_HANDLER); + else + lh = null; + if (lh == null) + lh = h; + producer.setProperty (LEXICAL_HANDLER, lh); + } catch (Exception e) { /* ignore */ } + + // this binding goes the other way around + if (producer.getErrorHandler () == null) + producer.setErrorHandler (h); + if (consumer != null) + consumer.setErrorHandler (producer.getErrorHandler ()); + } + + /** + * Initializes all handlers to null. + */ + // constructor used by PipelineFactory + public EventFilter () { } + + + /** + * Handlers that are not otherwise set will default to those from + * the specified consumer, making it easy to pass events through. + * If the consumer is null, all handlers are initialzed to null. + */ + // constructor used by PipelineFactory + public EventFilter (EventConsumer consumer) + { + if (consumer == null) + return; + + next = consumer; + + // We delegate through the "xxNext" handlers, and + // report the "xxHandler" ones on our input side. + + // Normally a subclass would both override handler + // methods and register itself as the "xxHandler". + + docHandler = docNext = consumer.getContentHandler (); + dtdHandler = dtdNext = consumer.getDTDHandler (); + try { + declHandler = declNext = (DeclHandler) + consumer.getProperty (DECL_HANDLER); + } catch (SAXException e) { /* leave value null */ } + try { + lexHandler = lexNext = (LexicalHandler) + consumer.getProperty (LEXICAL_HANDLER); + } catch (SAXException e) { /* leave value null */ } + } + + /** + * Treats the XMLFilterImpl as a limited functionality event consumer, + * by arranging to deliver events to it; this lets such classes be + * "wrapped" as pipeline stages. + * + *

      Upstream Event Setup: + * If no handlers have been assigned to this EventFilter, then the + * handlers from specified XMLFilterImpl are returned from this + * {@link EventConsumer}: the XMLFilterImpl is just "wrapped". + * Otherwise the specified handlers will be returned. + * + *

      Downstream Event Setup: + * Subclasses may chain event delivery to the specified XMLFilterImpl + * by invoking the appropiate superclass methods, + * as if their constructor passed a "next" EventConsumer to the + * constructor for this class. + * If this EventFilter has an ErrorHandler, it is assigned as + * the error handler for the XMLFilterImpl, just as would be + * done for a next stage implementing {@link EventConsumer}. + * + * @param next the next downstream component of the pipeline. + * @exception IllegalStateException if the "next" consumer has + * already been set through the constructor. + */ + public void chainTo (XMLFilterImpl next) + { + if (this.next != null) + throw new IllegalStateException (); + + docNext = next.getContentHandler (); + if (docHandler == null) + docHandler = docNext; + dtdNext = next.getDTDHandler (); + if (dtdHandler == null) + dtdHandler = dtdNext; + + try { + declNext = (DeclHandler) next.getProperty (DECL_HANDLER); + if (declHandler == null) + declHandler = declNext; + } catch (SAXException e) { /* leave value null */ } + try { + lexNext = (LexicalHandler) next.getProperty (LEXICAL_HANDLER); + if (lexHandler == null) + lexHandler = lexNext; + } catch (SAXException e) { /* leave value null */ } + + if (errHandler != null) + next.setErrorHandler (errHandler); + } + + /** + * Records the error handler that should be used by this stage, and + * passes it "downstream" to any subsequent stage. + */ + final public void setErrorHandler (ErrorHandler handler) + { + errHandler = handler; + if (next != null) + next.setErrorHandler (handler); + } + + /** + * Returns the error handler assigned this filter stage, or null + * if no such assigment has been made. + */ + final public ErrorHandler getErrorHandler () + { + return errHandler; + } + + + /** + * Returns the next event consumer in sequence; or null if there + * is no such handler. + */ + final public EventConsumer getNext () + { return next; } + + + /** + * Assigns the content handler to use; a null handler indicates + * that these events will not be forwarded. + * This overrides the previous settting for this handler, which was + * probably pointed to the next consumer by the base class constructor. + */ + final public void setContentHandler (ContentHandler h) + { + docHandler = h; + } + + /** Returns the content handler being used. */ + final public ContentHandler getContentHandler () + { + return docHandler; + } + + /** + * Assigns the DTD handler to use; a null handler indicates + * that these events will not be forwarded. + * This overrides the previous settting for this handler, which was + * probably pointed to the next consumer by the base class constructor. + */ + final public void setDTDHandler (DTDHandler h) + { dtdHandler = h; } + + /** Returns the dtd handler being used. */ + final public DTDHandler getDTDHandler () + { + return dtdHandler; + } + + /** + * Stores the property, normally a handler; a null handler indicates + * that these events will not be forwarded. + * This overrides the previous handler settting, which was probably + * pointed to the next consumer by the base class constructor. + */ + final public void setProperty (String id, Object o) + throws SAXNotRecognizedException, SAXNotSupportedException + { + try { + Object value = getProperty (id); + + if (value == o) + return; + if (DECL_HANDLER.equals (id)) { + declHandler = (DeclHandler) o; + return; + } + if (LEXICAL_HANDLER.equals (id)) { + lexHandler = (LexicalHandler) o; + return; + } + throw new SAXNotSupportedException (id); + + } catch (ClassCastException e) { + throw new SAXNotSupportedException (id); + } + } + + /** Retrieves a property of unknown intent (usually a handler) */ + final public Object getProperty (String id) + throws SAXNotRecognizedException + { + if (DECL_HANDLER.equals (id)) + return declHandler; + if (LEXICAL_HANDLER.equals (id)) + return lexHandler; + + throw new SAXNotRecognizedException (id); + } + + /** + * Returns any locator provided to the next consumer, if this class + * (or a subclass) is handling {@link ContentHandler } events. + */ + public Locator getDocumentLocator () + { return locator; } + + + // CONTENT HANDLER DELEGATIONS + + /** SAX2: passes this callback to the next consumer, if any */ + public void setDocumentLocator (Locator locator) + { + this.locator = locator; + if (docNext != null) + docNext.setDocumentLocator (locator); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void startDocument () throws SAXException + { + if (docNext != null) + docNext.startDocument (); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void skippedEntity (String name) throws SAXException + { + if (docNext != null) + docNext.skippedEntity (name); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void processingInstruction (String target, String data) + throws SAXException + { + if (docNext != null) + docNext.processingInstruction (target, data); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void characters (char ch [], int start, int length) + throws SAXException + { + if (docNext != null) + docNext.characters (ch, start, length); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void ignorableWhitespace (char ch [], int start, int length) + throws SAXException + { + if (docNext != null) + docNext.ignorableWhitespace (ch, start, length); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void startPrefixMapping (String prefix, String uri) + throws SAXException + { + if (docNext != null) + docNext.startPrefixMapping (prefix, uri); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void startElement ( + String uri, String localName, + String qName, Attributes atts + ) throws SAXException + { + if (docNext != null) + docNext.startElement (uri, localName, qName, atts); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void endElement (String uri, String localName, String qName) + throws SAXException + { + if (docNext != null) + docNext.endElement (uri, localName, qName); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void endPrefixMapping (String prefix) throws SAXException + { + if (docNext != null) + docNext.endPrefixMapping (prefix); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void endDocument () throws SAXException + { + if (docNext != null) + docNext.endDocument (); + locator = null; + } + + + // DTD HANDLER DELEGATIONS + + /** SAX1: passes this callback to the next consumer, if any */ + public void unparsedEntityDecl ( + String name, + String publicId, + String systemId, + String notationName + ) throws SAXException + { + if (dtdNext != null) + dtdNext.unparsedEntityDecl (name, publicId, systemId, notationName); + } + + /** SAX1: passes this callback to the next consumer, if any */ + public void notationDecl (String name, String publicId, String systemId) + throws SAXException + { + if (dtdNext != null) + dtdNext.notationDecl (name, publicId, systemId); + } + + + // LEXICAL HANDLER DELEGATIONS + + /** SAX2: passes this callback to the next consumer, if any */ + public void startDTD (String name, String publicId, String systemId) + throws SAXException + { + if (lexNext != null) + lexNext.startDTD (name, publicId, systemId); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void endDTD () + throws SAXException + { + if (lexNext != null) + lexNext.endDTD (); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void comment (char ch [], int start, int length) + throws SAXException + { + if (lexNext != null) + lexNext.comment (ch, start, length); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void startCDATA () + throws SAXException + { + if (lexNext != null) + lexNext.startCDATA (); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void endCDATA () + throws SAXException + { + if (lexNext != null) + lexNext.endCDATA (); + } + + /** + * SAX2: passes this callback to the next consumer, if any. + */ + public void startEntity (String name) + throws SAXException + { + if (lexNext != null) + lexNext.startEntity (name); + } + + /** + * SAX2: passes this callback to the next consumer, if any. + */ + public void endEntity (String name) + throws SAXException + { + if (lexNext != null) + lexNext.endEntity (name); + } + + + // DECLARATION HANDLER DELEGATIONS + + + /** SAX2: passes this callback to the next consumer, if any */ + public void elementDecl (String name, String model) + throws SAXException + { + if (declNext != null) + declNext.elementDecl (name, model); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void attributeDecl (String eName, String aName, + String type, String mode, String value) + throws SAXException + { + if (declNext != null) + declNext.attributeDecl (eName, aName, type, mode, value); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void externalEntityDecl (String name, + String publicId, String systemId) + throws SAXException + { + if (declNext != null) + declNext.externalEntityDecl (name, publicId, systemId); + } + + /** SAX2: passes this callback to the next consumer, if any */ + public void internalEntityDecl (String name, String value) + throws SAXException + { + if (declNext != null) + declNext.internalEntityDecl (name, value); + } +} diff --git a/libjava/classpath/gnu/xml/pipeline/LinkFilter.java b/libjava/classpath/gnu/xml/pipeline/LinkFilter.java new file mode 100644 index 000000000..e11a5eca6 --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/LinkFilter.java @@ -0,0 +1,242 @@ +/* LinkFilter.java -- + Copyright (C) 1999,2000,2001 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.pipeline; + +import java.io.IOException; +import java.net.URL; +import java.util.Enumeration; +import java.util.Vector; + +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; + + +/** + * Pipeline filter to remember XHTML links found in a document, + * so they can later be crawled. Fragments are not counted, and duplicates + * are ignored. Callers are responsible for filtering out URLs they aren't + * interested in. Events are passed through unmodified. + * + *

      Input MUST include a setDocumentLocator() call, as it's used to + * resolve relative links in the absence of a "base" element. Input MUST + * also include namespace identifiers, since it is the XHTML namespace + * identifier which is used to identify the relevant elements. + * + *

      FIXME: handle xml:base attribute ... in association with + * a stack of base URIs. Similarly, recognize/support XLink data. + * + * @author David Brownell + */ +public class LinkFilter extends EventFilter +{ + // for storing URIs + private Vector vector = new Vector (); + + // struct for "full" link record (tbd) + // these for troubleshooting original source: + // original uri + // uri as resolved (base, relative, etc) + // URI of originating doc + // line # + // original element + attrs (img src, desc, etc) + + // XLink model of the link ... for inter-site pairups ? + + private String baseURI; + + private boolean siteRestricted = false; + + // + // XXX leverage blacklist info (like robots.txt) + // + // XXX constructor w/param ... pipeline for sending link data + // probably XHTML --> XLink, providing info as sketched above + // + + + /** + * Constructs a new event filter, which collects links in private data + * structure for later enumeration. + */ + // constructor used by PipelineFactory + public LinkFilter () + { + super.setContentHandler (this); + } + + + /** + * Constructs a new event filter, which collects links in private data + * structure for later enumeration and passes all events, unmodified, + * to the next consumer. + */ + // constructor used by PipelineFactory + public LinkFilter (EventConsumer next) + { + super (next); + super.setContentHandler (this); + } + + + /** + * Returns an enumeration of the links found since the filter + * was constructed, or since removeAllLinks() was called. + * + * @return enumeration of strings. + */ + public Enumeration getLinks () + { + return vector.elements (); + } + + /** + * Removes records about all links reported to the event + * stream, as if the filter were newly created. + */ + public void removeAllLinks () + { + vector = new Vector (); + } + + + /** + * Collects URIs for (X)HTML content from elements which hold them. + */ + public void startElement ( + String uri, + String localName, + String qName, + Attributes atts + ) throws SAXException + { + String link; + + // Recognize XHTML links. + if ("http://www.w3.org/1999/xhtml".equals (uri)) { + + if ("a".equals (localName) || "base".equals (localName) + || "area".equals (localName)) + link = atts.getValue ("href"); + else if ("iframe".equals (localName) || "frame".equals (localName)) + link = atts.getValue ("src"); + else if ("blockquote".equals (localName) || "q".equals (localName) + || "ins".equals (localName) || "del".equals (localName)) + link = atts.getValue ("cite"); + else + link = null; + link = maybeAddLink (link); + + // "base" modifies designated baseURI + if ("base".equals (localName) && link != null) + baseURI = link; + + if ("iframe".equals (localName) || "img".equals (localName)) + maybeAddLink (atts.getValue ("longdesc")); + } + + super.startElement (uri, localName, qName, atts); + } + + private String maybeAddLink (String link) + { + int index; + + // ignore empty links and fragments inside docs + if (link == null) + return null; + if ((index = link.indexOf ("#")) >= 0) + link = link.substring (0, index); + if (link.equals ("")) + return null; + + try { + // get the real URI + URL base = new URL ((baseURI != null) + ? baseURI + : getDocumentLocator ().getSystemId ()); + URL url = new URL (base, link); + + link = url.toString (); + + // ignore duplicates + if (vector.contains (link)) + return link; + + // other than what "base" does, stick to original site: + if (siteRestricted) { + // don't switch protocols + if (!base.getProtocol ().equals (url.getProtocol ())) + return link; + // don't switch servers + if (base.getHost () != null + && !base.getHost ().equals (url.getHost ())) + return link; + } + + vector.addElement (link); + + return link; + + } catch (IOException e) { + // bad URLs we don't want + } + return null; + } + + /** + * Reports an error if no Locator has been made available. + */ + public void startDocument () + throws SAXException + { + if (getDocumentLocator () == null) + throw new SAXException ("no Locator!"); + } + + /** + * Forgets about any base URI information that may be recorded. + * Applications will often want to call removeAllLinks(), likely + * after examining the links which were reported. + */ + public void endDocument () + throws SAXException + { + baseURI = null; + super.endDocument (); + } +} diff --git a/libjava/classpath/gnu/xml/pipeline/NSFilter.java b/libjava/classpath/gnu/xml/pipeline/NSFilter.java new file mode 100644 index 000000000..0fa4621d3 --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/NSFilter.java @@ -0,0 +1,341 @@ +/* NSFilter.java -- + Copyright (C) 1999,2000,2001 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.pipeline; + +import java.util.Enumeration; +import java.util.Stack; + +import org.xml.sax.Attributes; +import org.xml.sax.ErrorHandler; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.helpers.AttributesImpl; +import org.xml.sax.helpers.NamespaceSupport; + +/** + * This filter ensures that element and attribute names are properly prefixed, + * and that such prefixes are declared. Such data is critical for operations + * like writing XML text, and validating against DTDs: names or their prefixes + * may have been discarded, although they are essential to the exchange of + * information using XML. There are various common ways that such data + * gets discarded:

        + * + *
      • By default, SAX2 parsers must discard the "xmlns*" + * attributes, and may also choose not to report properly prefixed + * names for elements or attributes. (Some parsers may support + * changing the namespace-prefixes value from the default + * to true, effectively eliminating the need to use this + * filter on their output.) + * + *
      • When event streams are generated from a DOM tree, they may + * have never have had prefixes or declarations for namespaces; or + * the existing prefixes or declarations may have been invalidated + * by structural modifications to that DOM tree. + * + *
      • Other software writing SAX event streams won't necessarily + * be worrying about prefix management, and so they will need to + * have a transparent solution for managing them. + * + *
      + * + *

      This filter uses a heuristic to choose the prefix to assign to any + * particular name which wasn't already corectly prefixed. The associated + * namespace will be correct, and the prefix will be declared. Original + * structures facilitating text editing, such as conventions about use of + * mnemonic prefix names or the scoping of prefixes, can't always be + * reconstructed after they are discarded, as strongly encouraged by the + * current SAX2 defaults. + * + *

      Note that this can't possibly know whether values inside attribute + * value or document content involve prefixed names. If your application + * requires using prefixed names in such locations you'll need to add some + * appropriate logic (perhaps adding additional heuristics in a subclass). + * + * @author David Brownell + */ +public class NSFilter extends EventFilter +{ + private NamespaceSupport nsStack = new NamespaceSupport (); + private Stack elementStack = new Stack (); + + private boolean pushedContext; + private String nsTemp [] = new String [3]; + private AttributesImpl attributes = new AttributesImpl (); + private boolean usedDefault; + + // gensymmed prefixes use this root name + private static final String prefixRoot = "prefix-"; + + + /** + * Passes events through to the specified consumer, after first + * processing them. + * + * @param next the next event consumer to receive events. + */ + // constructor used by PipelineFactory + public NSFilter (EventConsumer next) + { + super (next); + + setContentHandler (this); + } + + private void fatalError (String message) + throws SAXException + { + SAXParseException e; + ErrorHandler handler = getErrorHandler (); + Locator locator = getDocumentLocator (); + + if (locator == null) + e = new SAXParseException (message, null, null, -1, -1); + else + e = new SAXParseException (message, locator); + if (handler != null) + handler.fatalError (e); + throw e; + } + + + public void startDocument () throws SAXException + { + elementStack.removeAllElements (); + nsStack.reset (); + pushedContext = false; + super.startDocument (); + } + + /** + * This call is not passed to the next consumer in the chain. + * Prefix declarations and scopes are only exposed in the form + * of attributes; this callback just records a declaration that + * will be exposed as an attribute. + */ + public void startPrefixMapping (String prefix, String uri) + throws SAXException + { + if (pushedContext == false) { + nsStack.pushContext (); + pushedContext = true; + } + + // this check is awkward, but the paranoia prevents big trouble + for (Enumeration e = nsStack.getDeclaredPrefixes (); + e.hasMoreElements (); + /* NOP */ ) { + String declared = (String) e.nextElement (); + + if (!declared.equals (prefix)) + continue; + if (uri.equals (nsStack.getURI (prefix))) + return; + fatalError ("inconsistent binding for prefix '" + prefix + + "' ... " + uri + " (was " + nsStack.getURI (prefix) + ")"); + } + + if (!nsStack.declarePrefix (prefix, uri)) + fatalError ("illegal prefix declared: " + prefix); + } + + private String fixName (String ns, String l, String name, boolean isAttr) + throws SAXException + { + if ("".equals (name) || name == null) { + name = l; + if ("".equals (name) || name == null) + fatalError ("empty/null name"); + } + + // can we correctly process the name as-is? + // handles "element scope" attribute names here. + if (nsStack.processName (name, nsTemp, isAttr) != null + && nsTemp [0].equals (ns) + ) { + return nsTemp [2]; + } + + // nope, gotta modify the name or declare a default mapping + int temp; + + // get rid of any current prefix + if ((temp = name.indexOf (':')) >= 0) { + name = name.substring (temp + 1); + + // ... maybe that's enough (use/prefer default namespace) ... + if (!isAttr && nsStack.processName (name, nsTemp, false) != null + && nsTemp [0].equals (ns) + ) { + return nsTemp [2]; + } + } + + // must we define and use the default/undefined prefix? + if ("".equals (ns)) { + if (isAttr) + fatalError ("processName bug"); + if (attributes.getIndex ("xmlns") != -1) + fatalError ("need to undefine default NS, but it's bound: " + + attributes.getValue ("xmlns")); + + nsStack.declarePrefix ("", ""); + attributes.addAttribute ("", "", "xmlns", "CDATA", ""); + return name; + } + + // is there at least one non-null prefix we can use? + for (Enumeration e = nsStack.getDeclaredPrefixes (); + e.hasMoreElements (); + /* NOP */) { + String prefix = (String) e.nextElement (); + String uri = nsStack.getURI (prefix); + + if (uri == null || !uri.equals (ns)) + continue; + return prefix + ":" + name; + } + + // no such luck. create a prefix name, declare it, use it. + for (temp = 0; temp >= 0; temp++) { + String prefix = prefixRoot + temp; + + if (nsStack.getURI (prefix) == null) { + nsStack.declarePrefix (prefix, ns); + attributes.addAttribute ("", "", "xmlns:" + prefix, + "CDATA", ns); + return prefix + ":" + name; + } + } + fatalError ("too many prefixes genned"); + // NOTREACHED + return null; + } + + public void startElement ( + String uri, String localName, + String qName, Attributes atts + ) throws SAXException + { + if (!pushedContext) + nsStack.pushContext (); + pushedContext = false; + + // make sure we have all NS declarations handy before we start + int length = atts.getLength (); + + for (int i = 0; i < length; i++) { + String aName = atts.getQName (i); + + if (!aName.startsWith ("xmlns")) + continue; + + String prefix; + + if ("xmlns".equals (aName)) + prefix = ""; + else if (aName.indexOf (':') == 5) + prefix = aName.substring (6); + else // "xmlnsfoo" etc. + continue; + startPrefixMapping (prefix, atts.getValue (i)); + } + + // put namespace decls at the start of our regenned attlist + attributes.clear (); + for (Enumeration e = nsStack.getDeclaredPrefixes (); + e.hasMoreElements (); + /* NOP */) { + String prefix = (String) e.nextElement (); + + attributes.addAttribute ("", "", + ("".equals (prefix) + ? "xmlns" + : "xmlns:" + prefix), + "CDATA", + nsStack.getURI (prefix)); + } + + // name fixups: element, then attributes. + // fixName may declare a new prefix or, for the element, + // redeclare the default (if element name needs it). + qName = fixName (uri, localName, qName, false); + + for (int i = 0; i < length; i++) { + String aName = atts.getQName (i); + String aNS = atts.getURI (i); + String aLocal = atts.getLocalName (i); + String aType = atts.getType (i); + String aValue = atts.getValue (i); + + if (aName.startsWith ("xmlns")) + continue; + aName = fixName (aNS, aLocal, aName, true); + attributes.addAttribute (aNS, aLocal, aName, aType, aValue); + } + + elementStack.push (qName); + + // pass event along, with cleaned-up names and decls. + super.startElement (uri, localName, qName, attributes); + } + + public void endElement (String uri, String localName, String qName) + throws SAXException + { + nsStack.popContext (); + qName = (String) elementStack.pop (); + super.endElement (uri, localName, qName); + } + + /** + * This call is not passed to the next consumer in the chain. + * Prefix declarations and scopes are only exposed in their + * attribute form. + */ + public void endPrefixMapping (String prefix) + throws SAXException + { } + + public void endDocument () throws SAXException + { + elementStack.removeAllElements (); + nsStack.reset (); + super.endDocument (); + } +} diff --git a/libjava/classpath/gnu/xml/pipeline/PipelineFactory.java b/libjava/classpath/gnu/xml/pipeline/PipelineFactory.java new file mode 100644 index 000000000..c2adab021 --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/PipelineFactory.java @@ -0,0 +1,723 @@ +/* PipelineFactory.java -- + Copyright (C) 1999,2000,2001 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.pipeline; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.lang.reflect.Constructor; +import java.util.StringTokenizer; + +import org.xml.sax.*; +import org.xml.sax.ext.*; + + +/** + * This provides static factory methods for creating simple event pipelines. + * These pipelines are specified by strings, suitable for passing on + * command lines or embedding in element attributes. For example, one way + * to write a pipeline that restores namespace syntax, validates (stopping + * the pipeline on validity errors) and then writes valid data to standard + * output is this:

      + *      nsfix | validate | write ( stdout )
      + * + *

      In this syntax, the tokens are always separated by whitespace, and each + * stage of the pipeline may optionally have a parameter (which can be a + * pipeline) in parentheses. Interior stages are called filters, and the + * rightmost end of a pipeline is called a terminus. + * + *

      Stages are usually implemented by a single class, which may not be + * able to act as both a filter and a terminus; but any terminus can be + * automatically turned into a filter, through use of a {@link TeeConsumer}. + * The stage identifiers are either class names, or are one of the following + * short identifiers built into this class. (Most of these identifiers are + * no more than aliases for classes.) The built-in identifiers include:

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      StageParameterTerminusDescription
      domnone yes Applications code can access a DOM Document built + from the input event stream. When used as a filter, this buffers + data up to an endDocument call, and then uses a DOM parser + to report everything that has been recorded (which can easily be + less than what was reported to it).
      nsfixnonenoThis stage ensures that the XML element and attribute + names in its output use namespace prefixes and declarations correctly. + That is, so that they match the "Namespace plus LocalName" naming data + with which each XML element and attribute is already associated.
      nullnoneyesThis stage ignores all input event data.
      serverrequired
      server URL
      noSends its input as XML request to a remote server, + normally a web application server using the HTTP or HTTPS protocols. + The output of this stage is the parsed response from that server.
      teerequired
      first pipeline
      noThis sends its events down two paths; its parameter + is a pipeline descriptor for the first path, and the second path + is the output of this stage.
      validatenoneyesThis checks for validity errors, and reports them + through its error handler. The input must include declaration events + and some lexical events.
      wfnoneyes This class provides some basic "well formedness" + tests on the input event stream, and reports a fatal error if any + of them fail. One example: start/end calls for elements must match. + No SAX parser is permitted to produce malformed output, but other + components can easily do so.
      writerequired
      "stdout", "stderr", or filename
      yes Writes its input to the specified output, as pretty + printed XML text encoded using UTF-8. Input events must be well + formed and "namespace fixed", else the output won't be XML (or possibly + namespace) conformant. The symbolic names represent + System.out and System.err respectively; names must + correspond to files which don't yet exist.
      xhtmlrequired
      "stdout", "stderr", or filename
      yes Like write (above), except that XHTML rules + are followed. The XHTML 1.0 Transitional document type is declared, + and only ASCII characters are written (for interoperability). Other + characters are written as entity or character references; the text is + pretty printed.
      xincludenonenoThis stage handles XInclude processing. + This is like entity inclusion, except that the included content + is declared in-line rather than in the DTD at the beginning of + a document. +
      xsltrequired
      XSLT stylesheet URI
      noThis stage handles XSLT transformation + according to a stylesheet. + The implementation of the transformation may not actually + stream data, although if such an XSLT engine is in use + then that can happen. +
      + + *

      Note that {@link EventFilter#bind} can automatically eliminate + * some filters by setting SAX2 parser features appropriately. This means + * that you can routinely put filters like "nsfix", "validate", or "wf" at the + * front of a pipeline (for components that need inputs conditioned to match + * that level of correctness), and know that it won't actually be used unless + * it's absolutely necessary. + * + * @author David Brownell + */ +public class PipelineFactory +{ + /** + * Creates a simple pipeline according to the description string passed in. + */ + public static EventConsumer createPipeline (String description) + throws IOException + { + return createPipeline (description, null); + } + + /** + * Extends an existing pipeline by prepending the filter pipeline to the + * specified consumer. Some pipelines need more customization than can + * be done through this simplified syntax. When they are set up with + * direct API calls, use this method to merge more complex pipeline + * segments with easily configured ones. + */ + public static EventConsumer createPipeline ( + String description, + EventConsumer next + ) throws IOException + { + // tokens are (for now) what's separated by whitespace; + // very easy to parse, but IDs never have spaces. + + StringTokenizer tokenizer; + String tokens []; + + tokenizer = new StringTokenizer (description); + tokens = new String [tokenizer.countTokens ()]; + for (int i = 0; i < tokens.length; i++) + tokens [i] = tokenizer.nextToken (); + + PipelineFactory factory = new PipelineFactory (); + Pipeline pipeline = factory.parsePipeline (tokens, next); + + return pipeline.createPipeline (); + } + + + private PipelineFactory () { /* NYET */ } + + + /** + * Extends an existing pipeline by prepending a pre-tokenized filter + * pipeline to the specified consumer. Tokens are class names (or the + * predefined aliases) left and right parenthesis, and the vertical bar. + */ + public static EventConsumer createPipeline ( + String tokens [], + EventConsumer next + ) throws IOException + { + PipelineFactory factory = new PipelineFactory (); + Pipeline pipeline = factory.parsePipeline (tokens, next); + + return pipeline.createPipeline (); + } + + + private String tokens []; + private int index; + + private Pipeline parsePipeline (String toks [], EventConsumer next) + { + tokens = toks; + index = 0; + + Pipeline retval = parsePipeline (next); + + if (index != toks.length) + throw new ArrayIndexOutOfBoundsException ( + "extra token: " + tokens [index]); + return retval; + } + + // pipeline ::= stage | stage '|' pipeline + private Pipeline parsePipeline (EventConsumer next) + { + Pipeline retval = new Pipeline (parseStage ()); + + // minimal pipelines: "stage" and "... | id" + if (index > (tokens.length - 2) + || !"|".equals (tokens [index]) + ) { + retval.next = next; + return retval; + } + index++; + retval.rest = parsePipeline (next); + return retval; + } + + // stage ::= id | id '(' pipeline ')' + private Stage parseStage () + { + Stage retval = new Stage (tokens [index++]); + + // minimal stages: "id" and "id ( id )" + if (index > (tokens.length - 2) + || !"(".equals (tokens [index]) /*)*/ + ) + return retval; + + index++; + retval.param = parsePipeline (null); + if (index >= tokens.length) + throw new ArrayIndexOutOfBoundsException ( + "missing right paren"); + if (/*(*/ !")".equals (tokens [index++])) + throw new ArrayIndexOutOfBoundsException ( + "required right paren, not: " + tokens [index - 1]); + return retval; + } + + + // + // these classes obey the conventions for constructors, so they're + // only built in to this table of shortnames + // + // - filter (one or two types of arglist) + // * last constructor is 'next' element + // * optional (first) string parameter + // + // - terminus (one or types of arglist) + // * optional (only) string parameter + // + // terminus stages are transformed into filters if needed, by + // creating a "tee". filter stages aren't turned to terminus + // stages though; either eliminate such stages, or add some + // terminus explicitly. + // + private static final String builtinStages [][] = { + { "dom", "gnu.xml.dom.Consumer" }, + { "nsfix", "gnu.xml.pipeline.NSFilter" }, + { "null", "gnu.xml.pipeline.EventFilter" }, + { "server", "gnu.xml.pipeline.CallFilter" }, + { "tee", "gnu.xml.pipeline.TeeConsumer" }, + { "validate", "gnu.xml.pipeline.ValidationConsumer" }, + { "wf", "gnu.xml.pipeline.WellFormednessFilter" }, + { "xinclude", "gnu.xml.pipeline.XIncludeFilter" }, + { "xslt", "gnu.xml.pipeline.XsltFilter" }, + +// XXX want: option for validate, to preload external part of a DTD + + // xhtml, write ... nyet generic-ready + }; + + private static class Stage + { + String id; + Pipeline param; + + Stage (String name) + { id = name; } + + public String toString () + { + if (param == null) + return id; + return id + " ( " + param + " )"; + } + + private void fail (String message) + throws IOException + { + throw new IOException ("in '" + id + + "' stage of pipeline, " + message); + } + + EventConsumer createStage (EventConsumer next) + throws IOException + { + String name = id; + + // most builtins are just class aliases + for (int i = 0; i < builtinStages.length; i++) { + if (id.equals (builtinStages [i][0])) { + name = builtinStages [i][1]; + break; + } + } + + // Save output as XML or XHTML text + if ("write".equals (name) || "xhtml".equals (name)) { + String filename; + boolean isXhtml = "xhtml".equals (name); + OutputStream out = null; + TextConsumer consumer; + + if (param == null) + fail ("parameter is required"); + + filename = param.toString (); + if ("stdout".equals (filename)) + out = System.out; + else if ("stderr".equals (filename)) + out = System.err; + else { + File f = new File (filename); + +/* + if (!f.isAbsolute ()) + fail ("require absolute file paths"); + */ + if (f.exists ()) + fail ("file already exists: " + f.getName ()); + +// XXX this races against the existence test + out = new FileOutputStream (f); + } + + if (!isXhtml) + consumer = new TextConsumer (out); + else + consumer = new TextConsumer ( + new OutputStreamWriter (out, "8859_1"), + true); + + consumer.setPrettyPrinting (true); + if (next == null) + return consumer; + return new TeeConsumer (consumer, next); + + } else { + // + // Here go all the builtins that are just aliases for + // classes, and all stage IDs that started out as such + // class names. The following logic relies on several + // documented conventions for constructor invocation. + // + String msg = null; + + try { + Class klass = Class.forName (name); + Class argTypes [] = null; + Constructor constructor = null; + boolean filter = false; + Object params [] = null; + Object obj = null; + + // do we need a filter stage? + if (next != null) { + // "next" consumer is always passed, with + // or without the optional string param + if (param == null) { + argTypes = new Class [1]; + argTypes [0] = EventConsumer.class; + + params = new Object [1]; + params [0] = next; + + msg = "no-param filter"; + } else { + argTypes = new Class [2]; + argTypes [0] = String.class; + argTypes [1] = EventConsumer.class; + + params = new Object [2]; + params [0] = param.toString (); + params [1] = next; + + msg = "one-param filter"; + } + + + try { + constructor = klass.getConstructor (argTypes); + } catch (NoSuchMethodException e) { + // try creating a filter from a + // terminus and a tee + filter = true; + msg += " built from "; + } + } + + // build from a terminus stage, with or + // without the optional string param + if (constructor == null) { + String tmp; + + if (param == null) { + argTypes = new Class [0]; + params = new Object [0]; + + tmp = "no-param terminus"; + } else { + argTypes = new Class [1]; + argTypes [0] = String.class; + + params = new Object [1]; + params [0] = param.toString (); + + tmp = "one-param terminus"; + } + if (msg == null) + msg = tmp; + else + msg += tmp; + constructor = klass.getConstructor (argTypes); + // NOT creating terminus by dead-ending + // filters ... users should think about + // that one, something's likely wrong + } + + obj = constructor.newInstance (params); + + // return EventConsumers directly, perhaps after + // turning them into a filter + if (obj instanceof EventConsumer) { + if (filter) + return new TeeConsumer ((EventConsumer) obj, next); + return (EventConsumer) obj; + } + + // if it's not a handler, it's an error + // we can wrap handlers in a filter + EventFilter retval = new EventFilter (); + boolean updated = false; + + if (obj instanceof ContentHandler) { + retval.setContentHandler ((ContentHandler) obj); + updated = true; + } + if (obj instanceof DTDHandler) { + retval.setDTDHandler ((DTDHandler) obj); + updated = true; + } + if (obj instanceof LexicalHandler) { + retval.setProperty ( + EventFilter.PROPERTY_URI + "lexical-handler", + obj); + updated = true; + } + if (obj instanceof DeclHandler) { + retval.setProperty ( + EventFilter.PROPERTY_URI + "declaration-handler", + obj); + updated = true; + } + + if (!updated) + fail ("class is neither Consumer nor Handler"); + + if (filter) + return new TeeConsumer (retval, next); + return retval; + + } catch (IOException e) { + throw e; + + } catch (NoSuchMethodException e) { + fail (name + " constructor missing -- " + msg); + + } catch (ClassNotFoundException e) { + fail (name + " class not found"); + + } catch (Exception e) { + // e.printStackTrace (); + fail ("stage not available: " + e.getMessage ()); + } + } + // NOTREACHED + return null; + } + } + + private static class Pipeline + { + Stage stage; + + // rest may be null + Pipeline rest; + EventConsumer next; + + Pipeline (Stage s) + { stage = s; } + + public String toString () + { + if (rest == null && next == null) + return stage.toString (); + if (rest != null) + return stage + " | " + rest; + throw new IllegalArgumentException ("next"); + } + + EventConsumer createPipeline () + throws IOException + { + if (next == null) { + if (rest == null) + next = stage.createStage (null); + else + next = stage.createStage (rest.createPipeline ()); + } + return next; + } + } + +/* + public static void main (String argv []) + { + try { + // three basic terminus cases + createPipeline ("null"); + createPipeline ("validate"); + createPipeline ("write ( stdout )"); + + // four basic filters + createPipeline ("nsfix | write ( stderr )"); + createPipeline ("wf | null"); + createPipeline ("null | null"); + createPipeline ( +"call ( http://www.example.com/services/xml-1a ) | xhtml ( stdout )"); + + // tee junctions + createPipeline ("tee ( validate ) | write ( stdout )"); + createPipeline ("tee ( nsfix | write ( stdout ) ) | validate"); + + // longer pipeline + createPipeline ("nsfix | tee ( validate ) | write ( stdout )"); + createPipeline ( + "null | wf | nsfix | tee ( validate ) | write ( stdout )"); + + // try some parsing error cases + try { + createPipeline ("null ("); // extra token '(' + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + + try { + createPipeline ("nsfix |"); // extra token '|' + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + + try { + createPipeline ("xhtml ( foo"); // missing right paren + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + + try { + createPipeline ("xhtml ( foo bar"); // required right paren + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + + try { + createPipeline ("tee ( nsfix | validate");// missing right paren + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + + // try some construction error cases + + try { + createPipeline ("call"); // missing param + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + try { + createPipeline ("call ( foobar )"); // broken param + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + try { + createPipeline ("nsfix ( foobar )"); // illegal param + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + try { + createPipeline ("null ( foobar )"); // illegal param + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + try { + createPipeline ("wf ( foobar )"); // illegal param + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + try { + createPipeline ("xhtml ( foobar.html )"); + new File ("foobar.html").delete (); + // now supported + } catch (Exception e) { + System.err.println ("** err: " + e.getMessage ()); } + try { + createPipeline ("xhtml"); // missing param + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + try { + createPipeline ("write ( stdout ) | null"); // nonterminal + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + try { + createPipeline ("validate | null"); + // now supported + } catch (Exception e) { + System.err.println ("** err: " + e.getMessage ()); } + try { + createPipeline ("validate ( foo )"); // illegal param + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + try { + createPipeline ("tee"); // missing param + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + try { + // only builtins so far + createPipeline ("com.example.xml.FilterClass"); + System.err.println ("** didn't report error"); + } catch (Exception e) { + System.err.println ("== err: " + e.getMessage ()); } + + } catch (Exception e) { + e.printStackTrace (); + } + } +/**/ + +} diff --git a/libjava/classpath/gnu/xml/pipeline/TeeConsumer.java b/libjava/classpath/gnu/xml/pipeline/TeeConsumer.java new file mode 100644 index 000000000..3ac860575 --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/TeeConsumer.java @@ -0,0 +1,417 @@ +/* TeeConsumer.java -- + Copyright (C) 1999,2000,2001 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.pipeline; + +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.DTDHandler; +import org.xml.sax.ErrorHandler; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.ext.DeclHandler; +import org.xml.sax.ext.LexicalHandler; + +/** + * Fans its events out to two other consumers, a "tee" filter stage in an + * event pipeline. Networks can be assembled with multiple output points. + * + *

      Error handling should be simple if you remember that exceptions + * you throw will cancel later stages in that callback's pipeline, and + * generally the producer will stop if it sees such an exception. You + * may want to protect your pipeline against such backflows, making a + * kind of reverse filter (or valve?) so that certain exceptions thrown by + * your pipeline will caught and handled before the producer sees them. + * Just use a "try/catch" block, rememebering that really important + * cleanup tasks should be in "finally" clauses. + * + *

      That issue isn't unique to "tee" consumers, but tee consumers have + * the additional twist that exceptions thrown by the first consumer + * will cause the second consumer not to see the callback (except for + * the endDocument callback, which signals state cleanup). + * + * @author David Brownell + */ +final public class TeeConsumer + implements EventConsumer, + ContentHandler, DTDHandler, + LexicalHandler,DeclHandler +{ + private EventConsumer first, rest; + + // cached to minimize time overhead + private ContentHandler docFirst, docRest; + private DeclHandler declFirst, declRest; + private LexicalHandler lexFirst, lexRest; + + + /** + * Constructs a consumer which sends all its events to the first + * consumer, and then the second one. If the first consumer throws + * an exception, the second one will not see the event which + * caused that exception to be reported. + * + * @param car The first consumer to get the events + * @param cdr The second consumer to get the events + */ + public TeeConsumer (EventConsumer car, EventConsumer cdr) + { + if (car == null || cdr == null) + throw new NullPointerException (); + first = car; + rest = cdr; + + // + // Cache the handlers. + // + docFirst = first.getContentHandler (); + docRest = rest.getContentHandler (); + // DTD handler isn't cached (rarely needed) + + try { + declFirst = null; + declFirst = (DeclHandler) first.getProperty ( + EventFilter.DECL_HANDLER); + } catch (SAXException e) {} + try { + declRest = null; + declRest = (DeclHandler) rest.getProperty ( + EventFilter.DECL_HANDLER); + } catch (SAXException e) {} + + try { + lexFirst = null; + lexFirst = (LexicalHandler) first.getProperty ( + EventFilter.LEXICAL_HANDLER); + } catch (SAXException e) {} + try { + lexRest = null; + lexRest = (LexicalHandler) rest.getProperty ( + EventFilter.LEXICAL_HANDLER); + } catch (SAXException e) {} + } + +/* FIXME + /** + * Constructs a pipeline, and is otherwise a shorthand for the + * two-consumer constructor for this class. + * + * @param first Description of the first pipeline to get events, + * which will be passed to {@link PipelineFactory#createPipeline} + * @param rest The second pipeline to get the events + * / + // constructor used by PipelineFactory + public TeeConsumer (String first, EventConsumer rest) + throws IOException + { + this (PipelineFactory.createPipeline (first), rest); + } +*/ + + /** Returns the first pipeline to get event calls. */ + public EventConsumer getFirst () + { return first; } + + /** Returns the second pipeline to get event calls. */ + public EventConsumer getRest () + { return rest; } + + /** Returns the content handler being used. */ + final public ContentHandler getContentHandler () + { + if (docRest == null) + return docFirst; + if (docFirst == null) + return docRest; + return this; + } + + /** Returns the dtd handler being used. */ + final public DTDHandler getDTDHandler () + { + // not cached (hardly used) + if (rest.getDTDHandler () == null) + return first.getDTDHandler (); + if (first.getDTDHandler () == null) + return rest.getDTDHandler (); + return this; + } + + /** Returns the declaration or lexical handler being used. */ + final public Object getProperty (String id) + throws SAXNotRecognizedException + { + // + // in degenerate cases, we have no work to do. + // + Object firstProp = null, restProp = null; + + try { firstProp = first.getProperty (id); } + catch (SAXNotRecognizedException e) { /* ignore */ } + try { restProp = rest.getProperty (id); } + catch (SAXNotRecognizedException e) { /* ignore */ } + + if (restProp == null) + return firstProp; + if (firstProp == null) + return restProp; + + // + // we've got work to do; handle two builtin cases. + // + if (EventFilter.DECL_HANDLER.equals (id)) + return this; + if (EventFilter.LEXICAL_HANDLER.equals (id)) + return this; + + // + // non-degenerate, handled by both consumers, but we don't know + // how to handle this. + // + throw new SAXNotRecognizedException ("can't tee: " + id); + } + + /** + * Provides the error handler to both subsequent nodes of + * this filter stage. + */ + public void setErrorHandler (ErrorHandler handler) + { + first.setErrorHandler (handler); + rest.setErrorHandler (handler); + } + + + // + // ContentHandler + // + public void setDocumentLocator (Locator locator) + { + // this call is not made by all parsers + docFirst.setDocumentLocator (locator); + docRest.setDocumentLocator (locator); + } + + public void startDocument () + throws SAXException + { + docFirst.startDocument (); + docRest.startDocument (); + } + + public void endDocument () + throws SAXException + { + try { + docFirst.endDocument (); + } finally { + docRest.endDocument (); + } + } + + public void startPrefixMapping (String prefix, String uri) + throws SAXException + { + docFirst.startPrefixMapping (prefix, uri); + docRest.startPrefixMapping (prefix, uri); + } + + public void endPrefixMapping (String prefix) + throws SAXException + { + docFirst.endPrefixMapping (prefix); + docRest.endPrefixMapping (prefix); + } + + public void skippedEntity (String name) + throws SAXException + { + docFirst.skippedEntity (name); + docRest.skippedEntity (name); + } + + public void startElement (String uri, String localName, + String qName, Attributes atts) + throws SAXException + { + docFirst.startElement (uri, localName, qName, atts); + docRest.startElement (uri, localName, qName, atts); + } + + public void endElement (String uri, String localName, String qName) + throws SAXException + { + docFirst.endElement (uri, localName, qName); + docRest.endElement (uri, localName, qName); + } + + public void processingInstruction (String target, String data) + throws SAXException + { + docFirst.processingInstruction (target, data); + docRest.processingInstruction (target, data); + } + + public void characters (char ch [], int start, int length) + throws SAXException + { + docFirst.characters (ch, start, length); + docRest.characters (ch, start, length); + } + + public void ignorableWhitespace (char ch [], int start, int length) + throws SAXException + { + docFirst.ignorableWhitespace (ch, start, length); + docRest.ignorableWhitespace (ch, start, length); + } + + + // + // DTDHandler + // + public void notationDecl (String name, String publicId, String systemId) + throws SAXException + { + DTDHandler l1 = first.getDTDHandler (); + DTDHandler l2 = rest.getDTDHandler (); + + l1.notationDecl (name, publicId, systemId); + l2.notationDecl (name, publicId, systemId); + } + + public void unparsedEntityDecl (String name, + String publicId, String systemId, + String notationName + ) throws SAXException + { + DTDHandler l1 = first.getDTDHandler (); + DTDHandler l2 = rest.getDTDHandler (); + + l1.unparsedEntityDecl (name, publicId, systemId, notationName); + l2.unparsedEntityDecl (name, publicId, systemId, notationName); + } + + + // + // DeclHandler + // + public void attributeDecl (String eName, String aName, + String type, + String mode, String value) + throws SAXException + { + declFirst.attributeDecl (eName, aName, type, mode, value); + declRest.attributeDecl (eName, aName, type, mode, value); + } + + public void elementDecl (String name, String model) + throws SAXException + { + declFirst.elementDecl (name, model); + declRest.elementDecl (name, model); + } + + public void externalEntityDecl (String name, + String publicId, String systemId) + throws SAXException + { + declFirst.externalEntityDecl (name, publicId, systemId); + declRest.externalEntityDecl (name, publicId, systemId); + } + + public void internalEntityDecl (String name, String value) + throws SAXException + { + declFirst.internalEntityDecl (name, value); + declRest.internalEntityDecl (name, value); + } + + + // + // LexicalHandler + // + public void comment (char ch [], int start, int length) + throws SAXException + { + lexFirst.comment (ch, start, length); + lexRest.comment (ch, start, length); + } + + public void startCDATA () + throws SAXException + { + lexFirst.startCDATA (); + lexRest.startCDATA (); + } + + public void endCDATA () + throws SAXException + { + lexFirst.endCDATA (); + lexRest.endCDATA (); + } + + public void startEntity (String name) + throws SAXException + { + lexFirst.startEntity (name); + lexRest.startEntity (name); + } + + public void endEntity (String name) + throws SAXException + { + lexFirst.endEntity (name); + lexRest.endEntity (name); + } + + public void startDTD (String name, String publicId, String systemId) + throws SAXException + { + lexFirst.startDTD (name, publicId, systemId); + lexRest.startDTD (name, publicId, systemId); + } + + public void endDTD () + throws SAXException + { + lexFirst.endDTD (); + lexRest.endDTD (); + } +} diff --git a/libjava/classpath/gnu/xml/pipeline/TextConsumer.java b/libjava/classpath/gnu/xml/pipeline/TextConsumer.java new file mode 100644 index 000000000..13dcfa7f6 --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/TextConsumer.java @@ -0,0 +1,117 @@ +/* TextConsumer.java -- + Copyright (C) 1999,2000,2001 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.pipeline; + +import java.io.*; + +import org.xml.sax.*; + +import gnu.xml.util.XMLWriter; + + +/** + * Terminates a pipeline, consuming events to print them as well formed + * XML (or XHTML) text. + * + *

      Input must be well formed, and must include XML names (e.g. the + * prefixes and prefix declarations must be present), or the output of + * this class is undefined. + * + * @see NSFilter + * @see WellFormednessFilter + * + * @author David Brownell + */ +public class TextConsumer extends XMLWriter implements EventConsumer +{ + /** + * Constructs an event consumer which echoes its input as text, + * optionally adhering to some basic XHTML formatting options + * which increase interoperability with old (v3) browsers. + * + *

      For the best interoperability, when writing as XHTML only + * ASCII characters are emitted; other characters are turned to + * entity or character references as needed, and no XML declaration + * is provided in the document. + */ + public TextConsumer (Writer w, boolean isXhtml) + throws IOException + { + super (w, isXhtml ? "US-ASCII" : null); + setXhtml (isXhtml); + } + + /** + * Constructs a consumer that writes its input as XML text. + * XHTML rules are not followed. + */ + public TextConsumer (Writer w) + throws IOException + { + this (w, false); + } + + /** + * Constructs a consumer that writes its input as XML text, + * encoded in UTF-8. XHTML rules are not followed. + */ + public TextConsumer (OutputStream out) + throws IOException + { + this (new OutputStreamWriter (out, "UTF8"), false); + } + + /** EventConsumer Returns the document handler being used. */ + public ContentHandler getContentHandler () + { return this; } + + /** EventConsumer Returns the dtd handler being used. */ + public DTDHandler getDTDHandler () + { return this; } + + /** XMLReaderRetrieves a property (lexical and decl handlers) */ + public Object getProperty (String propertyId) + throws SAXNotRecognizedException + { + if (EventFilter.LEXICAL_HANDLER.equals (propertyId)) + return this; + if (EventFilter.DECL_HANDLER.equals (propertyId)) + return this; + throw new SAXNotRecognizedException (propertyId); + } +} diff --git a/libjava/classpath/gnu/xml/pipeline/ValidationConsumer.java b/libjava/classpath/gnu/xml/pipeline/ValidationConsumer.java new file mode 100644 index 000000000..0346984d3 --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/ValidationConsumer.java @@ -0,0 +1,1928 @@ +/* ValidationConsumer.java -- + Copyright (C) 1999,2000,2001 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.pipeline; + +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; +import java.util.EmptyStackException; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Stack; +import java.util.StringTokenizer; +import java.util.Vector; + +import org.xml.sax.Attributes; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.XMLReaderFactory; + +/** + * This class checks SAX2 events to report validity errors; it works as + * both a filter and a terminus on an event pipeline. It relies on the + * producer of SAX events to:

        + * + *
      1. Conform to the specification of a non-validating XML parser that + * reads all external entities, reported using SAX2 events.
      2. + * + *
      3. Report ignorable whitespace as such (through the ContentHandler + * interface). This is, strictly speaking, optional for nonvalidating + * XML processors.
      4. + * + *
      5. Make SAX2 DeclHandler callbacks, with default + * attribute values already normalized (and without "<").
      6. + * + *
      7. Make SAX2 LexicalHandler startDTD() and endDTD () + * callbacks.
      8. + * + *
      9. Act as if the (URI)/namespace-prefixes property were + * set to true, by providing XML 1.0 names and all xmlns* + * attributes (rather than omitting either or both).
      10. + * + *
      + * + *

      At this writing, the major SAX2 parsers (such as Ælfred2, + * Crimson, and Xerces) meet these requirements, and this validation + * module is used by the optional Ælfred2 validation support. + *

      + * + *

      Note that because this is a layered validator, it has to duplicate some + * work that the parser is doing; there are also other cost to layering. + * However, because of layering it doesn't need a parser in order + * to work! You can use it with anything that generates SAX events, such + * as an application component that wants to detect invalid content in + * a changed area without validating an entire document, or which wants to + * ensure that it doesn't write invalid data to a communications partner.

      + * + *

      Also, note that because this is a layered validator, the line numbers + * reported for some errors may seem strange. For example, if an element does + * not permit character content, the validator + * will use the locator provided to it. + * That might reflect the last character of a characters event + * callback, rather than the first non-whitespace character.

      + * + *
      + * + * + * + *

      Current limitations of the validation performed are in roughly three + * categories.

      + * + *

      The first category represents constraints which demand violations + * of software layering: exposing lexical details, one of the first things + * that application programming interfaces (APIs) hide. These + * invariably relate to XML entity handling, and to historical oddities + * of the XML validation semantics. Curiously, + * recent (Autumn 1999) conformance testing showed that these constraints are + * among those handled worst by existing XML validating parsers. Arguments + * have been made that each of these VCs should be turned into WFCs (most + * of them) or discarded (popular for the standalone declaration); in short, + * that these are bugs in the XML specification (not all via SGML):

        + * + *
      • The Proper Declaration/PE Nesting and + * Proper Group/PE Nesting VCs can't be tested because they + * require access to particularly low level lexical level information. + * In essence, the reason XML isn't a simple thing to parse is that + * it's not a context free grammar, and these constraints elevate that + * SGML-derived context sensitivity to the level of a semantic rule. + * + *
      • The Standalone Document Declaration VC can't be + * tested. This is for two reasons. First, this flag isn't made + * available through SAX2. Second, it also requires breaking that + * lexical layering boundary. (If you ever wondered why classes + * in compiler construction or language design barely mention the + * existence of context-sensitive grammars, it's because of messy + * issues like these.) + * + *
      • The Entity Declared VC can't be tested, because it + * also requires breaking that lexical layering boundary! There's also + * another issue: the VC wording (and seemingly intent) is ambiguous. + * (This is still true in the "Second edition" XML spec.) + * Since there is a WFC of the same name, everyone's life would be + * easier if references to undeclared parsed entities were always well + * formedness errors, regardless of whether they're parameter entities + * or not. (Note that nonvalidating parsers are not required + * to report all such well formedness errors if they don't read external + * parameter entities, although currently most XML parsers read them + * in an attempt to avoid problems from inconsistent parser behavior.) + * + *
      + * + *

      The second category of limitations on this validation represent + * constraints associated with information that is not guaranteed to be + * available (or in one case, is guaranteed not to be available, + * through the SAX2 API:

        + * + *
      • The Unique Element Type Declaration VC may not be + * reportable, if the underlying parser happens not to expose + * multiple declarations. (Ælfred2 reports these validity + * errors directly.)
      • + * + *
      • Similarly, the Unique Notation Name VC, added in the + * 14-January-2000 XML spec errata to restrict typing models used by + * elements, may not be reportable. (Ælfred reports these + * validity errors directly.)
      • + * + *
      + * + *

      A third category relates to ease of implementation. (Think of this + * as "bugs".) The most notable issue here is character handling. Rather + * than attempting to implement the voluminous character tables in the XML + * specification (Appendix B), Unicode rules are used directly from + * the java.lang.Character class. Recent JVMs have begun to diverge from + * the original specification for that class (Unicode 2.0), meaning that + * different JVMs may handle that aspect of conformance differently. + *

      + * + *

      Note that for some of the validity errors that SAX2 does not + * expose, a nonvalidating parser is permitted (by the XML specification) + * to report validity errors. When used with a parser that does so for + * the validity constraints mentioned above (or any other SAX2 event + * stream producer that does the same thing), overall conformance is + * substantially improved. + * + * @see gnu.xml.aelfred2.SAXDriver + * @see gnu.xml.aelfred2.XmlReader + * + * @author David Brownell + */ +public final class ValidationConsumer extends EventFilter +{ + // report error if we happen to notice a non-deterministic choice? + // we won't report buggy content models; just buggy instances + private static final boolean warnNonDeterministic = false; + + // for tracking active content models + private String rootName; + private Stack contentStack = new Stack (); + + // flags for "saved DTD" processing + private boolean disableDeclarations; + private boolean disableReset; + + // + // most VCs get tested when we see element start tags. the per-element + // info (including attributes) recorded here duplicates that found inside + // many nonvalidating parsers, hence dual lookups etc ... that's why a + // layered validator isn't going to be as fast as a non-layered one. + // + + // key = element name; value = ElementInfo + private Hashtable elements = new Hashtable (); + + // some VCs relate to ID/IDREF/IDREFS attributes + // key = id; value = boolean true (defd) or false (refd) + private Hashtable ids = new Hashtable (); + + // we just record declared notation and unparsed entity names. + // the implementation here is simple/slow; these features + // are seldom used, one hopes they'll wither away soon + private Vector notations = new Vector (5, 5); + private Vector nDeferred = new Vector (5, 5); + private Vector unparsed = new Vector (5, 5); + private Vector uDeferred = new Vector (5, 5); + + // note: DocBk 3.1.7 XML defines over 2 dozen notations, + // used when defining unparsed entities for graphics + // (and maybe in other places) + + + + /** + * Creates a pipeline terminus which consumes all events passed to + * it; this will report validity errors as if they were fatal errors, + * unless an error handler is assigned. + * + * @see #setErrorHandler + */ + // constructor used by PipelineFactory + // ... and want one taking system ID of an external subset + public ValidationConsumer () + { + this (null); + } + + /** + * Creates a pipeline filter which reports validity errors and then + * passes events on to the next consumer if they were not fatal. + * + * @see #setErrorHandler + */ + // constructor used by PipelineFactory + // ... and want one taking system ID of an external subset + // (which won't send declaration events) + public ValidationConsumer (EventConsumer next) + { + super (next); + + setContentHandler (this); + setDTDHandler (this); + try { setProperty (DECL_HANDLER, this); } + catch (Exception e) { /* "can't happen" */ } + try { setProperty (LEXICAL_HANDLER, this); } + catch (Exception e) { /* "can't happen" */ } + } + + + private static final String fakeRootName + = ":Nobody:in:their_Right.Mind_would:use:this-name:1x:"; + + /** + * Creates a validation consumer which is preloaded with the DTD provided. + * It does this by constructing a document with that DTD, then parsing + * that document and recording its DTD declarations. Then it arranges + * not to modify that information. + * + *

      The resulting validation consumer will only validate against + * the specified DTD, regardless of whether some other DTD is found + * in a document being parsed. + * + * @param rootName The name of the required root element; if this is + * null, any root element name will be accepted. + * @param publicId If non-null and there is a non-null systemId, this + * identifier provides an alternate access identifier for the DTD's + * external subset. + * @param systemId If non-null, this is a URI (normally URL) that + * may be used to access the DTD's external subset. + * @param internalSubset If non-null, holds literal markup declarations + * comprising the DTD's internal subset. + * @param resolver If non-null, this will be provided to the parser for + * use when resolving parameter entities (including any external subset). + * @param resolver If non-null, this will be provided to the parser for + * use when resolving parameter entities (including any external subset). + * @param minimalElement If non-null, a minimal valid document. + * + * @exception SAXNotSupportedException If the default SAX parser does + * not support the standard lexical or declaration handlers. + * @exception SAXParseException If the specified DTD has either + * well-formedness or validity errors + * @exception IOException If the specified DTD can't be read for + * some reason + */ + public ValidationConsumer ( + String rootName, + String publicId, + String systemId, + String internalSubset, + EntityResolver resolver, + String minimalDocument + ) throws SAXException, IOException + { + this (null); + + disableReset = true; + if (rootName == null) + rootName = fakeRootName; + + // + // Synthesize document with that DTD; is it possible to do + // better for the declaration of the root element? + // + // NOTE: can't use SAX2 to write internal subsets. + // + StringWriter writer = new StringWriter (); + + writer.write (""); + } + if (internalSubset != null) + writer.write (internalSubset); + writer.write ("\n ]>"); + + if (minimalDocument != null) { + writer.write ("\n"); + writer.write (minimalDocument); + writer.write ("\n"); + } else { + writer.write (" <"); + writer.write (rootName); + writer.write ("/>\n"); + } + minimalDocument = writer.toString (); + + // + // OK, load it + // + XMLReader producer; + + producer = XMLReaderFactory.createXMLReader (); + bind (producer, this); + + if (resolver != null) + producer.setEntityResolver (resolver); + + InputSource in; + + in = new InputSource (new StringReader (minimalDocument)); + producer.parse (in); + + disableDeclarations = true; + if (rootName == fakeRootName) + this.rootName = null; + } + + private void resetState () + { + if (!disableReset) { + rootName = null; + contentStack.removeAllElements (); + elements.clear (); + ids.clear (); + + notations.removeAllElements (); + nDeferred.removeAllElements (); + unparsed.removeAllElements (); + uDeferred.removeAllElements (); + } + } + + + private void warning (String description) + throws SAXException + { + ErrorHandler errHandler = getErrorHandler (); + Locator locator = getDocumentLocator (); + SAXParseException err; + + if (errHandler == null) + return; + + if (locator == null) + err = new SAXParseException (description, null, null, -1, -1); + else + err = new SAXParseException (description, locator); + errHandler.warning (err); + } + + // package private (for ChildrenRecognizer) + private void error (String description) + throws SAXException + { + ErrorHandler errHandler = getErrorHandler (); + Locator locator = getDocumentLocator (); + SAXParseException err; + + if (locator == null) + err = new SAXParseException (description, null, null, -1, -1); + else + err = new SAXParseException (description, locator); + if (errHandler != null) + errHandler.error (err); + else // else we always treat it as fatal! + throw err; + } + + private void fatalError (String description) + throws SAXException + { + ErrorHandler errHandler = getErrorHandler (); + Locator locator = getDocumentLocator (); + SAXParseException err; + + if (locator != null) + err = new SAXParseException (description, locator); + else + err = new SAXParseException (description, null, null, -1, -1); + if (errHandler != null) + errHandler.fatalError (err); + // we always treat this as fatal, regardless of the handler + throw err; + } + + + private static boolean isExtender (char c) + { + // [88] Extender ::= ... + return c == 0x00b7 || c == 0x02d0 || c == 0x02d1 || c == 0x0387 + || c == 0x0640 || c == 0x0e46 || c == 0x0ec6 || c == 0x3005 + || (c >= 0x3031 && c <= 0x3035) + || (c >= 0x309d && c <= 0x309e) + || (c >= 0x30fc && c <= 0x30fe); + } + + + // use augmented Unicode rules, not full XML rules + private boolean isName (String name, String context, String id) + throws SAXException + { + char buf [] = name.toCharArray (); + boolean pass = true; + + if (!Character.isUnicodeIdentifierStart (buf [0]) + && ":_".indexOf (buf [0]) == -1) + pass = false; + else { + int max = buf.length; + for (int i = 1; pass && i < max; i++) { + char c = buf [i]; + if (!Character.isUnicodeIdentifierPart (c) + && ":-_.".indexOf (c) == -1 + && !isExtender (c)) + pass = false; + } + } + + if (!pass) + error ("In " + context + " for " + id + + ", '" + name + "' is not a name"); + return pass; // true == OK + } + + // use augmented Unicode rules, not full XML rules + private boolean isNmtoken (String nmtoken, String context, String id) + throws SAXException + { + char buf [] = nmtoken.toCharArray (); + boolean pass = true; + int max = buf.length; + + // XXX make this share code with isName + + for (int i = 0; pass && i < max; i++) { + char c = buf [i]; + if (!Character.isUnicodeIdentifierPart (c) + && ":-_.".indexOf (c) == -1 + && !isExtender (c)) + pass = false; + } + + if (!pass) + error ("In " + context + " for " + id + + ", '" + nmtoken + "' is not a name token"); + return pass; // true == OK + } + + private void checkEnumeration (String value, String type, String name) + throws SAXException + { + if (!hasMatch (value, type)) + // VC: Enumeration + error ("Value '" + value + + "' for attribute '" + name + + "' is not permitted: " + type); + } + + // used to test enumerated attributes and mixed content models + // package private + static boolean hasMatch (String value, String orList) + { + int len = value.length (); + int max = orList.length () - len; + + for (int start = 0; + (start = orList.indexOf (value, start)) != -1; + start++) { + char c; + + if (start > max) + break; + c = orList.charAt (start - 1); + if (c != '|' && c != '('/*)*/) + continue; + c = orList.charAt (start + len); + if (c != '|' && /*(*/ c != ')') + continue; + return true; + } + return false; + } + + /** + * LexicalHandler Records the declaration of the root + * element, so it can be verified later. + * Passed to the next consumer, unless this one was + * preloaded with a particular DTD. + */ + public void startDTD (String name, String publicId, String systemId) + throws SAXException + { + if (disableDeclarations) + return; + + rootName = name; + super.startDTD (name, publicId, systemId); + } + + /** + * LexicalHandler Verifies that all referenced notations + * and unparsed entities have been declared. + * Passed to the next consumer, unless this one was + * preloaded with a particular DTD. + */ + public void endDTD () + throws SAXException + { + if (disableDeclarations) + return; + + // this is a convenient hook for end-of-dtd checks, but we + // could also trigger it in the first startElement call. + // locator info is more appropriate here though. + + // VC: Notation Declared (NDATA can refer to them before decls, + // as can NOTATION attribute enumerations and defaults) + int length = nDeferred.size (); + for (int i = 0; i < length; i++) { + String notation = (String) nDeferred.elementAt (i); + if (!notations.contains (notation)) { + error ("A declaration referred to notation '" + notation + + "' which was never declared"); + } + } + nDeferred.removeAllElements (); + + // VC: Entity Name (attribute values can refer to them + // before they're declared); VC Attribute Default Legal + length = uDeferred.size (); + for (int i = 0; i < length; i++) { + String entity = (String) uDeferred.elementAt (i); + if (!unparsed.contains (entity)) { + error ("An attribute default referred to entity '" + entity + + "' which was never declared"); + } + } + uDeferred.removeAllElements (); + super.endDTD (); + } + + + // These are interned, so we can rely on "==" to find the type of + // all attributes except enumerations ... + // "(this|or|that|...)" and "NOTATION (this|or|that|...)" + static final String types [] = { + "CDATA", + "ID", "IDREF", "IDREFS", + "NMTOKEN", "NMTOKENS", + "ENTITY", "ENTITIES" + }; + + + /** + * DecllHandler Records attribute declaration for later use + * in validating document content, and checks validity constraints + * that are applicable to attribute declarations. + * Passed to the next consumer, unless this one was + * preloaded with a particular DTD. + */ + public void attributeDecl ( + String eName, + String aName, + String type, + String mode, + String value + ) throws SAXException + { + if (disableDeclarations) + return; + + ElementInfo info = (ElementInfo) elements.get (eName); + AttributeInfo ainfo = new AttributeInfo (); + boolean checkOne = false; + boolean interned = false; + + // cheap interning of type names and #FIXED, #REQUIRED + // for faster startElement (we can use "==") + for (int i = 0; i < types.length; i++) { + if (types [i].equals (type)) { + type = types [i]; + interned = true; + break; + } + } + if ("#FIXED".equals (mode)) + mode = "#FIXED"; + else if ("#REQUIRED".equals (mode)) + mode = "#REQUIRED"; + + ainfo.type = type; + ainfo.mode = mode; + ainfo.value = value; + + // we might not have seen the content model yet + if (info == null) { + info = new ElementInfo (eName); + elements.put (eName, info); + } + if ("ID" == type) { + checkOne = true; + if (!("#REQUIRED" == mode || "#IMPLIED".equals (mode))) { + // VC: ID Attribute Default + error ("ID attribute '" + aName + + "' must be #IMPLIED or #REQUIRED"); + } + + } else if (!interned && type.startsWith ("NOTATION ")) { + checkOne = true; + + // VC: Notation Attributes (notations must be declared) + StringTokenizer tokens = new StringTokenizer ( + type.substring (10, type.lastIndexOf (')')), + "|"); + while (tokens.hasMoreTokens ()) { + String token = tokens.nextToken (); + if (!notations.contains (token)) + nDeferred.addElement (token); + } + } + if (checkOne) { + for (Enumeration e = info.attributes.keys (); + e.hasMoreElements (); + /* NOP */) { + String name; + AttributeInfo ainfo2; + + name = (String) e.nextElement (); + ainfo2 = (AttributeInfo) info.attributes.get (name); + if (type == ainfo2.type || !interned /* NOTATION */) { + // VC: One ID per Element Type + // VC: One Notation per Element TYpe + error ("Element '" + eName + + "' already has an attribute of type " + + (interned ? "NOTATION" : type) + + " ('" + name + + "') so '" + aName + + "' is a validity error"); + } + } + } + + // VC: Attribute Default Legal + if (value != null) { + + if ("CDATA" == type) { + // event source rejected '<' + + } else if ("NMTOKEN" == type) { + // VC: Name Token (is a nmtoken) + isNmtoken (value, "attribute default", aName); + + } else if ("NMTOKENS" == type) { + // VC: Name Token (is a nmtoken; at least one value) + StringTokenizer tokens = new StringTokenizer (value); + if (!tokens.hasMoreTokens ()) + error ("Default for attribute '" + aName + + "' must have at least one name token."); + else do { + String token = tokens.nextToken (); + isNmtoken (token, "attribute default", aName); + } while (tokens.hasMoreTokens ()); + + } else if ("IDREF" == type || "ENTITY" == type) { + // VC: Entity Name (is a name) + // VC: IDREF (is a name) (is declared) + isName (value, "attribute default", aName); + if ("ENTITY" == type && !unparsed.contains (value)) + uDeferred.addElement (value); + + } else if ("IDREFS" == type || "ENTITIES" == type) { + // VC: Entity Name (is a name; at least one value) + // VC: IDREF (is a name; at least one value) + StringTokenizer names = new StringTokenizer (value); + if (!names.hasMoreTokens ()) + error ("Default for attribute '" + aName + + "' must have at least one name."); + else do { + String name = names.nextToken (); + isName (name, "attribute default", aName); + if ("ENTITIES" == type && !unparsed.contains (name)) + uDeferred.addElement (value); + } while (names.hasMoreTokens ()); + + } else if (type.charAt (0) == '(' /*)*/ ) { + // VC: Enumeration (must match) + checkEnumeration (value, type, aName); + + } else if (!interned && checkOne) { /* NOTATION */ + // VC: Notation attributes (must be names) + isName (value, "attribute default", aName); + + // VC: Notation attributes (must be declared) + if (!notations.contains (value)) + nDeferred.addElement (value); + + // VC: Enumeration (must match) + checkEnumeration (value, type, aName); + + } else if ("ID" != type) + throw new RuntimeException ("illegal attribute type: " + type); + } + + if (info.attributes.get (aName) == null) + info.attributes.put (aName, ainfo); + /* + else + warning ("Element '" + eName + + "' already has an attribute named '" + aName + "'"); + */ + + if ("xml:space".equals (aName)) { + if (!("(default|preserve)".equals (type) + || "(preserve|default)".equals (type) + // these next two are arguable; XHTML's DTD doesn't + // deserve errors. After all, it's not like any + // illegal _value_ could pass ... + || "(preserve)".equals (type) + || "(default)".equals (type) + )) + error ( + "xml:space attribute type must be like '(default|preserve)'" + + " not '" + type + "'" + ); + + } + super.attributeDecl (eName, aName, type, mode, value); + } + + /** + * DecllHandler Records the element declaration for later use + * when checking document content, and checks validity constraints that + * apply to element declarations. Passed to the next consumer, unless + * this one was preloaded with a particular DTD. + */ + public void elementDecl (String name, String model) + throws SAXException + { + if (disableDeclarations) + return; + + ElementInfo info = (ElementInfo) elements.get (name); + + // we might have seen an attribute decl already + if (info == null) { + info = new ElementInfo (name); + elements.put (name, info); + } + if (info.model != null) { + // NOTE: not all parsers can report such duplicates. + // VC: Unique Element Type Declaration + error ("Element type '" + name + + "' was already declared."); + } else { + info.model = model; + + // VC: No Duplicate Types (in mixed content models) + if (model.charAt (1) == '#') // (#PCDATA... + info.getRecognizer (this); + } + super.elementDecl (name, model); + } + + /** + * DecllHandler passed to the next consumer, unless this + * one was preloaded with a particular DTD + */ + public void internalEntityDecl (String name, String value) + throws SAXException + { + if (!disableDeclarations) + super.internalEntityDecl (name, value); + } + + /** + * DecllHandler passed to the next consumer, unless this + * one was preloaded with a particular DTD + */ + public void externalEntityDecl (String name, + String publicId, String systemId) + throws SAXException + { + if (!disableDeclarations) + super.externalEntityDecl (name, publicId, systemId); + } + + + /** + * DTDHandler Records the notation name, for checking + * NOTATIONS attribute values and declararations of unparsed + * entities. Passed to the next consumer, unless this one was + * preloaded with a particular DTD. + */ + public void notationDecl (String name, String publicId, String systemId) + throws SAXException + { + if (disableDeclarations) + return; + + notations.addElement (name); + super.notationDecl (name, publicId, systemId); + } + + /** + * DTDHandler Records the entity name, for checking + * ENTITY and ENTITIES attribute values; records the notation + * name if it hasn't yet been declared. Passed to the next consumer, + * unless this one was preloaded with a particular DTD. + */ + public void unparsedEntityDecl ( + String name, + String publicId, + String systemId, + String notationName + ) throws SAXException + { + if (disableDeclarations) + return; + + unparsed.addElement (name); + if (!notations.contains (notationName)) + nDeferred.addElement (notationName); + super.unparsedEntityDecl (name, publicId, systemId, notationName); + } + + + /** + * ContentHandler Ensures that state from any previous parse + * has been deleted. + * Passed to the next consumer. + */ + public void startDocument () + throws SAXException + { + resetState (); + super.startDocument (); + } + + + private static boolean isAsciiLetter (char c) + { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); + } + + + /** + * ContentHandler Reports a fatal exception. Validating + * XML processors may not skip any entities. + */ + public void skippedEntity (String name) + throws SAXException + { + fatalError ("may not skip entities"); + } + + /* + * SAX2 doesn't expand non-PE refs in attribute defaults... + */ + private String expandDefaultRefs (String s) + throws SAXException + { + if (s.indexOf ('&') < 0) + return s; + +// FIXME: handle &#nn; &#xnn; &name; + String message = "Can't expand refs in attribute default: " + s; + warning (message); + + return s; + } + + /** + * ContentHandler Performs validity checks against element + * (and document) content models, and attribute values. + * Passed to the next consumer. + */ + public void startElement ( + String uri, + String localName, + String qName, + Attributes atts + ) throws SAXException + { + // + // First check content model for the enclosing scope. + // + if (contentStack.isEmpty ()) { + // VC: Root Element Type + if (!qName.equals (rootName)) { + if (rootName == null) + warning ("This document has no DTD, can't be valid"); + else + error ("Root element type '" + qName + + "' was declared to be '" + rootName + "'"); + } + } else { + Recognizer state = (Recognizer) contentStack.peek (); + + if (state != null) { + Recognizer newstate = state.acceptElement (qName); + + if (newstate == null) + error ("Element type '" + qName + + "' in element '" + state.type.name + + "' violates content model " + state.type.model + ); + if (newstate != state) { + contentStack.pop (); + contentStack.push (newstate); + } + } + } + + // + // Then check that this element was declared, and push the + // object used to validate its content model onto our stack. + // + // This is where the recognizer gets created, if needed; if + // it's a "children" (elements) content model, an NDFA is + // created. (One recognizer is used per content type, no + // matter how complex that recognizer is.) + // + ElementInfo info; + + info = (ElementInfo) elements.get (qName); + if (info == null || info.model == null) { + // VC: Element Valid (base clause) + error ("Element type '" + qName + "' was not declared"); + contentStack.push (null); + + // for less diagnostic noise, fake a declaration. + elementDecl (qName, "ANY"); + } else + contentStack.push (info.getRecognizer (this)); + + // + // Then check each attribute present + // + int len; + String aname; + AttributeInfo ainfo; + + if (atts != null) + len = atts.getLength (); + else + len = 0; + + for (int i = 0; i < len; i++) { + aname = atts.getQName (i); + + if (info == null + || (ainfo = (AttributeInfo) info.attributes.get (aname)) + == null) { + // VC: Attribute Value Type + error ("Attribute '" + aname + + "' was not declared for element type " + qName); + continue; + } + + String value = atts.getValue (i); + + // note that "==" for type names and "#FIXED" is correct + // (and fast) since we've interned those literals. + + if ("#FIXED" == ainfo.mode) { + String expanded = expandDefaultRefs (ainfo.value); + + // VC: Fixed Attribute Default + if (!value.equals (expanded)) { + error ("Attribute '" + aname + + "' must match " + expanded + ); + continue; + } + } + + if ("CDATA" == ainfo.type) + continue; + + // + // For all other attribute types, there are various + // rules to follow. + // + + if ("ID" == ainfo.type) { + // VC: ID (must be a name) + if (isName (value, "ID attribute", aname)) { + if (Boolean.TRUE == ids.get (value)) + // VC: ID (appears once) + error ("ID attribute " + aname + + " uses an ID value '" + value + + "' which was already declared."); + else + // any forward refs are no longer problems + ids.put (value, Boolean.TRUE); + } + continue; + } + + if ("IDREF" == ainfo.type) { + // VC: IDREF (value must be a name) + if (isName (value, "IDREF attribute", aname)) { + // VC: IDREF (must match some ID attribute) + if (ids.get (value) == null) + // new -- assume it's a forward ref + ids.put (value, Boolean.FALSE); + } + continue; + } + + if ("IDREFS" == ainfo.type) { + StringTokenizer tokens = new StringTokenizer (value, " "); + + if (!tokens.hasMoreTokens ()) { + // VC: IDREF (one or more values) + error ("IDREFS attribute " + aname + + " must have at least one ID ref"); + } else do { + String id = tokens.nextToken (); + + // VC: IDREF (value must be a name) + if (isName (id, "IDREFS attribute", aname)) { + // VC: IDREF (must match some ID attribute) + if (ids.get (id) == null) + // new -- assume it's a forward ref + ids.put (id, Boolean.FALSE); + } + } while (tokens.hasMoreTokens ()); + continue; + } + + if ("NMTOKEN" == ainfo.type) { + // VC: Name Token (is a name token) + isNmtoken (value, "NMTOKEN attribute", aname); + continue; + } + + if ("NMTOKENS" == ainfo.type) { + StringTokenizer tokens = new StringTokenizer (value, " "); + + if (!tokens.hasMoreTokens ()) { + // VC: Name Token (one or more values) + error ("NMTOKENS attribute " + aname + + " must have at least one name token"); + } else do { + String token = tokens.nextToken (); + + // VC: Name Token (is a name token) + isNmtoken (token, "NMTOKENS attribute", aname); + } while (tokens.hasMoreTokens ()); + continue; + } + + if ("ENTITY" == ainfo.type) { + if (!unparsed.contains (value)) + // VC: Entity Name + error ("Value of attribute '" + aname + + "' refers to unparsed entity '" + value + + "' which was not declared."); + continue; + } + + if ("ENTITIES" == ainfo.type) { + StringTokenizer tokens = new StringTokenizer (value, " "); + + if (!tokens.hasMoreTokens ()) { + // VC: Entity Name (one or more values) + error ("ENTITIES attribute " + aname + + " must have at least one name token"); + } else do { + String entity = tokens.nextToken (); + + if (!unparsed.contains (entity)) + // VC: Entity Name + error ("Value of attribute '" + aname + + "' refers to unparsed entity '" + entity + + "' which was not declared."); + } while (tokens.hasMoreTokens ()); + continue; + } + + // + // check for enumerations last; more expensive + // + if (ainfo.type.charAt (0) == '(' /*)*/ + || ainfo.type.startsWith ("NOTATION ") + ) { + // VC: Enumeration (value must be defined) + checkEnumeration (value, ainfo.type, aname); + continue; + } + } + + // + // Last, check that all #REQUIRED attributes were provided + // + if (info != null) { + Hashtable table = info.attributes; + + if (table.size () != 0) { + Enumeration e = table.keys (); + + // XXX table.keys uses the heap, bleech -- slows things + + while (e.hasMoreElements ()) { + aname = (String) e.nextElement (); + ainfo = (AttributeInfo) table.get (aname); + + // "#REQUIRED" mode was interned in attributeDecl + if ("#REQUIRED" == ainfo.mode + && atts.getValue (aname) == null) { + // VC: Required Attribute + error ("Attribute '" + aname + "' must be specified " + + "for element type " + qName); + } + } + } + } + super.startElement (uri, localName, qName, atts); + } + + /** + * ContentHandler Reports a validity error if the element's content + * model does not permit character data. + * Passed to the next consumer. + */ + public void characters (char ch [], int start, int length) + throws SAXException + { + Recognizer state; + + if (contentStack.empty ()) + state = null; + else + state = (Recognizer) contentStack.peek (); + + // NOTE: if this ever supports with SAX parsers that don't + // report ignorable whitespace as such (only XP?), this class + // needs to morph it into ignorableWhitespace() as needed ... + + if (state != null && !state.acceptCharacters ()) + // VC: Element Valid (clauses three, four -- see recognizer) + error ("Character content not allowed in element " + + state.type.name); + + super.characters (ch, start, length); + } + + + /** + * ContentHandler Reports a validity error if the element's content + * model does not permit end-of-element yet, or a well formedness error + * if there was no matching startElement call. + * Passed to the next consumer. + */ + public void endElement (String uri, String localName, String qName) + throws SAXException + { + try { + Recognizer state = (Recognizer) contentStack.pop (); + + if (state != null && !state.completed ()) + // VC: Element valid (clauses two, three, four; see Recognizer) + error ("Premature end for element '" + + state.type.name + + "', content model " + + state.type.model); + + // could insist on match of start element, but that's + // something the input stream must to guarantee. + + } catch (EmptyStackException e) { + fatalError ("endElement without startElement: " + qName + + ((uri == null) + ? "" + : ( " { '" + uri + "', " + localName + " }"))); + } + super.endElement (uri, localName, qName); + } + + /** + * ContentHandler Checks whether all ID values that were + * referenced have been declared, and releases all resources. + * Passed to the next consumer. + * + * @see #setDocumentLocator + */ + public void endDocument () + throws SAXException + { + for (Enumeration idNames = ids.keys (); + idNames.hasMoreElements (); + /* NOP */) { + String id = (String) idNames.nextElement (); + + if (Boolean.FALSE == ids.get (id)) { + // VC: IDREF (must match ID) + error ("Undeclared ID value '" + id + + "' was referred to by an IDREF/IDREFS attribute"); + } + } + + resetState (); + super.endDocument (); + } + + + /** Holds per-element declarations */ + static private final class ElementInfo + { + String name; + String model; + + // key = attribute name; value = AttributeInfo + Hashtable attributes = new Hashtable (11); + + ElementInfo (String n) { name = n; } + + private Recognizer recognizer; + + // for validating content models: one per type, shared, + // and constructed only on demand ... so unused elements do + // not need to consume resources. + Recognizer getRecognizer (ValidationConsumer consumer) + throws SAXException + { + if (recognizer == null) { + if ("ANY".equals (model)) + recognizer = ANY; + else if ("EMPTY".equals (model)) + recognizer = new EmptyRecognizer (this); + else if ('#' == model.charAt (1)) + // n.b. this constructor does a validity check + recognizer = new MixedRecognizer (this, consumer); + else + recognizer = new ChildrenRecognizer (this, consumer); + } + return recognizer; + } + } + + /** Holds per-attribute declarations */ + static private final class AttributeInfo + { + String type; + String mode; // #REQUIRED, etc (or null) + String value; // or null + } + + + // + // Content model validation + // + + static private final Recognizer ANY = new Recognizer (null); + + + // Base class defines the calls used to validate content, + // and supports the "ANY" content model + static private class Recognizer + { + final ElementInfo type; + + Recognizer (ElementInfo t) { type = t; } + + // return true iff character data is legal here + boolean acceptCharacters () + throws SAXException + // VC: Element Valid (third and fourth clauses) + { return true; } + + // null return = failure + // otherwise, next state (like an FSM) + // prerequisite: tested that name was declared + Recognizer acceptElement (String name) + throws SAXException + // VC: Element Valid (fourth clause) + { return this; } + + // return true iff model is completed, can finish + boolean completed () + throws SAXException + // VC: Element Valid (fourth clause) + { return true; } + + public String toString () + // n.b. "children" is the interesting case! + { return (type == null) ? "ANY" : type.model; } + } + + // "EMPTY" content model -- no characters or elements + private static final class EmptyRecognizer extends Recognizer + { + public EmptyRecognizer (ElementInfo type) + { super (type); } + + // VC: Element Valid (first clause) + boolean acceptCharacters () + { return false; } + + // VC: Element Valid (first clause) + Recognizer acceptElement (String name) + { return null; } + } + + // "Mixed" content model -- ANY, but restricts elements + private static final class MixedRecognizer extends Recognizer + { + private String permitted []; + + // N.B. constructor tests for duplicated element names (VC) + public MixedRecognizer (ElementInfo t, ValidationConsumer v) + throws SAXException + { + super (t); + + // (#PCDATA...)* or (#PCDATA) ==> ... or empty + // with the "..." being "|elname|..." + StringTokenizer tokens = new StringTokenizer ( + t.model.substring (8, t.model.lastIndexOf (')')), + "|"); + Vector vec = new Vector (); + + while (tokens.hasMoreTokens ()) { + String token = tokens.nextToken (); + + if (vec.contains (token)) + v.error ("element " + token + + " is repeated in mixed content model: " + + t.model); + else + vec.addElement (token.intern ()); + } + permitted = new String [vec.size ()]; + for (int i = 0; i < permitted.length; i++) + permitted [i] = (String) vec.elementAt (i); + + // in one large machine-derived DTD sample, most of about + // 250 mixed content models were empty, and 25 had ten or + // more entries. 2 had over a hundred elements. Linear + // search isn't obviously wrong. + } + + // VC: Element Valid (third clause) + Recognizer acceptElement (String name) + { + int length = permitted.length; + + // first pass -- optimistic w.r.t. event source interning + // (and document validity) + for (int i = 0; i < length; i++) + if (permitted [i] == name) + return this; + // second pass -- pessimistic w.r.t. event source interning + for (int i = 0; i < length; i++) + if (permitted [i].equals (name)) + return this; + return null; + } + } + + + // recognizer loop flags, see later + private static final int F_LOOPHEAD = 0x01; + private static final int F_LOOPNEXT = 0x02; + + // for debugging -- used to label/count nodes in toString() + private static int nodeCount; + + /** + * "Children" content model -- these are nodes in NDFA state graphs. + * They work in fixed space. Note that these graphs commonly have + * cycles, handling features such as zero-or-more and one-or-more. + * + *

      It's readonly, so only one copy is ever needed. The content model + * stack may have any number of pointers into each graph, when a model + * happens to be needed more than once due to element nesting. Since + * traversing the graph just moves to another node, and never changes + * it, traversals never interfere with each other. + * + *

      There is an option to report non-deterministic models. These are + * always XML errors, but ones which are not often reported despite the + * fact that they can lead to different validating parsers giving + * different results for the same input. (The XML spec doesn't require + * them to be reported.) + * + *

      FIXME There's currently at least one known bug here, in that + * it's not actually detecting the non-determinism it tries to detect. + * (Of the "optional.xml" test, the once-or-twice-2* tests are all non-D; + * maybe some others.) This may relate to the issue flagged below as + * "should not" happen (but it was), which showed up when patching the + * graph to have one exit node (or more EMPTY nodes). + */ + private static final class ChildrenRecognizer extends Recognizer + implements Cloneable + { + // for reporting non-deterministic content models + // ... a waste of space if we're not reporting those! + // ... along with the 'model' member (in base class) + private ValidationConsumer consumer; + + // for CHOICE nodes -- each component is an arc that + // accepts a different NAME (or is EMPTY indicating + // NDFA termination). + private Recognizer components []; + + // for NAME/SEQUENCE nodes -- accepts that NAME and + // then goes to the next node (CHOICE, NAME, EMPTY). + private String name; + private Recognizer next; + + // loops always point back to a CHOICE node. we mark such choice + // nodes (F_LOOPHEAD) for diagnostics and faster deep cloning. + // We also mark nodes before back pointers (F_LOOPNEXT), to ensure + // termination when we patch sequences and loops. + private int flags; + + + // prevent a needless indirection between 'this' and 'node' + private void copyIn (ChildrenRecognizer node) + { + // model & consumer are already set + components = node.components; + name = node.name; + next = node.next; + flags = node.flags; + } + + // used to construct top level "children" content models, + public ChildrenRecognizer (ElementInfo type, ValidationConsumer vc) + { + this (vc, type); + populate (type.model.toCharArray (), 0); + patchNext (new EmptyRecognizer (type), null); + } + + // used internally; populating is separate + private ChildrenRecognizer (ValidationConsumer vc, ElementInfo type) + { + super (type); + consumer = vc; + } + + + // + // When rewriting some graph nodes we need deep clones in one case; + // mostly shallow clones (what the JVM handles for us) are fine. + // + private ChildrenRecognizer shallowClone () + { + try { + return (ChildrenRecognizer) clone (); + } catch (CloneNotSupportedException e) { + throw new Error ("clone"); + } + } + + private ChildrenRecognizer deepClone () + { + return deepClone (new Hashtable (37)); + } + + private ChildrenRecognizer deepClone (Hashtable table) + { + ChildrenRecognizer retval; + + if ((flags & F_LOOPHEAD) != 0) { + retval = (ChildrenRecognizer) table.get (this); + if (retval != null) + return this; + + retval = shallowClone (); + table.put (this, retval); + } else + retval = shallowClone (); + + if (next != null) { + if (next instanceof ChildrenRecognizer) + retval.next = ((ChildrenRecognizer)next) + .deepClone (table); + else if (!(next instanceof EmptyRecognizer)) + throw new RuntimeException ("deepClone"); + } + + if (components != null) { + retval.components = new Recognizer [components.length]; + for (int i = 0; i < components.length; i++) { + Recognizer temp = components [i]; + + if (temp == null) + retval.components [i] = null; + else if (temp instanceof ChildrenRecognizer) + retval.components [i] = ((ChildrenRecognizer)temp) + .deepClone (table); + else if (!(temp instanceof EmptyRecognizer)) + throw new RuntimeException ("deepClone"); + } + } + + return retval; + } + + // connect subgraphs, first to next (sequencing) + private void patchNext (Recognizer theNext, Hashtable table) + { + // backpointers must not be repatched or followed + if ((flags & F_LOOPNEXT) != 0) + return; + + // XXX this table "shouldn't" be needed, right? + // but some choice nodes looped if it isn't there. + if (table != null && table.get (this) != null) + return; + if (table == null) + table = new Hashtable (); + + // NAME/SEQUENCE + if (name != null) { + if (next == null) + next = theNext; + else if (next instanceof ChildrenRecognizer) { + ((ChildrenRecognizer)next).patchNext (theNext, table); + } else if (!(next instanceof EmptyRecognizer)) + throw new RuntimeException ("patchNext"); + return; + } + + // CHOICE + for (int i = 0; i < components.length; i++) { + if (components [i] == null) + components [i] = theNext; + else if (components [i] instanceof ChildrenRecognizer) { + ((ChildrenRecognizer)components [i]) + .patchNext (theNext, table); + } else if (!(components [i] instanceof EmptyRecognizer)) + throw new RuntimeException ("patchNext"); + } + + if (table != null && (flags & F_LOOPHEAD) != 0) + table.put (this, this); + } + + /** + * Parses a 'children' spec (or recursively 'cp') and makes this + * become a regular graph node. + * + * @return index after this particle + */ + private int populate (char parseBuf [], int startPos) + { + int nextPos = startPos + 1; + char c; + + if (nextPos < 0 || nextPos >= parseBuf.length) + throw new IndexOutOfBoundsException (); + + // Grammar of the string is from the XML spec, but + // with whitespace removed by the SAX parser. + + // children ::= (choice | seq) ('?' | '*' | '+')? + // cp ::= (Name | choice | seq) ('?' | '*' | '+')? + // choice ::= '(' cp ('|' choice)* ')' + // seq ::= '(' cp (',' choice)* ')' + + // interior nodes only + // cp ::= name ... + if (parseBuf [startPos] != '('/*)*/) { + boolean done = false; + do { + switch (c = parseBuf [nextPos]) { + case '?': case '*': case '+': + case '|': case ',': + case /*(*/ ')': + done = true; + continue; + default: + nextPos++; + continue; + } + } while (!done); + name = new String (parseBuf, startPos, nextPos - startPos); + + // interior OR toplevel nodes + // cp ::= choice .. + // cp ::= seq .. + } else { + // collect everything as a separate list, and merge it + // into "this" later if we can (SEQUENCE or singleton) + ChildrenRecognizer first; + + first = new ChildrenRecognizer (consumer, type); + nextPos = first.populate (parseBuf, nextPos); + c = parseBuf [nextPos++]; + + if (c == ',' || c == '|') { + ChildrenRecognizer current = first; + char separator = c; + Vector v = null; + + if (separator == '|') { + v = new Vector (); + v.addElement (first); + } + + do { + ChildrenRecognizer link; + + link = new ChildrenRecognizer (consumer, type); + nextPos = link.populate (parseBuf, nextPos); + + if (separator == ',') { + current.patchNext (link, null); + current = link; + } else + v.addElement (link); + + c = parseBuf [nextPos++]; + } while (c == separator); + + // choice ... collect everything into one array. + if (separator == '|') { + // assert v.size() > 1 + components = new Recognizer [v.size ()]; + for (int i = 0; i < components.length; i++) { + components [i] = (Recognizer) + v.elementAt (i); + } + // assert flags == 0 + + // sequence ... merge into "this" to be smaller. + } else + copyIn (first); + + // treat singletons like one-node sequences. + } else + copyIn (first); + + if (c != /*(*/ ')') + throw new RuntimeException ("corrupt content model"); + } + + // + // Arity is optional, and the root of all fun. We keep the + // FSM state graph simple by only having NAME/SEQUENCE and + // CHOICE nodes (or EMPTY to terminate a model), easily + // evaluated. So we rewrite each node that has arity, using + // those primitives. We create loops here, if needed. + // + if (nextPos < parseBuf.length) { + c = parseBuf [nextPos]; + if (c == '?' || c == '*' || c == '+') { + nextPos++; + + // Rewrite 'zero-or-one' "?" arity to a CHOICE: + // - SEQUENCE (clone, what's next) + // - or, what's next + // Size cost: N --> N + 1 + if (c == '?') { + Recognizer once = shallowClone (); + + components = new Recognizer [2]; + components [0] = once; + // components [1] initted to null + name = null; + next = null; + flags = 0; + + + // Rewrite 'zero-or-more' "*" arity to a CHOICE. + // - LOOP (clone, back to this CHOICE) + // - or, what's next + // Size cost: N --> N + 1 + } else if (c == '*') { + ChildrenRecognizer loop = shallowClone (); + + loop.patchNext (this, null); + loop.flags |= F_LOOPNEXT; + flags = F_LOOPHEAD; + + components = new Recognizer [2]; + components [0] = loop; + // components [1] initted to null + name = null; + next = null; + + + // Rewrite 'one-or-more' "+" arity to a SEQUENCE. + // Basically (a)+ --> ((a),(a)*). + // - this + // - CHOICE + // * LOOP (clone, back to the CHOICE) + // * or, whatever's next + // Size cost: N --> 2N + 1 + } else if (c == '+') { + ChildrenRecognizer loop = deepClone (); + ChildrenRecognizer choice; + + choice = new ChildrenRecognizer (consumer, type); + loop.patchNext (choice, null); + loop.flags |= F_LOOPNEXT; + choice.flags = F_LOOPHEAD; + + choice.components = new Recognizer [2]; + choice.components [0] = loop; + // choice.components [1] initted to null + // choice.name, choice.next initted to null + + patchNext (choice, null); + } + } + } + + return nextPos; + } + + // VC: Element Valid (second clause) + boolean acceptCharacters () + { return false; } + + // VC: Element Valid (second clause) + Recognizer acceptElement (String type) + throws SAXException + { + // NAME/SEQUENCE + if (name != null) { + if (name.equals (type)) + return next; + return null; + } + + // CHOICE ... optionally reporting nondeterminism we + // run across. we won't check out every transition + // for nondeterminism; only the ones we follow. + Recognizer retval = null; + + for (int i = 0; i < components.length; i++) { + Recognizer temp = components [i].acceptElement (type); + + if (temp == null) + continue; + else if (!warnNonDeterministic) + return temp; + else if (retval == null) + retval = temp; + else if (retval != temp) + consumer.error ("Content model " + this.type.model + + " is non-deterministic for " + type); + } + return retval; + } + + // VC: Element Valid (second clause) + boolean completed () + throws SAXException + { + // expecting a specific element + if (name != null) + return false; + + // choice, some sequences + for (int i = 0; i < components.length; i++) { + if (components [i].completed ()) + return true; + } + + return false; + } + +/** / + // FOR DEBUGGING ... flattens the graph for printing. + + public String toString () + { + StringBuffer buf = new StringBuffer (); + + // only one set of loop labels can be generated + // at a time... + synchronized (ANY) { + nodeCount = 0; + + toString (buf, new Hashtable ()); + return buf.toString (); + } + } + + private void toString (StringBuffer buf, Hashtable table) + { + // When we visit a node, label and count it. + // Nodes are never visited/counted more than once. + // For small models labels waste space, but if arity + // mappings were used the savings are substantial. + // (Plus, the output can be more readily understood.) + String temp = (String) table.get (this); + + if (temp != null) { + buf.append ('{'); + buf.append (temp); + buf.append ('}'); + return; + } else { + StringBuffer scratch = new StringBuffer (15); + + if ((flags & F_LOOPHEAD) != 0) + scratch.append ("loop"); + else + scratch.append ("node"); + scratch.append ('-'); + scratch.append (++nodeCount); + temp = scratch.toString (); + + table.put (this, temp); + buf.append ('['); + buf.append (temp); + buf.append (']'); + buf.append (':'); + } + + // NAME/SEQUENCE + if (name != null) { + // n.b. some output encodings turn some name chars into '?' + // e.g. with Japanese names and ASCII output + buf.append (name); + if (components != null) // bug! + buf.append ('$'); + if (next == null) + buf.append (",*"); + else if (next instanceof EmptyRecognizer) // patch-to-next + buf.append (",{}"); + else if (next instanceof ChildrenRecognizer) { + buf.append (','); + ((ChildrenRecognizer)next).toString (buf, table); + } else // bug! + buf.append (",+"); + return; + } + + // CHOICE + buf.append ("<"); + for (int i = 0; i < components.length; i++) { + if (i != 0) + buf.append ("|"); + if (components [i] instanceof EmptyRecognizer) { + buf.append ("{}"); + } else if (components [i] == null) { // patch-to-next + buf.append ('*'); + } else { + ChildrenRecognizer r; + + r = (ChildrenRecognizer) components [i]; + r.toString (buf, table); + } + } + buf.append (">"); + } +/**/ + } +} diff --git a/libjava/classpath/gnu/xml/pipeline/WellFormednessFilter.java b/libjava/classpath/gnu/xml/pipeline/WellFormednessFilter.java new file mode 100644 index 000000000..7a3db6593 --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/WellFormednessFilter.java @@ -0,0 +1,363 @@ +/* WellFormednessFilter.java -- + Copyright (C) 1999,2000,2001 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.pipeline; + +import java.util.EmptyStackException; +import java.util.Stack; + +import org.xml.sax.Attributes; +import org.xml.sax.ErrorHandler; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +/** + * This filter reports fatal exceptions in the case of event streams that + * are not well formed. The rules currently tested include:

        + * + *
      • setDocumentLocator ... may be called only before startDocument + * + *
      • startDocument/endDocument ... must be paired, and all other + * calls (except setDocumentLocator) must be nested within these. + * + *
      • startElement/endElement ... must be correctly paired, and + * may never appear within CDATA sections. + * + *
      • comment ... can't contain "--" + * + *
      • character data ... can't contain "]]>" + * + *
      • whitespace ... can't contain CR + * + *
      • whitespace and character data must be within an element + * + *
      • processing instruction ... can't contain "?>" or CR + * + *
      • startCDATA/endCDATA ... must be correctly paired. + * + *
      + * + *

      Other checks for event stream correctness may be provided in + * the future. For example, insisting that + * entity boundaries nest correctly, + * namespace scopes nest correctly, + * namespace values never contain relative URIs, + * attributes don't have "<" characters; + * and more. + * + * @author David Brownell + */ +public final class WellFormednessFilter extends EventFilter +{ + private boolean startedDoc; + private Stack elementStack = new Stack (); + private boolean startedCDATA; + private String dtdState = "before"; + + + /** + * Swallows all events after performing well formedness checks. + */ + // constructor used by PipelineFactory + public WellFormednessFilter () + { this (null); } + + + /** + * Passes events through to the specified consumer, after first + * processing them. + */ + // constructor used by PipelineFactory + public WellFormednessFilter (EventConsumer consumer) + { + super (consumer); + + setContentHandler (this); + setDTDHandler (this); + + try { + setProperty (LEXICAL_HANDLER, this); + } catch (SAXException e) { /* can't happen */ } + } + + /** + * Resets state as if any preceding event stream was well formed. + * Particularly useful if it ended through some sort of error, + * and the endDocument call wasn't made. + */ + public void reset () + { + startedDoc = false; + startedCDATA = false; + elementStack.removeAllElements (); + } + + + private SAXParseException getException (String message) + { + SAXParseException e; + Locator locator = getDocumentLocator (); + + if (locator == null) + return new SAXParseException (message, null, null, -1, -1); + else + return new SAXParseException (message, locator); + } + + private void fatalError (String message) + throws SAXException + { + SAXParseException e = getException (message); + ErrorHandler handler = getErrorHandler (); + + if (handler != null) + handler.fatalError (e); + throw e; + } + + /** + * Throws an exception when called after startDocument. + * + * @param locator the locator, to be used in error reporting or relative + * URI resolution. + * + * @exception IllegalStateException when called after the document + * has already been started + */ + public void setDocumentLocator (Locator locator) + { + if (startedDoc) + throw new IllegalStateException ( + "setDocumentLocator called after startDocument"); + super.setDocumentLocator (locator); + } + + public void startDocument () throws SAXException + { + if (startedDoc) + fatalError ("startDocument called more than once"); + startedDoc = true; + startedCDATA = false; + elementStack.removeAllElements (); + super.startDocument (); + } + + public void startElement ( + String uri, String localName, + String qName, Attributes atts + ) throws SAXException + { + if (!startedDoc) + fatalError ("callback outside of document?"); + if ("inside".equals (dtdState)) + fatalError ("element inside DTD?"); + else + dtdState = "after"; + if (startedCDATA) + fatalError ("element inside CDATA section"); + if (qName == null || "".equals (qName)) + fatalError ("startElement name missing"); + elementStack.push (qName); + super.startElement (uri, localName, qName, atts); + } + + public void endElement (String uri, String localName, String qName) + throws SAXException + { + if (!startedDoc) + fatalError ("callback outside of document?"); + if (startedCDATA) + fatalError ("element inside CDATA section"); + if (qName == null || "".equals (qName)) + fatalError ("endElement name missing"); + + try { + String top = (String) elementStack.pop (); + + if (!qName.equals (top)) + fatalError ("<" + top + " ...>..."); + // XXX could record/test namespace info + } catch (EmptyStackException e) { + fatalError ("endElement without startElement: "); + } + super.endElement (uri, localName, qName); + } + + public void endDocument () throws SAXException + { + if (!startedDoc) + fatalError ("callback outside of document?"); + dtdState = "before"; + startedDoc = false; + super.endDocument (); + } + + + public void startDTD (String root, String publicId, String systemId) + throws SAXException + { + if (!startedDoc) + fatalError ("callback outside of document?"); + if ("before" != dtdState) + fatalError ("two DTDs?"); + if (!elementStack.empty ()) + fatalError ("DTD must precede root element"); + dtdState = "inside"; + super.startDTD (root, publicId, systemId); + } + + public void notationDecl (String name, String publicId, String systemId) + throws SAXException + { +// FIXME: not all parsers will report startDTD() ... +// we'd rather insist we're "inside". + if ("after" == dtdState) + fatalError ("not inside DTD"); + super.notationDecl (name, publicId, systemId); + } + + public void unparsedEntityDecl (String name, + String publicId, String systemId, String notationName) + throws SAXException + { +// FIXME: not all parsers will report startDTD() ... +// we'd rather insist we're "inside". + if ("after" == dtdState) + fatalError ("not inside DTD"); + super.unparsedEntityDecl (name, publicId, systemId, notationName); + } + + // FIXME: add the four DeclHandler calls too + + public void endDTD () + throws SAXException + { + if (!startedDoc) + fatalError ("callback outside of document?"); + if ("inside" != dtdState) + fatalError ("DTD ends without start?"); + dtdState = "after"; + super.endDTD (); + } + + public void characters (char ch [], int start, int length) + throws SAXException + { + int here = start, end = start + length; + if (elementStack.empty ()) + fatalError ("characters must be in an element"); + while (here < end) { + if (ch [here++] != ']') + continue; + if (here == end) // potential problem ... + continue; + if (ch [here++] != ']') + continue; + if (here == end) // potential problem ... + continue; + if (ch [here++] == '>') + fatalError ("character data can't contain \"]]>\""); + } + super.characters (ch, start, length); + } + + public void ignorableWhitespace (char ch [], int start, int length) + throws SAXException + { + int here = start, end = start + length; + if (elementStack.empty ()) + fatalError ("characters must be in an element"); + while (here < end) { + if (ch [here++] == '\r') + fatalError ("whitespace can't contain CR"); + } + super.ignorableWhitespace (ch, start, length); + } + + public void processingInstruction (String target, String data) + throws SAXException + { + if (data.indexOf ('\r') > 0) + fatalError ("PIs can't contain CR"); + if (data.indexOf ("?>") > 0) + fatalError ("PIs can't contain \"?>\""); + } + + public void comment (char ch [], int start, int length) + throws SAXException + { + if (!startedDoc) + fatalError ("callback outside of document?"); + if (startedCDATA) + fatalError ("comments can't nest in CDATA"); + int here = start, end = start + length; + while (here < end) { + if (ch [here] == '\r') + fatalError ("comments can't contain CR"); + if (ch [here++] != '-') + continue; + if (here == end) + fatalError ("comments can't end with \"--->\""); + if (ch [here++] == '-') + fatalError ("comments can't contain \"--\""); + } + super.comment (ch, start, length); + } + + public void startCDATA () + throws SAXException + { + if (!startedDoc) + fatalError ("callback outside of document?"); + if (startedCDATA) + fatalError ("CDATA starts can't nest"); + startedCDATA = true; + super.startCDATA (); + } + + public void endCDATA () + throws SAXException + { + if (!startedDoc) + fatalError ("callback outside of document?"); + if (!startedCDATA) + fatalError ("CDATA end without start?"); + startedCDATA = false; + super.endCDATA (); + } +} diff --git a/libjava/classpath/gnu/xml/pipeline/XIncludeFilter.java b/libjava/classpath/gnu/xml/pipeline/XIncludeFilter.java new file mode 100644 index 000000000..a1445fa0c --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/XIncludeFilter.java @@ -0,0 +1,579 @@ +/* XIncludeFilter.java -- + Copyright (C) 2001,2002 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.pipeline; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.net.URLConnection; +import java.util.Hashtable; +import java.util.Stack; +import java.util.Vector; + +import org.xml.sax.Attributes; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.XMLReaderFactory; + +import gnu.xml.util.Resolver; + + + +/** + * Filter to process an XPointer-free subset of + * XInclude, supporting its + * use as a kind of replacement for parsed general entities. + * XInclude works much like the #include of C/C++ but + * works for XML documents as well as unparsed text files. + * Restrictions from the 17-Sept-2002 CR draft of XInclude are as follows: + * + *

        + * + *
      • URIs must not include fragment identifiers. + * The CR specifies support for XPointer element() fragment IDs, + * which is not currently implemented here. + * + *
      • xi:fallback handling of resource errors is not + * currently supported. + * + *
      • DTDs are not supported in included files, since the SAX DTD events + * must have completely preceded any included file. + * The CR explicitly allows the DTD related portions of the infoset to + * grow as an effect of including XML documents. + * + *
      • xml:base fixup isn't done. + * + *
      + * + *

      XML documents that are included will normally be processed using + * the default SAX namespace rules, meaning that prefix information may + * be discarded. This may be changed with {@link #setSavingPrefixes + * setSavingPrefixes()}. You are strongly advised to do this. + * + *

      Note that XInclude allows highly incompatible implementations, which + * are specialized to handle application-specific infoset extensions. Some + * such implementations can be implemented by subclassing this one, but + * they may only be substituted in applications at "user option". + * + *

      TBD: "IURI" handling. + * + * @author David Brownell + */ +public class XIncludeFilter extends EventFilter implements Locator +{ + private Hashtable extEntities = new Hashtable (5, 5); + private int ignoreCount; + private Stack uris = new Stack (); + private Locator locator; + private Vector inclusions = new Vector (5, 5); + private boolean savingPrefixes; + + /** + */ + public XIncludeFilter (EventConsumer next) + throws SAXException + { + super (next); + setContentHandler (this); + // DTDHandler callbacks pass straight through + setProperty (DECL_HANDLER, this); + setProperty (LEXICAL_HANDLER, this); + } + + private void fatal (SAXParseException e) throws SAXException + { + ErrorHandler eh; + + eh = getErrorHandler (); + if (eh != null) + eh.fatalError (e); + throw e; + } + + /** + * Passes "this" down the filter chain as a proxy locator. + */ + public void setDocumentLocator (Locator locator) + { + this.locator = locator; + super.setDocumentLocator (this); + } + + /** Used for proxy locator; do not call directly. */ + public String getSystemId () + { return (locator == null) ? null : locator.getSystemId (); } + /** Used for proxy locator; do not call directly. */ + public String getPublicId () + { return (locator == null) ? null : locator.getPublicId (); } + /** Used for proxy locator; do not call directly. */ + public int getLineNumber () + { return (locator == null) ? -1 : locator.getLineNumber (); } + /** Used for proxy locator; do not call directly. */ + public int getColumnNumber () + { return (locator == null) ? -1 : locator.getColumnNumber (); } + + /** + * Assigns the flag controlling the setting of the SAX2 + * namespace-prefixes flag. + */ + public void setSavingPrefixes (boolean flag) + { savingPrefixes = flag; } + + /** + * Returns the flag controlling the setting of the SAX2 + * namespace-prefixes flag when parsing included documents. + * The default value is the SAX2 default (false), which discards + * information that can be useful. + */ + public boolean isSavingPrefixes () + { return savingPrefixes; } + + // + // Two mechanisms are interacting here. + // + // - XML Base implies a stack of base URIs, updated both by + // "real entity" boundaries and element boundaries. + // + // - Active "Real Entities" (for document and general entities, + // and by xincluded files) are tracked to prevent circular + // inclusions. + // + private String addMarker (String uri) + throws SAXException + { + if (locator != null && locator.getSystemId () != null) + uri = locator.getSystemId (); + + // guard against InputSource objects without system IDs + if (uri == null) + fatal (new SAXParseException ("Entity URI is unknown", locator)); + + try { + URL url = new URL (uri); + + uri = url.toString (); + if (inclusions.contains (uri)) + fatal (new SAXParseException ( + "XInclude, circular inclusion", locator)); + inclusions.addElement (uri); + uris.push (url); + } catch (IOException e) { + // guard against illegal relative URIs (Xerces) + fatal (new SAXParseException ("parser bug: relative URI", + locator, e)); + } + return uri; + } + + private void pop (String uri) + { + inclusions.removeElement (uri); + uris.pop (); + } + + // + // Document entity boundaries get both treatments. + // + public void startDocument () throws SAXException + { + ignoreCount = 0; + addMarker (null); + super.startDocument (); + } + + public void endDocument () throws SAXException + { + inclusions.setSize (0); + extEntities.clear (); + uris.setSize (0); + super.endDocument (); + } + + // + // External general entity boundaries get both treatments. + // + public void externalEntityDecl (String name, + String publicId, String systemId) + throws SAXException + { + if (name.charAt (0) == '%') + return; + try { + URL url = new URL (locator.getSystemId ()); + systemId = new URL (url, systemId).toString (); + } catch (IOException e) { + // what could we do? + } + extEntities.put (name, systemId); + } + + public void startEntity (String name) + throws SAXException + { + if (ignoreCount != 0) { + ignoreCount++; + return; + } + + String uri = (String) extEntities.get (name); + if (uri != null) + addMarker (uri); + super.startEntity (name); + } + + public void endEntity (String name) + throws SAXException + { + if (ignoreCount != 0) { + if (--ignoreCount != 0) + return; + } + + String uri = (String) extEntities.get (name); + + if (uri != null) + pop (uri); + super.endEntity (name); + } + + // + // element boundaries only affect the base URI stack, + // unless they're XInclude elements. + // + public void + startElement (String uri, String localName, String qName, Attributes atts) + throws SAXException + { + if (ignoreCount != 0) { + ignoreCount++; + return; + } + + URL baseURI = (URL) uris.peek (); + String base; + + base = atts.getValue ("http://www.w3.org/XML/1998/namespace", "base"); + if (base == null) + uris.push (baseURI); + else { + URL url; + + if (base.indexOf ('#') != -1) + fatal (new SAXParseException ( + "xml:base with fragment: " + base, + locator)); + + try { + baseURI = new URL (baseURI, base); + uris.push (baseURI); + } catch (Exception e) { + fatal (new SAXParseException ( + "xml:base with illegal uri: " + base, + locator, e)); + } + } + + if (!"http://www.w3.org/2001/XInclude".equals (uri)) { + super.startElement (uri, localName, qName, atts); + return; + } + + if ("include".equals (localName)) { + String href = atts.getValue ("href"); + String parse = atts.getValue ("parse"); + String encoding = atts.getValue ("encoding"); + URL url = (URL) uris.peek (); + SAXParseException x = null; + + if (href == null) + fatal (new SAXParseException ( + "XInclude missing href", + locator)); + if (href.indexOf ('#') != -1) + fatal (new SAXParseException ( + "XInclude with fragment: " + href, + locator)); + + if (parse == null || "xml".equals (parse)) + x = xinclude (url, href); + else if ("text".equals (parse)) + x = readText (url, href, encoding); + else + fatal (new SAXParseException ( + "unknown XInclude parsing mode: " + parse, + locator)); + if (x == null) { + // strip out all child content + ignoreCount++; + return; + } + + // FIXME the 17-Sept-2002 CR of XInclude says we "must" + // use xi:fallback elements to handle resource errors, + // if they exist. + fatal (x); + + } else if ("fallback".equals (localName)) { + fatal (new SAXParseException ( + "illegal top level XInclude 'fallback' element", + locator)); + } else { + ErrorHandler eh = getErrorHandler (); + + // CR doesn't say this is an error + if (eh != null) + eh.warning (new SAXParseException ( + "unrecognized toplevel XInclude element: " + localName, + locator)); + super.startElement (uri, localName, qName, atts); + } + } + + public void endElement (String uri, String localName, String qName) + throws SAXException + { + if (ignoreCount != 0) { + if (--ignoreCount != 0) + return; + } + + uris.pop (); + if (!("http://www.w3.org/2001/XInclude".equals (uri) + && "include".equals (localName))) + super.endElement (uri, localName, qName); + } + + // + // ignore all content within non-empty xi:include elements + // + public void characters (char ch [], int start, int length) + throws SAXException + { + if (ignoreCount == 0) + super.characters (ch, start, length); + } + + public void processingInstruction (String target, String value) + throws SAXException + { + if (ignoreCount == 0) + super.processingInstruction (target, value); + } + + public void ignorableWhitespace (char ch [], int start, int length) + throws SAXException + { + if (ignoreCount == 0) + super.ignorableWhitespace (ch, start, length); + } + + public void comment (char ch [], int start, int length) + throws SAXException + { + if (ignoreCount == 0) + super.comment (ch, start, length); + } + + public void startCDATA () throws SAXException + { + if (ignoreCount == 0) + super.startCDATA (); + } + + public void endCDATA () throws SAXException + { + if (ignoreCount == 0) + super.endCDATA (); + } + + public void startPrefixMapping (String prefix, String uri) + throws SAXException + { + if (ignoreCount == 0) + super.startPrefixMapping (prefix, uri); + } + + public void endPrefixMapping (String prefix) throws SAXException + { + if (ignoreCount == 0) + super.endPrefixMapping (prefix); + } + + public void skippedEntity (String name) throws SAXException + { + if (ignoreCount == 0) + super.skippedEntity (name); + } + + // JDK 1.1 seems to need it to be done this way, sigh + void setLocator (Locator l) { locator = l; } + Locator getLocator () { return locator; } + + + // + // for XIncluded entities, manage the current locator and + // filter out events that would be incorrect to report + // + private class Scrubber extends EventFilter + { + Scrubber (EventFilter f) + throws SAXException + { + // delegation passes to next in chain + super (f); + + // process all content events + super.setContentHandler (this); + super.setProperty (LEXICAL_HANDLER, this); + + // drop all DTD events + super.setDTDHandler (null); + super.setProperty (DECL_HANDLER, null); + } + + // maintain proxy locator + // only one startDocument()/endDocument() pair per event stream + public void setDocumentLocator (Locator l) + { setLocator (l); } + public void startDocument () + { } + public void endDocument () + { } + + private void reject (String message) throws SAXException + { fatal (new SAXParseException (message, getLocator ())); } + + // only the DTD from the "base document" gets reported + public void startDTD (String root, String publicId, String systemId) + throws SAXException + { reject ("XIncluded DTD: " + systemId); } + public void endDTD () + throws SAXException + { reject ("XIncluded DTD"); } + // ... so this should never happen + public void skippedEntity (String name) throws SAXException + { reject ("XInclude skipped entity: " + name); } + + // since we rejected DTDs, only builtin entities can be reported + } + + // + // relative to the base URI passed + private SAXParseException xinclude (URL url, String href) + throws SAXException + { + XMLReader helper; + Scrubber scrubber; + Locator savedLocator = locator; + + // start with a parser acting just like our input + // modulo DTD-ish stuff (validation flag, entity resolver) + helper = XMLReaderFactory.createXMLReader (); + helper.setErrorHandler (getErrorHandler ()); + helper.setFeature (FEATURE_URI + "namespace-prefixes", true); + + // Set up the proxy locator and event filter. + scrubber = new Scrubber (this); + locator = null; + bind (helper, scrubber); + + // Merge the included document, except its DTD + try { + url = new URL (url, href); + href = url.toString (); + + if (inclusions.contains (href)) + fatal (new SAXParseException ( + "XInclude, circular inclusion", locator)); + + inclusions.addElement (href); + uris.push (url); + helper.parse (new InputSource (href)); + return null; + } catch (java.io.IOException e) { + return new SAXParseException (href, locator, e); + } finally { + pop (href); + locator = savedLocator; + } + } + + // + // relative to the base URI passed + private SAXParseException readText (URL url, String href, String encoding) + throws SAXException + { + InputStream in = null; + + try { + URLConnection conn; + InputStreamReader reader; + char buf [] = new char [4096]; + int count; + + url = new URL (url, href); + conn = url.openConnection (); + in = conn.getInputStream (); + if (encoding == null) + encoding = Resolver.getEncoding (conn.getContentType ()); + if (encoding == null) { + ErrorHandler eh = getErrorHandler (); + if (eh != null) + eh.warning (new SAXParseException ( + "guessing text encoding for URL: " + url, + locator)); + reader = new InputStreamReader (in); + } else + reader = new InputStreamReader (in, encoding); + + while ((count = reader.read (buf, 0, buf.length)) != -1) + super.characters (buf, 0, count); + in.close (); + return null; + } catch (IOException e) { + return new SAXParseException ( + "can't XInclude text", + locator, e); + } + } +} diff --git a/libjava/classpath/gnu/xml/pipeline/XsltFilter.java b/libjava/classpath/gnu/xml/pipeline/XsltFilter.java new file mode 100644 index 000000000..86b6190c5 --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/XsltFilter.java @@ -0,0 +1,130 @@ +/* XsltFilter.java -- + Copyright (C) 2001 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.pipeline; + +import java.io.IOException; + +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.sax.*; +import javax.xml.transform.stream.StreamSource; + +import org.xml.sax.SAXException; +import org.xml.sax.ext.LexicalHandler; + + +/** + * Packages an XSLT transform as a pipeline component. + * Note that all DTD events (callbacks to DeclHandler and DTDHandler + * interfaces) are discarded, although XSLT transforms may be set up to + * use the LexicalHandler to write DTDs with only an external subset. + * Not every XSLT engine will necessarily be usable with this filter, + * but current versions of + * SAXON and + * Xalan should work well. + * + * @see TransformerFactory + * + * @author David Brownell + */ +final public class XsltFilter extends EventFilter +{ + /** + * Creates a filter that performs the specified transform. + * Uses the JAXP 1.1 interfaces to access the default XSLT + * engine configured for in the current execution context, + * and parses the stylesheet without custom EntityResolver + * or ErrorHandler support. + * + * @param stylesheet URI for the stylesheet specifying the + * XSLT transform + * @param next provides the ContentHandler and LexicalHandler + * to receive XSLT output. + * @exception SAXException if the stylesheet can't be parsed + * @exception IOException if there are difficulties + * bootstrapping the XSLT engine, such as it not supporting + * SAX well enough to use this way. + */ + public XsltFilter (String stylesheet, EventConsumer next) + throws SAXException, IOException + { + // First, get a transformer with the stylesheet preloaded + TransformerFactory tf = null; + TransformerHandler th; + + try { + SAXTransformerFactory stf; + + tf = TransformerFactory.newInstance (); + if (!tf.getFeature (SAXTransformerFactory.FEATURE) // sax inputs + || !tf.getFeature (SAXResult.FEATURE) // sax outputs + || !tf.getFeature (StreamSource.FEATURE) // stylesheet + ) + throw new IOException ("XSLT factory (" + + tf.getClass ().getName () + + ") does not support SAX"); + stf = (SAXTransformerFactory) tf; + th = stf.newTransformerHandler (new StreamSource (stylesheet)); + } catch (TransformerConfigurationException e) { + throw new IOException ("XSLT factory (" + + (tf == null + ? "none available" + : tf.getClass ().getName ()) + + ") configuration error, " + + e.getMessage () + ); + } + + // Hook its outputs up to the pipeline ... + SAXResult out = new SAXResult (); + + out.setHandler (next.getContentHandler ()); + try { + LexicalHandler lh; + lh = (LexicalHandler) next.getProperty (LEXICAL_HANDLER); + out.setLexicalHandler (lh); + } catch (Exception e) { + // ignore + } + th.setResult (out); + + // ... and make sure its inputs look like ours. + setContentHandler (th); + setProperty (LEXICAL_HANDLER, th); + } +} diff --git a/libjava/classpath/gnu/xml/pipeline/package.html b/libjava/classpath/gnu/xml/pipeline/package.html new file mode 100644 index 000000000..352f4c87c --- /dev/null +++ b/libjava/classpath/gnu/xml/pipeline/package.html @@ -0,0 +1,255 @@ + +blah +<!-- +/* + * Copyright (C) 1999-2001 The Free Software Foundation, Inc. + */ +--> + + +

      This package exposes a kind of XML processing pipeline, based on sending +SAX events, which can be used as components of application architectures. +Pipelines are used to convey streams of processing events from a producer +to one or more consumers, and to let each consumer control the data seen by +later consumers. + +

      There is a PipelineFactory class which +accepts a syntax describing how to construct some simple pipelines. Strings +describing such pipelines can be used in command line tools (see the +DoParse class) +and in other places that it is +useful to let processing be easily reconfigured. Pipelines can of course +be constructed programmatically, providing access to options that the +factory won't. + +

      Web applications are supported by making it easy for servlets (or +non-Java web application components) to be part of a pipeline. They can +originate XML (or XHTML) data through an InputSource or in +response to XML messages sent from clients using CallFilter +pipeline stages. Such facilities are available using the simple syntax +for pipeline construction. + + +

      Programming Models

      + +

      Pipelines should be simple to understand. + +

        +
      • XML content, typically entire documents, + is pushed through consumers by producers. + +
      • Pipelines are basically about consuming SAX2 callback events, + where the events encapsulate XML infoset-level data.
          + +
        • Pipelines are constructed by taking one or more consumer + stages and combining them to produce a composite consumer. + +
        • A pipeline is presumed to have pending tasks and state from + the beginning of its ContentHandler.startDocument() callback until + it's returned from its ContentHandler.doneDocument() callback. + +
        • Pipelines may have multiple output stages ("fan-out") + or multiple input stages ("fan-in") when appropriate. + +
        • Pipelines may be long-lived, but need not be. + +
        + +
      • There is flexibility about event production.
          + +
        • SAX2 XMLReader objects are producers, which + provide a high level "pull" model: documents (text or DOM) are parsed, + and the parser pushes individual events through the pipeline. + +
        • Events can be pushed directly to event consumer components + by application modules, if they invoke SAX2 callbacks directly. + That is, application modules use the XML Infoset as exposed + through SAX2 event callbacks. + +
        + +
      • Multiple producer threads may concurrently access a pipeline, + if they coordinate appropriately. + +
      • Pipeline processing is not the only framework applications + will use. + +
      + + +

      Producers: XMLReader or Custom

      + +

      Many producers will be SAX2 XMLReader objects, and +will read (pull) data which is then written (pushed) as events. +Typically these will parse XML text (acquired from +org.xml.sax.helpers.XMLReaderFactory) or a DOM tree +(using a DomParser) +These may be bound to event consumer using a convenience routine, +EventFilter.bind(). +Once bound, these producers may be given additional documents to +sent through its pipeline. + +

      In other cases, you will write producers yourself. For example, some +data structures might know how to write themselves out using one or +more XML models, expressed as sequences of SAX2 event callbacks. +An application module might +itself be a producer, issuing startDocument and endDocument events +and then asking those data structures to write themselves out to a +given EventConsumer, or walking data structures (such as JDBC query +results) and applying its own conversion rules. WAP format XML +(WBMXL) can be directly converted to producer output. + +

      SAX2 introduced an "XMLFilter" interface, which is a kind of XMLReader. +It is most useful in conjunction with its XMLFilterImpl helper class; +see the EventFilter javadoc +for information contrasting that XMLFilterImpl approach with the +relevant parts of this pipeline framework. Briefly, such XMLFilterImpl +children can be either producers or consumers, and are more limited in +configuration flexibility. In this framework, the focus of filters is +on the EventConsumer side; see the section on +pipe fitting below. + + +

      Consume to Standard or Custom Data Representations

      + +

      Many consumers will be used to create standard representations of XML +data. The TextConsumer takes its events +and writes them as text for a single XML document, +using an internal XMLWriter. +The DomConsumer takes its events and uses +them to create and populate a DOM Document. + +

      In other cases, you will write consumers yourself. For example, +you might use a particular unmarshaling filter to produce objects +that fit your application's requirements, instead of using DOM. +Such consumers work at the level of XML data models, rather than with +specific representations such as XML text or a DOM tree. You could +convert your output directly to WAP format data (WBXML). + + +

      Pipe Fitting

      + +

      Pipelines are composite event consumers, with each stage having +the opportunity to transform the data before delivering it to any +subsequent stages. + +

      The PipelineFactory class +provides access to much of this functionality through a simple syntax. +See the table in that class's javadoc describing a number of standard +components. Direct API calls are still needed for many of the most +interesting pipeline configurations, including ones leveraging actual +or logical concurrency. + +

      Four basic types of pipe fitting are directly supported. These may +be used to construct complex pipeline networks.

        + +
      • TeeConsumer objects split event + flow so it goes to two two different consumers, one before the other. + This is a basic form of event fan-out; you can use this class to + copy events to any number of output pipelines. + +
      • Clients can call remote components through HTTP or HTTPS using + the CallFilter component, and Servlets + can implement such components by extending the + XmlServlet component. Java is not + required on either end, and transport protocols other than HTTP may + also be used. + +
      • EventFilter objects selectively + provide handling for callbacks, and can pass unhandled ones to a + subsequent stage. They are often subclassed, since much of the + basic filtering machinery is already in place in the base class. + +
      • Applications can merge two event flows by just using the same + consumer in each one. If multiple threads are in use, synchronization + needs to be addressed by the appropriate application level policy. + +
      + +

      Note that filters can be as complex as +XSLT transforms +available) on input data, or as simple as removing simple syntax data +such as ignorable whitespace, comments, and CDATA delimiters. +Some simple "built-in" filters are part of this package. + + +

      Coding Conventions: Filter and Terminus Stages

      + +

      If you follow these coding conventions, your classes may be used +directly (give the full class name) in pipeline descriptions as understood +by the PipelineFactory. There are four constructors the factory may +try to use; in order of decreasing numbers of parameters, these are:

        + +
      • Filters that need a single String setup parameter should have + a public constructor with two parameters: that string, then the + EventConsumer holding the "next" consumer to get events. + +
      • Filters that don't need setup parameters should have a public + constructor that accepts a single EventConsumer holding the "next" + consumer to get events when they are done. + +
      • Terminus stages may have a public constructor taking a single + paramter: the string value of that parameter. + +
      • Terminus stages may have a public no-parameters constructor. + +
      + +

      Of course, classes may support more than one such usage convention; +if they do, they can automatically be used in multiple modes. If you +try to use a terminus class as a filter, and that terminus has a constructor +with the appropriate number of arguments, it is automatically wrapped in +a "tee" filter. + + +

      Debugging Tip: "Tee" Joints can Snapshot Data

      + +

      It can sometimes be hard to see what's happening, when something +goes wrong. Easily fixed: just snapshot the data. Then you can find +out where things start to go wrong. + +

      If you're using pipeline descriptors so that they're easily +administered, just stick a write ( filename ) +filter into the pipeline at an appropriate point. + +

      Inside your programs, you can do the same thing directly: perhaps +by saving a Writer (perhaps a StringWriter) in a variable, using that +to create a TextConsumer, and making that the first part of a tee -- +splicing that into your pipeline at a convenient location. + +

      You can also use a DomConsumer to buffer the data, but remember +that DOM doesn't save all the information that XML provides, so that DOM +snapshots are relatively low fidelity. They also are substantially more +expensive in terms of memory than a StringWriter holding similar data. + +

      Debugging Tip: Non-XML Producers

      + +

      Producers in pipelines don't need to start from XML +data structures, such as text in XML syntax (likely coming +from some XMLReader that parses XML) or a +DOM representation (perhaps with a +DomParser). + +

      One common type of event producer will instead make +direct calls to SAX event handlers returned from an +EventConsumer. +For example, making ContentHandler.startElement +calls and matching ContentHandler.endElement calls. + +

      Applications making such calls can catch certain +common "syntax errors" by using a +WellFormednessFilter. +That filter will detect (and report) erroneous input data +such as mismatched document, element, or CDATA start/end calls. +Use such a filter near the head of the pipeline that your +producer feeds, at least while debugging, to help ensure that +you're providing legal XML Infoset data. + +

      You can also arrange to validate data on the fly. +For DTD validation, you can configure a +ValidationConsumer +to work as a filter, using any DTD you choose. +Other validation schemes can be handled with other +validation filters. + + diff --git a/libjava/classpath/gnu/xml/stream/AttributeImpl.java b/libjava/classpath/gnu/xml/stream/AttributeImpl.java new file mode 100644 index 000000000..58a0dbe21 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/AttributeImpl.java @@ -0,0 +1,123 @@ +/* AttributeImpl.java -- + 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.xml.stream; + +import java.io.IOException; +import java.io.Writer; +import javax.xml.namespace.QName; +import javax.xml.stream.events.Attribute; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; + +/** + * An attribute event. + * + * @author Chris Burdess + */ +public class AttributeImpl + extends XMLEventImpl + implements Attribute +{ + + protected final QName name; + protected final String value; + protected final String type; + protected final boolean specified; + + protected AttributeImpl(Location location, + QName name, String value, String type, + boolean specified) + { + super(location); + this.name = name; + this.value = value; + this.type = type; + this.specified = specified; + } + + public int getEventType() + { + return ATTRIBUTE; + } + + public QName getName() + { + return name; + } + + public String getValue() + { + return value; + } + + public String getDTDType() + { + return type; + } + + public boolean isSpecified() + { + return specified; + } + + public void writeAsEncodedUnicode(Writer writer) + throws XMLStreamException + { + try + { + String prefix = name.getPrefix(); + if (prefix != null && !"".equals(prefix)) + { + writer.write(prefix); + writer.write(':'); + } + writer.write(name.getLocalPart()); + writer.write('='); + writer.write('"'); + writer.write(encode(value, true)); + writer.write('"'); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + +} diff --git a/libjava/classpath/gnu/xml/stream/BufferedReader.java b/libjava/classpath/gnu/xml/stream/BufferedReader.java new file mode 100644 index 000000000..dc69fb34b --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/BufferedReader.java @@ -0,0 +1,198 @@ +/* BufferedReader.java -- + 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.xml.stream; + +import java.io.IOException; +import java.io.Reader; + +/** + * A mark-capable buffered reader. + * + * @author Chris Burdess + */ +class BufferedReader + extends Reader +{ + + static final int DEFAULT_BUFFER_SIZE = 4096; + + final Reader in; + char[] buf; + int pos, count, markpos, marklimit, bufferSize; + + BufferedReader(Reader in) + { + this(in, DEFAULT_BUFFER_SIZE); + } + + BufferedReader(Reader in, int bufferSize) + { + if (bufferSize < 1) + throw new IllegalArgumentException(); + this.in = in; + this.bufferSize = bufferSize; + buf = new char[bufferSize]; + pos = count = bufferSize; + } + + public void close() + throws IOException + { + buf = null; + pos = count = 0; + markpos = -1; + in.close(); + } + + public void mark(int readlimit) + throws IOException + { + marklimit = readlimit; + markpos = pos; + } + + public boolean markSupported() + { + return true; + } + + public int read() + throws IOException + { + if (pos >= count && !refill()) + return -1; + return (int) buf[pos++]; + } + + public int read(char[] b) + throws IOException + { + return read(b, 0, b.length); + } + + public int read(char[] b, int off, int len) + throws IOException + { + if (off < 0 || len < 0 || b.length - off < len) + throw new IndexOutOfBoundsException(); + + if (len == 0) + return 0; + + if (pos >= count && !refill()) + return -1; + + int ret = Math.min(count - pos, len); + System.arraycopy(buf, pos, b, off, ret); + pos += ret; + off += ret; + len -= ret; + + while (len > 0 && refill()) + { + int remain = Math.min(count - pos, len); + System.arraycopy(buf, pos, b, off, remain); + pos += remain; + off += remain; + len -= remain; + ret += remain; + } + + return ret; + } + + public void reset() + throws IOException + { + if (markpos == -1) + throw new IOException(buf == null ? "Stream closed." : "Invalid mark."); + pos = markpos; + } + + public long skip(long n) + throws IOException + { + if (buf == null) + throw new IOException("Stream closed."); + final long origN = n; + while (n > 0L) + { + if (pos >= count && !refill()) + break; + int numread = (int) Math.min((long) (count - pos), n); + pos += numread; + n -= numread; + } + return origN - n; + } + + private boolean refill() + throws IOException + { + if (buf == null) + throw new IOException("Stream closed."); + + int markcount = count - markpos; + if (markpos == -1 || markcount >= marklimit) + { + markpos = -1; + pos = count = 0; + } + else + { + char[] newbuf = buf; + if (markpos < bufferSize) + { + newbuf = new char[count - markpos + bufferSize]; + } + System.arraycopy(buf, markpos, newbuf, 0, markcount); + buf = newbuf; + count = markcount; + pos -= markpos; + markpos = 0; + } + + int numread = in.read(buf, count, bufferSize); + if (numread <= 0) + return false; + + count += numread; + return true; + } + +} diff --git a/libjava/classpath/gnu/xml/stream/CRLFReader.java b/libjava/classpath/gnu/xml/stream/CRLFReader.java new file mode 100644 index 000000000..7f3cf4d74 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/CRLFReader.java @@ -0,0 +1,180 @@ +/* CRLFReader.java -- + 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.xml.stream; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.Reader; + +/** + * Filtered reader that normalizes CRLF pairs into LFs. + * + * @author Chris Burdess + */ +class CRLFReader + extends Reader +{ + + /** + * The CR octet. + */ + public static final int CR = 13; + + /** + * The LF octet. + */ + public static final int LF = 10; + + private boolean doReset; + + protected Reader in; + + /** + * Constructor. + */ + protected CRLFReader(Reader in) + { + if (!in.markSupported()) + in = new BufferedReader(in); + this.in = in; + } + + public int read() + throws IOException + { + int c = in.read(); + if (c == 13) // CR + { + in.mark(1); + int d = in.read(); + if (d == 10) // LF + c = d; + else + in.reset(); + } + return c; + } + + public int read(char[] b) + throws IOException + { + return read(b, 0, b.length); + } + + public int read(char[] b, int off, int len) + throws IOException + { + in.mark(len + 1); + int l = in.read(b, off, len); + if (l > 0) + { + int i = indexOfCRLF(b, off, l); + if (doReset) + { + in.reset(); + if (i != -1) + { + l = in.read(b, off, (i + 1) - off); // read to CR + in.read(); // skip LF + b[i] = '\n'; // fix CR as LF + } + else + l = in.read(b, off, len); // CR(s) but no LF + } + } + return l; + } + + public boolean markSupported() + { + return in.markSupported(); + } + + public void mark(int limit) + throws IOException + { + in.mark(limit); + } + + public void reset() + throws IOException + { + in.reset(); + } + + public long skip(long n) + throws IOException + { + return in.skip(n); + } + + public void close() + throws IOException + { + in.close(); + } + + private int indexOfCRLF(char[] b, int off, int len) + throws IOException + { + doReset = false; + int end = off + len; + int em1 = end - 1; + for (int i = off; i < end; i++) + { + if (b[i] == '\r') // CR + { + int d; + if (i == em1) + { + d = in.read(); + doReset = true; + } + else + d = b[i + 1]; + if (d == '\n') // LF + { + doReset = true; + return i; + } + } + } + return -1; + } + +} diff --git a/libjava/classpath/gnu/xml/stream/CharactersImpl.java b/libjava/classpath/gnu/xml/stream/CharactersImpl.java new file mode 100644 index 000000000..2107a5a6d --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/CharactersImpl.java @@ -0,0 +1,119 @@ +/* CharactersImpl.java -- + 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.xml.stream; + +import java.io.IOException; +import java.io.Writer; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Characters; + +/** + * A character data (text) event. + * + * @author Chris Burdess + */ +public class CharactersImpl + extends XMLEventImpl + implements Characters +{ + + protected final String data; + protected final boolean whitespace; + protected final boolean cdata; + protected final boolean ignorableWhitespace; + + protected CharactersImpl(Location location, + String data, boolean whitespace, boolean cdata, + boolean ignorableWhitespace) + { + super(location); + this.data = data; + this.whitespace = whitespace; + this.cdata = cdata; + this.ignorableWhitespace = ignorableWhitespace; + } + + public int getEventType() + { + return cdata ? CDATA : whitespace ? SPACE : CHARACTERS; + } + + public String getData() + { + return data; + } + + public boolean isWhiteSpace() + { + return whitespace; + } + + public boolean isCData() + { + return cdata; + } + + public boolean isIgnorableWhiteSpace() + { + return ignorableWhitespace; + } + + public void writeAsEncodedUnicode(Writer writer) + throws XMLStreamException + { + try + { + if (cdata) + { + writer.write(""); + } + else + writer.write(encode(data, false)); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + +} diff --git a/libjava/classpath/gnu/xml/stream/CommentImpl.java b/libjava/classpath/gnu/xml/stream/CommentImpl.java new file mode 100644 index 000000000..118ac7a57 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/CommentImpl.java @@ -0,0 +1,91 @@ +/* CommentImpl.java -- + 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.xml.stream; + +import java.io.IOException; +import java.io.Writer; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Comment; + +/** + * A comment event. + * + * @author Chris Burdess + */ +public class CommentImpl + extends XMLEventImpl + implements Comment +{ + + protected final String text; + + protected CommentImpl(Location location, String text) + { + super(location); + this.text = text; + } + + public int getEventType() + { + return COMMENT; + } + + public String getText() + { + return text; + } + + public void writeAsEncodedUnicode(Writer writer) + throws XMLStreamException + { + try + { + writer.write(""); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + +} diff --git a/libjava/classpath/gnu/xml/stream/DTDImpl.java b/libjava/classpath/gnu/xml/stream/DTDImpl.java new file mode 100644 index 000000000..cf049d362 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/DTDImpl.java @@ -0,0 +1,114 @@ +/* DTDImpl.java -- + 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.xml.stream; + +import java.io.IOException; +import java.io.Writer; +import java.util.List; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.DTD; + +/** + * A DOCTYPE declaration event. + * + * @author Chris Burdess + */ +public class DTDImpl + extends XMLEventImpl + implements DTD +{ + + protected final String body; + protected final Object impl; + protected final List notations; + protected final List entities; + + protected DTDImpl(Location location, + String body, Object impl, List notations, List entities) + { + super(location); + this.body = body; + this.impl = impl; + this.notations = notations; + this.entities = entities; + } + + public int getEventType() + { + return DTD; + } + + public String getDocumentTypeDeclaration() + { + return body; + } + + public Object getProcessedDTD() + { + return impl; + } + + public List getNotations() + { + return notations; + } + + public List getEntities() + { + return entities; + } + + public void writeAsEncodedUnicode(Writer writer) + throws XMLStreamException + { + try + { + writer.write(""); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + +} diff --git a/libjava/classpath/gnu/xml/stream/EndDocumentImpl.java b/libjava/classpath/gnu/xml/stream/EndDocumentImpl.java new file mode 100644 index 000000000..13877c5c9 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/EndDocumentImpl.java @@ -0,0 +1,70 @@ +/* EndDocumentImpl.java -- + 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.xml.stream; + +import java.io.Writer; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.EndDocument; + +/** + * An end-document event. + * + * @author Chris Burdess + */ +public class EndDocumentImpl + extends XMLEventImpl + implements EndDocument +{ + + protected EndDocumentImpl(Location location) + { + super(location); + } + + public int getEventType() + { + return END_DOCUMENT; + } + + public void writeAsEncodedUnicode(Writer writer) + throws XMLStreamException + { + } + +} diff --git a/libjava/classpath/gnu/xml/stream/EndElementImpl.java b/libjava/classpath/gnu/xml/stream/EndElementImpl.java new file mode 100644 index 000000000..71f6aa0bc --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/EndElementImpl.java @@ -0,0 +1,107 @@ +/* EndElementImpl.java -- + 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.xml.stream; + +import java.io.IOException; +import java.io.Writer; +import java.util.Iterator; +import java.util.List; +import javax.xml.namespace.QName; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.EndElement; + +/** + * An end-element event. + * + * @author Chris Burdess + */ +public class EndElementImpl + extends XMLEventImpl + implements EndElement +{ + + protected final QName name; + protected final List namespaces; + + protected EndElementImpl(Location location, QName name, List namespaces) + { + super(location); + this.name = name; + this.namespaces = namespaces; + } + + public int getEventType() + { + return END_ELEMENT; + } + + public QName getName() + { + return name; + } + + public Iterator getNamespaces() + { + return namespaces.iterator(); + } + + public void writeAsEncodedUnicode(Writer writer) + throws XMLStreamException + { + try + { + writer.write(""); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + +} diff --git a/libjava/classpath/gnu/xml/stream/EntityDeclarationImpl.java b/libjava/classpath/gnu/xml/stream/EntityDeclarationImpl.java new file mode 100644 index 000000000..b6e33e8d2 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/EntityDeclarationImpl.java @@ -0,0 +1,163 @@ +/* EntityDeclarationImpl.java -- + 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.xml.stream; + +import java.io.IOException; +import java.io.Writer; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.EntityDeclaration; + +/** + * An entity declaration event. + * + * @author Chris Burdess + */ +public class EntityDeclarationImpl + extends XMLEventImpl + implements EntityDeclaration +{ + + protected final String publicId; + protected final String systemId; + protected final String name; + protected final String notationName; + protected final String replacementText; + protected final String baseUri; + + protected EntityDeclarationImpl(Location location, + String publicId, String systemId, + String name, String notationName, + String replacementText, String baseUri) + { + super(location); + this.publicId = publicId; + this.systemId = systemId; + this.name = name; + this.notationName = notationName; + this.replacementText = replacementText; + this.baseUri = baseUri; + } + + public int getEventType() + { + return ENTITY_DECLARATION; + } + + public String getPublicId() + { + return publicId; + } + + public String getSystemId() + { + return systemId; + } + + public String getName() + { + return name; + } + + public String getNotationName() + { + return notationName; + } + + public String getReplacementText() + { + return replacementText; + } + + public String getBaseURI() + { + return baseUri; + } + + public void writeAsEncodedUnicode(Writer writer) + throws XMLStreamException + { + try + { + writer.write(""); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + +} diff --git a/libjava/classpath/gnu/xml/stream/EntityReferenceImpl.java b/libjava/classpath/gnu/xml/stream/EntityReferenceImpl.java new file mode 100644 index 000000000..6f8a11c80 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/EntityReferenceImpl.java @@ -0,0 +1,101 @@ +/* EntityReferenceImpl.java -- + 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.xml.stream; + +import java.io.IOException; +import java.io.Writer; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.EntityDeclaration; +import javax.xml.stream.events.EntityReference; + +/** + * An entity reference event. + * + * @author Chris Burdess + */ +public class EntityReferenceImpl + extends XMLEventImpl + implements EntityReference +{ + + protected final EntityDeclaration decl; + protected final String name; + + protected EntityReferenceImpl(Location location, + EntityDeclaration decl, + String name) + { + super(location); + this.decl = decl; + this.name = name; + } + + public int getEventType() + { + return ENTITY_REFERENCE; + } + + public EntityDeclaration getDeclaration() + { + return decl; + } + + public String getName() + { + return name; + } + + public void writeAsEncodedUnicode(Writer writer) + throws XMLStreamException + { + try + { + writer.write('&'); + writer.write(name); + writer.write(';'); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + +} diff --git a/libjava/classpath/gnu/xml/stream/FilteredEventReader.java b/libjava/classpath/gnu/xml/stream/FilteredEventReader.java new file mode 100644 index 000000000..1ddb469df --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/FilteredEventReader.java @@ -0,0 +1,114 @@ +/* FilteredEventReader.java -- + 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.xml.stream; + +import javax.xml.stream.EventFilter; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.XMLEvent; +import javax.xml.stream.util.EventReaderDelegate; + +class FilteredEventReader + extends EventReaderDelegate +{ + + final EventFilter filter; + + FilteredEventReader(XMLEventReader reader, EventFilter filter) + { + super(reader); + this.filter = filter; + } + + public boolean hasNext() + { + // XXX ??? + return super.hasNext(); + } + + public XMLEvent nextEvent() + throws XMLStreamException + { + XMLEvent ret; + do + { + ret = super.nextEvent(); + } + while (!filter.accept(ret)); + return ret; + } + + public Object next() + { + try + { + return nextEvent(); + } + catch (XMLStreamException e) + { + RuntimeException e2 = new RuntimeException(); + e2.initCause(e); + throw e2; + } + } + + public XMLEvent peek() + throws XMLStreamException + { + XMLEvent ret; + do + { + ret = super.peek(); + } + while (!filter.accept(ret)); + return ret; + } + + public XMLEvent nextTag() + throws XMLStreamException + { + XMLEvent ret; + do + { + ret = super.nextTag(); + } + while (!filter.accept(ret)); + return ret; + } + +} diff --git a/libjava/classpath/gnu/xml/stream/FilteredStreamReader.java b/libjava/classpath/gnu/xml/stream/FilteredStreamReader.java new file mode 100644 index 000000000..62d96488e --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/FilteredStreamReader.java @@ -0,0 +1,90 @@ +/* FilteredStreamReader.java -- + 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.xml.stream; + +import javax.xml.stream.StreamFilter; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.util.StreamReaderDelegate; + +class FilteredStreamReader + extends StreamReaderDelegate +{ + + final XMLStreamReader reader; + final StreamFilter filter; + + FilteredStreamReader(XMLStreamReader reader, StreamFilter filter) + { + super(reader); + this.reader = reader; + this.filter = filter; + } + + public boolean hasNext() + throws XMLStreamException + { + // XXX ??? + return super.hasNext(); + } + + public int next() + throws XMLStreamException + { + int ret; + do + { + ret = super.next(); + } + while (!filter.accept(reader)); + return ret; + } + + public int nextTag() + throws XMLStreamException + { + int ret; + do + { + ret = super.nextTag(); + } + while (!filter.accept(reader)); + return ret; + } + +} diff --git a/libjava/classpath/gnu/xml/stream/NamespaceImpl.java b/libjava/classpath/gnu/xml/stream/NamespaceImpl.java new file mode 100644 index 000000000..241f980b6 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/NamespaceImpl.java @@ -0,0 +1,137 @@ +/* NamespaceImpl.java -- + 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.xml.stream; + +import java.io.IOException; +import java.io.Writer; +import javax.xml.namespace.QName; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Namespace; + +/** + * A namespace declaration event. + * + * @author Chris Burdess + */ +public class NamespaceImpl + extends XMLEventImpl + implements Namespace +{ + + protected final String prefix; + protected final String uri; + protected final boolean specified; + + protected NamespaceImpl(Location location, String prefix, String uri, + boolean specified) + { + super(location); + this.prefix = prefix; + this.uri = uri; + this.specified = specified; + } + + public int getEventType() + { + return NAMESPACE; + } + + public String getPrefix() + { + return prefix; + } + + public String getNamespaceURI() + { + return uri; + } + + public boolean isSpecified() + { + return specified; + } + + public QName getName() + { + if (isDefaultNamespaceDeclaration()) + return new QName("", "xmlns", null); + else + return new QName("", prefix, "xmlns"); + } + + public String getDTDType() + { + return "CDATA"; + } + + public String getValue() + { + return uri; + } + + public boolean isDefaultNamespaceDeclaration() + { + return (prefix == null || "".equals(prefix)); + } + + public void writeAsEncodedUnicode(Writer writer) + throws XMLStreamException + { + try + { + writer.write("xmlns"); + if (prefix != null && !"".equals(prefix)) + { + writer.write(':'); + writer.write(prefix); + } + writer.write('='); + writer.write('"'); + writer.write(encode(uri, true)); + writer.write('"'); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + +} diff --git a/libjava/classpath/gnu/xml/stream/NotationDeclarationImpl.java b/libjava/classpath/gnu/xml/stream/NotationDeclarationImpl.java new file mode 100644 index 000000000..a338237ee --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/NotationDeclarationImpl.java @@ -0,0 +1,125 @@ +/* NotationDeclarationImpl.java -- + 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.xml.stream; + +import java.io.IOException; +import java.io.Writer; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.NotationDeclaration; + +/** + * A notation declaration event. + * + * @author Chris Burdess + */ +public class NotationDeclarationImpl + extends XMLEventImpl + implements NotationDeclaration +{ + + protected final String name; + protected final String publicId; + protected final String systemId; + + protected NotationDeclarationImpl(Location location, + String name, String publicId, + String systemId) + { + super(location); + this.name = name; + this.publicId = publicId; + this.systemId = systemId; + } + + public int getEventType() + { + return NOTATION_DECLARATION; + } + + public String getName() + { + return name; + } + + public String getPublicId() + { + return publicId; + } + + public String getSystemId() + { + return systemId; + } + + public void writeAsEncodedUnicode(Writer writer) + throws XMLStreamException + { + try + { + writer.write("'); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + +} diff --git a/libjava/classpath/gnu/xml/stream/ProcessingInstructionImpl.java b/libjava/classpath/gnu/xml/stream/ProcessingInstructionImpl.java new file mode 100644 index 000000000..4ce0badc8 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/ProcessingInstructionImpl.java @@ -0,0 +1,104 @@ +/* ProcessingInstructionImpl.java -- + 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.xml.stream; + +import java.io.IOException; +import java.io.Writer; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.ProcessingInstruction; + +/** + * A processing instruction event. + * + * @author Chris Burdess + */ +public class ProcessingInstructionImpl + extends XMLEventImpl + implements ProcessingInstruction +{ + + protected final String target; + protected final String data; + + protected ProcessingInstructionImpl(Location location, + String target, String data) + { + super(location); + this.target = target; + this.data = data; + } + + public int getEventType() + { + return PROCESSING_INSTRUCTION; + } + + public String getTarget() + { + return target; + } + + public String getData() + { + return data; + } + + public void writeAsEncodedUnicode(Writer writer) + throws XMLStreamException + { + try + { + writer.write(""); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + +} diff --git a/libjava/classpath/gnu/xml/stream/SAXParser.java b/libjava/classpath/gnu/xml/stream/SAXParser.java new file mode 100644 index 000000000..b71d98ed3 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/SAXParser.java @@ -0,0 +1,1041 @@ +/* SAXParser.java -- + Copyright (C) 2005, 2006, 2007 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.stream; + +import java.io.InputStream; +import java.io.IOException; +import java.io.Reader; +import java.net.URL; +import java.util.Iterator; +import java.util.Map; +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import javax.xml.stream.Location; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLReporter; +import javax.xml.stream.XMLResolver; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import org.xml.sax.ContentHandler; +import org.xml.sax.DTDHandler; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.Parser; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.SAXParseException; +import org.xml.sax.XMLReader; +import org.xml.sax.ext.Attributes2; +import org.xml.sax.ext.DeclHandler; +import org.xml.sax.ext.LexicalHandler; +import org.xml.sax.ext.Locator2; + +/** + * JAXP SAX parser using an underlying StAX parser. + * This parser supports the following additional SAX features and + * properties: + * + * + * + * + * + * + * + * + * + * + * + * + *
      Features
      http://gnu.org/sax/features/xml-baseread/writeIndicates or sets whether XML Base processing is enabled
      Properties
      http://gnu.org/sax/properties/base-uriread-onlyStringReturns the base URI of the current event
      http://gnu.org/sax/properties/document-xml-encodingread-onlyStringReturns the encoding specified in the XML declaration
      + * + * @author Chris Burdess + */ +public class SAXParser + extends javax.xml.parsers.SAXParser + implements XMLReader, Attributes2, Locator2, XMLReporter, XMLResolver +{ + + ContentHandler contentHandler; + DeclHandler declHandler; + DTDHandler dtdHandler; + EntityResolver entityResolver; + ErrorHandler errorHandler; + LexicalHandler lexicalHandler; + + boolean validating = false; + boolean namespaceAware = true; + boolean xIncludeAware = false; + boolean stringInterning = true; + boolean coalescing = true; + boolean replaceERefs = true; + boolean externalEntities = true; + boolean supportDTD = true; + boolean baseAware = true; + + XMLParser parser; + XMLStreamReader reader; + String encoding; + String xmlVersion; + boolean xmlStandalone; + String xmlEncoding; + String baseURI; + + public SAXParser() + { + } + + SAXParser(boolean validating, boolean namespaceAware, boolean xIncludeAware) + { + this.validating = validating; + this.namespaceAware = namespaceAware; + this.xIncludeAware = xIncludeAware; + } + + // -- SAXParser -- + + public Parser getParser() + throws SAXException + { + return null; + } + + public XMLReader getXMLReader() + throws SAXException + { + return this; + } + + public boolean isNamespaceAware() + { + return namespaceAware; + } + + public boolean isValidating() + { + return validating; + } + + public void setProperty(String name, Object value) + throws SAXNotRecognizedException, SAXNotSupportedException + { + if (parser != null) + throw new IllegalStateException("parsing in progress"); + final String FEATURES = "http://xml.org/sax/features/"; + final String PROPERTIES = "http://xml.org/sax/properties/"; + final String GNU_FEATURES = "http://gnu.org/sax/features/"; + if ((FEATURES + "namespaces").equals(name)) + namespaceAware = Boolean.TRUE.equals(value); + else if ((FEATURES + "namespace-prefixes").equals(name)) + { + // NOOP + } + else if ((FEATURES + "string-interning").equals(name)) + stringInterning = Boolean.TRUE.equals(value); + else if ((FEATURES + "use-attributes2").equals(name)) + { + // NOOP + } + else if ((FEATURES + "validation").equals(name)) + validating = Boolean.TRUE.equals(value); + else if ((FEATURES + "external-general-entities").equals(name)) + externalEntities = Boolean.TRUE.equals(value); + else if ((FEATURES + "external-parameter-entities").equals(name)) + externalEntities = Boolean.TRUE.equals(value); + else if ((PROPERTIES + "declaration-handler").equals(name)) + declHandler = (DeclHandler) value; + else if ((PROPERTIES + "lexical-handler").equals(name)) + lexicalHandler = (LexicalHandler) value; + else if ((GNU_FEATURES + "xml-base").equals(name)) + baseAware = Boolean.TRUE.equals(value); + else if ((GNU_FEATURES + "coalescing").equals(name)) + coalescing = Boolean.TRUE.equals(value); + else + throw new SAXNotSupportedException(name); + } + + public Object getProperty(String name) + throws SAXNotRecognizedException, SAXNotSupportedException + { + final String FEATURES = "http://xml.org/sax/features/"; + final String PROPERTIES = "http://xml.org/sax/properties/"; + final String GNU_FEATURES = "http://gnu.org/sax/features/"; + final String GNU_PROPERTIES = "http://gnu.org/sax/properties/"; + if ((GNU_FEATURES + "base-uri").equals(name)) + return baseURI; + if ((FEATURES + "is-standalone").equals(name)) + return xmlStandalone ? Boolean.TRUE : Boolean.FALSE; + if ((FEATURES + "namespaces").equals(name)) + return namespaceAware ? Boolean.TRUE : Boolean.FALSE; + if ((FEATURES + "namespace-prefixes").equals(name)) + return Boolean.TRUE; + if ((FEATURES + "string-interning").equals(name)) + return stringInterning ? Boolean.TRUE : Boolean.FALSE; + if ((FEATURES + "use-attributes2").equals(name)) + return Boolean.TRUE; + if ((FEATURES + "use-locator2").equals(name)) + return Boolean.TRUE; + if ((FEATURES + "use-entity-resolver2").equals(name)) + return Boolean.FALSE; + if ((FEATURES + "validation").equals(name)) + return validating ? Boolean.TRUE : Boolean.FALSE; + if ((FEATURES + "external-general-entities").equals(name)) + return externalEntities ? Boolean.TRUE : Boolean.FALSE; + if ((FEATURES + "external-parameter-entities").equals(name)) + return externalEntities ? Boolean.TRUE : Boolean.FALSE; + if ((FEATURES + "xml-1.1").equals(name)) + return Boolean.TRUE; + if ((PROPERTIES + "declaration-handler").equals(name)) + return declHandler; + if ((PROPERTIES + "document-xml-version").equals(name)) + return xmlVersion; + if ((PROPERTIES + "lexical-handler").equals(name)) + return lexicalHandler; + if ((GNU_FEATURES + "xml-base").equals(name)) + return baseAware ? Boolean.TRUE : Boolean.FALSE; + if ((GNU_PROPERTIES + "document-xml-encoding").equals(name)) + return xmlEncoding; + throw new SAXNotRecognizedException(name); + } + + public boolean isXIncludeAware() + { + return xIncludeAware; + } + + public void reset() + { + parser = null; + encoding = null; + xmlVersion = null; + xmlStandalone = false; + } + + // -- XMLReader -- + + public boolean getFeature(String name) + throws SAXNotRecognizedException, SAXNotSupportedException + { + Object ret = getProperty(name); + if (ret instanceof Boolean) + return ((Boolean) ret).booleanValue(); + throw new SAXNotSupportedException(name); + } + + public void setFeature(String name, boolean value) + throws SAXNotRecognizedException, SAXNotSupportedException + { + setProperty(name, value ? Boolean.TRUE : Boolean.FALSE); + } + + public void setEntityResolver(EntityResolver resolver) + { + entityResolver = resolver; + } + + public EntityResolver getEntityResolver() + { + return entityResolver; + } + + public void setDTDHandler(DTDHandler handler) + { + dtdHandler = handler; + } + + public DTDHandler getDTDHandler() + { + return dtdHandler; + } + + public void setContentHandler(ContentHandler handler) + { + contentHandler = handler; + } + + public ContentHandler getContentHandler() + { + return contentHandler; + } + + public void setErrorHandler(ErrorHandler handler) + { + errorHandler = handler; + } + + public ErrorHandler getErrorHandler() + { + return errorHandler; + } + + public synchronized void parse(InputSource input) + throws IOException, SAXException + { + reset(); + String systemId = input.getSystemId(); + InputStream in = input.getByteStream(); + boolean opened = false; + if (in != null) + parser = new XMLParser(in, systemId, + validating, + namespaceAware, + coalescing, + replaceERefs, + externalEntities, + supportDTD, + baseAware, + stringInterning, + true, + this, + this); + else + { + Reader r = input.getCharacterStream(); + if (r != null) + parser = new XMLParser(r, systemId, + validating, + namespaceAware, + coalescing, + replaceERefs, + externalEntities, + supportDTD, + baseAware, + stringInterning, + true, + this, + this); + } + if (parser == null) + { + if (systemId == null) + throw new SAXException("No stream or system ID specified"); + systemId = XMLParser.absolutize(null, systemId); + in = new URL(systemId).openStream(); + opened = true; + parser = new XMLParser(in, systemId, + validating, + namespaceAware, + coalescing, + replaceERefs, + externalEntities, + supportDTD, + baseAware, + stringInterning, + true, + this, + this); + } + reader = parser; + baseURI = systemId; + + if (xIncludeAware) + reader = new XIncludeFilter(parser, systemId, namespaceAware, + validating, true); + + if (contentHandler != null) + contentHandler.setDocumentLocator(this); + boolean startDocumentDone = false; + try + { + while (parser.hasNext()) + { + int event = parser.next(); + if (baseAware) + baseURI = parser.getXMLBase(); + switch (event) + { + case XMLStreamConstants.CHARACTERS: + if (contentHandler != null) + { + char[] b = reader.getTextCharacters(); + contentHandler.characters(b, 0, b.length); + } + break; + case XMLStreamConstants.SPACE: + if (contentHandler != null) + { + char[] b = reader.getTextCharacters(); + if (isIgnorableWhitespace(parser, b, false)) + contentHandler.ignorableWhitespace(b, 0, b.length); + else + contentHandler.characters(b, 0, b.length); + } + break; + case XMLStreamConstants.CDATA: + if (lexicalHandler != null) + lexicalHandler.startCDATA(); + if (contentHandler != null) + { + char[] b = reader.getTextCharacters(); + if (isIgnorableWhitespace(parser, b, true)) + contentHandler.ignorableWhitespace(b, 0, b.length); + else + contentHandler.characters(b, 0, b.length); + } + if (lexicalHandler != null) + lexicalHandler.endCDATA(); + break; + case XMLStreamConstants.START_ELEMENT: + if (contentHandler != null) + { + QName name = reader.getName(); + String uri = name.getNamespaceURI(); + String localName = name.getLocalPart(); + String prefix = name.getPrefix(); + String qName = localName; + if (!"".equals(prefix)) + qName = prefix + ":" + localName; + if (!namespaceAware) + { + uri = ""; + localName = ""; + } + else + { + int nc = reader.getNamespaceCount(); + for (int i = 0; i < nc; i++) + { + String nsuri = reader.getNamespaceURI(i); + String nsprefix = reader.getNamespacePrefix(i); + if ("xml".equals(nsprefix)) + continue; + contentHandler.startPrefixMapping(nsprefix, nsuri); + } + } + contentHandler.startElement(uri, localName, qName, this); + } + break; + case XMLStreamConstants.END_ELEMENT: + if (contentHandler != null) + { + QName name = reader.getName(); + String uri = name.getNamespaceURI(); + String localName = name.getLocalPart(); + String prefix = name.getPrefix(); + String qName = localName; + if (!"".equals(prefix)) + qName = prefix + ":" + localName; + if (!namespaceAware) + { + uri = ""; + localName = ""; + } + contentHandler.endElement(uri, localName, qName); + if (namespaceAware) + { + int nc = reader.getNamespaceCount(); + for (int i = 0; i < nc; i++) + { + String nsprefix = reader.getNamespacePrefix(i); + if ("xml".equals(nsprefix)) + continue; + contentHandler.endPrefixMapping(nsprefix); + } + } + } + break; + case XMLStreamConstants.COMMENT: + if (lexicalHandler != null) + { + char[] b = reader.getTextCharacters(); + lexicalHandler.comment(b, 0, b.length); + } + break; + case XMLStreamConstants.PROCESSING_INSTRUCTION: + if (contentHandler != null) + { + String target = reader.getPITarget(); + String data = reader.getPIData(); + if (data == null) + data = ""; + contentHandler.processingInstruction(target, data); + } + break; + case XMLParser.START_ENTITY: + if (lexicalHandler != null) + { + String name = reader.getText(); + lexicalHandler.startEntity(name); + } + break; + case XMLParser.END_ENTITY: + if (lexicalHandler != null) + { + String name = reader.getText(); + lexicalHandler.endEntity(name); + } + break; + case XMLStreamConstants.START_DOCUMENT: + encoding = reader.getEncoding(); + xmlVersion = reader.getVersion(); + xmlStandalone = reader.isStandalone(); + xmlEncoding = reader.getCharacterEncodingScheme(); + if (contentHandler != null) + contentHandler.startDocument(); + startDocumentDone = true; + break; + case XMLStreamConstants.END_DOCUMENT: + if (contentHandler != null) + contentHandler.endDocument(); + break; + case XMLStreamConstants.DTD: + XMLParser.Doctype doctype = parser.doctype; + if (lexicalHandler != null) + { + String rootName = doctype.rootName; + String publicId = doctype.publicId; + String systemId2 = doctype.systemId; + lexicalHandler.startDTD(rootName, publicId, systemId2); + } + for (Iterator i = doctype.entryIterator(); i.hasNext(); ) + { + String entry = (String) i.next(); + char c = entry.charAt(0); + String name = entry.substring(1); + if ('E' == c) + { + // Element decl + if (declHandler != null) + { + XMLParser.ContentModel model = + doctype.getElementModel(name); + declHandler.elementDecl(name, model.text); + } + } + else if ('A' == c) + { + // Attlist decl + if (declHandler != null) + { + for (Iterator j = doctype.attlistIterator(name); + j.hasNext(); ) + { + Map.Entry att = (Map.Entry) j.next(); + String aname = (String) att.getKey(); + XMLParser.AttributeDecl decl = + (XMLParser.AttributeDecl) att.getValue(); + String type = decl.type; + String value = decl.value; + String mode = null; + switch (decl.valueType) + { + case XMLParser.ATTRIBUTE_DEFAULT_FIXED: + mode = "#FIXED"; + break; + case XMLParser.ATTRIBUTE_DEFAULT_REQUIRED: + mode = "#REQUIRED"; + break; + case XMLParser.ATTRIBUTE_DEFAULT_IMPLIED: + mode = "#IMPLIED"; + break; + } + declHandler.attributeDecl(name, aname, + type, mode, value); + } + } + } + else if ('e' == c) + { + // Entity decl + Object entity = doctype.getEntity(name); + if (entity instanceof String) + { + if (declHandler != null) + declHandler.internalEntityDecl(name, + (String) entity); + } + else + { + XMLParser.ExternalIds ids = + (XMLParser.ExternalIds) entity; + if (ids.notationName != null) + { + if (dtdHandler != null) + { + String pub = ids.publicId; + String url = ids.systemId; + String not = ids.notationName; + dtdHandler.unparsedEntityDecl(name, + pub, + url, + not); + } + } + else + { + if (declHandler != null) + { + String pub = ids.publicId; + String url = ids.systemId; + declHandler.externalEntityDecl(name, + pub, + url); + } + } + } + } + else if ('n' == c) + { + // Notation decl + if (dtdHandler != null) + { + XMLParser.ExternalIds ids = + doctype.getNotation(name); + String pub = ids.publicId; + String url = ids.systemId; + dtdHandler.notationDecl(name, pub, url); + } + } + else if ('c' == c) + { + // Comment + if (lexicalHandler != null) + { + String comment = doctype.getComment(name); + char[] b = comment.toCharArray(); + lexicalHandler.comment(b, 0, b.length); + } + } + else if ('p' == c) + { + // Processing instruction + if (contentHandler != null) + { + String[] pi = doctype.getPI(name); + String target = pi[0]; + String data = pi[1]; + if (data == null) + data = ""; + contentHandler.processingInstruction(target, data); + } + } + } + if (lexicalHandler != null) + lexicalHandler.endDTD(); + } + } + reset(); + if (opened) + in.close(); + } + catch (Exception e) + { + SAXParseException e2 = new SAXParseException(e.getMessage(), this); + e2.initCause(e); + try + { + if (!startDocumentDone && contentHandler != null) + contentHandler.startDocument(); + if (errorHandler != null) + errorHandler.fatalError(e2); + if (contentHandler != null) + contentHandler.endDocument(); + } + catch (SAXException sex) + { + // Ignored, we will rethrow the original exception. + } + reset(); + if (opened) + in.close(); + if (e instanceof SAXException) + throw (SAXException) e; + if (e instanceof IOException) + throw (IOException) e; + else + throw e2; + } + } + + /** + * Indicates whether the specified characters are ignorable whitespace. + */ + private boolean isIgnorableWhitespace(XMLParser reader, char[] b, + boolean testCharacters) + throws XMLStreamException + { + XMLParser.Doctype doctype = reader.doctype; + if (doctype == null) + return false; + String currentElement = reader.getCurrentElement(); + // check for xml:space + int ac = reader.getAttributeCount(); + for (int i = 0; i < ac; i++) + { + QName aname = reader.getAttributeName(i); + if ("space".equals(aname.getLocalPart()) && + XMLConstants.XML_NS_URI.equals(aname.getNamespaceURI())) + { + if ("preserve".equals(reader.getAttributeValue(i))) + return false; + } + } + XMLParser.ContentModel model = doctype.getElementModel(currentElement); + if (model == null || model.type != XMLParser.ContentModel.ELEMENT) + return false; + if (model.external && xmlStandalone) + return false; + boolean white = true; + if (testCharacters) + { + for (int i = 0; i < b.length; i++) + { + if (b[i] != ' ' && b[i] != '\t' && b[i] != '\n' && b[i] != '\r') + { + white = false; + break; + } + } + } + return white; + } + + public void parse(String systemId) + throws IOException, SAXException + { + parse(new InputSource(systemId)); + } + + // -- Attributes2 -- + + public int getIndex(String qName) + { + int len = reader.getAttributeCount(); + for (int i = 0; i < len; i++) + { + QName q = reader.getAttributeName(i); + String localName = q.getLocalPart(); + String prefix = q.getPrefix(); + String qn = ("".equals(prefix)) ? localName : prefix + ":" + localName; + if (qName.equals(qn)) + return i; + } + return -1; + } + + public int getIndex(String uri, String localName) + { + int len = reader.getAttributeCount(); + for (int i = 0; i < len; i++) + { + QName q = reader.getAttributeName(i); + String ln = q.getLocalPart(); + String u = q.getNamespaceURI(); + if (u == null && uri != null) + continue; + if (u != null && !u.equals(uri)) + continue; + if (ln.equals(localName)) + return i; + } + return -1; + } + + public int getLength() + { + return reader.getAttributeCount(); + } + + public String getLocalName(int index) + { + return reader.getAttributeLocalName(index); + } + + public String getQName(int index) + { + QName q = reader.getAttributeName(index); + String localName = q.getLocalPart(); + String prefix = q.getPrefix(); + return ("".equals(prefix)) ? localName : prefix + ":" + localName; + } + + public String getType(int index) + { + String ret = reader.getAttributeType(index); + // SAX doesn't permit ENUMERATION? + return ("ENUMERATION".equals(ret)) ? "NMTOKEN" : ret; + } + + public String getType(String qName) + { + int index = getIndex(qName); + return (index == -1) ? null : getType(index); + } + + public String getType(String uri, String localName) + { + int index = getIndex(uri, localName); + return (index == -1) ? null : getType(index); + } + + public String getURI(int index) + { + String ret = reader.getAttributeNamespace(index); + return (ret == null) ? "" : ret; + } + + public String getValue(int index) + { + return reader.getAttributeValue(index); + } + + public String getValue(String qName) + { + int index = getIndex(qName); + return (index == -1) ? null : getValue(index); + } + + public String getValue(String uri, String localName) + { + int index = getIndex(uri, localName); + return (index == -1) ? null : getValue(index); + } + + public boolean isDeclared(int index) + { + return parser.isAttributeDeclared(index); + } + + public boolean isDeclared(String qName) + { + int index = getIndex(qName); + return (index == -1) ? false : isDeclared(index); + } + + public boolean isDeclared(String uri, String localName) + { + int index = getIndex(uri, localName); + return (index == -1) ? false : isDeclared(index); + } + + public boolean isSpecified(int index) + { + return reader.isAttributeSpecified(index); + } + + public boolean isSpecified(String qName) + { + int index = getIndex(qName); + return (index == -1) ? false : isSpecified(index); + } + + public boolean isSpecified(String uri, String localName) + { + int index = getIndex(uri, localName); + return (index == -1) ? false : isSpecified(index); + } + + // -- Locator2 -- + + public int getColumnNumber() + { + Location l = reader.getLocation(); + return l.getColumnNumber(); + } + + public int getLineNumber() + { + Location l = reader.getLocation(); + return l.getLineNumber(); + } + + public String getPublicId() + { + Location l = reader.getLocation(); + return l.getPublicId(); + } + + public String getSystemId() + { + Location l = reader.getLocation(); + return l.getSystemId(); + } + + public String getEncoding() + { + return encoding; + } + + public String getXMLVersion() + { + return xmlVersion; + } + + // -- XMLResolver -- + + public Object resolveEntity(String publicId, String systemId, + String baseURI, String namespace) + throws XMLStreamException + { + if (entityResolver != null) + { + try + { + InputSource input = + entityResolver.resolveEntity(publicId, systemId); + if (input != null) + { + 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) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + return null; + } + + public XMLEventReader resolveAsXMLEventReader(String uri) + throws XMLStreamException + { + // unused + return null; + } + + public XMLStreamReader resolveAsXMLStreamReader(String uri) + throws XMLStreamException + { + // unused + return null; + } + + // -- XMLReporter -- + + public void report(String message, String errorType, + Object relatedInformation, Location location) + throws XMLStreamException + { + if (errorHandler != null) + { + try + { + errorHandler.warning(new SAXParseException(message, this)); + } + catch (SAXException e) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + } + + public static void main(String[] args) + throws Exception + { + boolean validating = false; + boolean namespaceAware = false; + boolean xIncludeAware = false; + boolean expectCallbackClass = false; + String callbackClass = null; + int pos = 0; + while (pos < args.length && (args[pos].startsWith("-") || expectCallbackClass)) + { + if ("-x".equals(args[pos])) + xIncludeAware = true; + else if ("-v".equals(args[pos])) + validating = true; + else if ("-n".equals(args[pos])) + namespaceAware = true; + else if ("-c".equals(args[pos])) + expectCallbackClass = true; + else if (expectCallbackClass) + { + callbackClass = args[pos]; + expectCallbackClass = false; + } + pos++; + } + if (pos >= args.length || expectCallbackClass) + { + System.out.println("Syntax: SAXParser [-n] [-v] [-x] [-c ] [ [...]]"); + System.out.println("\t-n: use namespace aware mode"); + System.out.println("\t-v: use validating parser"); + System.out.println("\t-x: use XInclude aware mode"); + System.out.println("\t-c : use specified class as callback handler (must have a no-arg public constructor)"); + System.exit(2); + } + while (pos < args.length) + { + ContentHandler handler = null; + if (callbackClass != null) + { + Class t = Class.forName(callbackClass); + handler = (ContentHandler) t.newInstance(); + } + else + handler = new org.xml.sax.helpers.DefaultHandler(); + SAXParser parser = new SAXParser(validating, namespaceAware, + xIncludeAware); + InputSource input = new InputSource(args[pos]); + java.io.FileReader fr = new java.io.FileReader(args[pos]); + input.setCharacterStream(fr); + try + { + XMLReader reader = parser.getXMLReader(); + reader.setContentHandler(handler); + reader.parse(input); + } + finally + { + fr.close(); + } + pos++; + } + } + +} diff --git a/libjava/classpath/gnu/xml/stream/SAXParserFactory.java b/libjava/classpath/gnu/xml/stream/SAXParserFactory.java new file mode 100644 index 000000000..ebaeb3cb2 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/SAXParserFactory.java @@ -0,0 +1,104 @@ +/* SAXParserFactory.java -- + 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.xml.stream; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import javax.xml.parsers.ParserConfigurationException; + +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; + +/** + * SAX parser factory providing a SAX compatibility layer on top of StAX. + * + * @author Chris Burdess + */ +public class SAXParserFactory + extends javax.xml.parsers.SAXParserFactory +{ + + static final Set FEATURE_NAMES = new HashSet(); + static + { + FEATURE_NAMES.add("http://xml.org/sax/features/namespaces"); + FEATURE_NAMES.add("http://xml.org/sax/features/string-interning"); + FEATURE_NAMES.add("http://xml.org/sax/features/validation"); + } + + Map features = new HashMap(); + + public javax.xml.parsers.SAXParser newSAXParser() + throws ParserConfigurationException, SAXException + { + boolean validating = isValidating(); + boolean namespaceAware = isNamespaceAware(); + boolean xIncludeAware = isXIncludeAware(); + SAXParser ret = new SAXParser(validating, namespaceAware, xIncludeAware); + for (Iterator i = features.entrySet().iterator(); i.hasNext(); ) + { + Map.Entry entry = (Map.Entry) i.next(); + String name = (String) entry.getKey(); + Boolean value = (Boolean) entry.getValue(); + ret.setFeature(name, value.booleanValue()); + } + return ret; + } + + public void setFeature(String name, boolean value) + throws ParserConfigurationException, SAXNotRecognizedException, SAXNotSupportedException + { + if (!FEATURE_NAMES.contains(name)) + throw new SAXNotSupportedException(name); + features.put(name, value ? Boolean.TRUE : Boolean.FALSE); + } + + public boolean getFeature(String name) + throws ParserConfigurationException, SAXNotRecognizedException, SAXNotSupportedException + { + if (!FEATURE_NAMES.contains(name)) + throw new SAXNotSupportedException(name); + Boolean value = (Boolean) features.get(name); + return (value == null) ? false : value.booleanValue(); + } + +} diff --git a/libjava/classpath/gnu/xml/stream/StartDocumentImpl.java b/libjava/classpath/gnu/xml/stream/StartDocumentImpl.java new file mode 100644 index 000000000..d2e590cfc --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/StartDocumentImpl.java @@ -0,0 +1,143 @@ +/* StartDocumentImpl.java -- + 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.xml.stream; + +import java.io.IOException; +import java.io.Writer; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.StartDocument; + +/** + * A start-document event. + * + * @author Chris Burdess + */ +public class StartDocumentImpl + extends XMLEventImpl + implements StartDocument +{ + + protected final String systemId; + protected final String encoding; + protected final String xmlVersion; + protected final boolean xmlStandalone; + protected final boolean standaloneDeclared; + protected final boolean encodingDeclared; + + protected StartDocumentImpl(Location location, + String systemId, String encoding, + String xmlVersion, boolean xmlStandalone, + boolean standaloneDeclared, + boolean encodingDeclared) + { + super(location); + this.systemId = systemId; + this.encoding = encoding; + this.xmlVersion = xmlVersion; + this.xmlStandalone = xmlStandalone; + this.standaloneDeclared = standaloneDeclared; + this.encodingDeclared = encodingDeclared; + } + + public int getEventType() + { + return START_DOCUMENT; + } + + public String getSystemId() + { + return systemId; + } + + public String getCharacterEncodingScheme() + { + return encoding; + } + + public boolean encodingSet() + { + return encodingDeclared; + } + + public boolean isStandalone() + { + return xmlStandalone; + } + + public boolean standaloneSet() + { + return standaloneDeclared; + } + + public String getVersion() + { + return xmlVersion; + } + + public void writeAsEncodedUnicode(Writer writer) + throws XMLStreamException + { + try + { + writer.write(""); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + +} diff --git a/libjava/classpath/gnu/xml/stream/StartElementImpl.java b/libjava/classpath/gnu/xml/stream/StartElementImpl.java new file mode 100644 index 000000000..66e68d560 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/StartElementImpl.java @@ -0,0 +1,152 @@ +/* StartElementImpl.java -- + 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.xml.stream; + +import java.io.IOException; +import java.io.Writer; +import java.util.Iterator; +import java.util.List; +import javax.xml.namespace.NamespaceContext; +import javax.xml.namespace.QName; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Attribute; +import javax.xml.stream.events.Namespace; +import javax.xml.stream.events.StartElement; + +/** + * A start-element event. + * + * @author Chris Burdess + */ +public class StartElementImpl + extends XMLEventImpl + implements StartElement +{ + + protected final QName name; + protected final List attributes; + protected final List namespaces; + protected final NamespaceContext namespaceContext; + + protected StartElementImpl(Location location, + QName name, List attributes, List namespaces, + NamespaceContext namespaceContext) + { + super(location); + this.name = name; + this.attributes = attributes; + this.namespaces = namespaces; + this.namespaceContext = namespaceContext; + } + + public int getEventType() + { + return START_ELEMENT; + } + + public QName getName() + { + return name; + } + + public Iterator getAttributes() + { + return attributes.iterator(); + } + + public Iterator getNamespaces() + { + return namespaces.iterator(); + } + + public Attribute getAttributeByName(QName name) + { + for (Iterator i = attributes.iterator(); i.hasNext(); ) + { + Attribute attr = (Attribute) i.next(); + if (name.equals(attr.getName())) + return attr; + } + return null; + } + + public NamespaceContext getNamespaceContext() + { + return namespaceContext; + } + + public String getNamespaceURI(String prefix) + { + return namespaceContext.getNamespaceURI(prefix); + } + + public void writeAsEncodedUnicode(Writer writer) + throws XMLStreamException + { + try + { + writer.write('<'); + String prefix = name.getPrefix(); + if (prefix != null && !"".equals(prefix)) + { + writer.write(prefix); + writer.write(':'); + } + writer.write(name.getLocalPart()); + for (Iterator i = namespaces.iterator(); i.hasNext(); ) + { + writer.write(' '); + ((Namespace) i.next()).writeAsEncodedUnicode(writer); + } + for (Iterator i = attributes.iterator(); i.hasNext(); ) + { + writer.write(' '); + ((Attribute) i.next()).writeAsEncodedUnicode(writer); + } + writer.write('>'); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + +} diff --git a/libjava/classpath/gnu/xml/stream/UnicodeReader.java b/libjava/classpath/gnu/xml/stream/UnicodeReader.java new file mode 100644 index 000000000..aa2a95422 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/UnicodeReader.java @@ -0,0 +1,205 @@ +/* UnicodeReader.java -- + 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.xml.stream; + +import java.io.IOException; +import java.io.Reader; + +/** + * A reader that converts UTF-16 characters to Unicode code points. + * + * @author Chris Burdess + */ +public class UnicodeReader +{ + + final Reader in; + + UnicodeReader(Reader in) + { + this.in = in; + } + + public void mark(int limit) + throws IOException + { + in.mark(limit * 2); + } + + public void reset() + throws IOException + { + in.reset(); + } + + public int read() + throws IOException + { + int ret = in.read(); + if (ret == -1) + return ret; + if (ret >= 0xd800 && ret < 0xdc00) + { + // Unicode surrogate? + int low = in.read(); + if (low >= 0xdc00 && low < 0xe000) + ret = Character.toCodePoint((char) ret, (char) low); + else + throw new IOException("unpaired surrogate: U+" + + Integer.toHexString(ret)); + } + else if (ret >= 0xdc00 && ret < 0xe000) + throw new IOException("unpaired surrogate: U+" + + Integer.toHexString(ret)); + return ret; + } + + public int read(int[] buf, int off, int len) + throws IOException + { + if (len == 0) + return 0; + char[] b2 = new char[len]; + int ret = in.read(b2, 0, len); + if (ret <= 0) + return ret; + int l = ret - 1; + int i = 0, j = off; + for (; i < l; i++) + { + char c = b2[i]; + if (c >= 0xd800 && c < 0xdc00) + { + // Unicode surrogate? + char d = b2[i + 1]; + if (d >= 0xdc00 && d < 0xe000) + { + buf[j++] = Character.toCodePoint(c, d); + i++; + continue; + } + else + throw new IOException("unpaired surrogate: U+" + + Integer.toHexString(c)); + } + else if (c >= 0xdc00 && c < 0xe000) + throw new IOException("unpaired surrogate: U+" + + Integer.toHexString(c)); + buf[j++] = (int) c; + } + if (i == l) + { + // last char + char c = b2[l]; + if (c >= 0xd800 && c < 0xdc00) + { + int low = in.read(); + if (low >= 0xdc00 && low < 0xe000) + { + buf[j++] = Character.toCodePoint(c, (char) low); + return j; + } + else + throw new IOException("unpaired surrogate: U+" + + Integer.toHexString(c)); + } + else if (c >= 0xdc00 && c < 0xe000) + throw new IOException("unpaired surrogate: U+" + + Integer.toHexString(c)); + buf[j++] = (int) c; + } + return j; + } + + public void close() + throws IOException + { + in.close(); + } + + /** + * Returns the specified UTF-16 char array as an array of Unicode code + * points. + */ + public static int[] toCodePointArray(String text) + throws IOException + { + char[] b2 = text.toCharArray(); + int[] buf = new int[b2.length]; + if (b2.length > 0) + { + int l = b2.length - 1; + int i = 0, j = 0; + for (; i < l; i++) + { + char c = b2[i]; + if (c >= 0xd800 && c < 0xdc00) + { + // Unicode surrogate? + char d = b2[i + 1]; + if (d >= 0xdc00 && d < 0xe000) + { + buf[j++] = Character.toCodePoint(c, d); + i++; + continue; + } + else + throw new IOException("unpaired surrogate: U+" + + Integer.toHexString(c)); + } + else if (c >= 0xdc00 && c < 0xe000) + throw new IOException("unpaired surrogate: U+" + + Integer.toHexString(c)); + buf[j++] = (int) c; + } + if (i == l) + { + // last char + buf[j++] = (int) b2[l]; + if (j < buf.length) + { + int[] buf2 = new int[j]; + System.arraycopy(buf, 0, buf2, 0, j); + buf = buf2; + } + } + } + return buf; + } + +} diff --git a/libjava/classpath/gnu/xml/stream/XIncludeFilter.java b/libjava/classpath/gnu/xml/stream/XIncludeFilter.java new file mode 100644 index 000000000..6d955c492 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/XIncludeFilter.java @@ -0,0 +1,931 @@ +/* XIncludeFilter.java -- + 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.xml.stream; + +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.IOException; +import java.io.Reader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.util.HashSet; +import java.util.NoSuchElementException; +import java.util.StringTokenizer; +import javax.xml.namespace.QName; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.util.StreamReaderDelegate; + +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.DOMImplementation; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.ProcessingInstruction; +import org.w3c.dom.TypeInfo; +import org.w3c.dom.traversal.DocumentTraversal; +import org.w3c.dom.traversal.NodeFilter; +import org.w3c.dom.traversal.TreeWalker; +import org.w3c.dom.xpath.XPathEvaluator; +import org.w3c.dom.xpath.XPathNSResolver; +import org.w3c.dom.xpath.XPathResult; +import org.xml.sax.SAXException; + +/** + * StAX filter for performing XInclude processing. + * + * @see http://www.w3.org/TR/xinclude/ + * @see http://www.w3.org/TR/xptr-framework/ + * @see http://www.w3.org/TR/xptr-element/ + * + * @author Chris Burdess + */ +class XIncludeFilter + extends StreamReaderDelegate +{ + + static final String XINCLUDE_NS_URI = "http://www.w3.org/2001/XInclude"; + static final int SHOW_FLAGS = + NodeFilter.SHOW_CDATA_SECTION | + NodeFilter.SHOW_COMMENT | + NodeFilter.SHOW_ELEMENT | + NodeFilter.SHOW_ENTITY_REFERENCE | + NodeFilter.SHOW_PROCESSING_INSTRUCTION | + NodeFilter.SHOW_TEXT; + + final String systemId; + final boolean namespaceAware; + final boolean validating; + final boolean expandERefs; + String href; + int event; + boolean included; + XPathResult result; + int snapshotIndex; + Node current; + TreeWalker walker; + HashSet seen = new HashSet(); + boolean backtracking; + boolean lookahead; + + Reader includedText; + char[] buf; + int len = -1; + boolean inInclude, inFallback, seenFallback; + + DocumentBuilder builder; + + XIncludeFilter(XMLStreamReader reader, String systemId, + boolean namespaceAware, boolean validating, + boolean expandERefs) + { + super(reader); + this.systemId = XMLParser.absolutize(null, systemId); + this.namespaceAware = namespaceAware; + this.validating = validating; + this.expandERefs = expandERefs; + } + + public int getAttributeCount() + { + if (current != null) + { + NamedNodeMap attrs = current.getAttributes(); + return (attrs == null) ? 0 : attrs.getLength(); + } + return super.getAttributeCount(); + } + + public String getAttributeLocalName(int index) + { + if (current != null) + { + NamedNodeMap attrs = current.getAttributes(); + if (attrs == null) + return null; + Node attr = attrs.item(index); + return attr.getLocalName(); + } + return super.getAttributeLocalName(index); + } + + public String getAttributeNamespace(int index) + { + if (current != null) + { + NamedNodeMap attrs = current.getAttributes(); + if (attrs == null) + return null; + Node attr = attrs.item(index); + return attr.getNamespaceURI(); + } + return super.getAttributeNamespace(index); + } + + public String getAttributePrefix(int index) + { + if (current != null) + { + NamedNodeMap attrs = current.getAttributes(); + if (attrs == null) + return null; + Node attr = attrs.item(index); + return attr.getPrefix(); + } + return super.getAttributePrefix(index); + } + + public QName getAttributeName(int index) + { + if (current != null) + { + NamedNodeMap attrs = current.getAttributes(); + if (attrs == null) + return null; + Node attr = attrs.item(index); + String localName = attr.getLocalName(); + String uri = attr.getNamespaceURI(); + String prefix = attr.getPrefix(); + return new QName(uri, localName, prefix); + } + return super.getAttributeName(index); + } + + public String getAttributeType(int index) + { + if (current != null) + { + NamedNodeMap attrs = current.getAttributes(); + if (attrs == null) + return null; + Attr attr = (Attr) attrs.item(index); + TypeInfo ti = attr.getSchemaTypeInfo(); + return (ti == null) ? "CDATA" : ti.getTypeName(); + } + return super.getAttributeType(index); + } + + public boolean isAttributeSpecified(int index) + { + if (current != null) + { + NamedNodeMap attrs = current.getAttributes(); + if (attrs == null) + return false; + Attr attr = (Attr) attrs.item(index); + return attr.getSpecified(); + } + return super.isAttributeSpecified(index); + } + + public String getAttributeValue(int index) + { + if (current != null) + { + NamedNodeMap attrs = current.getAttributes(); + if (attrs == null) + return null; + Node attr = attrs.item(index); + return attr.getNodeValue(); + } + return super.getAttributeValue(index); + } + + public String getAttributeValue(String uri, String localName) + { + if (current != null) + { + NamedNodeMap attrs = current.getAttributes(); + if (attrs == null) + return null; + Node attr = attrs.getNamedItemNS(uri, localName); + return (attr == null) ? null : attr.getNodeValue(); + } + return super.getAttributeValue(uri, localName); + } + + public String getElementText() + throws XMLStreamException + { + if (current != null) + return current.getTextContent(); + return super.getElementText(); + } + + public int getEventType() + { + return event; + } + + public String getLocalName() + { + if (current != null) + return current.getLocalName(); + return super.getLocalName(); + } + + public QName getName() + { + if (current != null) + { + String localName = current.getLocalName(); + String uri = current.getNamespaceURI(); + String prefix = current.getPrefix(); + return new QName(uri, localName, prefix); + } + return super.getName(); + } + + public String getNamespaceURI() + { + if (current != null) + return current.getNamespaceURI(); + return super.getNamespaceURI(); + } + + // TODO namespaces + + public String getPIData() + { + if (current != null) + return ((ProcessingInstruction) current).getData(); + return super.getPIData(); + } + + public String getPITarget() + { + if (current != null) + return ((ProcessingInstruction) current).getTarget(); + return super.getPITarget(); + } + + public String getPrefix() + { + if (current != null) + return current.getPrefix(); + return super.getPrefix(); + } + + public String getText() + { + if (current != null) + return current.getNodeValue(); + if (walker != null) + { + Node n = walker.getCurrentNode(); + if (n != null) + return n.getTextContent(); + } + if (buf != null) + return new String(buf, 0, len); + return super.getText(); + } + + public char[] getTextCharacters() + { + if (current != null) + { + buf = current.getNodeValue().toCharArray(); + len = buf.length; + } + if (buf != null) + return buf; + return super.getTextCharacters(); + } + + public int getTextCharacters(int sourceStart, char[] target, + int targetStart, int length) + throws XMLStreamException + { + if (current != null) + { + buf = current.getNodeValue().toCharArray(); + len = buf.length; + } + if (buf != null) + { + int max = Math.min(len - sourceStart, length); + if (max > 0) + System.arraycopy(buf, sourceStart, target, targetStart, max); + return max; + } + return super.getTextCharacters(sourceStart, target, targetStart, length); + } + + public int getTextLength() + { + if (current != null) + { + buf = current.getNodeValue().toCharArray(); + len = buf.length; + } + if (buf != null) + return len; + return super.getTextLength(); + } + + public int getTextStart() + { + if (current != null) + { + buf = current.getNodeValue().toCharArray(); + len = buf.length; + } + if (buf != null) + return 0; + return super.getTextStart(); + } + + public boolean hasNext() + throws XMLStreamException + { + if (!lookahead) + { + try + { + next(); + } + catch (NoSuchElementException e) + { + event = -1; + } + lookahead = true; + } + return (event != -1); + } + + public int next() + throws XMLStreamException + { + if (lookahead) + { + lookahead = false; + return event; + } + buf = null; + len = 0; + if (walker != null) + { + Node c = walker.getCurrentNode(); + Node n = null; + if (c.getNodeType() == Node.ELEMENT_NODE) + { + boolean isStartElement = !seen.contains(c); + if (isStartElement) + { + seen.add(c); + current = c; + event = XMLStreamConstants.START_ELEMENT; + return event; + } + else if (backtracking) + { + n = walker.nextSibling(); + if (n != null) + backtracking = false; + } + else + { + n = walker.firstChild(); + if (n == null) + n = walker.nextSibling(); + } + } + else + { + n = walker.firstChild(); + if (n == null) + n = walker.nextSibling(); + } + if (n == null) + { + current = walker.parentNode(); + if (current != null && current.getNodeType() == Node.ELEMENT_NODE) + { + // end-element + backtracking = true; + event = XMLStreamConstants.END_ELEMENT; + return event; + } + else + { + walker = null; + current = null; + } + } + else + { + current = n; + switch (n.getNodeType()) + { + case Node.ELEMENT_NODE: + return next(); + case Node.TEXT_NODE: + String text = n.getNodeValue(); + buf = text.toCharArray(); + len = buf.length; + event = isSpace(buf, len) ? + XMLStreamConstants.SPACE : + XMLStreamConstants.CHARACTERS; + return event; + case Node.CDATA_SECTION_NODE: + event = XMLStreamConstants.CDATA; + return event; + case Node.COMMENT_NODE: + event = XMLStreamConstants.COMMENT; + return event; + case Node.PROCESSING_INSTRUCTION_NODE: + event = XMLStreamConstants.PROCESSING_INSTRUCTION; + return event; + case Node.ENTITY_REFERENCE_NODE: + event = XMLStreamConstants.ENTITY_REFERENCE; + return event; + default: + throw new IllegalStateException(); + } + } + } + if (result != null) + { + switch (result.getResultType()) + { + case XPathResult.BOOLEAN_TYPE: + boolean bval = result.getBooleanValue(); + String btext = bval ? "true" : "false"; + buf = btext.toCharArray(); + len = buf.length; + result = null; + event = XMLStreamConstants.CHARACTERS; + return event; + case XPathResult.NUMBER_TYPE: + double nval = result.getNumberValue(); + String ntext = Double.toString(nval); + buf = ntext.toCharArray(); + len = buf.length; + result = null; + event = XMLStreamConstants.CHARACTERS; + return event; + case XPathResult.STRING_TYPE: + String stext = result.getStringValue(); + buf = stext.toCharArray(); + len = buf.length; + result = null; + event = isSpace(buf, len) ? + XMLStreamConstants.SPACE : + XMLStreamConstants.CHARACTERS; + return event; + case XPathResult.ANY_UNORDERED_NODE_TYPE: + case XPathResult.FIRST_ORDERED_NODE_TYPE: + Node n1 = result.getSingleNodeValue(); + Document d1 = getDocument(n1); + walker = getDocumentTraversal(d1) + .createTreeWalker(n1, SHOW_FLAGS, null, expandERefs); + result = null; + return next(); + case XPathResult.ORDERED_NODE_ITERATOR_TYPE: + case XPathResult.UNORDERED_NODE_ITERATOR_TYPE: + Node n2 = result.iterateNext(); + if (n2 == null) + { + result = null; + return next(); + } + Document d2 = getDocument(n2); + walker = getDocumentTraversal(d2) + .createTreeWalker(n2, SHOW_FLAGS, null, expandERefs); + return next(); + case XPathResult.ORDERED_NODE_SNAPSHOT_TYPE: + case XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE: + Node n3 = result.snapshotItem(snapshotIndex++); + if (n3 == null) + { + result = null; + return next(); + } + Document d3 = getDocument(n3); + walker = getDocumentTraversal(d3) + .createTreeWalker(n3, SHOW_FLAGS, null, expandERefs); + return next(); + default: + throw new IllegalStateException(); + } + } + if (includedText != null) + { + // fill buffer + if (buf == null) + buf = new char[2048]; + try + { + len = includedText.read(buf, 0, buf.length); + if (len == -1) + { + includedText = null; + buf = null; + return next(); + } + // chars or space? + return (event = isSpace(buf, len) ? + XMLStreamConstants.SPACE : + XMLStreamConstants.CHARACTERS); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + event = super.next(); + switch (event) + { + case XMLStreamConstants.START_ELEMENT: + String uri = getNamespaceURI(); + if (XINCLUDE_NS_URI.equals(uri)) + { + String localName = getLocalName(); + if ("include".equals(localName)) + { + href = getAttributeValue(null, "href"); + String parse = getAttributeValue(null, "parse"); + String xpointer = getAttributeValue(null, "xpointer"); + String encoding = getAttributeValue(null, "encoding"); + String accept = getAttributeValue(null, "accept"); + String acceptLanguage = getAttributeValue(null, + "accept-language"); + if (includeResource(href, parse, xpointer, encoding, + accept, acceptLanguage)) + { + // Skip to xi:include end-element event + int depth = 0; + while (depth >= 0) + { + event = super.next(); + switch (event) + { + case XMLStreamConstants.START_ELEMENT: + depth++; + break; + case XMLStreamConstants.END_ELEMENT: + depth--; + } + } + } + else + inInclude = true; + } + else if (inInclude && "fallback".equals(localName)) + { + if (!seenFallback) + inFallback = seenFallback = true; + else + throw new XMLStreamException("duplicate xi:fallback element"); + } + else if (inInclude) + { + throw new XMLStreamException("illegal xi element '" + + localName + "'"); + } + return next(); + } + break; + case XMLStreamConstants.END_ELEMENT: + String uri2 = getNamespaceURI(); + if (XINCLUDE_NS_URI.equals(uri2)) + { + String localName = getLocalName(); + if ("include".equals(localName)) + { + if (!seenFallback && included) + { + String msg = "Unable to read " + href + + " and no xi:fallback element present"; + throw new XMLStreamException(msg); + } + included = false; + href = null; + inInclude = inFallback = seenFallback = false; + } + else if ("fallback".equals(localName)) + inFallback = false; + return next(); + } + break; + } + if (inInclude && !inFallback) + return next(); + return event; + } + + boolean isSpace(char[] text, int len) + { + boolean space = true; + for (int i = 0; i < len; i++) + { + char c = text[i]; + if (c != ' ' && c != '\t' && c != '\n' && c != '\r') + { + space = false; + break; + } + } + return space; + } + + String getBaseURI() + { + String base = (String) getParent().getProperty("gnu.xml.stream.baseURI"); + return (base == null) ? systemId : base; + } + + boolean includeResource(String href, String parse, String xpointer, + String encoding, String accept, + String acceptLanguage) + { + included = false; + try + { + if (xpointer != null) + throw new XMLStreamException("xpointer attribute not yet supported"); + String base = getBaseURI(); + if (href == null || "".equals(href)) + href = base; + else + href = XMLParser.absolutize(base, href); + if (parse == null || "xml".equals(parse)) + { + seen.clear(); + result = null; + snapshotIndex = 0; + walker = null; + current = null; + backtracking = false; + + URLConnection connection = getURLConnection(href, accept, + acceptLanguage); + InputStream in = connection.getInputStream(); + Document doc = getDocumentBuilder().parse(in, href); + DocumentTraversal dt = getDocumentTraversal(doc); + if (xpointer == null) + { + result = null; + Node item = doc.getDocumentElement(); + walker = dt.createTreeWalker(item, SHOW_FLAGS, null, + expandERefs); + } + else + { + result = null; + snapshotIndex = 0; + walker = null; + // shorthand or scheme-based? + int lpi = xpointer.indexOf('('); + int rpi = xpointer.indexOf(')', lpi); + if (lpi != -1 && rpi != -1) + { + String scheme = xpointer.substring(0, lpi); + if ("element".equals(scheme)) + { + // element() scheme + String elementSchemeData = + xpointer.substring(lpi + 1, rpi); + Node item = doc; + int si = elementSchemeData.indexOf('/'); + if (si == -1) + { + if (elementSchemeData.length() > 0) + item = doc.getElementById(elementSchemeData); + } + else + { + if (si > 0) + { + String context = + elementSchemeData.substring(0, si); + item = doc.getElementById(context); + elementSchemeData = + elementSchemeData.substring(si + 1); + } + StringTokenizer st = + new StringTokenizer(elementSchemeData, "/"); + while (st.hasMoreTokens() && item != null) + { + int n = Integer.parseInt(st.nextToken()); + Node ctx = item.getFirstChild(); + int count = 1; + while (ctx != null && count++ < n) + ctx = ctx.getNextSibling(); + item = ctx; + } + } + walker = dt.createTreeWalker(item, SHOW_FLAGS, null, + expandERefs); + included = true; + } + else if ("xpointer".equals(scheme)) + { + xpointer = xpointer.substring(lpi + 1, rpi); + XPathEvaluator eval = getXPathEvaluator(doc); + XPathNSResolver resolver = eval.createNSResolver(doc); + result = + (XPathResult) eval.evaluate(xpointer, doc, + resolver, + XPathResult.ANY_TYPE, + null); + // TODO xpointer() scheme functions + included = true; + } + else + { + String msg = "Unknown XPointer scheme: " + scheme; + throw new XMLStreamException(msg); + } + } + else + { + Node item = doc.getElementById(xpointer); + walker = dt.createTreeWalker(item, SHOW_FLAGS, null, + expandERefs); + included = true; + } + } + } + else if ("text".equals(parse)) + { + URLConnection connection = getURLConnection(href, accept, + acceptLanguage); + InputStream in = connection.getInputStream(); + if (encoding == null) + { + encoding = connection.getContentEncoding(); + if (encoding == null) + { + String contentType = connection.getContentType(); + if (contentType != null) + encoding = getParameter(contentType, "charset"); + } + } + if (encoding == null) + includedText = new InputStreamReader(in, "UTF-8"); + else + includedText = new InputStreamReader(in, encoding); + included = true; + } + else + throw new XMLStreamException("value of 'parse' attribute must be "+ + "'xml' or 'text'"); + return true; + } + catch (IOException e) + { + return false; + } + catch (XMLStreamException e) + { + return false; + } + catch (SAXException e) + { + return false; + } + } + + URLConnection getURLConnection(String href, String accept, + String acceptLanguage) + throws IOException + { + URL url = new URL(href); + URLConnection connection = url.openConnection(); + if (connection instanceof HttpURLConnection) + { + HttpURLConnection http = (HttpURLConnection) connection; + http.setInstanceFollowRedirects(true); + if (accept != null) + http.setRequestProperty("Accept", accept); + if (acceptLanguage != null) + http.setRequestProperty("Accept-Language", acceptLanguage); + } + return connection; + } + + Document getDocument(Node node) + { + if (node.getNodeType() == Node.DOCUMENT_NODE) + return (Document) node; + return node.getOwnerDocument(); + } + + DocumentBuilder getDocumentBuilder() + throws XMLStreamException + { + if (builder == null) + { + try + { + DocumentBuilderFactory f = DocumentBuilderFactory.newInstance(); + f.setXIncludeAware(true); + f.setNamespaceAware(namespaceAware); + f.setValidating(validating); + builder = f.newDocumentBuilder(); + } + catch (ParserConfigurationException e) + { + XMLStreamException e2 = new XMLStreamException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + builder.reset(); + return builder; + } + + DocumentTraversal getDocumentTraversal(Document doc) + throws XMLStreamException + { + DOMImplementation dom = doc.getImplementation(); + if (!dom.hasFeature("Traversal", "2.0")) + throw new XMLStreamException("Traversal not supported"); + return (DocumentTraversal) doc; + } + + XPathEvaluator getXPathEvaluator(Document doc) + throws XMLStreamException + { + DOMImplementation dom = doc.getImplementation(); + if (!dom.hasFeature("XPath", "3.0")) + throw new XMLStreamException("XPath not supported"); + return (XPathEvaluator) doc; + } + + static String getParameter(String contentType, String name) + { + StringTokenizer st = new StringTokenizer(contentType, " ;"); + if (st.hasMoreTokens()) + st.nextToken(); + while (st.hasMoreTokens()) + { + String token = st.nextToken(); + int ei = token.indexOf('='); + if (ei != -1) + { + String key = token.substring(0, ei); + if (key.equals(name)) + { + String value = token.substring(ei + 1); + int len = value.length(); + if (len > 1 && + value.charAt(0) == '"' && + value.charAt(len - 1) == '"') + value = value.substring(1, len - 1); + else if (len > 1 && + value.charAt(0) == '\'' && + value.charAt(len - 1) == '\'') + value = value.substring(1, len - 1); + return value; + } + } + } + return null; + } + +} diff --git a/libjava/classpath/gnu/xml/stream/XMLEventAllocatorImpl.java b/libjava/classpath/gnu/xml/stream/XMLEventAllocatorImpl.java new file mode 100644 index 000000000..a1824bfc5 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/XMLEventAllocatorImpl.java @@ -0,0 +1,204 @@ +/* XMLEventAllocatorImpl.java -- + 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.xml.stream; + +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import javax.xml.namespace.QName; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.events.EntityDeclaration; +import javax.xml.stream.events.XMLEvent; +import javax.xml.stream.util.XMLEventAllocator; +import javax.xml.stream.util.XMLEventConsumer; + +/** + * Allocator for creating XML events based on a reader state. + * + * @author Chris Burdess + */ +public class XMLEventAllocatorImpl + implements XMLEventAllocator +{ + + protected Map entityDeclarations; + + protected XMLEventAllocatorImpl() + { + entityDeclarations = new HashMap(); + } + + public XMLEvent allocate(XMLStreamReader reader) + throws XMLStreamException + { + String text; + boolean whitespace; + boolean ignorableWhitespace; + int len; + List namespaces; + int eventType = reader.getEventType(); + Location location = reader.getLocation(); + switch (eventType) + { + case XMLStreamConstants.CDATA: + text = reader.getText(); + whitespace = isWhitespace(text); + // TODO ignorableWhitespace + ignorableWhitespace = whitespace && false; + return new CharactersImpl(location, text, + whitespace, true, ignorableWhitespace); + case XMLStreamConstants.CHARACTERS: + text = reader.getText(); + whitespace = false; + // TODO ignorableWhitespace + ignorableWhitespace = whitespace && false; + return new CharactersImpl(location, text, + whitespace, false, ignorableWhitespace); + case XMLStreamConstants.COMMENT: + text = reader.getText(); + return new CommentImpl(location, text); + case XMLStreamConstants.DTD: + text = reader.getText(); + List notations = new LinkedList(); + List entities = new LinkedList(); + // TODO readDTDBody(notations, entities); + return new DTDImpl(location, text, null, notations, entities); + case XMLStreamConstants.END_DOCUMENT: + return new EndDocumentImpl(location); + case XMLStreamConstants.END_ELEMENT: + len = reader.getNamespaceCount(); + namespaces = new LinkedList(); + for (int i = 0; i < len; i++) + namespaces.add(new NamespaceImpl(location, + reader.getNamespacePrefix(i), + reader.getNamespaceURI(i), + false)); + return new EndElementImpl(location, + reader.getName(), + namespaces); + case XMLStreamConstants.ENTITY_REFERENCE: + String name = reader.getLocalName(); + EntityDeclaration decl = + (EntityDeclaration) entityDeclarations.get(name); + return new EntityReferenceImpl(location, decl, name); + case XMLStreamConstants.PROCESSING_INSTRUCTION: + return new ProcessingInstructionImpl(location, + reader.getPITarget(), + reader.getPIData()); + case XMLStreamConstants.SPACE: + text = reader.getText(); + whitespace = true; + // TODO ignorableWhitespace + ignorableWhitespace = whitespace && false; + return new CharactersImpl(location, text, + whitespace, false, ignorableWhitespace); + case XMLStreamConstants.START_DOCUMENT: + String systemId = location.getSystemId(); + String encoding = reader.getCharacterEncodingScheme(); + boolean encodingDeclared = encoding != null; + if (encoding == null) + { + encoding = reader.getEncoding(); + if (encoding == null) + encoding = "UTF-8"; + } + String xmlVersion = reader.getVersion(); + if (xmlVersion == null) + xmlVersion = "1.0"; + boolean xmlStandalone = reader.isStandalone(); + boolean standaloneDeclared = reader.standaloneSet(); + return new StartDocumentImpl(location, + systemId, + encoding, + xmlVersion, + xmlStandalone, + standaloneDeclared, + encodingDeclared); + case XMLStreamConstants.START_ELEMENT: + len = reader.getNamespaceCount(); + namespaces = new LinkedList(); + for (int i = 0; i < len; i++) + namespaces.add(new NamespaceImpl(location, + reader.getNamespacePrefix(i), + reader.getNamespaceURI(i), + false)); + len = reader.getAttributeCount(); + List attributes = new LinkedList(); + for (int i = 0; i < len; i++) + attributes.add(new AttributeImpl(location, + reader.getAttributeName(i), + reader.getAttributeValue(i), + reader.getAttributeType(i), + reader.isAttributeSpecified(i))); + return new StartElementImpl(location, + reader.getName(), + attributes, namespaces, + reader.getNamespaceContext()); + default: + throw new XMLStreamException("Unknown event type: " + eventType); + } + } + + public void allocate(XMLStreamReader reader, XMLEventConsumer consumer) + throws XMLStreamException + { + consumer.add(allocate(reader)); + } + + public XMLEventAllocator newInstance() + { + return new XMLEventAllocatorImpl(); + } + + protected boolean isWhitespace(String text) + { + int len = text.length(); + for (int i = 0; i < len; i++) + { + char c = text.charAt(i); + if (c != 0x20 && c != 0x09 && c != 0x0a && c != 0x0d) + return false; + } + return true; + } + +} diff --git a/libjava/classpath/gnu/xml/stream/XMLEventFactoryImpl.java b/libjava/classpath/gnu/xml/stream/XMLEventFactoryImpl.java new file mode 100644 index 000000000..12f7f2c79 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/XMLEventFactoryImpl.java @@ -0,0 +1,269 @@ +/* XMLEventFactoryImpl.java -- + 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.xml.stream; + +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import javax.xml.XMLConstants; +import javax.xml.namespace.NamespaceContext; +import javax.xml.namespace.QName; +import javax.xml.stream.Location; +import javax.xml.stream.XMLEventFactory; +import javax.xml.stream.events.Attribute; +import javax.xml.stream.events.Characters; +import javax.xml.stream.events.Comment; +import javax.xml.stream.events.DTD; +import javax.xml.stream.events.EndDocument; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.EntityDeclaration; +import javax.xml.stream.events.EntityReference; +import javax.xml.stream.events.Namespace; +import javax.xml.stream.events.ProcessingInstruction; +import javax.xml.stream.events.StartDocument; +import javax.xml.stream.events.StartElement; + +/** + * Factory for XML events. + * + * @author Chris Burdess + */ +public class XMLEventFactoryImpl + extends XMLEventFactory +{ + + protected Location location; + + public void setLocation(Location location) + { + this.location = location; + } + + public Attribute createAttribute(String prefix, String namespaceURI, + String localName, String value) + { + return new AttributeImpl(location, + new QName(namespaceURI, localName, prefix), + value, "CDATA", true); + } + + public Attribute createAttribute(String localName, String value) + { + return new AttributeImpl(location, + new QName(localName), + value, "CDATA", true); + } + + public Attribute createAttribute(QName name, String value) + { + return new AttributeImpl(location, name, value, + "CDATA", true); + } + + public Namespace createNamespace(String namespaceURI) + { + return new NamespaceImpl(location, + XMLConstants.DEFAULT_NS_PREFIX, + namespaceURI, + true); + } + + public Namespace createNamespace(String prefix, String namespaceUri) + { + return new NamespaceImpl(location, prefix, namespaceUri, true); + } + + public StartElement createStartElement(QName name, + Iterator attributes, + Iterator namespaces) + { + return new StartElementImpl(location, name, + createLinkedList(attributes), + createLinkedList(namespaces), + null); + } + + public StartElement createStartElement(String prefix, + String namespaceUri, + String localName) + { + return new StartElementImpl(location, + new QName(namespaceUri, localName, prefix), + Collections.EMPTY_LIST, + Collections.EMPTY_LIST, + null); + } + + public StartElement createStartElement(String prefix, + String namespaceUri, + String localName, + Iterator attributes, + Iterator namespaces) + { + return new StartElementImpl(location, + new QName(namespaceUri, localName, prefix), + createLinkedList(attributes), + createLinkedList(namespaces), + null); + } + + public StartElement createStartElement(String prefix, + String namespaceUri, + String localName, + Iterator attributes, + Iterator namespaces, + NamespaceContext context) + { + return new StartElementImpl(location, + new QName(namespaceUri, localName, prefix), + createLinkedList(attributes), + createLinkedList(namespaces), + context); + } + + public EndElement createEndElement(QName name, + Iterator namespaces) + { + return new EndElementImpl(location, name, + createLinkedList(namespaces)); + } + + public EndElement createEndElement(String prefix, + String namespaceUri, + String localName) + { + return new EndElementImpl(location, + new QName(namespaceUri, localName, prefix), + Collections.EMPTY_LIST); + } + + public EndElement createEndElement(String prefix, + String namespaceUri, + String localName, + Iterator namespaces) + { + return new EndElementImpl(location, + new QName(namespaceUri, localName, prefix), + createLinkedList(namespaces)); + } + + public Characters createCharacters(String content) + { + return new CharactersImpl(location, content, false, false, false); + } + + public Characters createCData(String content) + { + return new CharactersImpl(location, content, false, true, false); + } + + public Characters createSpace(String content) + { + return new CharactersImpl(location, content, true, false, false); + } + + public Characters createIgnorableSpace(String content) + { + return new CharactersImpl(location, content, true, false, true); + } + + public StartDocument createStartDocument() + { + return new StartDocumentImpl(location, null, "UTF-8", "1.0", + false, false, false); + } + + public StartDocument createStartDocument(String encoding, + String version, + boolean standalone) + { + return new StartDocumentImpl(location, null, encoding, version, + standalone, true, true); + } + + public StartDocument createStartDocument(String encoding, + String version) + { + return new StartDocumentImpl(location, null, encoding, version, + false, false, true); + } + + public StartDocument createStartDocument(String encoding) + { + return new StartDocumentImpl(location, null, encoding, "1.0", + false, false, true); + } + + public EndDocument createEndDocument() + { + return new EndDocumentImpl(location); + } + + public EntityReference createEntityReference(String name, + EntityDeclaration declaration) + { + return new EntityReferenceImpl(location, declaration, name); + } + + public Comment createComment(String text) + { + return new CommentImpl(location, text); + } + + public ProcessingInstruction createProcessingInstruction(String target, + String data) + { + return new ProcessingInstructionImpl(location, target, data); + } + + public DTD createDTD(String dtd) + { + return new DTDImpl(location, dtd, null, + Collections.EMPTY_LIST, + Collections.EMPTY_LIST); + } + + LinkedList createLinkedList(Iterator i) + { + LinkedList ret = new LinkedList(); + while (i.hasNext()) + ret.add(i.next()); + return ret; + } + +} diff --git a/libjava/classpath/gnu/xml/stream/XMLEventImpl.java b/libjava/classpath/gnu/xml/stream/XMLEventImpl.java new file mode 100644 index 000000000..2e650bf74 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/XMLEventImpl.java @@ -0,0 +1,198 @@ +/* XMLEventImpl.java -- + 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.xml.stream; + +import gnu.java.lang.CPStringBuilder; + +import java.io.Writer; +import javax.xml.namespace.QName; +import javax.xml.stream.Location; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.Characters; +import javax.xml.stream.events.EndElement; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; + +/** + * An XML stream event. + * + * @author Chris Burdess + */ +public abstract class XMLEventImpl + implements XMLEvent +{ + + protected final Location location; + + protected XMLEventImpl(Location location) + { + this.location = location; + } + + public abstract int getEventType(); + + public Location getLocation() + { + return location; + } + + public boolean isStartElement() + { + return getEventType() == START_ELEMENT; + } + + public boolean isAttribute() + { + return getEventType() == ATTRIBUTE; + } + + public boolean isNamespace() + { + return getEventType() == NAMESPACE; + } + + public boolean isEndElement() + { + return getEventType() == END_ELEMENT; + } + + public boolean isEntityReference() + { + return getEventType() == ENTITY_REFERENCE; + } + + public boolean isProcessingInstruction() + { + return getEventType() == PROCESSING_INSTRUCTION; + } + + public boolean isCharacters() + { + int et = getEventType(); + return et == CHARACTERS || et == CDATA; + } + + public boolean isStartDocument() + { + return getEventType() == START_DOCUMENT; + } + + public boolean isEndDocument() + { + return getEventType() == END_DOCUMENT; + } + + public StartElement asStartElement() + { + return (StartElement) this; + } + + public EndElement asEndElement() + { + return (EndElement) this; + } + + public Characters asCharacters() + { + return (Characters) this; + } + + public QName getSchemaType() + { + return null; + } + + public abstract void writeAsEncodedUnicode(Writer writer) + throws XMLStreamException; + + protected String encode(String text, boolean inAttr) + { + int len = text.length(); + CPStringBuilder buf = null; + for (int i = 0; i < len; i++) + { + char c = text.charAt(i); + if (c == '<') + { + if (buf == null) + { + buf = new CPStringBuilder(text.substring(0, i)); + } + buf.append("<"); + } + else if (c == '>') + { + if (buf == null) + { + buf = new CPStringBuilder(text.substring(0, i)); + } + buf.append(">"); + } + else if (c == '&') + { + if (buf == null) + { + buf = new CPStringBuilder(text.substring(0, i)); + } + buf.append("&"); + } + else if (c == '\'' && inAttr) + { + if (buf == null) + { + buf = new CPStringBuilder(text.substring(0, i)); + } + buf.append("'"); + } + else if (c == '"' && inAttr) + { + if (buf == null) + { + buf = new CPStringBuilder(text.substring(0, i)); + } + buf.append("""); + } + else if (buf != null) + { + buf.append(c); + } + } + return (buf == null) ? text : buf.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/stream/XMLEventReaderImpl.java b/libjava/classpath/gnu/xml/stream/XMLEventReaderImpl.java new file mode 100644 index 000000000..bab6d9378 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/XMLEventReaderImpl.java @@ -0,0 +1,157 @@ +/* XMLEventReaderImpl.java -- + 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.xml.stream; + +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.events.XMLEvent; +import javax.xml.stream.util.XMLEventAllocator; + +/** + * Parser using XML events. + * + * @author Chris Burdess + */ +public class XMLEventReaderImpl + implements XMLEventReader +{ + + protected final XMLStreamReader reader; + protected final XMLEventAllocator allocator; + protected final String systemId; + protected XMLEvent peekEvent; + + protected XMLEventReaderImpl(XMLStreamReader reader, + XMLEventAllocator allocator, + String systemId) + { + this.reader = reader; + this.allocator = allocator; + this.systemId = systemId; + } + + public XMLEvent nextEvent() + throws XMLStreamException + { + XMLEvent ret = peek(); + peekEvent = null; + return ret; + } + + public Object next() + { + try + { + return nextEvent(); + } + catch (XMLStreamException e) + { + RuntimeException e2 = new RuntimeException(); + e2.initCause(e); + throw e2; + } + } + + public boolean hasNext() + { + if (peekEvent != null) + return true; + try + { + return reader.hasNext(); + } + catch (XMLStreamException e) + { + return false; + } + } + + public XMLEvent peek() + throws XMLStreamException + { + if (peekEvent != null) + return peekEvent; + if (!reader.hasNext()) + return null; + reader.next(); + peekEvent = allocator.allocate(reader); + return peekEvent; + } + + public String getElementText() + throws XMLStreamException + { + return reader.getElementText(); + } + + public XMLEvent nextTag() + throws XMLStreamException + { + if (peekEvent != null) + { + int eventType = peekEvent.getEventType(); + if (eventType == XMLStreamConstants.START_ELEMENT || + eventType == XMLStreamConstants.END_ELEMENT) + return peekEvent; + else + peekEvent = null; + } + reader.nextTag(); + return allocator.allocate(reader); + } + + public Object getProperty(String name) + throws IllegalArgumentException + { + return reader.getProperty(name); + } + + public void close() + throws XMLStreamException + { + reader.close(); + } + + public void remove() + { + throw new UnsupportedOperationException(); + } + +} diff --git a/libjava/classpath/gnu/xml/stream/XMLEventWriterImpl.java b/libjava/classpath/gnu/xml/stream/XMLEventWriterImpl.java new file mode 100644 index 000000000..33b1dce31 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/XMLEventWriterImpl.java @@ -0,0 +1,190 @@ +/* XMLEventWriterImpl.java -- + 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.xml.stream; + +import javax.xml.namespace.NamespaceContext; +import javax.xml.namespace.QName; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; +import javax.xml.stream.events.Attribute; +import javax.xml.stream.events.Characters; +import javax.xml.stream.events.Comment; +import javax.xml.stream.events.DTD; +import javax.xml.stream.events.Namespace; +import javax.xml.stream.events.ProcessingInstruction; +import javax.xml.stream.events.StartDocument; +import javax.xml.stream.events.StartElement; +import javax.xml.stream.events.XMLEvent; + +/** + * Writer to write events to an underlying XML stream writer. + * + * @author Chris Burdess + */ +public class XMLEventWriterImpl + implements XMLEventWriter +{ + + protected final XMLStreamWriter writer; + + protected XMLEventWriterImpl(XMLStreamWriter writer) + { + this.writer = writer; + } + + public void flush() + throws XMLStreamException + { + writer.flush(); + } + + public void close() + throws XMLStreamException + { + writer.close(); + } + + public void add(XMLEvent event) + throws XMLStreamException + { + QName name; + String uri; + switch (event.getEventType()) + { + case XMLStreamConstants.START_ELEMENT: + StartElement startElement = event.asStartElement(); + name = startElement.getName(); + uri = name.getNamespaceURI(); + if (uri != null && !"".equals(uri)) + writer.writeStartElement(name.getPrefix(), name.getLocalPart(), uri); + else + writer.writeStartElement(name.getLocalPart()); + break; + case XMLStreamConstants.END_ELEMENT: + writer.writeEndElement(); + break; + case XMLStreamConstants.ATTRIBUTE: + Attribute attribute = (Attribute) event; + name = attribute.getName(); + uri = name.getNamespaceURI(); + if (uri != null && !"".equals(uri)) + writer.writeAttribute(name.getPrefix(), uri, name.getLocalPart(), + attribute.getValue()); + else + writer.writeAttribute(name.getLocalPart(), attribute.getValue()); + break; + case XMLStreamConstants.NAMESPACE: + Namespace namespace = (Namespace) event; + uri = namespace.getNamespaceURI(); + writer.writeNamespace(namespace.getPrefix(), uri); + break; + case XMLStreamConstants.PROCESSING_INSTRUCTION: + ProcessingInstruction pi = (ProcessingInstruction) event; + String data = pi.getData(); + if (data == null) + writer.writeProcessingInstruction(pi.getTarget()); + else + writer.writeProcessingInstruction(pi.getTarget(), data); + break; + case XMLStreamConstants.COMMENT: + Comment comment = (Comment) event; + writer.writeComment(comment.getText()); + break; + case XMLStreamConstants.START_DOCUMENT: + StartDocument startDocument = (StartDocument) event; + writer.writeStartDocument(startDocument.getVersion()); + break; + case XMLStreamConstants.END_DOCUMENT: + writer.writeEndDocument(); + break; + case XMLStreamConstants.DTD: + DTD dtd = (DTD) event; + writer.writeDTD(dtd.getDocumentTypeDeclaration()); + break; + case XMLStreamConstants.CHARACTERS: + case XMLStreamConstants.SPACE: + Characters characters = event.asCharacters(); + writer.writeCharacters(characters.getData()); + break; + case XMLStreamConstants.CDATA: + Characters cdata = event.asCharacters(); + writer.writeCData(cdata.getData()); + break; + } + } + + public void add(XMLEventReader reader) + throws XMLStreamException + { + while (reader.hasNext()) + add(reader.nextEvent()); + } + + public String getPrefix(String uri) + throws XMLStreamException + { + return writer.getPrefix(uri); + } + + public void setPrefix(String prefix, String uri) + throws XMLStreamException + { + writer.setPrefix(prefix, uri); + } + + public void setDefaultNamespace(String uri) + throws XMLStreamException + { + writer.setDefaultNamespace(uri); + } + + public void setNamespaceContext(NamespaceContext context) + throws XMLStreamException + { + writer.setNamespaceContext(context); + } + + public NamespaceContext getNamespaceContext() + { + return writer.getNamespaceContext(); + } + +} diff --git a/libjava/classpath/gnu/xml/stream/XMLInputFactoryImpl.java b/libjava/classpath/gnu/xml/stream/XMLInputFactoryImpl.java new file mode 100644 index 000000000..87aa32107 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/XMLInputFactoryImpl.java @@ -0,0 +1,397 @@ +/* XMLInputFactoryImpl.java -- + 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.xml.stream; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.io.IOException; +import java.io.Reader; +import java.net.MalformedURLException; +import java.net.URL; + +import javax.xml.transform.Source; +import javax.xml.transform.stream.StreamSource; +import javax.xml.stream.EventFilter; +import javax.xml.stream.StreamFilter; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLReporter; +import javax.xml.stream.XMLResolver; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.util.XMLEventAllocator; + +/** + * Factory for creating parsers from various kinds of XML source. + * + * @author Chris Burdess + */ +public class XMLInputFactoryImpl + extends XMLInputFactory +{ + + protected XMLResolver resolver; + protected XMLReporter reporter; + protected XMLEventAllocator allocator; + + protected boolean validating; + protected boolean namespaceAware = true; + protected boolean coalescing; + protected boolean replacingEntityReferences = true; + protected boolean externalEntities = true; + protected boolean supportDTD = true; + protected boolean xIncludeAware = false; + protected boolean baseAware = true; + protected boolean stringInterning = true; + + public XMLInputFactoryImpl() + { + allocator = new XMLEventAllocatorImpl(); + } + + public XMLStreamReader createXMLStreamReader(Reader reader) + throws XMLStreamException + { + return createXMLStreamReader(null, reader); + } + + public XMLStreamReader createXMLStreamReader(Source source) + throws XMLStreamException + { + String systemId = source.getSystemId(); + InputStream in = getInputStream(source); + XMLParser ret = new XMLParser(in, systemId, + validating, + namespaceAware, + coalescing, + replacingEntityReferences, + externalEntities, + supportDTD, + baseAware, + stringInterning, + false, + reporter, + resolver); + if (xIncludeAware) + return new XIncludeFilter(ret, systemId, namespaceAware, validating, + replacingEntityReferences); + return ret; + } + + public XMLStreamReader createXMLStreamReader(InputStream in) + throws XMLStreamException + { + return createXMLStreamReader(null, in); + } + + public XMLStreamReader createXMLStreamReader(InputStream in, String encoding) + throws XMLStreamException + { + return createXMLStreamReader(in); + } + + public XMLStreamReader createXMLStreamReader(String systemId, InputStream in) + throws XMLStreamException + { + XMLParser ret = new XMLParser(in, systemId, + validating, + namespaceAware, + coalescing, + replacingEntityReferences, + externalEntities, + supportDTD, + baseAware, + stringInterning, + false, + reporter, + resolver); + if (xIncludeAware) + return new XIncludeFilter(ret, null, namespaceAware, validating, + replacingEntityReferences); + return ret; + } + + public XMLStreamReader createXMLStreamReader(String systemId, Reader reader) + throws XMLStreamException + { + XMLParser ret = new XMLParser(reader, systemId, + validating, + namespaceAware, + coalescing, + replacingEntityReferences, + externalEntities, + supportDTD, + baseAware, + stringInterning, + false, + reporter, + resolver); + if (xIncludeAware) + return new XIncludeFilter(ret, null, namespaceAware, validating, + replacingEntityReferences); + return ret; + } + + public XMLEventReader createXMLEventReader(Reader reader) + throws XMLStreamException + { + XMLStreamReader sr = createXMLStreamReader(reader); + return new XMLEventReaderImpl(sr, allocator, null); + } + + public XMLEventReader createXMLEventReader(String systemId, Reader reader) + throws XMLStreamException + { + XMLStreamReader sr = createXMLStreamReader(systemId, reader); + return new XMLEventReaderImpl(sr, allocator, null); + } + + public XMLEventReader createXMLEventReader(XMLStreamReader reader) + throws XMLStreamException + { + return new XMLEventReaderImpl(reader, allocator, null); + } + + public XMLEventReader createXMLEventReader(Source source) + throws XMLStreamException + { + XMLStreamReader sr = createXMLStreamReader(source); + return new XMLEventReaderImpl(sr, allocator, null); + } + + public XMLEventReader createXMLEventReader(InputStream in) + throws XMLStreamException + { + XMLStreamReader sr = createXMLStreamReader(in); + return new XMLEventReaderImpl(sr, allocator, null); + } + + public XMLEventReader createXMLEventReader(InputStream in, String encoding) + throws XMLStreamException + { + XMLStreamReader sr = createXMLStreamReader(in, encoding); + return new XMLEventReaderImpl(sr, allocator, null); + } + + public XMLEventReader createXMLEventReader(String systemId, InputStream in) + throws XMLStreamException + { + XMLStreamReader sr = createXMLStreamReader(systemId, in); + return new XMLEventReaderImpl(sr, allocator, null); + } + + public XMLStreamReader createFilteredReader(XMLStreamReader reader, + StreamFilter filter) + throws XMLStreamException + { + return new FilteredStreamReader(reader, filter); + } + + public XMLEventReader createFilteredReader(XMLEventReader reader, + EventFilter filter) + throws XMLStreamException + { + return new FilteredEventReader(reader, filter); + } + + public XMLResolver getXMLResolver() + { + return resolver; + } + + public void setXMLResolver(XMLResolver resolver) + { + this.resolver = resolver; + } + + public XMLReporter getXMLReporter() + { + return reporter; + } + + public void setXMLReporter(XMLReporter reporter) + { + this.reporter = reporter; + } + + public void setProperty(String name, Object value) + throws IllegalArgumentException + { + if (name.equals(IS_NAMESPACE_AWARE)) + namespaceAware = ((Boolean) value).booleanValue(); + else if (name.equals(IS_VALIDATING)) + validating = ((Boolean) value).booleanValue(); + else if (name.equals(IS_COALESCING)) + coalescing = ((Boolean) value).booleanValue(); + else if (name.equals(IS_REPLACING_ENTITY_REFERENCES)) + replacingEntityReferences = ((Boolean) value).booleanValue(); + else if (name.equals(IS_SUPPORTING_EXTERNAL_ENTITIES)) + externalEntities = ((Boolean) value).booleanValue(); + else if (name.equals(SUPPORT_DTD)) + supportDTD = ((Boolean) value).booleanValue(); + else if (name.equals(REPORTER)) + reporter = (XMLReporter) value; + else if (name.equals(RESOLVER)) + resolver = (XMLResolver) value; + else if (name.equals(ALLOCATOR)) + allocator = (XMLEventAllocator) value; + else if (name.equals("gnu.xml.stream.stringInterning")) + stringInterning = ((Boolean) value).booleanValue(); + else if (name.equals("gnu.xml.stream.baseAware")) + baseAware = ((Boolean) value).booleanValue(); + else if (name.equals("gnu.xml.stream.xIncludeAware")) + xIncludeAware = ((Boolean) value).booleanValue(); + else + throw new IllegalArgumentException(name); + } + + public Object getProperty(String name) + throws IllegalArgumentException + { + if (name.equals(IS_NAMESPACE_AWARE)) + return namespaceAware ? Boolean.TRUE : Boolean.FALSE; + if (name.equals(IS_VALIDATING)) + return validating ? Boolean.TRUE : Boolean.FALSE; + if (name.equals(IS_COALESCING)) + return coalescing ? Boolean.TRUE : Boolean.FALSE; + if (name.equals(IS_REPLACING_ENTITY_REFERENCES)) + return replacingEntityReferences ? Boolean.TRUE : Boolean.FALSE; + if (name.equals(IS_SUPPORTING_EXTERNAL_ENTITIES)) + return externalEntities ? Boolean.TRUE : Boolean.FALSE; + if (name.equals(SUPPORT_DTD)) + return supportDTD ? Boolean.TRUE : Boolean.FALSE; + if (name.equals(REPORTER)) + return reporter; + if (name.equals(RESOLVER)) + return resolver; + if (name.equals(ALLOCATOR)) + return allocator; + if (name.equals("gnu.xml.stream.stringInterning")) + return stringInterning ? Boolean.TRUE : Boolean.FALSE; + if (name.equals("gnu.xml.stream.baseAware")) + return baseAware ? Boolean.TRUE : Boolean.FALSE; + if (name.equals("gnu.xml.stream.xIncludeAware")) + return xIncludeAware ? Boolean.TRUE : Boolean.FALSE; + throw new IllegalArgumentException(name); + } + + public boolean isPropertySupported(String name) + { + return name.equals(IS_NAMESPACE_AWARE) || + name.equals(IS_VALIDATING) || + name.equals(IS_COALESCING) || + name.equals(IS_REPLACING_ENTITY_REFERENCES) || + name.equals(IS_SUPPORTING_EXTERNAL_ENTITIES) || + name.equals(SUPPORT_DTD) || + name.equals(REPORTER) || + name.equals(RESOLVER) || + name.equals(ALLOCATOR) || + name.equals("gnu.xml.stream.stringInterning") || + name.equals("gnu.xml.stream.baseAware") || + name.equals("gnu.xml.stream.xIncludeAware"); + } + + public void setEventAllocator(XMLEventAllocator allocator) + { + this.allocator = allocator; + } + + public XMLEventAllocator getEventAllocator() + { + return allocator; + } + + public void setCoalescing(boolean coalescing) + { + this.coalescing = coalescing; + } + + public boolean isCoalescing() + { + return coalescing; + } + + protected InputStream getInputStream(Source source) + throws XMLStreamException + { + InputStream in = null; + if (source instanceof StreamSource) + { + StreamSource streamSource = (StreamSource) source; + in = streamSource.getInputStream(); + } + if (in == null) + { + String systemId = source.getSystemId(); + try + { + URL url = new URL(systemId); + try + { + in = url.openStream(); + } + catch (IOException e2) + { + XMLStreamException e3 = new XMLStreamException(e2); + e3.initCause(e2); + throw e3; + } + } + catch (MalformedURLException e) + { + // Fall back to relative file + if (File.separatorChar != '/') + systemId = systemId.replace('/', File.separatorChar); + try + { + in = new FileInputStream(systemId); + } + catch (FileNotFoundException e2) + { + XMLStreamException e3 = new XMLStreamException(e2); + e3.initCause(e2); + throw e3; + } + } + } + return in; + } + +} diff --git a/libjava/classpath/gnu/xml/stream/XMLOutputFactoryImpl.java b/libjava/classpath/gnu/xml/stream/XMLOutputFactoryImpl.java new file mode 100644 index 000000000..d849e8ba5 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/XMLOutputFactoryImpl.java @@ -0,0 +1,187 @@ +/* XMLOutputFactoryImpl.java -- + 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.xml.stream; + +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.io.UnsupportedEncodingException; + +import javax.xml.transform.Result; +import javax.xml.transform.stream.StreamResult; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +/** + * Standard output factory. + * + * @author Chris Burdess + */ +public class XMLOutputFactoryImpl + extends XMLOutputFactory +{ + + protected boolean prefixDefaulting = false; + + public XMLOutputFactoryImpl() + { + } + + public XMLStreamWriter createXMLStreamWriter(Writer stream) + throws XMLStreamException + { + // XXX try to determine character encoding of writer? + return new XMLStreamWriterImpl(stream, null, prefixDefaulting); + } + + public XMLStreamWriter createXMLStreamWriter(OutputStream stream) + throws XMLStreamException + { + return createXMLStreamWriter(stream, "UTF-8"); + } + + public XMLStreamWriter createXMLStreamWriter(OutputStream stream, + String encoding) + throws XMLStreamException + { + if (encoding == null) + encoding = "UTF-8"; + try + { + Writer writer = new OutputStreamWriter(stream, encoding); + return new XMLStreamWriterImpl(writer, encoding, prefixDefaulting); + } + catch (UnsupportedEncodingException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + public XMLStreamWriter createXMLStreamWriter(Result result) + throws XMLStreamException + { + if (result instanceof StreamResult) + { + StreamResult sr = (StreamResult) result; + OutputStream out = sr.getOutputStream(); + if (out != null) + return createXMLStreamWriter(out); + Writer writer = sr.getWriter(); + if (writer != null) + return createXMLStreamWriter(writer); + } + throw new UnsupportedOperationException(); + } + + public XMLEventWriter createXMLEventWriter(OutputStream stream) + throws XMLStreamException + { + XMLStreamWriter writer = createXMLStreamWriter(stream); + return new XMLEventWriterImpl(writer); + } + + public XMLEventWriter createXMLEventWriter(OutputStream stream, + String encoding) + throws XMLStreamException + { + XMLStreamWriter writer = createXMLStreamWriter(stream, encoding); + return new XMLEventWriterImpl(writer); + } + + public XMLEventWriter createXMLEventWriter(Writer stream) + throws XMLStreamException + { + XMLStreamWriter writer = createXMLStreamWriter(stream); + return new XMLEventWriterImpl(writer); + } + + public XMLEventWriter createXMLEventWriter(Result result) + throws XMLStreamException + { + if (result instanceof StreamResult) + { + StreamResult sr = (StreamResult) result; + OutputStream out = sr.getOutputStream(); + if (out != null) + return createXMLEventWriter(out); + Writer writer = sr.getWriter(); + if (writer != null) + return createXMLEventWriter(writer); + } + throw new UnsupportedOperationException(); + } + + public void setProperty(String name, Object value) + throws IllegalArgumentException + { + if (IS_REPAIRING_NAMESPACES.equals(name)) + prefixDefaulting = ((Boolean) value).booleanValue(); + else + throw new IllegalArgumentException(name); + } + + public Object getProperty(String name) + throws IllegalArgumentException + { + if (IS_REPAIRING_NAMESPACES.equals(name)) + return new Boolean(prefixDefaulting); + throw new IllegalArgumentException(name); + } + + public boolean isPropertySupported(String name) + { + if (IS_REPAIRING_NAMESPACES.equals(name)) + return true; + return false; + } + + public boolean isPrefixDefaulting() + { + return prefixDefaulting; + } + + public void setPrefixDefaulting(boolean value) + { + prefixDefaulting = value; + } + +} diff --git a/libjava/classpath/gnu/xml/stream/XMLParser.java b/libjava/classpath/gnu/xml/stream/XMLParser.java new file mode 100644 index 000000000..71e876569 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/XMLParser.java @@ -0,0 +1,5434 @@ +/* XMLParser.java -- + 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. + +Partly derived from code which carried the following notice: + + Copyright (c) 1997, 1998 by Microstar Software Ltd. + + AElfred is free for both commercial and non-commercial use and + redistribution, provided that Microstar's copyright and disclaimer are + retained intact. You are free to modify AElfred for your own use and + to redistribute AElfred with your modifications, provided that the + modifications are clearly documented. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + merchantability or fitness for a particular purpose. Please use it AT + YOUR OWN RISK. +*/ + +package gnu.xml.stream; + +import gnu.java.lang.CPStringBuilder; + +import java.io.BufferedInputStream; +import java.io.EOFException; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.IOException; +import java.io.Reader; +import java.io.StringReader; +import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.StringTokenizer; + +import javax.xml.XMLConstants; +import javax.xml.namespace.NamespaceContext; +import javax.xml.namespace.QName; +import javax.xml.stream.Location; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLReporter; +import javax.xml.stream.XMLResolver; +import javax.xml.stream.XMLStreamConstants; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamReader; + +import gnu.java.net.CRLFInputStream; +import gnu.classpath.debug.TeeInputStream; +import gnu.classpath.debug.TeeReader; + +/** + * An XML parser. + * This parser supports the following additional StAX properties: + * + * + * + * + * + * + * + * + * + * + *
      gnu.xml.stream.stringInterningBooleanIndicates whether markup strings will be interned
      gnu.xml.stream.xmlBaseBooleanIndicates whether XML Base processing will be performed
      gnu.xml.stream.baseURIStringReturns the base URI of the current event
      + * + * @see http://www.w3.org/TR/REC-xml/ + * @see http://www.w3.org/TR/xml11/ + * @see http://www.w3.org/TR/REC-xml-names + * @see http://www.w3.org/TR/xml-names11 + * @see http://www.w3.org/TR/xmlbase/ + * + * @author Chris Burdess + */ +public class XMLParser + implements XMLStreamReader, NamespaceContext +{ + + // -- parser state machine states -- + private static final int INIT = 0; // start state + private static final int PROLOG = 1; // in prolog + private static final int CONTENT = 2; // in content + private static final int EMPTY_ELEMENT = 3; // empty element state + private static final int MISC = 4; // in Misc (after root element) + + // -- parameters for parsing literals -- + private final static int LIT_ENTITY_REF = 2; + private final static int LIT_NORMALIZE = 4; + private final static int LIT_ATTRIBUTE = 8; + private final static int LIT_DISABLE_PE = 16; + private final static int LIT_DISABLE_CREF = 32; + private final static int LIT_DISABLE_EREF = 64; + private final static int LIT_PUBID = 256; + + // -- types of attribute values -- + final static int ATTRIBUTE_DEFAULT_UNDECLARED = 30; + final static int ATTRIBUTE_DEFAULT_SPECIFIED = 31; + final static int ATTRIBUTE_DEFAULT_IMPLIED = 32; + final static int ATTRIBUTE_DEFAULT_REQUIRED = 33; + final static int ATTRIBUTE_DEFAULT_FIXED = 34; + + // -- additional event types -- + final static int START_ENTITY = 50; + final static int END_ENTITY = 51; + + /** + * The current input. + */ + private Input input; + + /** + * Stack of inputs representing XML general entities. + * The input representing the XML input stream or reader is always the + * first element in this stack. + */ + private LinkedList inputStack = new LinkedList(); + + /** + * Stack of start-entity events to be reported. + */ + private LinkedList startEntityStack = new LinkedList(); + + /** + * Stack of end-entity events to be reported. + */ + private LinkedList endEntityStack = new LinkedList(); + + /** + * Current parser state within the main state machine. + */ + private int state = INIT; + + /** + * The (type of the) current event. + */ + private int event; + + /** + * The element name stack. The first element in this stack will be the + * root element. + */ + private LinkedList stack = new LinkedList(); + + /** + * Stack of namespace contexts. These are maps specifying prefix-to-URI + * mappings. The first element in this stack is the most recent namespace + * context (i.e. the other way around from the element name stack). + */ + private LinkedList namespaces = new LinkedList(); + + /** + * The base-URI stack. This holds the base URI context for each element. + * The first element in this stack is the most recent context (i.e. the + * other way around from the element name stack). + */ + private LinkedList bases = new LinkedList(); + + /** + * The list of attributes for the current element, in the order defined in + * the XML stream. + */ + private ArrayList attrs = new ArrayList(); + + /** + * Buffer for text and character data. + */ + private StringBuffer buf = new StringBuffer(); + + /** + * Buffer for NMTOKEN strings (markup). + */ + private StringBuffer nmtokenBuf = new StringBuffer(); + + /** + * Buffer for string literals. (e.g. attribute values) + */ + private StringBuffer literalBuf = new StringBuffer(); + + /** + * Temporary Unicode character buffer used during character data reads. + */ + private int[] tmpBuf = new int[1024]; + + /** + * The element content model for the current element. + */ + private ContentModel currentContentModel; + + /** + * The validation stack. This holds lists of the elements seen for each + * element, in order to determine whether the names and order of these + * elements match the content model for the element. The last entry in + * this stack represents the current element. + */ + private LinkedList validationStack; + + /** + * These sets contain the IDs and the IDREFs seen in the document, to + * ensure that IDs are unique and that each IDREF refers to an ID in the + * document. + */ + private HashSet ids, idrefs; + + /** + * The target and data associated with the current processing instruction + * event. + */ + private String piTarget, piData; + + /** + * The XML version declared in the XML declaration. + */ + private String xmlVersion; + + /** + * The encoding declared in the XML declaration. + */ + private String xmlEncoding; + + /** + * The standalone value declared in the XML declaration. + */ + private Boolean xmlStandalone; + + /** + * The document type definition. + */ + Doctype doctype; + + /** + * State variables for determining parameter-entity expansion. + */ + private boolean expandPE, peIsError; + + /** + * Whether this is a validating parser. + */ + private final boolean validating; + + /** + * Whether strings representing markup will be interned. + */ + private final boolean stringInterning; + + /** + * If true, CDATA sections will be merged with adjacent text nodes into a + * single event. + */ + private final boolean coalescing; + + /** + * Whether to replace general entity references with their replacement + * text automatically during parsing. + * Otherwise entity-reference events will be issued. + */ + private final boolean replaceERefs; + + /** + * Whether to support external entities. + */ + private final boolean externalEntities; + + /** + * Whether to support DTDs. + */ + private final boolean supportDTD; + + /** + * Whether to support XML namespaces. If true, namespace information will + * be available. Otherwise namespaces will simply be reported as ordinary + * attributes. + */ + private final boolean namespaceAware; + + /** + * Whether to support XML Base. If true, URIs specified in xml:base + * attributes will be honoured when resolving external entities. + */ + private final boolean baseAware; + + /** + * Whether to report extended event types (START_ENTITY and END_ENTITY) + * in addition to the standard event types. Used by the SAX parser. + */ + private final boolean extendedEventTypes; + + /** + * The reporter to receive parsing warnings. + */ + final XMLReporter reporter; + + /** + * Callback interface for resolving external entities. + */ + final XMLResolver resolver; + + // -- Constants for testing the next kind of markup event -- + private static final String TEST_START_ELEMENT = "<"; + private static final String TEST_END_ELEMENT = ""; + private static final String TEST_END_COMMENT = "--"; + private static final String TEST_END_PI = "?>"; + private static final String TEST_END_CDATA = "]]>"; + + /** + * The general entities predefined by the XML specification. + */ + private static final LinkedHashMap PREDEFINED_ENTITIES = new LinkedHashMap(); + static + { + PREDEFINED_ENTITIES.put("amp", "&"); + PREDEFINED_ENTITIES.put("lt", "<"); + PREDEFINED_ENTITIES.put("gt", ">"); + PREDEFINED_ENTITIES.put("apos", "'"); + PREDEFINED_ENTITIES.put("quot", "\""); + } + + /** + * Creates a new XML parser for the given input stream. + * This constructor should be used where possible, as it allows the + * encoding of the XML data to be correctly determined from the stream. + * @param in the input stream + * @param systemId the URL from which the input stream was retrieved + * (necessary if there are external entities to be resolved) + * @param validating if the parser is to be a validating parser + * @param namespaceAware if the parser should support XML Namespaces + * @param coalescing if CDATA sections should be merged into adjacent text + * nodes + * @param replaceERefs if entity references should be automatically + * replaced by their replacement text (otherwise they will be reported as + * entity-reference events) + * @param externalEntities if external entities should be loaded + * @param supportDTD if support for the XML DTD should be enabled + * @param baseAware if the parser should support XML Base to resolve + * external entities + * @param stringInterning whether strings will be interned during parsing + * @param reporter the reporter to receive warnings during processing + * @param resolver the callback interface used to resolve external + * entities + */ + public XMLParser(InputStream in, String systemId, + boolean validating, + boolean namespaceAware, + boolean coalescing, + boolean replaceERefs, + boolean externalEntities, + boolean supportDTD, + boolean baseAware, + boolean stringInterning, + boolean extendedEventTypes, + XMLReporter reporter, + XMLResolver resolver) + { + this.validating = validating; + this.namespaceAware = namespaceAware; + this.coalescing = coalescing; + this.replaceERefs = replaceERefs; + this.externalEntities = externalEntities; + this.supportDTD = supportDTD; + this.baseAware = baseAware; + this.stringInterning = stringInterning; + this.extendedEventTypes = extendedEventTypes; + this.reporter = reporter; + this.resolver = resolver; + if (validating) + { + validationStack = new LinkedList(); + ids = new HashSet(); + idrefs = new HashSet(); + } + String debug = System.getProperty("gnu.xml.debug.input"); + if (debug != null) + { + try + { + File file = File.createTempFile(debug, ".xml"); + in = new TeeInputStream(in, new FileOutputStream(file)); + } + catch (IOException e) + { + RuntimeException e2 = new RuntimeException(); + e2.initCause(e); + throw e2; + } + } + systemId = canonicalize(systemId); + pushInput(new Input(in, null, null, systemId, null, null, false, true)); + } + + /** + * Creates a new XML parser for the given character stream. + * This constructor is only available for compatibility with the JAXP + * APIs, which permit XML to be parsed from a character stream. Because + * the encoding specified by the character stream may conflict with that + * specified in the XML declaration, this method should be avoided where + * possible. + * @param in the input stream + * @param systemId the URL from which the input stream was retrieved + * (necessary if there are external entities to be resolved) + * @param validating if the parser is to be a validating parser + * @param namespaceAware if the parser should support XML Namespaces + * @param coalescing if CDATA sections should be merged into adjacent text + * nodes + * @param replaceERefs if entity references should be automatically + * replaced by their replacement text (otherwise they will be reported as + * entity-reference events) + * @param externalEntities if external entities should be loaded + * @param supportDTD if support for the XML DTD should be enabled + * @param baseAware if the parser should support XML Base to resolve + * external entities + * @param stringInterning whether strings will be interned during parsing + * @param reporter the reporter to receive warnings during processing + * @param resolver the callback interface used to resolve external + * entities + */ + public XMLParser(Reader reader, String systemId, + boolean validating, + boolean namespaceAware, + boolean coalescing, + boolean replaceERefs, + boolean externalEntities, + boolean supportDTD, + boolean baseAware, + boolean stringInterning, + boolean extendedEventTypes, + XMLReporter reporter, + XMLResolver resolver) + { + this.validating = validating; + this.namespaceAware = namespaceAware; + this.coalescing = coalescing; + this.replaceERefs = replaceERefs; + this.externalEntities = externalEntities; + this.supportDTD = supportDTD; + this.baseAware = baseAware; + this.stringInterning = stringInterning; + this.extendedEventTypes = extendedEventTypes; + this.reporter = reporter; + this.resolver = resolver; + if (validating) + { + validationStack = new LinkedList(); + ids = new HashSet(); + idrefs = new HashSet(); + } + String debug = System.getProperty("gnu.xml.debug.input"); + if (debug != null) + { + try + { + File file = File.createTempFile(debug, ".xml"); + reader = new TeeReader(reader, new FileWriter(file)); + } + catch (IOException e) + { + RuntimeException e2 = new RuntimeException(); + e2.initCause(e); + throw e2; + } + } + systemId = canonicalize(systemId); + pushInput(new Input(null, reader, null, systemId, null, null, false, true)); + } + + // -- NamespaceContext -- + + public String getNamespaceURI(String prefix) + { + if (XMLConstants.XML_NS_PREFIX.equals(prefix)) + return XMLConstants.XML_NS_URI; + if (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix)) + return XMLConstants.XMLNS_ATTRIBUTE_NS_URI; + for (Iterator i = namespaces.iterator(); i.hasNext(); ) + { + LinkedHashMap ctx = (LinkedHashMap) i.next(); + String namespaceURI = (String) ctx.get(prefix); + if (namespaceURI != null) + return namespaceURI; + } + return null; + } + + public String getPrefix(String namespaceURI) + { + if (XMLConstants.XML_NS_URI.equals(namespaceURI)) + return XMLConstants.XML_NS_PREFIX; + if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI)) + return XMLConstants.XMLNS_ATTRIBUTE; + for (Iterator i = namespaces.iterator(); i.hasNext(); ) + { + LinkedHashMap ctx = (LinkedHashMap) i.next(); + if (ctx.containsValue(namespaceURI)) + { + for (Iterator j = ctx.entrySet().iterator(); j.hasNext(); ) + { + Map.Entry entry = (Map.Entry) i.next(); + String uri = (String) entry.getValue(); + if (uri.equals(namespaceURI)) + return (String) entry.getKey(); + } + } + } + return null; + } + + public Iterator getPrefixes(String namespaceURI) + { + if (XMLConstants.XML_NS_URI.equals(namespaceURI)) + return Collections.singleton(XMLConstants.XML_NS_PREFIX).iterator(); + if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI)) + return Collections.singleton(XMLConstants.XMLNS_ATTRIBUTE).iterator(); + LinkedList acc = new LinkedList(); + for (Iterator i = namespaces.iterator(); i.hasNext(); ) + { + LinkedHashMap ctx = (LinkedHashMap) i.next(); + if (ctx.containsValue(namespaceURI)) + { + for (Iterator j = ctx.entrySet().iterator(); j.hasNext(); ) + { + Map.Entry entry = (Map.Entry) i.next(); + String uri = (String) entry.getValue(); + if (uri.equals(namespaceURI)) + acc.add(entry.getKey()); + } + } + } + return acc.iterator(); + } + + // -- XMLStreamReader -- + + public void close() + throws XMLStreamException + { + stack = null; + namespaces = null; + bases = null; + buf = null; + attrs = null; + doctype = null; + + inputStack = null; + validationStack = null; + ids = null; + idrefs = null; + } + + public NamespaceContext getNamespaceContext() + { + return this; + } + + public int getAttributeCount() + { + return attrs.size(); + } + + public String getAttributeLocalName(int index) + { + Attribute a = (Attribute) attrs.get(index); + return a.localName; + } + + public String getAttributeNamespace(int index) + { + String prefix = getAttributePrefix(index); + return getNamespaceURI(prefix); + } + + public String getAttributePrefix(int index) + { + Attribute a = (Attribute) attrs.get(index); + return a.prefix; + } + + public QName getAttributeName(int index) + { + Attribute a = (Attribute) attrs.get(index); + String namespaceURI = getNamespaceURI(a.prefix); + return new QName(namespaceURI, a.localName, a.prefix); + } + + public String getAttributeType(int index) + { + Attribute a = (Attribute) attrs.get(index); + return a.type; + } + + private String getAttributeType(String elementName, String attName) + { + if (doctype != null) + { + AttributeDecl att = doctype.getAttributeDecl(elementName, attName); + if (att != null) + return att.type; + } + return "CDATA"; + } + + public String getAttributeValue(int index) + { + Attribute a = (Attribute) attrs.get(index); + return a.value; + } + + public String getAttributeValue(String namespaceURI, String localName) + { + for (Iterator i = attrs.iterator(); i.hasNext(); ) + { + Attribute a = (Attribute) i.next(); + if (a.localName.equals(localName)) + { + String uri = getNamespaceURI(a.prefix); + if ((uri == null && namespaceURI == null) || + (uri != null && uri.equals(namespaceURI))) + return a.value; + } + } + return null; + } + + boolean isAttributeDeclared(int index) + { + if (doctype == null) + return false; + Attribute a = (Attribute) attrs.get(index); + String qn = ("".equals(a.prefix)) ? a.localName : + a.prefix + ":" + a.localName; + String elementName = buf.toString(); + return doctype.isAttributeDeclared(elementName, qn); + } + + public String getCharacterEncodingScheme() + { + return xmlEncoding; + } + + public String getElementText() + throws XMLStreamException + { + if (event != XMLStreamConstants.START_ELEMENT) + throw new XMLStreamException("current event must be START_ELEMENT"); + CPStringBuilder elementText = new CPStringBuilder(); + int depth = stack.size(); + while (event != XMLStreamConstants.END_ELEMENT || stack.size() > depth) + { + switch (next()) + { + case XMLStreamConstants.CHARACTERS: + case XMLStreamConstants.SPACE: + elementText.append(buf.toString()); + } + } + return elementText.toString(); + } + + public String getEncoding() + { + return (input.inputEncoding == null) ? "UTF-8" : input.inputEncoding; + } + + public int getEventType() + { + return event; + } + + public String getLocalName() + { + switch (event) + { + case XMLStreamConstants.START_ELEMENT: + case XMLStreamConstants.END_ELEMENT: + String qName = buf.toString(); + int ci = qName.indexOf(':'); + String localName = (ci == -1) ? qName : qName.substring(ci + 1); + if (stringInterning) + localName = localName.intern(); + return localName; + default: + return null; + } + } + + public Location getLocation() + { + return input; + } + + public QName getName() + { + switch (event) + { + case XMLStreamConstants.START_ELEMENT: + case XMLStreamConstants.END_ELEMENT: + String qName = buf.toString(); + int ci = qName.indexOf(':'); + String localName = (ci == -1) ? qName : qName.substring(ci + 1); + if (stringInterning) + localName = localName.intern(); + String prefix = (ci == -1) ? + (namespaceAware ? XMLConstants.DEFAULT_NS_PREFIX : null) : + qName.substring(0, ci); + if (stringInterning && prefix != null) + prefix = prefix.intern(); + String namespaceURI = getNamespaceURI(prefix); + return new QName(namespaceURI, localName, prefix); + default: + return null; + } + } + + public int getNamespaceCount() + { + if (!namespaceAware || namespaces.isEmpty()) + return 0; + switch (event) + { + case XMLStreamConstants.START_ELEMENT: + case XMLStreamConstants.END_ELEMENT: + LinkedHashMap ctx = (LinkedHashMap) namespaces.getFirst(); + return ctx.size(); + default: + return 0; + } + } + + public String getNamespacePrefix(int index) + { + LinkedHashMap ctx = (LinkedHashMap) namespaces.getFirst(); + int count = 0; + for (Iterator i = ctx.keySet().iterator(); i.hasNext(); ) + { + String prefix = (String) i.next(); + if (count++ == index) + return prefix; + } + return null; + } + + public String getNamespaceURI() + { + switch (event) + { + case XMLStreamConstants.START_ELEMENT: + case XMLStreamConstants.END_ELEMENT: + String qName = buf.toString(); + int ci = qName.indexOf(':'); + if (ci == -1) + return null; + String prefix = qName.substring(0, ci); + return getNamespaceURI(prefix); + default: + return null; + } + } + + public String getNamespaceURI(int index) + { + LinkedHashMap ctx = (LinkedHashMap) namespaces.getFirst(); + int count = 0; + for (Iterator i = ctx.values().iterator(); i.hasNext(); ) + { + String uri = (String) i.next(); + if (count++ == index) + return uri; + } + return null; + } + + public String getPIData() + { + return piData; + } + + public String getPITarget() + { + return piTarget; + } + + public String getPrefix() + { + switch (event) + { + case XMLStreamConstants.START_ELEMENT: + case XMLStreamConstants.END_ELEMENT: + String qName = buf.toString(); + int ci = qName.indexOf(':'); + String prefix = (ci == -1) ? + (namespaceAware ? XMLConstants.DEFAULT_NS_PREFIX : null) : + qName.substring(0, ci); + if (stringInterning && prefix != null) + prefix = prefix.intern(); + return prefix; + default: + return null; + } + } + + public Object getProperty(String name) + throws IllegalArgumentException + { + if (name == null) + throw new IllegalArgumentException("name is null"); + if (XMLInputFactory.ALLOCATOR.equals(name)) + return null; + if (XMLInputFactory.IS_COALESCING.equals(name)) + return coalescing ? Boolean.TRUE : Boolean.FALSE; + if (XMLInputFactory.IS_NAMESPACE_AWARE.equals(name)) + return namespaceAware ? Boolean.TRUE : Boolean.FALSE; + if (XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES.equals(name)) + return replaceERefs ? Boolean.TRUE : Boolean.FALSE; + if (XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES.equals(name)) + return externalEntities ? Boolean.TRUE : Boolean.FALSE; + if (XMLInputFactory.IS_VALIDATING.equals(name)) + return Boolean.FALSE; + if (XMLInputFactory.REPORTER.equals(name)) + return reporter; + if (XMLInputFactory.RESOLVER.equals(name)) + return resolver; + if (XMLInputFactory.SUPPORT_DTD.equals(name)) + return supportDTD ? Boolean.TRUE : Boolean.FALSE; + if ("gnu.xml.stream.stringInterning".equals(name)) + return stringInterning ? Boolean.TRUE : Boolean.FALSE; + if ("gnu.xml.stream.xmlBase".equals(name)) + return baseAware ? Boolean.TRUE : Boolean.FALSE; + if ("gnu.xml.stream.baseURI".equals(name)) + return getXMLBase(); + return null; + } + + public String getText() + { + return buf.toString(); + } + + public char[] getTextCharacters() + { + return buf.toString().toCharArray(); + } + + public int getTextCharacters(int sourceStart, char[] target, + int targetStart, int length) + throws XMLStreamException + { + length = Math.min(sourceStart + buf.length(), length); + int sourceEnd = sourceStart + length; + buf.getChars(sourceStart, sourceEnd, target, targetStart); + return length; + } + + public int getTextLength() + { + return buf.length(); + } + + public int getTextStart() + { + return 0; + } + + public String getVersion() + { + return (xmlVersion == null) ? "1.0" : xmlVersion; + } + + public boolean hasName() + { + switch (event) + { + case XMLStreamConstants.START_ELEMENT: + case XMLStreamConstants.END_ELEMENT: + return true; + default: + return false; + } + } + + public boolean hasText() + { + switch (event) + { + case XMLStreamConstants.CHARACTERS: + case XMLStreamConstants.SPACE: + return true; + default: + return false; + } + } + + public boolean isAttributeSpecified(int index) + { + Attribute a = (Attribute) attrs.get(index); + return a.specified; + } + + public boolean isCharacters() + { + return (event == XMLStreamConstants.CHARACTERS); + } + + public boolean isEndElement() + { + return (event == XMLStreamConstants.END_ELEMENT); + } + + public boolean isStandalone() + { + return Boolean.TRUE.equals(xmlStandalone); + } + + public boolean isStartElement() + { + return (event == XMLStreamConstants.START_ELEMENT); + } + + public boolean isWhiteSpace() + { + return (event == XMLStreamConstants.SPACE); + } + + public int nextTag() + throws XMLStreamException + { + do + { + switch (next()) + { + case XMLStreamConstants.START_ELEMENT: + case XMLStreamConstants.END_ELEMENT: + case XMLStreamConstants.CHARACTERS: + case XMLStreamConstants.SPACE: + case XMLStreamConstants.COMMENT: + case XMLStreamConstants.PROCESSING_INSTRUCTION: + break; + default: + throw new XMLStreamException("Unexpected event type: " + event); + } + } + while (event != XMLStreamConstants.START_ELEMENT && + event != XMLStreamConstants.END_ELEMENT); + return event; + } + + public void require(int type, String namespaceURI, String localName) + throws XMLStreamException + { + if (event != type) + throw new XMLStreamException("Current event type is " + event); + if (event == XMLStreamConstants.START_ELEMENT || + event == XMLStreamConstants.END_ELEMENT) + { + String ln = getLocalName(); + if (!ln.equals(localName)) + throw new XMLStreamException("Current local-name is " + ln); + String uri = getNamespaceURI(); + if ((uri == null && namespaceURI != null) || + (uri != null && !uri.equals(namespaceURI))) + throw new XMLStreamException("Current namespace URI is " + uri); + } + } + + public boolean standaloneSet() + { + return (xmlStandalone != null); + } + + public boolean hasNext() + throws XMLStreamException + { + return (event != XMLStreamConstants.END_DOCUMENT && event != -1); + } + + public int next() + throws XMLStreamException + { + if (event == XMLStreamConstants.END_ELEMENT) + { + // Pop namespace context + if (namespaceAware && !namespaces.isEmpty()) + namespaces.removeFirst(); + // Pop base context + if (baseAware && !bases.isEmpty()) + bases.removeFirst(); + } + if (!startEntityStack.isEmpty()) + { + String entityName = (String) startEntityStack.removeFirst(); + buf.setLength(0); + buf.append(entityName); + event = START_ENTITY; + return extendedEventTypes ? event : next(); + } + else if (!endEntityStack.isEmpty()) + { + String entityName = (String) endEntityStack.removeFirst(); + buf.setLength(0); + buf.append(entityName); + event = END_ENTITY; + return extendedEventTypes ? event : next(); + } + try + { + if (!input.initialized) + input.init(); + switch (state) + { + case CONTENT: + if (tryRead(TEST_END_ELEMENT)) + { + readEndElement(); + if (stack.isEmpty()) + state = MISC; + event = XMLStreamConstants.END_ELEMENT; + } + else if (tryRead(TEST_COMMENT)) + { + readComment(false); + event = XMLStreamConstants.COMMENT; + } + else if (tryRead(TEST_PI)) + { + readPI(false); + event = XMLStreamConstants.PROCESSING_INSTRUCTION; + } + else if (tryRead(TEST_CDATA)) + { + readCDSect(); + event = XMLStreamConstants.CDATA; + } + else if (tryRead(TEST_START_ELEMENT)) + { + state = readStartElement(); + event = XMLStreamConstants.START_ELEMENT; + } + else + { + // Check for character reference or predefined entity + mark(8); + int c = readCh(); + if (c == 0x26) // '&' + { + c = readCh(); + if (c == 0x23) // '#' + { + reset(); + event = readCharData(null); + } + else + { + // entity reference + reset(); + readCh(); // & + readReference(); + String ref = buf.toString(); + String text = (String) PREDEFINED_ENTITIES.get(ref); + if (text != null) + { + event = readCharData(text); + } + else if (replaceERefs && !isUnparsedEntity(ref)) + { + // this will report a start-entity event + boolean external = false; + if (doctype != null) + { + Object entity = doctype.getEntity(ref); + if (entity instanceof ExternalIds) + external = true; + } + expandEntity(ref, false, external); + event = next(); + } + else + { + event = XMLStreamConstants.ENTITY_REFERENCE; + } + } + } + else + { + reset(); + event = readCharData(null); + if (validating && doctype != null) + validatePCData(buf.toString()); + } + } + break; + case EMPTY_ELEMENT: + String elementName = (String) stack.removeLast(); + buf.setLength(0); + buf.append(elementName); + state = stack.isEmpty() ? MISC : CONTENT; + event = XMLStreamConstants.END_ELEMENT; + if (validating && doctype != null) + endElementValidationHook(); + break; + case INIT: // XMLDecl? + if (tryRead(TEST_XML_DECL)) + readXMLDecl(); + input.finalizeEncoding(); + event = XMLStreamConstants.START_DOCUMENT; + state = PROLOG; + break; + case PROLOG: // Misc* (doctypedecl Misc*)? + skipWhitespace(); + if (doctype == null && tryRead(TEST_DOCTYPE_DECL)) + { + readDoctypeDecl(); + event = XMLStreamConstants.DTD; + } + else if (tryRead(TEST_COMMENT)) + { + readComment(false); + event = XMLStreamConstants.COMMENT; + } + else if (tryRead(TEST_PI)) + { + readPI(false); + event = XMLStreamConstants.PROCESSING_INSTRUCTION; + } + else if (tryRead(TEST_START_ELEMENT)) + { + state = readStartElement(); + event = XMLStreamConstants.START_ELEMENT; + } + else + { + int c = readCh(); + error("no root element: U+" + Integer.toHexString(c)); + } + break; + case MISC: // Comment | PI | S + skipWhitespace(); + if (tryRead(TEST_COMMENT)) + { + readComment(false); + event = XMLStreamConstants.COMMENT; + } + else if (tryRead(TEST_PI)) + { + readPI(false); + event = XMLStreamConstants.PROCESSING_INSTRUCTION; + } + else + { + if (event == XMLStreamConstants.END_DOCUMENT) + throw new NoSuchElementException(); + int c = readCh(); + if (c != -1) + error("Only comments and PIs may appear after " + + "the root element"); + event = XMLStreamConstants.END_DOCUMENT; + } + break; + default: + event = -1; + } + return event; + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(); + e2.initCause(e); + throw e2; + } + } + + // package private + + /** + * Returns the current element name. + */ + String getCurrentElement() + { + return (String) stack.getLast(); + } + + // private + + private void mark(int limit) + throws IOException + { + input.mark(limit); + } + + private void reset() + throws IOException + { + input.reset(); + } + + private int read() + throws IOException + { + return input.read(); + } + + private int read(int[] b, int off, int len) + throws IOException + { + return input.read(b, off, len); + } + + /** + * Parsed character read. + */ + private int readCh() + throws IOException, XMLStreamException + { + int c = read(); + if (expandPE && c == 0x25) // '%' + { + if (peIsError) + error("PE reference within decl in internal subset."); + expandPEReference(); + return readCh(); + } + return c; + } + + /** + * Reads the next character, ensuring it is the character specified. + * @param delim the character to match + * @exception XMLStreamException if the next character is not the + * specified one + */ + private void require(char delim) + throws IOException, XMLStreamException + { + mark(1); + int c = readCh(); + if (delim != c) + { + reset(); + error("required character (got U+" + Integer.toHexString(c) + ")", + new Character(delim)); + } + } + + /** + * Reads the next few characters, ensuring they match the string specified. + * @param delim the string to match + * @exception XMLStreamException if the next characters do not match the + * specified string + */ + private void require(String delim) + throws IOException, XMLStreamException + { + char[] chars = delim.toCharArray(); + int len = chars.length; + mark(len); + int off = 0; + do + { + int l2 = read(tmpBuf, off, len - off); + if (l2 == -1) + { + reset(); + error("EOF before required string", delim); + } + off += l2; + } + while (off < len); + for (int i = 0; i < chars.length; i++) + { + if (chars[i] != tmpBuf[i]) + { + reset(); + error("required string", delim); + } + } + } + + /** + * Try to read a single character. On failure, reset the stream. + * @param delim the character to test + * @return true if the character matched delim, false otherwise. + */ + private boolean tryRead(char delim) + throws IOException, XMLStreamException + { + mark(1); + int c = readCh(); + if (delim != c) + { + reset(); + return false; + } + return true; + } + + /** + * Tries to read the specified characters. + * If successful, the stream is positioned after the last character, + * otherwise it is reset. + * @param test the string to test + * @return true if the characters matched the test string, false otherwise. + */ + private boolean tryRead(String test) + throws IOException + { + char[] chars = test.toCharArray(); + int len = chars.length; + mark(len); + int count = 0; + int l2 = read(tmpBuf, 0, len); + if (l2 == -1) + { + reset(); + return false; + } + count += l2; + // check the characters we received first before doing additional reads + for (int i = 0; i < count; i++) + { + if (chars[i] != tmpBuf[i]) + { + reset(); + return false; + } + } + while (count < len) + { + // force read + int c = read(); + if (c == -1) + { + reset(); + return false; + } + tmpBuf[count] = (char) c; + // check each character as it is read + if (chars[count] != tmpBuf[count]) + { + reset(); + return false; + } + count++; + } + return true; + } + + /** + * Reads characters until the specified test string is encountered. + * @param delim the string delimiting the end of the characters + */ + private void readUntil(String delim) + throws IOException, XMLStreamException + { + int startLine = input.line; + try + { + while (!tryRead(delim)) + { + int c = readCh(); + if (c == -1) + throw new EOFException(); + else if (input.xml11) + { + if (!isXML11Char(c) || isXML11RestrictedChar(c)) + error("illegal XML 1.1 character", + "U+" + Integer.toHexString(c)); + } + else if (!isChar(c)) + error("illegal XML character", + "U+" + Integer.toHexString(c)); + buf.append(Character.toChars(c)); + } + } + catch (EOFException e) + { + error("end of input while looking for delimiter "+ + "(started on line " + startLine + ')', delim); + } + } + + /** + * Reads any whitespace characters. + * @return true if whitespace characters were read, false otherwise + */ + private boolean tryWhitespace() + throws IOException, XMLStreamException + { + boolean white; + boolean ret = false; + do + { + mark(1); + int c = readCh(); + while (c == -1 && inputStack.size() > 1) + { + popInput(); + c = readCh(); + } + white = (c == 0x20 || c == 0x09 || c == 0x0a || c == 0x0d); + if (white) + ret = true; + } + while (white); + reset(); + return ret; + } + + /** + * Skip over any whitespace characters. + */ + private void skipWhitespace() + throws IOException, XMLStreamException + { + boolean white; + do + { + mark(1); + int c = readCh(); + while (c == -1 && inputStack.size() > 1) + { + popInput(); + c = readCh(); + } + white = (c == 0x20 || c == 0x09 || c == 0x0a || c == 0x0d); + } + while (white); + reset(); + } + + /** + * Try to read as many whitespace characters as are available. + * @exception XMLStreamException if no whitespace characters were seen + */ + private void requireWhitespace() + throws IOException, XMLStreamException + { + if (!tryWhitespace()) + error("whitespace required"); + } + + /** + * Returns the current base URI for resolving external entities. + */ + String getXMLBase() + { + if (baseAware) + { + for (Iterator i = bases.iterator(); i.hasNext(); ) + { + String base = (String) i.next(); + if (base != null) + return base; + } + } + return input.systemId; + } + + /** + * Push the specified text input source. + */ + private void pushInput(String name, String text, boolean report, + boolean normalize) + throws IOException, XMLStreamException + { + // Check for recursion + if (name != null && !"".equals(name)) + { + for (Iterator i = inputStack.iterator(); i.hasNext(); ) + { + Input ctx = (Input) i.next(); + if (name.equals(ctx.name)) + error("entities may not be self-recursive", name); + } + } + else + report = false; + pushInput(new Input(null, new StringReader(text), input.publicId, + input.systemId, name, input.inputEncoding, report, + normalize)); + } + + /** + * Push the specified external input source. + */ + private void pushInput(String name, ExternalIds ids, boolean report, + boolean normalize) + throws IOException, XMLStreamException + { + if (!externalEntities) + return; + String url = canonicalize(absolutize(input.systemId, ids.systemId)); + // Check for recursion + for (Iterator i = inputStack.iterator(); i.hasNext(); ) + { + Input ctx = (Input) i.next(); + if (url.equals(ctx.systemId)) + error("entities may not be self-recursive", url); + if (name != null && !"".equals(name) && name.equals(ctx.name)) + error("entities may not be self-recursive", name); + } + if (name == null || "".equals(name)) + report = false; + InputStream in = null; + if (resolver != null) + { + Object obj = resolver.resolveEntity(ids.publicId, url, getXMLBase(), + null); + if (obj instanceof InputStream) + in = (InputStream) obj; + } + if (in == null) + in = resolve(url); + if (in == null) + error("unable to resolve external entity", + (ids.systemId != null) ? ids.systemId : ids.publicId); + pushInput(new Input(in, null, ids.publicId, url, name, null, report, + normalize)); + input.init(); + if (tryRead(TEST_XML_DECL)) + readTextDecl(); + input.finalizeEncoding(); + } + + /** + * Push the specified input source (general entity) onto the input stack. + */ + private void pushInput(Input input) + { + if (input.report) + startEntityStack.addFirst(input.name); + inputStack.addLast(input); + if (this.input != null) + input.xml11 = this.input.xml11; + this.input = input; + } + + /** + * Returns a canonicalized version of the specified URL. + * This is largely to work around a problem with the specification of + * file URLs. + */ + static String canonicalize(String url) + { + if (url == null) + return null; + if (url.startsWith("file:") && !url.startsWith("file://")) + url = "file://" + url.substring(5); + return url; + } + + /** + * "Absolutize" a URL. This resolves a relative URL into an absolute one. + * @param base the current base URL + * @param href the (absolute or relative) URL to resolve + */ + public static String absolutize(String base, String href) + { + if (href == null) + return null; + int ci = href.indexOf(':'); + if (ci > 1 && isURLScheme(href.substring(0, ci))) + { + // href is absolute already + return href; + } + if (base == null) + base = ""; + else + { + int i = base.lastIndexOf('/'); + if (i != -1) + base = base.substring(0, i + 1); + else + base = ""; + } + if ("".equals(base)) + { + // assume file URL relative to current directory + base = System.getProperty("user.dir"); + if (base.charAt(0) == '/') + base = base.substring(1); + base = "file:///" + base.replace(File.separatorChar, '/'); + if (!base.endsWith("/")) + base += "/"; + } + // We can't use java.net.URL here to do the parsing, as it searches for + // a protocol handler. A protocol handler may not be registered for the + // URL scheme here. Do it manually. + // + // Set aside scheme and host portion of base URL + String basePrefix = null; + ci = base.indexOf(':'); + if (ci > 1 && isURLScheme(base.substring(0, ci))) + { + if (base.length() > (ci + 3) && + base.charAt(ci + 1) == '/' && + base.charAt(ci + 2) == '/') + { + int si = base.indexOf('/', ci + 3); + if (si == -1) + base = null; + else + { + basePrefix = base.substring(0, si); + base = base.substring(si); + } + } + else + base = null; + } + if (base == null) // unknown or malformed base URL, use href + return href; + if (href.startsWith("/")) // absolute href pathname + return (basePrefix == null) ? href : basePrefix + href; + // relative href pathname + if (!base.endsWith("/")) + { + int lsi = base.lastIndexOf('/'); + if (lsi == -1) + base = "/"; + else + base = base.substring(0, lsi + 1); + } + while (href.startsWith("../") || href.startsWith("./")) + { + if (href.startsWith("../")) + { + // strip last path component from base + int lsi = base.lastIndexOf('/', base.length() - 2); + if (lsi > -1) + base = base.substring(0, lsi + 1); + href = href.substring(3); // strip ../ prefix + } + else + { + href = href.substring(2); // strip ./ prefix + } + } + return (basePrefix == null) ? base + href : basePrefix + base + href; + } + + /** + * 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 == '+' || c == '.' || c == '-') + continue; + if (c < 65 || (c > 90 && c < 97) || c > 122) + return false; + } + return true; + } + + /** + * Returns an input stream for the given URL. + */ + static InputStream resolve(String url) + throws IOException + { + try + { + return new URL(url).openStream(); + } + catch (MalformedURLException e) + { + return null; + } + catch (IOException e) + { + IOException e2 = new IOException("error resolving " + url); + e2.initCause(e); + throw e2; + } + } + + /** + * Pops the current input source (general entity) off the stack. + */ + private void popInput() + { + Input old = (Input) inputStack.removeLast(); + if (old.report) + endEntityStack.addFirst(old.name); + input = (Input) inputStack.getLast(); + } + + /** + * Parse an entity text declaration. + */ + private void readTextDecl() + throws IOException, XMLStreamException + { + final int flags = LIT_DISABLE_CREF | LIT_DISABLE_PE | LIT_DISABLE_EREF; + requireWhitespace(); + if (tryRead("version")) + { + readEq(); + String v = readLiteral(flags, false); + if ("1.0".equals(v)) + input.xml11 = false; + else if ("1.1".equals(v)) + { + Input i1 = (Input) inputStack.getFirst(); + if (!i1.xml11) + error("external entity specifies later version number"); + input.xml11 = true; + } + else + throw new XMLStreamException("illegal XML version: " + v); + requireWhitespace(); + } + require("encoding"); + readEq(); + String enc = readLiteral(flags, false); + skipWhitespace(); + require("?>"); + input.setInputEncoding(enc); + } + + /** + * Parse the XML declaration. + */ + private void readXMLDecl() + throws IOException, XMLStreamException + { + final int flags = LIT_DISABLE_CREF | LIT_DISABLE_PE | LIT_DISABLE_EREF; + + requireWhitespace(); + require("version"); + readEq(); + xmlVersion = readLiteral(flags, false); + if ("1.0".equals(xmlVersion)) + input.xml11 = false; + else if ("1.1".equals(xmlVersion)) + input.xml11 = true; + else + throw new XMLStreamException("illegal XML version: " + xmlVersion); + + boolean white = tryWhitespace(); + + if (tryRead("encoding")) + { + if (!white) + error("whitespace required before 'encoding='"); + readEq(); + xmlEncoding = readLiteral(flags, false); + white = tryWhitespace(); + } + + if (tryRead("standalone")) + { + if (!white) + error("whitespace required before 'standalone='"); + readEq(); + String standalone = readLiteral(flags, false); + if ("yes".equals(standalone)) + xmlStandalone = Boolean.TRUE; + else if ("no".equals(standalone)) + xmlStandalone = Boolean.FALSE; + else + error("standalone flag must be 'yes' or 'no'", standalone); + } + + skipWhitespace(); + require("?>"); + if (xmlEncoding != null) + input.setInputEncoding(xmlEncoding); + } + + /** + * Parse the DOCTYPE declaration. + */ + private void readDoctypeDecl() + throws IOException, XMLStreamException + { + if (!supportDTD) + error("parser was configured not to support DTDs"); + requireWhitespace(); + String rootName = readNmtoken(true); + skipWhitespace(); + ExternalIds ids = readExternalIds(false, true); + doctype = + this.new Doctype(rootName, ids.publicId, ids.systemId); + + // Parse internal subset first + skipWhitespace(); + if (tryRead('[')) + { + while (true) + { + expandPE = true; + skipWhitespace(); + expandPE = false; + if (tryRead(']')) + break; + else + readMarkupdecl(false); + } + } + skipWhitespace(); + require('>'); + + // Parse external subset + if (ids.systemId != null && externalEntities) + { + pushInput("", ">", false, false); + pushInput("[dtd]", ids, true, true); + // loop until we get back to ">" + while (true) + { + expandPE = true; + skipWhitespace(); + expandPE = false; + mark(1); + int c = readCh(); + if (c == 0x3e) // '>' + break; + else if (c == -1) + popInput(); + else + { + reset(); + expandPE = true; + readMarkupdecl(true); + expandPE = true; + } + } + if (inputStack.size() != 2) + error("external subset has unmatched '>'"); + popInput(); + } + checkDoctype(); + if (validating) + validateDoctype(); + + // Make rootName available for reading + buf.setLength(0); + buf.append(rootName); + } + + /** + * Checks the well-formedness of the DTD. + */ + private void checkDoctype() + throws XMLStreamException + { + // TODO check entity recursion + } + + /** + * Parse the markupdecl production. + */ + private void readMarkupdecl(boolean inExternalSubset) + throws IOException, XMLStreamException + { + boolean saved = expandPE; + mark(1); + require('<'); + reset(); + expandPE = false; + if (tryRead(TEST_ELEMENT_DECL)) + { + expandPE = saved; + readElementDecl(); + } + else if (tryRead(TEST_ATTLIST_DECL)) + { + expandPE = saved; + readAttlistDecl(); + } + else if (tryRead(TEST_ENTITY_DECL)) + { + expandPE = saved; + readEntityDecl(inExternalSubset); + } + else if (tryRead(TEST_NOTATION_DECL)) + { + expandPE = saved; + readNotationDecl(inExternalSubset); + } + else if (tryRead(TEST_PI)) + { + readPI(true); + expandPE = saved; + } + else if (tryRead(TEST_COMMENT)) + { + readComment(true); + expandPE = saved; + } + else if (tryRead("")) + { + readMarkupdecl(inExternalSubset); + skipWhitespace(); + } + } + else if (tryRead("IGNORE")) + { + skipWhitespace(); + require('['); + expandPE = false; + for (int nesting = 1; nesting > 0; ) + { + int c = readCh(); + switch (c) + { + case 0x3c: // '<' + if (tryRead("![")) + nesting++; + break; + case 0x5d: // ']' + if (tryRead("]>")) + nesting--; + break; + case -1: + throw new EOFException(); + } + } + expandPE = saved; + } + else + error("conditional section must begin with INCLUDE or IGNORE"); + } + else + error("expected markup declaration"); + } + + /** + * Parse the elementdecl production. + */ + private void readElementDecl() + throws IOException, XMLStreamException + { + requireWhitespace(); + boolean saved = expandPE; + expandPE = (inputStack.size() > 1); + String name = readNmtoken(true); + expandPE = saved; + requireWhitespace(); + readContentspec(name); + skipWhitespace(); + require('>'); + } + + /** + * Parse the contentspec production. + */ + private void readContentspec(String elementName) + throws IOException, XMLStreamException + { + if (tryRead("EMPTY")) + doctype.addElementDecl(elementName, "EMPTY", new EmptyContentModel()); + else if (tryRead("ANY")) + doctype.addElementDecl(elementName, "ANY", new AnyContentModel()); + else + { + ContentModel model; + CPStringBuilder acc = new CPStringBuilder(); + require('('); + acc.append('('); + skipWhitespace(); + if (tryRead("#PCDATA")) + { + // mixed content + acc.append("#PCDATA"); + MixedContentModel mm = new MixedContentModel(); + model = mm; + skipWhitespace(); + if (tryRead(')')) + { + acc.append(")"); + if (tryRead('*')) + { + mm.min = 0; + mm.max = -1; + } + } + else + { + while (!tryRead(")")) + { + require('|'); + acc.append('|'); + skipWhitespace(); + String name = readNmtoken(true); + acc.append(name); + mm.addName(name); + skipWhitespace(); + } + require('*'); + acc.append(")*"); + mm.min = 0; + mm.max = -1; + } + } + else + model = readElements(acc); + doctype.addElementDecl(elementName, acc.toString(), model); + } + } + + /** + * Parses an element content model. + */ + private ElementContentModel readElements(CPStringBuilder acc) + throws IOException, XMLStreamException + { + int separator; + ElementContentModel model = new ElementContentModel(); + + // Parse first content particle + skipWhitespace(); + model.addContentParticle(readContentParticle(acc)); + // End or separator + skipWhitespace(); + int c = readCh(); + switch (c) + { + case 0x29: // ')' + acc.append(')'); + mark(1); + c = readCh(); + switch (c) + { + case 0x3f: // '?' + acc.append('?'); + model.min = 0; + model.max = 1; + break; + case 0x2a: // '*' + acc.append('*'); + model.min = 0; + model.max = -1; + break; + case 0x2b: // '+' + acc.append('+'); + model.min = 1; + model.max = -1; + break; + default: + reset(); + } + return model; // done + case 0x7c: // '|' + model.or = true; + // fall through + case 0x2c: // ',' + separator = c; + acc.append(Character.toChars(c)); + break; + default: + error("bad separator in content model", + "U+" + Integer.toHexString(c)); + return model; + } + // Parse subsequent content particles + while (true) + { + skipWhitespace(); + model.addContentParticle(readContentParticle(acc)); + skipWhitespace(); + c = readCh(); + if (c == 0x29) // ')' + { + acc.append(')'); + break; + } + else if (c != separator) + { + error("bad separator in content model", + "U+" + Integer.toHexString(c)); + return model; + } + else + acc.append(c); + } + // Check for occurrence indicator + mark(1); + c = readCh(); + switch (c) + { + case 0x3f: // '?' + acc.append('?'); + model.min = 0; + model.max = 1; + break; + case 0x2a: // '*' + acc.append('*'); + model.min = 0; + model.max = -1; + break; + case 0x2b: // '+' + acc.append('+'); + model.min = 1; + model.max = -1; + break; + default: + reset(); + } + return model; + } + + /** + * Parse a cp production. + */ + private ContentParticle readContentParticle(CPStringBuilder acc) + throws IOException, XMLStreamException + { + ContentParticle cp = new ContentParticle(); + if (tryRead('(')) + { + acc.append('('); + cp.content = readElements(acc); + } + else + { + String name = readNmtoken(true); + acc.append(name); + cp.content = name; + mark(1); + int c = readCh(); + switch (c) + { + case 0x3f: // '?' + acc.append('?'); + cp.min = 0; + cp.max = 1; + break; + case 0x2a: // '*' + acc.append('*'); + cp.min = 0; + cp.max = -1; + break; + case 0x2b: // '+' + acc.append('+'); + cp.min = 1; + cp.max = -1; + break; + default: + reset(); + } + } + return cp; + } + + /** + * Parse an attribute-list definition. + */ + private void readAttlistDecl() + throws IOException, XMLStreamException + { + requireWhitespace(); + boolean saved = expandPE; + expandPE = (inputStack.size() > 1); + String elementName = readNmtoken(true); + expandPE = saved; + boolean white = tryWhitespace(); + while (!tryRead('>')) + { + if (!white) + error("whitespace required before attribute definition"); + readAttDef(elementName); + white = tryWhitespace(); + } + } + + /** + * Parse a single attribute definition. + */ + private void readAttDef(String elementName) + throws IOException, XMLStreamException + { + String name = readNmtoken(true); + requireWhitespace(); + CPStringBuilder acc = new CPStringBuilder(); + HashSet values = new HashSet(); + String type = readAttType(acc, values); + if (validating) + { + if ("ID".equals(type)) + { + // VC: One ID per Element Type + for (Iterator i = doctype.attlistIterator(elementName); + i.hasNext(); ) + { + Map.Entry entry = (Map.Entry) i.next(); + AttributeDecl decl = (AttributeDecl) entry.getValue(); + if ("ID".equals(decl.type)) + error("element types must not have more than one ID " + + "attribute"); + } + } + else if ("NOTATION".equals(type)) + { + // VC: One Notation Per Element Type + for (Iterator i = doctype.attlistIterator(elementName); + i.hasNext(); ) + { + Map.Entry entry = (Map.Entry) i.next(); + AttributeDecl decl = (AttributeDecl) entry.getValue(); + if ("NOTATION".equals(decl.type)) + error("element types must not have more than one NOTATION " + + "attribute"); + } + // VC: No Notation on Empty Element + ContentModel model = doctype.getElementModel(elementName); + if (model != null && model.type == ContentModel.EMPTY) + error("attributes of type NOTATION must not be declared on an " + + "element declared EMPTY"); + } + } + String enumer = null; + if ("ENUMERATION".equals(type) || "NOTATION".equals(type)) + enumer = acc.toString(); + else + values = null; + requireWhitespace(); + readDefault(elementName, name, type, enumer, values); + } + + /** + * Parse an attribute type. + */ + private String readAttType(CPStringBuilder acc, HashSet values) + throws IOException, XMLStreamException + { + if (tryRead('(')) + { + readEnumeration(false, acc, values); + return "ENUMERATION"; + } + else + { + String typeString = readNmtoken(true); + if ("NOTATION".equals(typeString)) + { + readNotationType(acc, values); + return typeString; + } + else if ("CDATA".equals(typeString) || + "ID".equals(typeString) || + "IDREF".equals(typeString) || + "IDREFS".equals(typeString) || + "ENTITY".equals(typeString) || + "ENTITIES".equals(typeString) || + "NMTOKEN".equals(typeString) || + "NMTOKENS".equals(typeString)) + return typeString; + else + { + error("illegal attribute type", typeString); + return null; + } + } + } + + /** + * Parse an enumeration. + */ + private void readEnumeration(boolean isNames, CPStringBuilder acc, + HashSet values) + throws IOException, XMLStreamException + { + acc.append('('); + // first token + skipWhitespace(); + String token = readNmtoken(isNames); + acc.append(token); + values.add(token); + // subsequent tokens + skipWhitespace(); + while (!tryRead(')')) + { + require('|'); + acc.append('|'); + skipWhitespace(); + token = readNmtoken(isNames); + // VC: No Duplicate Tokens + if (validating && values.contains(token)) + error("duplicate token", token); + acc.append(token); + values.add(token); + skipWhitespace(); + } + acc.append(')'); + } + + /** + * Parse a notation type for an attribute. + */ + private void readNotationType(CPStringBuilder acc, HashSet values) + throws IOException, XMLStreamException + { + requireWhitespace(); + require('('); + readEnumeration(true, acc, values); + } + + /** + * Parse the default value for an attribute. + */ + private void readDefault(String elementName, String name, + String type, String enumeration, HashSet values) + throws IOException, XMLStreamException + { + int valueType = ATTRIBUTE_DEFAULT_SPECIFIED; + int flags = LIT_ATTRIBUTE; + String value = null, defaultType = null; + boolean saved = expandPE; + + if (!"CDATA".equals(type)) + flags |= LIT_NORMALIZE; + + expandPE = false; + if (tryRead('#')) + { + if (tryRead("FIXED")) + { + defaultType = "#FIXED"; + valueType = ATTRIBUTE_DEFAULT_FIXED; + requireWhitespace(); + value = readLiteral(flags, false); + } + else if (tryRead("REQUIRED")) + { + defaultType = "#REQUIRED"; + valueType = ATTRIBUTE_DEFAULT_REQUIRED; + } + else if (tryRead("IMPLIED")) + { + defaultType = "#IMPLIED"; + valueType = ATTRIBUTE_DEFAULT_IMPLIED; + } + else + error("illegal keyword for attribute default value"); + } + else + value = readLiteral(flags, false); + expandPE = saved; + if (validating) + { + if ("ID".equals(type)) + { + // VC: Attribute Default Value Syntactically Correct + if (value != null && !isNmtoken(value, true)) + error("default value must match Name production", value); + // VC: ID Attribute Default + if (valueType != ATTRIBUTE_DEFAULT_REQUIRED && + valueType != ATTRIBUTE_DEFAULT_IMPLIED) + error("ID attributes must have a declared default of " + + "#IMPLIED or #REQUIRED"); + } + else if (value != null) + { + // VC: Attribute Default Value Syntactically Correct + if ("IDREF".equals(type) || "ENTITY".equals(type)) + { + if (!isNmtoken(value, true)) + error("default value must match Name production", value); + } + else if ("IDREFS".equals(type) || "ENTITIES".equals(type)) + { + StringTokenizer st = new StringTokenizer(value); + while (st.hasMoreTokens()) + { + String token = st.nextToken(); + if (!isNmtoken(token, true)) + error("default value must match Name production", token); + } + } + else if ("NMTOKEN".equals(type) || "ENUMERATION".equals(type)) + { + if (!isNmtoken(value, false)) + error("default value must match Nmtoken production", value); + } + else if ("NMTOKENS".equals(type)) + { + StringTokenizer st = new StringTokenizer(value); + while (st.hasMoreTokens()) + { + String token = st.nextToken(); + if (!isNmtoken(token, false)) + error("default value must match Nmtoken production", + token); + } + } + } + } + // Register attribute def + AttributeDecl attribute = + new AttributeDecl(type, value, valueType, enumeration, values, + inputStack.size() != 1); + doctype.addAttributeDecl(elementName, name, attribute); + } + + /** + * Parse the EntityDecl production. + */ + private void readEntityDecl(boolean inExternalSubset) + throws IOException, XMLStreamException + { + int flags = 0; + // Check if parameter entity + boolean peFlag = false; + expandPE = false; + requireWhitespace(); + if (tryRead('%')) + { + peFlag = true; + requireWhitespace(); + } + expandPE = true; + // Read entity name + String name = readNmtoken(true); + if (name.indexOf(':') != -1) + error("illegal character ':' in entity name", name); + if (peFlag) + name = "%" + name; + requireWhitespace(); + mark(1); + int c = readCh(); + reset(); + if (c == 0x22 || c == 0x27) // " | ' + { + // Internal entity replacement text + String value = readLiteral(flags | LIT_DISABLE_EREF, true); + int ai = value.indexOf('&'); + while (ai != -1) + { + int sci = value.indexOf(';', ai); + if (sci == -1) + error("malformed reference in entity value", value); + String ref = value.substring(ai + 1, sci); + int[] cp = UnicodeReader.toCodePointArray(ref); + if (cp.length == 0) + error("malformed reference in entity value", value); + if (cp[0] == 0x23) // # + { + if (cp.length == 1) + error("malformed reference in entity value", value); + if (cp[1] == 0x78) // 'x' + { + if (cp.length == 2) + error("malformed reference in entity value", value); + for (int i = 2; i < cp.length; i++) + { + int x = cp[i]; + if (x < 0x30 || + (x > 0x39 && x < 0x41) || + (x > 0x46 && x < 0x61) || + x > 0x66) + error("malformed character reference in entity value", + value); + } + } + else + { + for (int i = 1; i < cp.length; i++) + { + int x = cp[i]; + if (x < 0x30 || x > 0x39) + error("malformed character reference in entity value", + value); + } + } + } + else + { + 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], input.xml11)) + error("malformed reference in entity value", value); + } + } + ai = value.indexOf('&', sci); + } + doctype.addEntityDecl(name, value, inExternalSubset); + } + else + { + ExternalIds ids = readExternalIds(false, false); + // Check for NDATA + boolean white = tryWhitespace(); + if (!peFlag && tryRead("NDATA")) + { + if (!white) + error("whitespace required before NDATA"); + requireWhitespace(); + ids.notationName = readNmtoken(true); + } + doctype.addEntityDecl(name, ids, inExternalSubset); + } + // finish + skipWhitespace(); + require('>'); + } + + /** + * Parse the NotationDecl production. + */ + private void readNotationDecl(boolean inExternalSubset) + throws IOException, XMLStreamException + { + requireWhitespace(); + String notationName = readNmtoken(true); + if (notationName.indexOf(':') != -1) + error("illegal character ':' in notation name", notationName); + if (validating) + { + // VC: Unique Notation Name + ExternalIds notation = doctype.getNotation(notationName); + if (notation != null) + error("duplicate notation name", notationName); + } + requireWhitespace(); + ExternalIds ids = readExternalIds(true, false); + ids.notationName = notationName; + doctype.addNotationDecl(notationName, ids, inExternalSubset); + skipWhitespace(); + require('>'); + } + + /** + * Returns a tuple {publicId, systemId}. + */ + private ExternalIds readExternalIds(boolean inNotation, boolean isSubset) + throws IOException, XMLStreamException + { + int c; + int flags = LIT_DISABLE_CREF | LIT_DISABLE_PE | LIT_DISABLE_EREF; + ExternalIds ids = new ExternalIds(); + + if (tryRead("PUBLIC")) + { + requireWhitespace(); + ids.publicId = readLiteral(LIT_NORMALIZE | LIT_PUBID | flags, false); + if (inNotation) + { + skipWhitespace(); + mark(1); + c = readCh(); + reset(); + if (c == 0x22 || c == 0x27) // " | ' + { + String href = readLiteral(flags, false); + ids.systemId = absolutize(input.systemId, href); + } + } + else + { + requireWhitespace(); + String href = readLiteral(flags, false); + ids.systemId = absolutize(input.systemId, href); + } + // Check valid URI characters + for (int i = 0; i < ids.publicId.length(); i++) + { + char d = ids.publicId.charAt(i); + if (d >= 'a' && d <= 'z') + continue; + if (d >= 'A' && d <= 'Z') + continue; + if (" \r\n0123456789-' ()+,./:=?;!*#@$_%".indexOf(d) != -1) + continue; + error("illegal PUBLIC id character", + "U+" + Integer.toHexString(d)); + } + } + else if (tryRead("SYSTEM")) + { + requireWhitespace(); + String href = readLiteral(flags, false); + ids.systemId = absolutize(input.systemId, href); + } + else if (!isSubset) + { + error("missing SYSTEM or PUBLIC keyword"); + } + if (ids.systemId != null && !inNotation) + { + if (ids.systemId.indexOf('#') != -1) + error("SYSTEM id has a URI fragment", ids.systemId); + } + return ids; + } + + /** + * Parse the start of an element. + * @return the state of the parser afterwards (EMPTY_ELEMENT or CONTENT) + */ + private int readStartElement() + throws IOException, XMLStreamException + { + // Read element name + String elementName = readNmtoken(true); + attrs.clear(); + // Push namespace context + if (namespaceAware) + { + if (elementName.charAt(0) == ':' || + elementName.charAt(elementName.length() - 1) == ':') + error("not a QName", elementName); + namespaces.addFirst(new LinkedHashMap()); + } + // Read element content + boolean white = tryWhitespace(); + mark(1); + int c = readCh(); + while (c != 0x2f && c != 0x3e) // '/' | '>' + { + // Read attribute + reset(); + if (!white) + error("need whitespace between attributes"); + readAttribute(elementName); + white = tryWhitespace(); + mark(1); + c = readCh(); + } + // supply defaulted attributes + if (doctype != null) + { + for (Iterator i = doctype.attlistIterator(elementName); i.hasNext(); ) + { + Map.Entry entry = (Map.Entry) i.next(); + String attName = (String) entry.getKey(); + AttributeDecl decl = (AttributeDecl) entry.getValue(); + if (validating) + { + switch (decl.valueType) + { + case ATTRIBUTE_DEFAULT_REQUIRED: + // VC: Required Attribute + if (decl.value == null && !attributeSpecified(attName)) + error("value for " + attName + " attribute is required"); + break; + case ATTRIBUTE_DEFAULT_FIXED: + // VC: Fixed Attribute Default + for (Iterator j = attrs.iterator(); j.hasNext(); ) + { + Attribute a = (Attribute) j.next(); + if (attName.equals(a.name) && + !decl.value.equals(a.value)) + error("value for " + attName + " attribute must be " + + decl.value); + } + break; + } + } + if (namespaceAware && attName.equals("xmlns")) + { + LinkedHashMap ctx = + (LinkedHashMap) namespaces.getFirst(); + if (ctx.containsKey(XMLConstants.DEFAULT_NS_PREFIX)) + continue; // namespace was specified + } + else if (namespaceAware && attName.startsWith("xmlns:")) + { + LinkedHashMap ctx = + (LinkedHashMap) namespaces.getFirst(); + if (ctx.containsKey(attName.substring(6))) + continue; // namespace was specified + } + else if (attributeSpecified(attName)) + continue; + if (decl.value == null) + continue; + // VC: Standalone Document Declaration + if (validating && decl.external && xmlStandalone == Boolean.TRUE) + error("standalone must be 'no' if attributes inherit values " + + "from externally declared markup declarations"); + Attribute attr = + new Attribute(attName, decl.type, false, decl.value); + if (namespaceAware) + { + if (!addNamespace(attr)) + attrs.add(attr); + } + else + attrs.add(attr); + } + } + if (baseAware) + { + String uri = getAttributeValue(XMLConstants.XML_NS_URI, "base"); + String base = getXMLBase(); + bases.addFirst(absolutize(base, uri)); + } + if (namespaceAware) + { + // check prefix bindings + int ci = elementName.indexOf(':'); + if (ci != -1) + { + String prefix = elementName.substring(0, ci); + String uri = getNamespaceURI(prefix); + if (uri == null) + error("unbound element prefix", prefix); + else if (input.xml11 && "".equals(uri)) + error("XML 1.1 unbound element prefix", prefix); + } + for (Iterator i = attrs.iterator(); i.hasNext(); ) + { + Attribute attr = (Attribute) i.next(); + if (attr.prefix != null && + !XMLConstants.XMLNS_ATTRIBUTE.equals(attr.prefix)) + { + String uri = getNamespaceURI(attr.prefix); + if (uri == null) + error("unbound attribute prefix", attr.prefix); + else if (input.xml11 && "".equals(uri)) + error("XML 1.1 unbound attribute prefix", attr.prefix); + } + } + } + if (validating && doctype != null) + { + validateStartElement(elementName); + currentContentModel = doctype.getElementModel(elementName); + if (currentContentModel == null) + error("no element declaration", elementName); + validationStack.add(new LinkedList()); + } + // make element name available for read + buf.setLength(0); + buf.append(elementName); + // push element onto stack + stack.addLast(elementName); + switch (c) + { + case 0x3e: // '>' + return CONTENT; + case 0x2f: // '/' + require('>'); + return EMPTY_ELEMENT; + } + return -1; // to satisfy compiler + } + + /** + * Indicates whether the specified attribute name was specified for the + * current element. + */ + private boolean attributeSpecified(String attName) + { + for (Iterator j = attrs.iterator(); j.hasNext(); ) + { + Attribute a = (Attribute) j.next(); + if (attName.equals(a.name)) + return true; + } + return false; + } + + /** + * Parse an attribute. + */ + private void readAttribute(String elementName) + throws IOException, XMLStreamException + { + // Read attribute name + String attributeName = readNmtoken(true); + String type = getAttributeType(elementName, attributeName); + readEq(); + // Read literal + final int flags = LIT_ATTRIBUTE | LIT_ENTITY_REF; + String value = (type == null || "CDATA".equals(type)) ? + readLiteral(flags, false) : readLiteral(flags | LIT_NORMALIZE, false); + // add attribute event + Attribute attr = this.new Attribute(attributeName, type, true, value); + if (namespaceAware) + { + if (attributeName.charAt(0) == ':' || + attributeName.charAt(attributeName.length() - 1) == ':') + error("not a QName", attributeName); + else if (attributeName.equals("xmlns")) + { + LinkedHashMap ctx = (LinkedHashMap) namespaces.getFirst(); + if (ctx.containsKey(XMLConstants.DEFAULT_NS_PREFIX)) + error("duplicate default namespace"); + } + else if (attributeName.startsWith("xmlns:")) + { + LinkedHashMap ctx = (LinkedHashMap) namespaces.getFirst(); + if (ctx.containsKey(attributeName.substring(6))) + error("duplicate namespace", attributeName.substring(6)); + } + else if (attrs.contains(attr)) + error("duplicate attribute", attributeName); + } + else if (attrs.contains(attr)) + error("duplicate attribute", attributeName); + if (validating && doctype != null) + { + // VC: Attribute Value Type + AttributeDecl decl = + doctype.getAttributeDecl(elementName, attributeName); + if (decl == null) + error("attribute must be declared", attributeName); + if ("ENUMERATION".equals(decl.type)) + { + // VC: Enumeration + if (!decl.values.contains(value)) + error("value does not match enumeration " + decl.enumeration, + value); + } + else if ("ID".equals(decl.type)) + { + // VC: ID + if (!isNmtoken(value, true)) + error("ID values must match the Name production"); + if (ids.contains(value)) + error("Duplicate ID", value); + ids.add(value); + } + else if ("IDREF".equals(decl.type) || "IDREFS".equals(decl.type)) + { + StringTokenizer st = new StringTokenizer(value); + while (st.hasMoreTokens()) + { + String token = st.nextToken(); + // VC: IDREF + if (!isNmtoken(token, true)) + error("IDREF values must match the Name production"); + idrefs.add(token); + } + } + else if ("NMTOKEN".equals(decl.type) || "NMTOKENS".equals(decl.type)) + { + StringTokenizer st = new StringTokenizer(value); + while (st.hasMoreTokens()) + { + String token = st.nextToken(); + // VC: Name Token + if (!isNmtoken(token, false)) + error("NMTOKEN values must match the Nmtoken production"); + } + } + else if ("ENTITY".equals(decl.type)) + { + // VC: Entity Name + if (!isNmtoken(value, true)) + error("ENTITY values must match the Name production"); + Object entity = doctype.getEntity(value); + if (entity == null || !(entity instanceof ExternalIds) || + ((ExternalIds) entity).notationName == null) + error("ENTITY values must match the name of an unparsed " + + "entity declared in the DTD"); + } + else if ("NOTATION".equals(decl.type)) + { + if (!decl.values.contains(value)) + error("NOTATION values must match a declared notation name", + value); + // VC: Notation Attributes + ExternalIds notation = doctype.getNotation(value); + if (notation == null) + error("NOTATION values must match the name of a notation " + + "declared in the DTD", value); + } + } + if (namespaceAware) + { + if (!addNamespace(attr)) + attrs.add(attr); + } + else + attrs.add(attr); + } + + /** + * Determines whether the specified attribute is a namespace declaration, + * and adds it to the current namespace context if so. Returns false if + * the attribute is an ordinary attribute. + */ + private boolean addNamespace(Attribute attr) + throws XMLStreamException + { + if ("xmlns".equals(attr.name)) + { + LinkedHashMap ctx = (LinkedHashMap) namespaces.getFirst(); + if (ctx.get(XMLConstants.DEFAULT_NS_PREFIX) != null) + error("Duplicate default namespace declaration"); + if (XMLConstants.XML_NS_URI.equals(attr.value)) + error("can't bind XML namespace"); + ctx.put(XMLConstants.DEFAULT_NS_PREFIX, attr.value); + return true; + } + else if ("xmlns".equals(attr.prefix)) + { + LinkedHashMap ctx = (LinkedHashMap) namespaces.getFirst(); + if (ctx.get(attr.localName) != null) + error("Duplicate namespace declaration for prefix", + attr.localName); + if (XMLConstants.XML_NS_PREFIX.equals(attr.localName)) + { + if (!XMLConstants.XML_NS_URI.equals(attr.value)) + error("can't redeclare xml prefix"); + else + return false; // treat as attribute + } + if (XMLConstants.XML_NS_URI.equals(attr.value)) + error("can't bind non-xml prefix to XML namespace"); + if (XMLConstants.XMLNS_ATTRIBUTE.equals(attr.localName)) + error("can't redeclare xmlns prefix"); + if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(attr.value)) + error("can't bind non-xmlns prefix to XML Namespace namespace"); + if ("".equals(attr.value) && !input.xml11) + error("illegal use of 1.1-style prefix unbinding in 1.0 document"); + ctx.put(attr.localName, attr.value); + return true; + } + return false; + } + + /** + * Parse a closing tag. + */ + private void readEndElement() + throws IOException, XMLStreamException + { + // pop element off stack + String expected = (String) stack.removeLast(); + require(expected); + skipWhitespace(); + require('>'); + // Make element name available + buf.setLength(0); + buf.append(expected); + if (validating && doctype != null) + endElementValidationHook(); + } + + /** + * Validate the end of an element. + * Called on an end-element or empty element if validating. + */ + private void endElementValidationHook() + throws XMLStreamException + { + validateEndElement(); + validationStack.removeLast(); + if (stack.isEmpty()) + currentContentModel = null; + else + { + String parent = (String) stack.getLast(); + currentContentModel = doctype.getElementModel(parent); + } + } + + /** + * Parse a comment. + */ + private void readComment(boolean inDTD) + throws IOException, XMLStreamException + { + boolean saved = expandPE; + expandPE = false; + buf.setLength(0); + readUntil(TEST_END_COMMENT); + require('>'); + expandPE = saved; + if (inDTD) + doctype.addComment(buf.toString()); + } + + /** + * Parse a processing instruction. + */ + private void readPI(boolean inDTD) + throws IOException, XMLStreamException + { + boolean saved = expandPE; + expandPE = false; + piTarget = readNmtoken(true); + if (piTarget.indexOf(':') != -1) + error("illegal character in PI target", new Character(':')); + if ("xml".equalsIgnoreCase(piTarget)) + error("illegal PI target", piTarget); + if (tryRead(TEST_END_PI)) + piData = null; + else + { + if (!tryWhitespace()) + error("whitespace required between PI target and data"); + buf.setLength(0); + readUntil(TEST_END_PI); + piData = buf.toString(); + } + expandPE = saved; + if (inDTD) + doctype.addPI(piTarget, piData); + } + + /** + * Parse an entity reference. + */ + private void readReference() + throws IOException, XMLStreamException + { + buf.setLength(0); + String entityName = readNmtoken(true); + require(';'); + buf.setLength(0); + buf.append(entityName); + } + + /** + * Read an CDATA section. + */ + private void readCDSect() + throws IOException, XMLStreamException + { + buf.setLength(0); + readUntil(TEST_END_CDATA); + } + + /** + * Read character data. + * @return the type of text read (CHARACTERS or SPACE) + */ + private int readCharData(String prefix) + throws IOException, XMLStreamException + { + boolean white = true; + buf.setLength(0); + if (prefix != null) + buf.append(prefix); + boolean done = false; + boolean entities = false; + while (!done) + { + // Block read + mark(tmpBuf.length); + int len = read(tmpBuf, 0, tmpBuf.length); + if (len == -1) + { + if (inputStack.size() > 1) + { + popInput(); + // report end-entity + done = true; + } + else + throw new EOFException(); + } + for (int i = 0; i < len && !done; i++) + { + int c = tmpBuf[i]; + switch (c) + { + case 0x20: + case 0x09: + case 0x0a: + case 0x0d: + buf.append(Character.toChars(c)); + break; // whitespace + case 0x26: // '&' + reset(); + read(tmpBuf, 0, i); + // character reference? + mark(3); + c = readCh(); // & + c = readCh(); + if (c == 0x23) // '#' + { + mark(1); + c = readCh(); + boolean hex = (c == 0x78); // 'x' + if (!hex) + reset(); + char[] ch = readCharacterRef(hex ? 16 : 10); + buf.append(ch, 0, ch.length); + for (int j = 0; j < ch.length; j++) + { + switch (ch[j]) + { + case 0x20: + case 0x09: + case 0x0a: + case 0x0d: + break; // whitespace + default: + white = false; + } + } + } + else + { + // entity reference + reset(); + c = readCh(); // & + String entityName = readNmtoken(true); + require(';'); + String text = + (String) PREDEFINED_ENTITIES.get(entityName); + if (text != null) + buf.append(text); + else + { + pushInput("", "&" + entityName + ";", false, false); + done = true; + break; + } + } + // continue processing + i = -1; + mark(tmpBuf.length); + len = read(tmpBuf, 0, tmpBuf.length); + if (len == -1) + { + if (inputStack.size() > 1) + { + popInput(); + done = true; + } + else + throw new EOFException(); + } + entities = true; + break; // end of text sequence + case 0x3e: // '>' + int l = buf.length(); + if (l > 1 && + buf.charAt(l - 1) == ']' && + buf.charAt(l - 2) == ']') + error("Character data may not contain unescaped ']]>'"); + buf.append(Character.toChars(c)); + break; + case 0x3c: // '<' + reset(); + // 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 + else + done = true; // end of text sequence + break; + default: + if (input.xml11) + { + if (!isXML11Char(c) || isXML11RestrictedChar(c)) + error("illegal XML 1.1 character", + "U+" + Integer.toHexString(c)); + } + else if (!isChar(c)) + error("illegal XML character", + "U+" + Integer.toHexString(c)); + white = false; + buf.append(Character.toChars(c)); + } + } + // if text buffer >= 2MB, return it as a chunk + // to avoid excessive memory use + if (buf.length() >= 2097152) + done = true; + } + if (entities) + normalizeCRLF(buf); + return white ? XMLStreamConstants.SPACE : XMLStreamConstants.CHARACTERS; + } + + /** + * Expands the specified entity. + */ + private void expandEntity(String name, boolean inAttr, boolean normalize) + throws IOException, XMLStreamException + { + if (doctype != null) + { + Object value = doctype.getEntity(name); + if (value != null) + { + if (xmlStandalone == Boolean.TRUE) + { + // VC: Standalone Document Declaration + if (doctype.isEntityExternal(name)) + error("reference to external entity in standalone document"); + else if (value instanceof ExternalIds) + { + ExternalIds ids = (ExternalIds) value; + if (ids.notationName != null && + doctype.isNotationExternal(ids.notationName)) + error("reference to external notation in " + + "standalone document"); + } + } + if (value instanceof String) + { + String text = (String) value; + if (inAttr && text.indexOf('<') != -1) + error("< in attribute value"); + pushInput(name, text, !inAttr, normalize); + } + else if (inAttr) + error("reference to external entity in attribute value", name); + else + pushInput(name, (ExternalIds) value, !inAttr, normalize); + return; + } + } + error("reference to undeclared entity", name); + } + + /** + * Indicates whether the specified entity is unparsed. + */ + private boolean isUnparsedEntity(String name) + { + if (doctype != null) + { + Object value = doctype.getEntity(name); + if (value != null && value instanceof ExternalIds) + return ((ExternalIds) value).notationName != null; + } + return false; + } + + /** + * Read an equals sign. + */ + private void readEq() + throws IOException, XMLStreamException + { + skipWhitespace(); + require('='); + skipWhitespace(); + } + + /** + * Character read for reading literals. + * @param recognizePEs whether to recognize parameter-entity references + */ + private int literalReadCh(boolean recognizePEs) + throws IOException, XMLStreamException + { + int c = recognizePEs ? readCh() : read(); + while (c == -1) + { + if (inputStack.size() > 1) + { + inputStack.removeLast(); + input = (Input) inputStack.getLast(); + // Don't issue end-entity + c = recognizePEs ? readCh() : read(); + } + else + throw new EOFException(); + } + return c; + } + + /** + * Read a string literal. + */ + private String readLiteral(int flags, boolean recognizePEs) + throws IOException, XMLStreamException + { + boolean saved = expandPE; + int delim = readCh(); + if (delim != 0x27 && delim != 0x22) + error("expected '\"' or \"'\"", "U+" + Integer.toHexString(delim)); + literalBuf.setLength(0); + if ((flags & LIT_DISABLE_PE) != 0) + expandPE = false; + boolean entities = false; + int inputStackSize = inputStack.size(); + do + { + int c = literalReadCh(recognizePEs); + if (c == delim && inputStackSize == inputStack.size()) + break; + switch (c) + { + case 0x0a: + case 0x0d: + if ((flags & (LIT_ATTRIBUTE | LIT_PUBID)) != 0) + c = 0x20; // normalize to space + break; + case 0x09: + if ((flags & LIT_ATTRIBUTE) != 0) + c = 0x20; // normalize to space + break; + case 0x26: // '&' + mark(2); + c = readCh(); + if (c == 0x23) // '#' + { + if ((flags & LIT_DISABLE_CREF) != 0) + { + reset(); + c = 0x26; // '&' + } + else + { + mark(1); + c = readCh(); + boolean hex = (c == 0x78); // 'x' + if (!hex) + reset(); + char[] ref = readCharacterRef(hex ? 16 : 10); + for (int i = 0; i < ref.length; i++) + literalBuf.append(ref[i]); + entities = true; + continue; + } + } + else + { + if ((flags & LIT_DISABLE_EREF) != 0) + { + reset(); + c = 0x26; // '&' + } + else + { + reset(); + String entityName = readNmtoken(true); + require(';'); + String text = + (String) PREDEFINED_ENTITIES.get(entityName); + if (text != null) + literalBuf.append(text); + else + expandEntity(entityName, + (flags & LIT_ATTRIBUTE) != 0, + true); + entities = true; + continue; + } + } + break; + case 0x3c: // '<' + if ((flags & LIT_ATTRIBUTE) != 0) + error("attribute values may not contain '<'"); + break; + case -1: + if (inputStack.size() > 1) + { + popInput(); + continue; + } + throw new EOFException(); + default: + if ((c < 0x0020 || c > 0xfffd) || + (c >= 0xd800 && c < 0xdc00) || + (input.xml11 && (c >= 0x007f) && + (c <= 0x009f) && (c != 0x0085))) + error("illegal character", "U+" + Integer.toHexString(c)); + } + literalBuf.append(Character.toChars(c)); + } + while (true); + expandPE = saved; + if (entities) + normalizeCRLF(literalBuf); + if ((flags & LIT_NORMALIZE) > 0) + literalBuf = normalize(literalBuf); + return literalBuf.toString(); + } + + /** + * Performs attribute-value normalization of the text buffer. + * This discards leading and trailing whitespace, and replaces sequences + * of whitespace with a single space. + */ + private StringBuffer normalize(StringBuffer buf) + { + StringBuffer acc = new StringBuffer(); + int len = buf.length(); + int avState = 0; + for (int i = 0; i < len; i++) + { + char c = buf.charAt(i); + if (c == ' ') + avState = (avState == 0) ? 0 : 1; + else + { + if (avState == 1) + acc.append(' '); + acc.append(c); + avState = 2; + } + } + return acc; + } + + /** + * Replace any CR/LF pairs in the buffer with LF. + * This may be necessary if combinations of CR or LF were declared as + * (character) entity references in the input. + */ + private void normalizeCRLF(StringBuffer buf) + { + int len = buf.length() - 1; + for (int i = 0; i < len; i++) + { + char c = buf.charAt(i); + if (c == '\r' && buf.charAt(i + 1) == '\n') + { + buf.deleteCharAt(i--); + len--; + } + } + } + + /** + * Parse and expand a parameter entity reference. + */ + private void expandPEReference() + throws IOException, XMLStreamException + { + String name = readNmtoken(true, new StringBuffer()); + require(';'); + mark(1); // ensure we don't reset to before the semicolon + if (doctype != null) + { + String entityName = "%" + name; + Object entity = doctype.getEntity(entityName); + if (entity != null) + { + if (xmlStandalone == Boolean.TRUE) + { + if (doctype.isEntityExternal(entityName)) + error("reference to external parameter entity in " + + "standalone document"); + } + if (entity instanceof String) + { + pushInput(name, (String) entity, false, input.normalize); + //pushInput(name, " " + (String) entity + " "); + } + else + { + //pushInput("", " "); + pushInput(name, (ExternalIds) entity, false, input.normalize); + //pushInput("", " "); + } + } + else + error("reference to undeclared parameter entity", name); + } + else + error("reference to parameter entity without doctype", name); + } + + /** + * Parse the digits in a character reference. + * @param base the base of the digits (10 or 16) + */ + private char[] readCharacterRef(int base) + throws IOException, XMLStreamException + { + CPStringBuilder b = new CPStringBuilder(); + for (int c = readCh(); c != 0x3b && c != -1; c = readCh()) + b.append(Character.toChars(c)); + try + { + int ord = Integer.parseInt(b.toString(), base); + if (input.xml11) + { + if (!isXML11Char(ord)) + error("illegal XML 1.1 character reference " + + "U+" + Integer.toHexString(ord)); + } + else + { + if ((ord < 0x20 && !(ord == 0x0a || ord == 0x09 || ord == 0x0d)) + || (ord >= 0xd800 && ord <= 0xdfff) + || ord == 0xfffe || ord == 0xffff + || ord > 0x0010ffff) + error("illegal XML character reference " + + "U+" + Integer.toHexString(ord)); + } + return Character.toChars(ord); + } + catch (NumberFormatException e) + { + error("illegal characters in character reference", b.toString()); + return null; + } + } + + /** + * Parses an NMTOKEN or Name production. + * @param isName if a Name, otherwise an NMTOKEN + */ + private String readNmtoken(boolean isName) + throws IOException, XMLStreamException + { + return readNmtoken(isName, nmtokenBuf); + } + + /** + * Parses an NMTOKEN or Name production using the specified buffer. + * @param isName if a Name, otherwise an NMTOKEN + * @param buf the character buffer to use + */ + private String readNmtoken(boolean isName, StringBuffer buf) + throws IOException, XMLStreamException + { + buf.setLength(0); + int c = readCh(); + if (isName) + { + if (!isNameStartCharacter(c, input.xml11)) + error("not a name start character", + "U+" + Integer.toHexString(c)); + } + else + { + if (!isNameCharacter(c, input.xml11)) + error("not a name character", + "U+" + Integer.toHexString(c)); + } + buf.append(Character.toChars(c)); + do + { + mark(1); + c = readCh(); + switch (c) + { + case 0x25: // '%' + case 0x3c: // '<' + case 0x3e: // '>' + case 0x26: // '&' + case 0x2c: // ',' + case 0x7c: // '|' + case 0x2a: // '*' + case 0x2b: // '+' + case 0x3f: // '?' + case 0x29: // ')' + case 0x3d: // '=' + case 0x27: // '\'' + case 0x22: // '"' + case 0x5b: // '[' + case 0x20: // ' ' + case 0x09: // '\t' + case 0x0a: // '\n' + case 0x0d: // '\r' + case 0x3b: // ';' + case 0x2f: // '/' + case -1: + reset(); + return intern(buf.toString()); + default: + if (!isNameCharacter(c, input.xml11)) + error("not a name character", + "U+" + Integer.toHexString(c)); + else + buf.append(Character.toChars(c)); + } + } + while (true); + } + + /** + * Indicates whether the specified Unicode character is an XML 1.1 Char. + */ + public static boolean isXML11Char(int c) + { + return ((c >= 0x0001 && c <= 0xD7FF) || + (c >= 0xE000 && c < 0xFFFE) || + (c >= 0x10000 && c <= 0x10FFFF)); + } + + /** + * Indicates whether the specified Unicode character is an XML 1.1 + * RestrictedChar. + */ + public static boolean isXML11RestrictedChar(int c) + { + return ((c >= 0x0001 && c <= 0x0008) || + (c >= 0x000B && c <= 0x000C) || + (c >= 0x000E && c <= 0x001F) || + (c >= 0x007F && c <= 0x0084) || + (c >= 0x0086 && c <= 0x009F)); + } + + /** + * Indicates whether the specified text matches the Name or Nmtoken + * production. + */ + private boolean isNmtoken(String text, boolean isName) + { + try + { + int[] cp = UnicodeReader.toCodePointArray(text); + if (cp.length == 0) + return false; + if (isName) + { + if (!isNameStartCharacter(cp[0], input.xml11)) + return false; + } + else + { + if (!isNameCharacter(cp[0], input.xml11)) + return false; + } + for (int i = 1; i < cp.length; i++) + { + if (!isNameCharacter(cp[i], input.xml11)) + return false; + } + return true; + } + catch (IOException e) + { + return false; + } + } + + /** + * Indicates whether the specified Unicode character is a Name start + * character. + */ + public static boolean isNameStartCharacter(int c, boolean xml11) + { + if (xml11) + return ((c >= 0x0041 && c <= 0x005a) || + (c >= 0x0061 && c <= 0x007a) || + c == 0x3a | + c == 0x5f | + (c >= 0xC0 && c <= 0xD6) || + (c >= 0xD8 && c <= 0xF6) || + (c >= 0xF8 && c <= 0x2FF) || + (c >= 0x370 && c <= 0x37D) || + (c >= 0x37F && c <= 0x1FFF) || + (c >= 0x200C && c <= 0x200D) || + (c >= 0x2070 && c <= 0x218F) || + (c >= 0x2C00 && c <= 0x2FEF) || + (c >= 0x3001 && c <= 0xD7FF) || + (c >= 0xF900 && c <= 0xFDCF) || + (c >= 0xFDF0 && c <= 0xFFFD) || + (c >= 0x10000 && c <= 0xEFFFF)); + else + return (c == 0x5f || c == 0x3a || isLetter(c)); + } + + /** + * Indicates whether the specified Unicode character is a Name non-initial + * character. + */ + public static boolean isNameCharacter(int c, boolean xml11) + { + if (xml11) + return ((c >= 0x0041 && c <= 0x005a) || + (c >= 0x0061 && c <= 0x007a) || + (c >= 0x0030 && c <= 0x0039) || + c == 0x3a | + c == 0x5f | + c == 0x2d | + c == 0x2e | + c == 0xB7 | + (c >= 0xC0 && c <= 0xD6) || + (c >= 0xD8 && c <= 0xF6) || + (c >= 0xF8 && c <= 0x2FF) || + (c >= 0x300 && c <= 0x37D) || + (c >= 0x37F && c <= 0x1FFF) || + (c >= 0x200C && c <= 0x200D) || + (c >= 0x203F && c <= 0x2040) || + (c >= 0x2070 && c <= 0x218F) || + (c >= 0x2C00 && c <= 0x2FEF) || + (c >= 0x3001 && c <= 0xD7FF) || + (c >= 0xF900 && c <= 0xFDCF) || + (c >= 0xFDF0 && c <= 0xFFFD) || + (c >= 0x10000 && c <= 0xEFFFF)); + else + return (c == 0x2e || c == 0x2d || c == 0x5f || c == 0x3a || + isLetter(c) || isDigit(c) || + isCombiningChar(c) || isExtender(c)); + } + + /** + * Indicates whether the specified Unicode character matches the Letter + * production. + */ + public static boolean isLetter(int c) + { + if ((c >= 0x0041 && c <= 0x005A) || + (c >= 0x0061 && c <= 0x007A) || + (c >= 0x00C0 && c <= 0x00D6) || + (c >= 0x00D8 && c <= 0x00F6) || + (c >= 0x00F8 && c <= 0x00FF) || + (c >= 0x0100 && c <= 0x0131) || + (c >= 0x0134 && c <= 0x013E) || + (c >= 0x0141 && c <= 0x0148) || + (c >= 0x014A && c <= 0x017E) || + (c >= 0x0180 && c <= 0x01C3) || + (c >= 0x01CD && c <= 0x01F0) || + (c >= 0x01F4 && c <= 0x01F5) || + (c >= 0x01FA && c <= 0x0217) || + (c >= 0x0250 && c <= 0x02A8) || + (c >= 0x02BB && c <= 0x02C1) || + c == 0x0386 || + (c >= 0x0388 && c <= 0x038A) || + c == 0x038C || + (c >= 0x038E && c <= 0x03A1) || + (c >= 0x03A3 && c <= 0x03CE) || + (c >= 0x03D0 && c <= 0x03D6) || + c == 0x03DA || + c == 0x03DC || + c == 0x03DE || + c == 0x03E0 || + (c >= 0x03E2 && c <= 0x03F3) || + (c >= 0x0401 && c <= 0x040C) || + (c >= 0x040E && c <= 0x044F) || + (c >= 0x0451 && c <= 0x045C) || + (c >= 0x045E && c <= 0x0481) || + (c >= 0x0490 && c <= 0x04C4) || + (c >= 0x04C7 && c <= 0x04C8) || + (c >= 0x04CB && c <= 0x04CC) || + (c >= 0x04D0 && c <= 0x04EB) || + (c >= 0x04EE && c <= 0x04F5) || + (c >= 0x04F8 && c <= 0x04F9) || + (c >= 0x0531 && c <= 0x0556) || + c == 0x0559 || + (c >= 0x0561 && c <= 0x0586) || + (c >= 0x05D0 && c <= 0x05EA) || + (c >= 0x05F0 && c <= 0x05F2) || + (c >= 0x0621 && c <= 0x063A) || + (c >= 0x0641 && c <= 0x064A) || + (c >= 0x0671 && c <= 0x06B7) || + (c >= 0x06BA && c <= 0x06BE) || + (c >= 0x06C0 && c <= 0x06CE) || + (c >= 0x06D0 && c <= 0x06D3) || + c == 0x06D5 || + (c >= 0x06E5 && c <= 0x06E6) || + (c >= 0x0905 && c <= 0x0939) || + c == 0x093D || + (c >= 0x0958 && c <= 0x0961) || + (c >= 0x0985 && c <= 0x098C) || + (c >= 0x098F && c <= 0x0990) || + (c >= 0x0993 && c <= 0x09A8) || + (c >= 0x09AA && c <= 0x09B0) || + c == 0x09B2 || + (c >= 0x09B6 && c <= 0x09B9) || + (c >= 0x09DC && c <= 0x09DD) || + (c >= 0x09DF && c <= 0x09E1) || + (c >= 0x09F0 && c <= 0x09F1) || + (c >= 0x0A05 && c <= 0x0A0A) || + (c >= 0x0A0F && c <= 0x0A10) || + (c >= 0x0A13 && c <= 0x0A28) || + (c >= 0x0A2A && c <= 0x0A30) || + (c >= 0x0A32 && c <= 0x0A33) || + (c >= 0x0A35 && c <= 0x0A36) || + (c >= 0x0A38 && c <= 0x0A39) || + (c >= 0x0A59 && c <= 0x0A5C) || + c == 0x0A5E || + (c >= 0x0A72 && c <= 0x0A74) || + (c >= 0x0A85 && c <= 0x0A8B) || + c == 0x0A8D || + (c >= 0x0A8F && c <= 0x0A91) || + (c >= 0x0A93 && c <= 0x0AA8) || + (c >= 0x0AAA && c <= 0x0AB0) || + (c >= 0x0AB2 && c <= 0x0AB3) || + (c >= 0x0AB5 && c <= 0x0AB9) || + c == 0x0ABD || + c == 0x0AE0 || + (c >= 0x0B05 && c <= 0x0B0C) || + (c >= 0x0B0F && c <= 0x0B10) || + (c >= 0x0B13 && c <= 0x0B28) || + (c >= 0x0B2A && c <= 0x0B30) || + (c >= 0x0B32 && c <= 0x0B33) || + (c >= 0x0B36 && c <= 0x0B39) || + c == 0x0B3D || + (c >= 0x0B5C && c <= 0x0B5D) || + (c >= 0x0B5F && c <= 0x0B61) || + (c >= 0x0B85 && c <= 0x0B8A) || + (c >= 0x0B8E && c <= 0x0B90) || + (c >= 0x0B92 && c <= 0x0B95) || + (c >= 0x0B99 && c <= 0x0B9A) || + c == 0x0B9C || + (c >= 0x0B9E && c <= 0x0B9F) || + (c >= 0x0BA3 && c <= 0x0BA4) || + (c >= 0x0BA8 && c <= 0x0BAA) || + (c >= 0x0BAE && c <= 0x0BB5) || + (c >= 0x0BB7 && c <= 0x0BB9) || + (c >= 0x0C05 && c <= 0x0C0C) || + (c >= 0x0C0E && c <= 0x0C10) || + (c >= 0x0C12 && c <= 0x0C28) || + (c >= 0x0C2A && c <= 0x0C33) || + (c >= 0x0C35 && c <= 0x0C39) || + (c >= 0x0C60 && c <= 0x0C61) || + (c >= 0x0C85 && c <= 0x0C8C) || + (c >= 0x0C8E && c <= 0x0C90) || + (c >= 0x0C92 && c <= 0x0CA8) || + (c >= 0x0CAA && c <= 0x0CB3) || + (c >= 0x0CB5 && c <= 0x0CB9) || + c == 0x0CDE || + (c >= 0x0CE0 && c <= 0x0CE1) || + (c >= 0x0D05 && c <= 0x0D0C) || + (c >= 0x0D0E && c <= 0x0D10) || + (c >= 0x0D12 && c <= 0x0D28) || + (c >= 0x0D2A && c <= 0x0D39) || + (c >= 0x0D60 && c <= 0x0D61) || + (c >= 0x0E01 && c <= 0x0E2E) || + c == 0x0E30 || + (c >= 0x0E32 && c <= 0x0E33) || + (c >= 0x0E40 && c <= 0x0E45) || + (c >= 0x0E81 && c <= 0x0E82) || + c == 0x0E84 || + (c >= 0x0E87 && c <= 0x0E88) || + c == 0x0E8A || + c == 0x0E8D || + (c >= 0x0E94 && c <= 0x0E97) || + (c >= 0x0E99 && c <= 0x0E9F) || + (c >= 0x0EA1 && c <= 0x0EA3) || + c == 0x0EA5 || + c == 0x0EA7 || + (c >= 0x0EAA && c <= 0x0EAB) || + (c >= 0x0EAD && c <= 0x0EAE) || + c == 0x0EB0 || + (c >= 0x0EB2 && c <= 0x0EB3) || + c == 0x0EBD || + (c >= 0x0EC0 && c <= 0x0EC4) || + (c >= 0x0F40 && c <= 0x0F47) || + (c >= 0x0F49 && c <= 0x0F69) || + (c >= 0x10A0 && c <= 0x10C5) || + (c >= 0x10D0 && c <= 0x10F6) || + c == 0x1100 || + (c >= 0x1102 && c <= 0x1103) || + (c >= 0x1105 && c <= 0x1107) || + c == 0x1109 || + (c >= 0x110B && c <= 0x110C) || + (c >= 0x110E && c <= 0x1112) || + c == 0x113C || + c == 0x113E || + c == 0x1140 || + c == 0x114C || + c == 0x114E || + c == 0x1150 || + (c >= 0x1154 && c <= 0x1155) || + c == 0x1159 || + (c >= 0x115F && c <= 0x1161) || + c == 0x1163 || + c == 0x1165 || + c == 0x1167 || + c == 0x1169 || + (c >= 0x116D && c <= 0x116E) || + (c >= 0x1172 && c <= 0x1173) || + c == 0x1175 || + c == 0x119E || + c == 0x11A8 || + c == 0x11AB || + (c >= 0x11AE && c <= 0x11AF) || + (c >= 0x11B7 && c <= 0x11B8) || + c == 0x11BA || + (c >= 0x11BC && c <= 0x11C2) || + c == 0x11EB || + c == 0x11F0 || + c == 0x11F9 || + (c >= 0x1E00 && c <= 0x1E9B) || + (c >= 0x1EA0 && c <= 0x1EF9) || + (c >= 0x1F00 && c <= 0x1F15) || + (c >= 0x1F18 && c <= 0x1F1D) || + (c >= 0x1F20 && c <= 0x1F45) || + (c >= 0x1F48 && c <= 0x1F4D) || + (c >= 0x1F50 && c <= 0x1F57) || + c == 0x1F59 || + c == 0x1F5B || + c == 0x1F5D || + (c >= 0x1F5F && c <= 0x1F7D) || + (c >= 0x1F80 && c <= 0x1FB4) || + (c >= 0x1FB6 && c <= 0x1FBC) || + c == 0x1FBE || + (c >= 0x1FC2 && c <= 0x1FC4) || + (c >= 0x1FC6 && c <= 0x1FCC) || + (c >= 0x1FD0 && c <= 0x1FD3) || + (c >= 0x1FD6 && c <= 0x1FDB) || + (c >= 0x1FE0 && c <= 0x1FEC) || + (c >= 0x1FF2 && c <= 0x1FF4) || + (c >= 0x1FF6 && c <= 0x1FFC) || + c == 0x2126 || + (c >= 0x212A && c <= 0x212B) || + c == 0x212E || + (c >= 0x2180 && c <= 0x2182) || + (c >= 0x3041 && c <= 0x3094) || + (c >= 0x30A1 && c <= 0x30FA) || + (c >= 0x3105 && c <= 0x312C) || + (c >= 0xAC00 && c <= 0xD7A3)) + return true; // BaseChar + if ((c >= 0x4e00 && c <= 0x9fa5) || + c == 0x3007 || + (c >= 0x3021 && c <= 0x3029)) + return true; // Ideographic + return false; + } + + /** + * Indicates whether the specified Unicode character matches the Digit + * production. + */ + public static boolean isDigit(int c) + { + return ((c >= 0x0030 && c <= 0x0039) || + (c >= 0x0660 && c <= 0x0669) || + (c >= 0x06F0 && c <= 0x06F9) || + (c >= 0x0966 && c <= 0x096F) || + (c >= 0x09E6 && c <= 0x09EF) || + (c >= 0x0A66 && c <= 0x0A6F) || + (c >= 0x0AE6 && c <= 0x0AEF) || + (c >= 0x0B66 && c <= 0x0B6F) || + (c >= 0x0BE7 && c <= 0x0BEF) || + (c >= 0x0C66 && c <= 0x0C6F) || + (c >= 0x0CE6 && c <= 0x0CEF) || + (c >= 0x0D66 && c <= 0x0D6F) || + (c >= 0x0E50 && c <= 0x0E59) || + (c >= 0x0ED0 && c <= 0x0ED9) || + (c >= 0x0F20 && c <= 0x0F29)); + } + + /** + * Indicates whether the specified Unicode character matches the + * CombiningChar production. + */ + public static boolean isCombiningChar(int c) + { + return ((c >= 0x0300 && c <= 0x0345) || + (c >= 0x0360 && c <= 0x0361) || + (c >= 0x0483 && c <= 0x0486) || + (c >= 0x0591 && c <= 0x05A1) || + (c >= 0x05A3 && c <= 0x05B9) || + (c >= 0x05BB && c <= 0x05BD) || + c == 0x05BF || + (c >= 0x05C1 && c <= 0x05C2) || + c == 0x05C4 || + (c >= 0x064B && c <= 0x0652) || + c == 0x0670 || + (c >= 0x06D6 && c <= 0x06DC) || + (c >= 0x06DD && c <= 0x06DF) || + (c >= 0x06E0 && c <= 0x06E4) || + (c >= 0x06E7 && c <= 0x06E8) || + (c >= 0x06EA && c <= 0x06ED) || + (c >= 0x0901 && c <= 0x0903) || + c == 0x093C || + (c >= 0x093E && c <= 0x094C) || + c == 0x094D || + (c >= 0x0951 && c <= 0x0954) || + (c >= 0x0962 && c <= 0x0963) || + (c >= 0x0981 && c <= 0x0983) || + c == 0x09BC || + c == 0x09BE || + c == 0x09BF || + (c >= 0x09C0 && c <= 0x09C4) || + (c >= 0x09C7 && c <= 0x09C8) || + (c >= 0x09CB && c <= 0x09CD) || + c == 0x09D7 || + (c >= 0x09E2 && c <= 0x09E3) || + c == 0x0A02 || + c == 0x0A3C || + c == 0x0A3E || + c == 0x0A3F || + (c >= 0x0A40 && c <= 0x0A42) || + (c >= 0x0A47 && c <= 0x0A48) || + (c >= 0x0A4B && c <= 0x0A4D) || + (c >= 0x0A70 && c <= 0x0A71) || + (c >= 0x0A81 && c <= 0x0A83) || + c == 0x0ABC || + (c >= 0x0ABE && c <= 0x0AC5) || + (c >= 0x0AC7 && c <= 0x0AC9) || + (c >= 0x0ACB && c <= 0x0ACD) || + (c >= 0x0B01 && c <= 0x0B03) || + c == 0x0B3C || + (c >= 0x0B3E && c <= 0x0B43) || + (c >= 0x0B47 && c <= 0x0B48) || + (c >= 0x0B4B && c <= 0x0B4D) || + (c >= 0x0B56 && c <= 0x0B57) || + (c >= 0x0B82 && c <= 0x0B83) || + (c >= 0x0BBE && c <= 0x0BC2) || + (c >= 0x0BC6 && c <= 0x0BC8) || + (c >= 0x0BCA && c <= 0x0BCD) || + c == 0x0BD7 || + (c >= 0x0C01 && c <= 0x0C03) || + (c >= 0x0C3E && c <= 0x0C44) || + (c >= 0x0C46 && c <= 0x0C48) || + (c >= 0x0C4A && c <= 0x0C4D) || + (c >= 0x0C55 && c <= 0x0C56) || + (c >= 0x0C82 && c <= 0x0C83) || + (c >= 0x0CBE && c <= 0x0CC4) || + (c >= 0x0CC6 && c <= 0x0CC8) || + (c >= 0x0CCA && c <= 0x0CCD) || + (c >= 0x0CD5 && c <= 0x0CD6) || + (c >= 0x0D02 && c <= 0x0D03) || + (c >= 0x0D3E && c <= 0x0D43) || + (c >= 0x0D46 && c <= 0x0D48) || + (c >= 0x0D4A && c <= 0x0D4D) || + c == 0x0D57 || + c == 0x0E31 || + (c >= 0x0E34 && c <= 0x0E3A) || + (c >= 0x0E47 && c <= 0x0E4E) || + c == 0x0EB1 || + (c >= 0x0EB4 && c <= 0x0EB9) || + (c >= 0x0EBB && c <= 0x0EBC) || + (c >= 0x0EC8 && c <= 0x0ECD) || + (c >= 0x0F18 && c <= 0x0F19) || + c == 0x0F35 || + c == 0x0F37 || + c == 0x0F39 || + c == 0x0F3E || + c == 0x0F3F || + (c >= 0x0F71 && c <= 0x0F84) || + (c >= 0x0F86 && c <= 0x0F8B) || + (c >= 0x0F90 && c <= 0x0F95) || + c == 0x0F97 || + (c >= 0x0F99 && c <= 0x0FAD) || + (c >= 0x0FB1 && c <= 0x0FB7) || + c == 0x0FB9 || + (c >= 0x20D0 && c <= 0x20DC) || + c == 0x20E1 || + (c >= 0x302A && c <= 0x302F) || + c == 0x3099 || + c == 0x309A); + } + + /** + * Indicates whether the specified Unicode character matches the Extender + * production. + */ + public static boolean isExtender(int c) + { + return (c == 0x00B7 || + c == 0x02D0 || + c == 0x02D1 || + c == 0x0387 || + c == 0x0640 || + c == 0x0E46 || + c == 0x0EC6 || + c == 0x3005 || + (c >= 0x3031 && c <= 0x3035) || + (c >= 0x309D && c <= 0x309E) || + (c >= 0x30FC && c <= 0x30FE)); + } + + /** + * Indicates whether the specified Unicode character matches the Char + * production. + */ + public static boolean isChar(int c) + { + return (c >= 0x20 && c < 0xd800) || + (c >= 0xe00 && c < 0xfffe) || + (c >= 0x10000 && c < 0x110000) || + c == 0xa || c == 0x9 || c == 0xd; + } + + /** + * Interns the specified text or not, depending on the value of + * stringInterning. + */ + private String intern(String text) + { + return stringInterning ? text.intern() : text; + } + + /** + * Report a parsing error. + */ + private void error(String message) + throws XMLStreamException + { + error(message, null); + } + + /** + * Report a parsing error. + */ + private void error(String message, Object info) + throws XMLStreamException + { + if (info != null) + { + if (info instanceof String) + message += ": \"" + ((String) info) + "\""; + else if (info instanceof Character) + message += ": '" + ((Character) info) + "'"; + } + throw new XMLStreamException(message); + } + + /** + * Perform validation of a start-element event. + */ + private void validateStartElement(String elementName) + throws XMLStreamException + { + if (currentContentModel == null) + { + // root element + // VC: Root Element Type + if (!elementName.equals(doctype.rootName)) + error("root element name must match name in DTD"); + return; + } + // VC: Element Valid + switch (currentContentModel.type) + { + case ContentModel.EMPTY: + error("child element found in empty element", elementName); + break; + case ContentModel.ELEMENT: + LinkedList ctx = (LinkedList) validationStack.getLast(); + ctx.add(elementName); + break; + case ContentModel.MIXED: + MixedContentModel mm = (MixedContentModel) currentContentModel; + if (!mm.containsName(elementName)) + error("illegal element for content model", elementName); + break; + } + } + + /** + * Perform validation of an end-element event. + */ + private void validateEndElement() + throws XMLStreamException + { + if (currentContentModel == null) + { + // root element + // VC: IDREF + if (!idrefs.containsAll(ids)) + error("IDREF values must match the value of some ID attribute"); + return; + } + // VC: Element Valid + switch (currentContentModel.type) + { + case ContentModel.ELEMENT: + LinkedList ctx = (LinkedList) validationStack.getLast(); + ElementContentModel ecm = (ElementContentModel) currentContentModel; + validateElementContent(ecm, ctx); + break; + } + } + + /** + * Perform validation of character data. + */ + private void validatePCData(String text) + throws XMLStreamException + { + // VC: Element Valid + switch (currentContentModel.type) + { + case ContentModel.EMPTY: + error("character data found in empty element", text); + break; + case ContentModel.ELEMENT: + boolean white = true; + int len = text.length(); + for (int i = 0; i < len; i++) + { + char c = text.charAt(i); + if (c != ' ' && c != '\t' && c != '\n' && c != '\r') + { + white = false; + break; + } + } + if (!white) + error("character data found in element with element content", text); + else if (xmlStandalone == Boolean.TRUE && currentContentModel.external) + // VC: Standalone Document Declaration + error("whitespace in element content of externally declared " + + "element in standalone document"); + break; + } + } + + /** + * Validates the specified validation context (list of child elements) + * against the element content model for the current element. + */ + private void validateElementContent(ElementContentModel model, + LinkedList children) + throws XMLStreamException + { + // Use regular expression + CPStringBuilder buf = new CPStringBuilder(); + for (Iterator i = children.iterator(); i.hasNext(); ) + { + buf.append((String) i.next()); + buf.append(' '); + } + String c = buf.toString(); + String regex = createRegularExpression(model); + if (!c.matches(regex)) + error("element content "+model.text+" does not match expression "+regex, c); + } + + /** + * Creates the regular expression used to validate an element content + * model. + */ + private String createRegularExpression(ElementContentModel model) + { + if (model.regex == null) + { + CPStringBuilder buf = new CPStringBuilder(); + buf.append('('); + for (Iterator i = model.contentParticles.iterator(); i.hasNext(); ) + { + ContentParticle cp = (ContentParticle) i.next(); + if (cp.content instanceof String) + { + buf.append('('); + buf.append((String) cp.content); + buf.append(' '); + buf.append(')'); + if (cp.max == -1) + { + if (cp.min == 0) + buf.append('*'); + else + buf.append('+'); + } + else if (cp.min == 0) + buf.append('?'); + } + else + { + ElementContentModel ecm = (ElementContentModel) cp.content; + buf.append(createRegularExpression(ecm)); + } + if (model.or && i.hasNext()) + buf.append('|'); + } + buf.append(')'); + if (model.max == -1) + { + if (model.min == 0) + buf.append('*'); + else + buf.append('+'); + } + else if (model.min == 0) + buf.append('?'); + model.regex = buf.toString(); + } + return model.regex; + } + + /** + * Performs validation of a document type declaration event. + */ + void validateDoctype() + throws XMLStreamException + { + for (Iterator i = doctype.entityIterator(); i.hasNext(); ) + { + Map.Entry entry = (Map.Entry) i.next(); + Object entity = entry.getValue(); + if (entity instanceof ExternalIds) + { + ExternalIds ids = (ExternalIds) entity; + if (ids.notationName != null) + { + // VC: Notation Declared + ExternalIds notation = doctype.getNotation(ids.notationName); + if (notation == null) + error("Notation name must match the declared name of a " + + "notation", ids.notationName); + } + } + } + } + + /** + * Simple test harness for reading an XML file. + * args[0] is the filename of the XML file + * If args[1] is "-x", enable XInclude processing + */ + public static void main(String[] args) + throws Exception + { + boolean validating = false; + boolean namespaceAware = false; + boolean xIncludeAware = false; + int pos = 0; + while (pos < args.length && args[pos].startsWith("-")) + { + if ("-x".equals(args[pos])) + xIncludeAware = true; + else if ("-v".equals(args[pos])) + validating = true; + else if ("-n".equals(args[pos])) + namespaceAware = true; + pos++; + } + if (pos >= args.length) + { + System.out.println("Syntax: XMLParser [-n] [-v] [-x] [ [...]]"); + System.out.println("\t-n: use namespace aware mode"); + System.out.println("\t-v: use validating parser"); + System.out.println("\t-x: use XInclude aware mode"); + System.exit(2); + } + while (pos < args.length) + { + XMLParser p = new XMLParser(new java.io.FileInputStream(args[pos]), + absolutize(null, args[pos]), + validating, // validating + namespaceAware, // namespaceAware + true, // coalescing, + true, // replaceERefs + true, // externalEntities + true, // supportDTD + true, // baseAware + true, // stringInterning + true, // extendedEventTypes + null, + null); + XMLStreamReader reader = p; + if (xIncludeAware) + reader = new XIncludeFilter(p, args[pos], true, true, true); + try + { + int event; + //do + while (reader.hasNext()) + { + event = reader.next(); + Location loc = reader.getLocation(); + System.out.print(loc.getLineNumber() + ":" + + loc.getColumnNumber() + " "); + switch (event) + { + case XMLStreamConstants.START_DOCUMENT: + System.out.println("START_DOCUMENT version=" + + reader.getVersion() + + " encoding=" + + reader.getEncoding()); + break; + case XMLStreamConstants.END_DOCUMENT: + System.out.println("END_DOCUMENT"); + break; + case XMLStreamConstants.START_ELEMENT: + System.out.println("START_ELEMENT " + + reader.getName()); + int l = reader.getNamespaceCount(); + for (int i = 0; i < l; i++) + System.out.println("\tnamespace " + + reader.getNamespacePrefix(i) + "='" + + reader.getNamespaceURI(i)+"'"); + l = reader.getAttributeCount(); + for (int i = 0; i < l; i++) + System.out.println("\tattribute " + + reader.getAttributeName(i) + "='" + + reader.getAttributeValue(i) + "'"); + break; + case XMLStreamConstants.END_ELEMENT: + System.out.println("END_ELEMENT " + reader.getName()); + break; + case XMLStreamConstants.CHARACTERS: + System.out.println("CHARACTERS '" + + encodeText(reader.getText()) + "'"); + break; + case XMLStreamConstants.CDATA: + System.out.println("CDATA '" + + encodeText(reader.getText()) + "'"); + break; + case XMLStreamConstants.SPACE: + System.out.println("SPACE '" + + encodeText(reader.getText()) + "'"); + break; + case XMLStreamConstants.DTD: + System.out.println("DTD " + reader.getText()); + break; + case XMLStreamConstants.ENTITY_REFERENCE: + System.out.println("ENTITY_REFERENCE " + reader.getText()); + break; + case XMLStreamConstants.COMMENT: + System.out.println("COMMENT '" + + encodeText(reader.getText()) + "'"); + break; + case XMLStreamConstants.PROCESSING_INSTRUCTION: + System.out.println("PROCESSING_INSTRUCTION " + + reader.getPITarget() + " " + + reader.getPIData()); + break; + case START_ENTITY: + System.out.println("START_ENTITY " + reader.getText()); + break; + case END_ENTITY: + System.out.println("END_ENTITY " + reader.getText()); + break; + default: + System.out.println("Unknown event: " + event); + } + } + } + catch (XMLStreamException e) + { + Location l = reader.getLocation(); + System.out.println("At line "+l.getLineNumber()+ + ", column "+l.getColumnNumber()+ + " of "+l.getSystemId()); + throw e; + } + pos++; + } + } + + /** + * Escapes control characters in the specified text. For debugging. + */ + private static String encodeText(String text) + { + CPStringBuilder b = new CPStringBuilder(); + int len = text.length(); + for (int i = 0; i < len; i++) + { + char c = text.charAt(i); + switch (c) + { + case '\t': + b.append("\\t"); + break; + case '\n': + b.append("\\n"); + break; + case '\r': + b.append("\\r"); + break; + default: + b.append(c); + } + } + return b.toString(); + } + + /** + * An attribute instance. + */ + class Attribute + { + + /** + * Attribute name. + */ + final String name; + + /** + * Attribute type as declared in the DTD, or CDATA otherwise. + */ + final String type; + + /** + * Whether the attribute was specified or defaulted. + */ + final boolean specified; + + /** + * The attribute value. + */ + final String value; + + /** + * The namespace prefix. + */ + final String prefix; + + /** + * The namespace local-name. + */ + final String localName; + + Attribute(String name, String type, boolean specified, String value) + { + this.name = name; + this.type = type; + this.specified = specified; + this.value = value; + int ci = name.indexOf(':'); + if (ci == -1) + { + prefix = null; + localName = intern(name); + } + else + { + prefix = intern(name.substring(0, ci)); + localName = intern(name.substring(ci + 1)); + } + } + + public boolean equals(Object other) + { + if (other instanceof Attribute) + { + Attribute a = (Attribute) other; + if (namespaceAware) + { + if (!a.localName.equals(localName)) + return false; + String auri = getNamespaceURI(a.prefix); + String uri = getNamespaceURI(prefix); + if (uri == null && (auri == null || + (input.xml11 && "".equals(auri)))) + return true; + if (uri != null) + { + if ("".equals(uri) && input.xml11 && "".equals(auri)) + return true; + return uri.equals(auri); + } + return false; + } + else + return a.name.equals(name); + } + return false; + } + + public String toString() + { + CPStringBuilder buf = new CPStringBuilder(getClass().getName()); + buf.append('['); + buf.append("name="); + buf.append(name); + if (value != null) + { + buf.append(",value="); + buf.append(value); + } + if (type != null) + { + buf.append(",type="); + buf.append(type); + } + if (specified) + buf.append(",specified"); + buf.append(']'); + return buf.toString(); + } + + } + + /** + * Representation of a DTD. + */ + class Doctype + { + + /** + * Name of the root element. + */ + final String rootName; + + /** + * Public ID, if any, of external subset. + */ + final String publicId; + + /** + * System ID (URL), if any, of external subset. + */ + final String systemId; + + /** + * Map of element names to content models. + */ + private final LinkedHashMap elements = new LinkedHashMap(); + + /** + * Map of element names to maps of attribute declarations. + */ + private final LinkedHashMap attlists = new LinkedHashMap(); + + /** + * Map of entity names to entities (String or ExternalIds). + */ + private final LinkedHashMap entities = new LinkedHashMap(); + + /** + * Map of notation names to ExternalIds. + */ + private final LinkedHashMap notations = new LinkedHashMap(); + + /** + * Map of anonymous keys to comments. + */ + private final LinkedHashMap comments = new LinkedHashMap(); + + /** + * Map of anonymous keys to processing instructions (String[2] + * containing {target, data}). + */ + private final LinkedHashMap pis = new LinkedHashMap(); + + /** + * List of keys to all markup entries in the DTD. + */ + private final LinkedList entries = new LinkedList(); + + /** + * Set of the entities defined in the external subset. + */ + private final HashSet externalEntities = new HashSet(); + + /** + * Set of the notations defined in the external subset. + */ + private final HashSet externalNotations = new HashSet(); + + /** + * Counter for making anonymous keys. + */ + private int anon = 1; + + /** + * Constructor. + */ + Doctype(String rootName, String publicId, String systemId) + { + this.rootName = rootName; + this.publicId = publicId; + this.systemId = systemId; + } + + /** + * Adds an element declaration. + * @param name the element name + * @param text the content model text + * @param model the parsed content model + */ + void addElementDecl(String name, String text, ContentModel model) + { + if (elements.containsKey(name)) + return; + model.text = text; + model.external = (inputStack.size() != 1); + elements.put(name, model); + entries.add("E" + name); + } + + /** + * Adds an attribute declaration. + * @param ename the element name + * @param aname the attribute name + * @param decl the attribute declaration details + */ + void addAttributeDecl(String ename, String aname, AttributeDecl decl) + { + LinkedHashMap attlist = (LinkedHashMap) attlists.get(ename); + if (attlist == null) + { + attlist = new LinkedHashMap(); + attlists.put(ename, attlist); + } + else if (attlist.containsKey(aname)) + return; + attlist.put(aname, decl); + String key = "A" + ename; + if (!entries.contains(key)) + entries.add(key); + } + + /** + * Adds an entity declaration. + * @param name the entity name + * @param text the entity replacement text + * @param inExternalSubset if we are in the exernal subset + */ + void addEntityDecl(String name, String text, boolean inExternalSubset) + { + if (entities.containsKey(name)) + return; + entities.put(name, text); + entries.add("e" + name); + if (inExternalSubset) + externalEntities.add(name); + } + + /** + * Adds an entity declaration. + * @param name the entity name + * @param ids the external IDs + * @param inExternalSubset if we are in the exernal subset + */ + void addEntityDecl(String name, ExternalIds ids, boolean inExternalSubset) + { + if (entities.containsKey(name)) + return; + entities.put(name, ids); + entries.add("e" + name); + if (inExternalSubset) + externalEntities.add(name); + } + + /** + * Adds a notation declaration. + * @param name the notation name + * @param ids the external IDs + * @param inExternalSubset if we are in the exernal subset + */ + void addNotationDecl(String name, ExternalIds ids, boolean inExternalSubset) + { + if (notations.containsKey(name)) + return; + notations.put(name, ids); + entries.add("n" + name); + if (inExternalSubset) + externalNotations.add(name); + } + + /** + * Adds a comment. + */ + void addComment(String text) + { + String key = Integer.toString(anon++); + comments.put(key, text); + entries.add("c" + key); + } + + /** + * Adds a processing instruction. + */ + void addPI(String target, String data) + { + String key = Integer.toString(anon++); + pis.put(key, new String[] {target, data}); + entries.add("p" + key); + } + + /** + * Returns the content model for the specified element. + * @param name the element name + */ + ContentModel getElementModel(String name) + { + return (ContentModel) elements.get(name); + } + + /** + * Returns the attribute definition for the given attribute + * @param ename the element name + * @param aname the attribute name + */ + AttributeDecl getAttributeDecl(String ename, String aname) + { + LinkedHashMap attlist = (LinkedHashMap) attlists.get(ename); + return (attlist == null) ? null : (AttributeDecl) attlist.get(aname); + } + + /** + * Indicates whether the specified attribute was declared in the DTD. + * @param ename the element name + * @param aname the attribute name + */ + boolean isAttributeDeclared(String ename, String aname) + { + LinkedHashMap attlist = (LinkedHashMap) attlists.get(ename); + return (attlist == null) ? false : attlist.containsKey(aname); + } + + /** + * Returns an iterator over the entries in the attribute list for the + * given element. + * @param ename the element name + */ + Iterator attlistIterator(String ename) + { + LinkedHashMap attlist = (LinkedHashMap) attlists.get(ename); + return (attlist == null) ? Collections.EMPTY_LIST.iterator() : + attlist.entrySet().iterator(); + } + + /** + * Returns the entity (String or ExternalIds) for the given entity name. + */ + Object getEntity(String name) + { + return entities.get(name); + } + + /** + * Indicates whether the specified entity was declared in the external + * subset. + */ + boolean isEntityExternal(String name) + { + return externalEntities.contains(name); + } + + /** + * Returns an iterator over the entity map entries. + */ + Iterator entityIterator() + { + return entities.entrySet().iterator(); + } + + /** + * Returns the notation IDs for the given notation name. + */ + ExternalIds getNotation(String name) + { + return (ExternalIds) notations.get(name); + } + + /** + * Indicates whether the specified notation was declared in the external + * subset. + */ + boolean isNotationExternal(String name) + { + return externalNotations.contains(name); + } + + /** + * Returns the comment associated with the specified (anonymous) key. + */ + String getComment(String key) + { + return (String) comments.get(key); + } + + /** + * Returns the processing instruction associated with the specified + * (anonymous) key. + */ + String[] getPI(String key) + { + return (String[]) pis.get(key); + } + + /** + * Returns an iterator over the keys of the markup entries in this DTD, + * in the order declared. + */ + Iterator entryIterator() + { + return entries.iterator(); + } + + } + + /** + * Combination of an ExternalID and an optional NDataDecl. + */ + class ExternalIds + { + + /** + * The public ID. + */ + String publicId; + + /** + * The system ID. + */ + String systemId; + + /** + * The notation name declared with the NDATA keyword. + */ + String notationName; + } + + /** + * A content model. + */ + abstract class ContentModel + { + static final int EMPTY = 0; + static final int ANY = 1; + static final int ELEMENT = 2; + static final int MIXED = 3; + + int min; + int max; + final int type; + String text; + boolean external; + + ContentModel(int type) + { + this.type = type; + min = 1; + max = 1; + } + + } + + /** + * The EMPTY content model. + */ + class EmptyContentModel + extends ContentModel + { + + EmptyContentModel() + { + super(ContentModel.EMPTY); + min = 0; + max = 0; + } + + } + + /** + * The ANY content model. + */ + class AnyContentModel + extends ContentModel + { + + AnyContentModel() + { + super(ContentModel.ANY); + min = 0; + max = -1; + } + + } + + /** + * An element content model. + */ + class ElementContentModel + extends ContentModel + { + + LinkedList contentParticles; + boolean or; + String regex; // regular expression cache + + ElementContentModel() + { + super(ContentModel.ELEMENT); + contentParticles = new LinkedList(); + } + + void addContentParticle(ContentParticle cp) + { + contentParticles.add(cp); + } + + } + + class ContentParticle + { + + int min = 1; + int max = 1; + Object content; // Name (String) or ElementContentModel + + } + + /** + * A mixed content model. + */ + class MixedContentModel + extends ContentModel + { + + private HashSet names; + + MixedContentModel() + { + super(ContentModel.MIXED); + names = new HashSet(); + } + + void addName(String name) + { + names.add(name); + } + + boolean containsName(String name) + { + return names.contains(name); + } + + } + + /** + * An attribute definition. + */ + class AttributeDecl + { + + /** + * The attribute type (CDATA, ID, etc). + */ + final String type; + + /** + * The default value. + */ + final String value; + + /** + * The value type (#FIXED, #IMPLIED, etc). + */ + final int valueType; + + /** + * The enumeration text. + */ + final String enumeration; + + /** + * The enumeration tokens. + */ + final HashSet values; + + /** + * Whether this attribute declaration occurred in the external subset. + */ + final boolean external; + + AttributeDecl(String type, String value, + int valueType, String enumeration, + HashSet values, boolean external) + { + this.type = type; + this.value = value; + this.valueType = valueType; + this.enumeration = enumeration; + this.values = values; + this.external = external; + } + + } + + /** + * An XML input source. + */ + static class Input + implements Location + { + + int line = 1, markLine; + int column, markColumn; + int offset, markOffset; + final String publicId, systemId, name; + final boolean report; // report start- and end-entity + final boolean normalize; // normalize CR, etc to LF + + InputStream in; + Reader reader; + UnicodeReader unicodeReader; + boolean initialized; + boolean encodingDetected; + String inputEncoding; + boolean xml11; + + Input(InputStream in, Reader reader, String publicId, String systemId, + String name, String inputEncoding, boolean report, + boolean normalize) + { + if (inputEncoding == null) + inputEncoding = "UTF-8"; + this.inputEncoding = inputEncoding; + this.publicId = publicId; + this.systemId = systemId; + this.name = name; + this.report = report; + this.normalize = normalize; + if (in != null) + { + if (reader != null) + throw new IllegalStateException("both byte and char streams "+ + "specified"); + if (normalize) + in = new CRLFInputStream(in); + in = new BufferedInputStream(in); + this.in = in; + } + else + { + this.reader = normalize ? new CRLFReader(reader) : reader; + unicodeReader = new UnicodeReader(this.reader); + } + initialized = false; + } + + // -- Location -- + + public int getCharacterOffset() + { + return offset; + } + + public int getColumnNumber() + { + return column; + } + + public int getLineNumber() + { + return line; + } + + public String getPublicId() + { + return publicId; + } + + public String getSystemId() + { + return systemId; + } + + void init() + throws IOException + { + if (initialized) + return; + if (in != null) + detectEncoding(); + initialized = true; + } + + void mark(int len) + throws IOException + { + markOffset = offset; + markLine = line; + markColumn = column; + if (unicodeReader != null) + unicodeReader.mark(len); + else + in.mark(len); + } + + /** + * Character read. + */ + int read() + throws IOException + { + offset++; + int ret = (unicodeReader != null) ? unicodeReader.read() : in.read(); + if (normalize && + (ret == 0x0d || (xml11 && (ret == 0x85 || ret == 0x2028)))) + { + // Normalize CR etc to LF + ret = 0x0a; + } + // Locator handling + if (ret == 0x0a) + { + line++; + column = 0; + } + else + column++; + return ret; + } + + /** + * Block read. + */ + int read(int[] b, int off, int len) + throws IOException + { + int ret; + if (unicodeReader != null) + { + ret = unicodeReader.read(b, off, len); + } + else + { + byte[] b2 = new byte[len]; + ret = in.read(b2, 0, len); + if (ret != -1) + { + String s = new String(b2, 0, ret, inputEncoding); + int[] c = UnicodeReader.toCodePointArray(s); + ret = c.length; + System.arraycopy(c, 0, b, off, ret); + } + } + if (ret != -1) + { + // Locator handling + for (int i = 0; i < ret; i++) + { + int c = b[off + i]; + if (normalize && + (c == 0x0d || (xml11 && (c == 0x85 || c == 0x2028)))) + { + // Normalize CR etc to LF + c = 0x0a; + b[off + i] = c; + } + if (c == 0x0a) + { + line++; + column = 0; + } + else + column++; + } + } + return ret; + } + + void reset() + throws IOException + { + if (unicodeReader != null) + unicodeReader.reset(); + else + in.reset(); + offset = markOffset; + line = markLine; + column = markColumn; + } + + // Detection of input encoding + + private static final int[] SIGNATURE_UCS_4_1234 = + new int[] { 0x00, 0x00, 0x00, 0x3c }; + private static final int[] SIGNATURE_UCS_4_4321 = + new int[] { 0x3c, 0x00, 0x00, 0x00 }; + private static final int[] SIGNATURE_UCS_4_2143 = + new int[] { 0x00, 0x00, 0x3c, 0x00 }; + private static final int[] SIGNATURE_UCS_4_3412 = + new int[] { 0x00, 0x3c, 0x00, 0x00 }; + private static final int[] SIGNATURE_UCS_2_12 = + new int[] { 0xfe, 0xff }; + private static final int[] SIGNATURE_UCS_2_21 = + new int[] { 0xff, 0xfe }; + private static final int[] SIGNATURE_UCS_2_12_NOBOM = + new int[] { 0x00, 0x3c, 0x00, 0x3f }; + private static final int[] SIGNATURE_UCS_2_21_NOBOM = + new int[] { 0x3c, 0x00, 0x3f, 0x00 }; + private static final int[] SIGNATURE_UTF_8 = + new int[] { 0x3c, 0x3f, 0x78, 0x6d }; + private static final int[] SIGNATURE_UTF_8_BOM = + new int[] { 0xef, 0xbb, 0xbf }; + + /** + * Detect the input encoding. + */ + private void detectEncoding() + throws IOException + { + int[] signature = new int[4]; + in.mark(4); + for (int i = 0; i < 4; i++) + signature[i] = in.read(); + in.reset(); + + // 4-byte encodings + if (equals(SIGNATURE_UCS_4_1234, signature)) + { + in.read(); + in.read(); + in.read(); + in.read(); + setInputEncoding("UTF-32BE"); + encodingDetected = true; + } + else if (equals(SIGNATURE_UCS_4_4321, signature)) + { + in.read(); + in.read(); + in.read(); + in.read(); + setInputEncoding("UTF-32LE"); + encodingDetected = true; + } + else if (equals(SIGNATURE_UCS_4_2143, signature) || + equals(SIGNATURE_UCS_4_3412, signature)) + throw new UnsupportedEncodingException("unsupported UCS-4 byte ordering"); + + // 2-byte encodings + else if (equals(SIGNATURE_UCS_2_12, signature)) + { + in.read(); + in.read(); + setInputEncoding("UTF-16BE"); + encodingDetected = true; + } + else if (equals(SIGNATURE_UCS_2_21, signature)) + { + in.read(); + in.read(); + setInputEncoding("UTF-16LE"); + encodingDetected = true; + } + else if (equals(SIGNATURE_UCS_2_12_NOBOM, signature)) + { + //setInputEncoding("UTF-16BE"); + throw new UnsupportedEncodingException("no byte-order mark for UCS-2 entity"); + } + else if (equals(SIGNATURE_UCS_2_21_NOBOM, signature)) + { + //setInputEncoding("UTF-16LE"); + throw new UnsupportedEncodingException("no byte-order mark for UCS-2 entity"); + } + // ASCII-derived encodings + else if (equals(SIGNATURE_UTF_8, signature)) + { + // UTF-8 input encoding implied, TextDecl + } + else if (equals(SIGNATURE_UTF_8_BOM, signature)) + { + in.read(); + in.read(); + in.read(); + setInputEncoding("UTF-8"); + encodingDetected = true; + } + } + + private static boolean equals(int[] b1, int[] b2) + { + for (int i = 0; i < b1.length; i++) + { + if (b1[i] != b2[i]) + return false; + } + return true; + } + + void setInputEncoding(String encoding) + throws IOException + { + if (encoding.equals(inputEncoding)) + return; + if ("UTF-16".equalsIgnoreCase(encoding) && + inputEncoding.startsWith("UTF-16")) + return; + if (encodingDetected) + throw new UnsupportedEncodingException("document is not in its " + + "declared encoding " + + inputEncoding + + ": " + encoding); + inputEncoding = encoding; + finalizeEncoding(); + } + + void finalizeEncoding() + throws IOException + { + if (reader != null) + return; + reader = new BufferedReader(new InputStreamReader(in, inputEncoding)); + unicodeReader = new UnicodeReader(reader); + mark(1); + } + + } + +} diff --git a/libjava/classpath/gnu/xml/stream/XMLStreamWriterImpl.java b/libjava/classpath/gnu/xml/stream/XMLStreamWriterImpl.java new file mode 100644 index 000000000..83b8f7239 --- /dev/null +++ b/libjava/classpath/gnu/xml/stream/XMLStreamWriterImpl.java @@ -0,0 +1,1016 @@ +/* XMLStreamWriterImpl.java -- + 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.xml.stream; + +import java.io.IOException; +import java.io.Writer; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Set; + +import javax.xml.XMLConstants; +import javax.xml.namespace.NamespaceContext; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +import org.xml.sax.helpers.NamespaceSupport; + +/** + * Simple XML stream writer. + * + * @author Chris Burdess + */ +public class XMLStreamWriterImpl + implements XMLStreamWriter +{ + + /** + * The underlying character stream to write to. + */ + protected final Writer writer; + + /** + * The encoding being used. + * Note that this must match the encoding of the character stream. + */ + protected final String encoding; + + /** + * Whether prefix defaulting is being used. + * If true and a prefix has not been defined for a namespace specified on + * an element or an attribute, a new prefix and namespace declaration will + * be created. + */ + protected final boolean prefixDefaulting; + + /** + * The namespace context used to determine the namespace-prefix mappings + * in scope. + */ + protected NamespaceContext namespaceContext; + + /** + * The stack of elements in scope. + * Used to close the remaining elements. + */ + private LinkedList elements; + + /** + * Whether a start element has been opened but not yet closed. + */ + private boolean inStartElement; + + /** + * Whether we are in an empty element. + */ + private boolean emptyElement; + + private NamespaceSupport namespaces; + private int count = 0; + + private boolean xml11; + private boolean hasXML11RestrictedChars; + + /** + * Constructor. + * @see #writer + * @see #encoding + * @see #prefixDefaulting + */ + protected XMLStreamWriterImpl(Writer writer, String encoding, + boolean prefixDefaulting) + { + this.writer = writer; + this.encoding = encoding; + this.prefixDefaulting = prefixDefaulting; + elements = new LinkedList(); + namespaces = new NamespaceSupport(); + } + + /** + * Write the end of a start-element event. + * This will close the element if it was defined to be an empty element. + */ + private void endStartElement() + throws IOException + { + if (!inStartElement) + return; + if (emptyElement) + { + writer.write('/'); + elements.removeLast(); + namespaces.popContext(); + emptyElement = false; + } + writer.write('>'); + inStartElement = false; + } + + public void writeStartElement(String localName) + throws XMLStreamException + { + try + { + if (!isName(localName)) + throw new IllegalArgumentException("illegal Name: " + localName); + + endStartElement(); + namespaces.pushContext(); + + writer.write('<'); + writer.write(localName); + + elements.addLast(new String[] { null, localName }); + inStartElement = true; + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + public void writeStartElement(String namespaceURI, String localName) + throws XMLStreamException + { + try + { + if (namespaceURI != null && !isURI(namespaceURI)) + throw new IllegalArgumentException("illegal URI: " + namespaceURI); + if (!isName(localName)) + throw new IllegalArgumentException("illegal Name: " + localName); + + endStartElement(); + namespaces.pushContext(); + + String prefix = getPrefix(namespaceURI); + boolean isDeclared = (prefix != null); + if (!isDeclared) + { + if (prefixDefaulting) + prefix = createPrefix(namespaceURI); + else + throw new XMLStreamException("namespace " + namespaceURI + + " has not been declared"); + } + writer.write('<'); + if (!"".equals(prefix)) + { + writer.write(prefix); + writer.write(':'); + } + writer.write(localName); + inStartElement = true; + if (!isDeclared) + { + writeNamespaceImpl(prefix, namespaceURI); + } + + elements.addLast(new String[] { prefix, localName }); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + /** + * Creates a new unique prefix in the document. + * Subclasses may override this method to provide a suitably unique prefix + * for the given namespace. + * @param namespaceURI the namespace URI + */ + protected String createPrefix(String namespaceURI) + { + Set prefixes = new HashSet(); + for (Enumeration e = namespaces.getPrefixes(); e.hasMoreElements(); ) + prefixes.add(e.nextElement()); + String ret; + do + { + ret = "ns" + (count++); + } + while (prefixes.contains(ret)); + return ret; + } + + public void writeStartElement(String prefix, String localName, + String namespaceURI) + throws XMLStreamException + { + try + { + if (namespaceURI != null && !isURI(namespaceURI)) + throw new IllegalArgumentException("illegal URI: " + namespaceURI); + if (prefix != null && !isPrefix(prefix)) + throw new IllegalArgumentException("illegal NCName: " + prefix); + if (!isNCName(localName)) + throw new IllegalArgumentException("illegal NCName: " + localName); + + endStartElement(); + namespaces.pushContext(); + + String currentPrefix = getPrefix(namespaceURI); + boolean isCurrent = prefix.equals(currentPrefix); + writer.write('<'); + if (!"".equals(prefix)) + { + writer.write(prefix); + writer.write(':'); + } + writer.write(localName); + if (prefixDefaulting && !isCurrent) + { + writeNamespaceImpl(prefix, namespaceURI); + } + + elements.addLast(new String[] { prefix, localName }); + inStartElement = true; + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + public void writeEmptyElement(String namespaceURI, String localName) + throws XMLStreamException + { + writeStartElement(namespaceURI, localName); + emptyElement = true; + } + + public void writeEmptyElement(String prefix, String localName, + String namespaceURI) + throws XMLStreamException + { + writeStartElement(prefix, localName, namespaceURI); + emptyElement = true; + } + + public void writeEmptyElement(String localName) + throws XMLStreamException + { + writeStartElement(localName); + emptyElement = true; + } + + public void writeEndElement() + throws XMLStreamException + { + if (elements.isEmpty()) + throw new IllegalStateException("no matching start element"); + try + { + endStartElement(); + String[] element = (String[]) elements.removeLast(); + namespaces.popContext(); + + writer.write('<'); + writer.write('/'); + if (element[0] != null && !"".equals(element[0])) + { + writer.write(element[0]); + writer.write(':'); + } + writer.write(element[1]); + writer.write('>'); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + public void writeEndDocument() + throws XMLStreamException + { + while (!elements.isEmpty()) + writeEndElement(); + } + + public void close() + throws XMLStreamException + { + flush(); + } + + public void flush() + throws XMLStreamException + { + try + { + writer.flush(); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + public void writeAttribute(String localName, String value) + throws XMLStreamException + { + if (!inStartElement) + 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('"'); + if (hasXML11RestrictedChars) + writeEncodedWithRestrictedChars(value, true); + else + writeEncoded(value, true); + writer.write('"'); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + public void writeAttribute(String prefix, String namespaceURI, + String localName, String value) + throws XMLStreamException + { + if (!inStartElement) + throw new IllegalStateException(); + try + { + if (namespaceURI != null && !isURI(namespaceURI)) + throw new IllegalArgumentException("illegal URI: " + namespaceURI); + if (prefix != null && !isPrefix(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) + writeNamespaceImpl(prefix, namespaceURI); + else + throw new XMLStreamException("namespace " + namespaceURI + + " is not bound"); + } + else if (!currentPrefix.equals(prefix)) + throw new XMLStreamException("namespace " + namespaceURI + + " is bound to prefix " + + currentPrefix); + writer.write(' '); + if (!"".equals(prefix)) + { + writer.write(prefix); + writer.write(':'); + } + writer.write(localName); + writer.write('='); + writer.write('"'); + if (hasXML11RestrictedChars) + writeEncodedWithRestrictedChars(value, true); + else + writeEncoded(value, true); + writer.write('"'); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + public void writeAttribute(String namespaceURI, String localName, + String value) + throws XMLStreamException + { + if (!inStartElement) + 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; + writeNamespaceImpl(prefix, namespaceURI); + } + else + throw new XMLStreamException("namespace " + namespaceURI + + " is not bound"); + } + writer.write(' '); + if (!"".equals(prefix)) + { + writer.write(prefix); + writer.write(':'); + } + writer.write(localName); + writer.write('='); + writer.write('"'); + if (hasXML11RestrictedChars) + writeEncodedWithRestrictedChars(value, true); + else + writeEncoded(value, true); + writer.write('"'); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + public void writeNamespace(String prefix, String namespaceURI) + throws XMLStreamException + { + if (prefix == null || "".equals(prefix) || "xmlns".equals(prefix)) + { + writeDefaultNamespace(namespaceURI); + return; + } + if (!inStartElement) + throw new IllegalStateException(); + try + { + if (!isURI(namespaceURI)) + throw new IllegalArgumentException("illegal URI: " + namespaceURI); + if (!isPrefix(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) + prefix = XMLConstants.DEFAULT_NS_PREFIX; + + setPrefix(prefix, namespaceURI); + + writer.write(' '); + writer.write("xmlns"); + if (!XMLConstants.DEFAULT_NS_PREFIX.equals(prefix)) + { + writer.write(':'); + writer.write(prefix); + } + writer.write('='); + writer.write('"'); + writer.write(namespaceURI); + writer.write('"'); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + public void writeDefaultNamespace(String namespaceURI) + throws XMLStreamException + { + 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(); + + writer.write(""); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + public void writeProcessingInstruction(String target) + throws XMLStreamException + { + writeProcessingInstruction(target, null); + } + + public void writeProcessingInstruction(String target, String data) + throws XMLStreamException + { + 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('<'); + writer.write('?'); + writer.write(target); + if (data != null) + { + writer.write(' '); + 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('>'); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + public void writeCData(String data) + throws XMLStreamException + { + try + { + if (!isChars(data) || hasXML11RestrictedChars) + throw new IllegalArgumentException("illegal XML character: " + data); + if (data.indexOf("]]") != -1) + throw new IllegalArgumentException("illegal CDATA section: " + data); + + endStartElement(); + + writer.write(""); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + public void writeDTD(String dtd) + throws XMLStreamException + { + try + { + // XXX: Should we parse the doctypedecl at this point to ensure + // wellformedness? + writer.write("'); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + public void writeEntityRef(String name) + throws XMLStreamException + { + try + { + if (!isName(name)) + throw new IllegalArgumentException("illegal Name: " + name); + + endStartElement(); + + writer.write('&'); + writer.write(name); + writer.write(';'); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + public void writeStartDocument() + throws XMLStreamException + { + writeStartDocument(null, null); + } + + public void writeStartDocument(String version) + throws XMLStreamException + { + writeStartDocument(null, version); + } + + public void writeStartDocument(String encoding, String version) + throws XMLStreamException + { + 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"; + if (!"1.0".equals(version) && !"1.1".equals(version)) + throw new IllegalArgumentException(version); + try + { + writer.write(""); + writer.write(System.getProperty("line.separator")); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + public void writeCharacters(String text) + throws XMLStreamException + { + if (text == null) + return; + try + { + if (!isChars(text)) + throw new IllegalArgumentException("illegal XML character: " + text); + + endStartElement(); + + if (hasXML11RestrictedChars) + writeEncodedWithRestrictedChars(text, false); + else + writeEncoded(text, false); + } + catch (IOException e) + { + XMLStreamException e2 = new XMLStreamException(e); + e2.initCause(e); + throw e2; + } + } + + public void writeCharacters(char[] text, int start, int len) + throws XMLStreamException + { + writeCharacters(new String(text, start, len)); + } + + public String getPrefix(String uri) + throws XMLStreamException + { + String prefix = namespaces.getPrefix(uri); + if (prefix == null && namespaceContext != null) + prefix = namespaceContext.getPrefix(uri); + return prefix; + } + + public void setPrefix(String prefix, String uri) + throws XMLStreamException + { + try + { + if (!isURI(uri)) + throw new IllegalArgumentException("illegal URI: " + uri); + if (!isPrefix(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); + } + + 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"); + } + + public void setNamespaceContext(NamespaceContext context) + throws XMLStreamException + { + namespaceContext = context; + } + + public NamespaceContext getNamespaceContext() + { + return namespaceContext; + } + + public Object getProperty(String name) + throws IllegalArgumentException + { + throw new IllegalArgumentException(name); + } + + /** + * Write the specified text, ensuring that the content is suitably encoded + * for XML. + * @param text the text to write + * @param inAttr whether we are in an attribute value + */ + private void writeEncoded(String text, boolean inAttr) + throws IOException + { + char[] chars = text.toCharArray(); + int start = 0; + int end = chars.length; + int len = 0; + for (int i = start; i < end; i++) + { + char c = chars[i]; + if (c == '<' || c == '>' || c == '&') + { + writer.write(chars, start, len); + if (c == '<') + writer.write("<"); + else if (c == '>') + writer.write(">"); + else + writer.write("&"); + start = i + 1; + len = 0; + } + else if (inAttr && (c == '"' || c == '\'')) + { + writer.write(chars, start, len); + if (c == '"') + writer.write("""); + else + writer.write("'"); + start = i + 1; + len = 0; + } + else + len++; + } + 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 isPrefix(String text) + throws IOException + { + if (XMLConstants.DEFAULT_NS_PREFIX.equals(text)) { + return true; + } + return isNCName(text); + } + + 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/libjava/classpath/gnu/xml/transform/AbstractNumberNode.java b/libjava/classpath/gnu/xml/transform/AbstractNumberNode.java new file mode 100644 index 000000000..6e478bdc4 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/AbstractNumberNode.java @@ -0,0 +1,330 @@ +/* AbstractNumberNode.java -- + 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.xml.transform; + +import gnu.java.lang.CPStringBuilder; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Node; +import org.w3c.dom.Text; +import gnu.xml.xpath.Expr; + +/** + * A template node representing the XSL number instruction. + * + * @author Chris Burdess + */ +abstract class AbstractNumberNode + extends TemplateNode +{ + + static final int ALPHABETIC = 0; + static final int TRADITIONAL = 1; + + final TemplateNode format; + final String lang; + final int letterValue; + final String groupingSeparator; + final int groupingSize; + + AbstractNumberNode(TemplateNode format, String lang, + int letterValue, String groupingSeparator, + int groupingSize) + { + this.format = format; + this.lang = lang; + this.letterValue = letterValue; + this.groupingSeparator = groupingSeparator; + this.groupingSize = groupingSize; + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + Document doc = (parent instanceof Document) ? (Document) parent : + parent.getOwnerDocument(); + DocumentFragment fragment = doc.createDocumentFragment(); + format.apply(stylesheet, mode, context, pos, len, fragment, null); + String f = Expr._string(context, Collections.singleton(fragment)); + String value = format(f, compute(stylesheet, context, pos, len)); + Text text = doc.createTextNode(value); + if (nextSibling != null) + { + parent.insertBefore(text, nextSibling); + } + else + { + parent.appendChild(text); + } + // xsl:number doesn't process children + if (next != null) + { + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + } + + String format(String format, int[] number) + { + if (number.length == 0) + { + return ""; + } + int start = 0, end = 0, len = format.length(); // region of format + // Tokenize + List tokens = new ArrayList((number.length * 2) + 1); + List types = new ArrayList(tokens.size()); + while (end < len) + { + while (end < len && !isAlphanumeric(format.charAt(end))) + { + end++; + } + if (end > start) + { + tokens.add(format.substring(start, end)); + types.add(Boolean.FALSE); + } + start = end; + while (end < len && isAlphanumeric(format.charAt(end))) + { + end++; + } + if (end > start) + { + tokens.add(format.substring(start, end)); + types.add(Boolean.TRUE); + } + start = end; + } + // Process tokens + CPStringBuilder buf = new CPStringBuilder(); + len = tokens.size(); + int pos = 0; + for (int i = 0; i < len; i++) + { + String token = (i < 0) ? "." : (String) tokens.get(i); + boolean alpha = (i < 0) ? true : + ((Boolean) types.get(i)).booleanValue(); + if (!alpha) + { + buf.append(token); + } + else + { + if (pos < number.length) + { + format(buf, number[pos++], token); + if (((i + 1 == len) || (i + 2 == len)) && + (pos < number.length)) + { + // More numbers than tokens, reuse last token + i -= 2; + } + } + if (pos == number.length && i < (len - 2)) + { + // No more numbers. Skip to the end... + i = len - 2; + if (((Boolean) types.get(i + 1)).booleanValue()) + { + // number formatting token, ignore + i++; + } + } + } + } + //System.err.println("format: '"+format+"' "+asList(number)+" = '"+buf.toString()+"'"); + return buf.toString(); + } + + /*List asList(int[] number) + { + List l = new ArrayList(); + for (int i = 0; i < number.length; i++) + l.add(new Integer(number[i])); + return l; + }*/ + + void format(CPStringBuilder buf, int number, String formatToken) + { + int len = formatToken.length(); + char c = formatToken.charAt(len - 1); + if (Character.digit(c, 10) == 1) + { + // Check preceding characters + for (int i = len - 2; i >= 0; i--) + { + if (formatToken.charAt(i) != (c - 1)) + { + format(buf, number, "1"); + return; + } + } + // Decimal representation + String val = Integer.toString(number); + for (int d = len - val.length(); d > 0; d--) + { + buf.append('0'); + } + buf.append(val); + } + else if ("A".equals(formatToken)) + { + buf.append(alphabetic('@', number)); + } + else if ("a".equals(formatToken)) + { + buf.append(alphabetic('`', number)); + } + else if ("i".equals(formatToken)) + { + buf.append(roman(false, number)); + } + else if ("I".equals(formatToken)) + { + buf.append(roman(true, number)); + } + else + { + // Unknown numbering sequence + format(buf, number, "1"); + } + } + + static final boolean isAlphanumeric(char c) + { + switch (Character.getType(c)) + { + case Character.DECIMAL_DIGIT_NUMBER: // Nd + case Character.LETTER_NUMBER: // Nl + case Character.OTHER_NUMBER: // No + case Character.UPPERCASE_LETTER: // Lu + case Character.LOWERCASE_LETTER: // Ll + case Character.TITLECASE_LETTER: // Lt + case Character.MODIFIER_LETTER: // Lm + case Character.OTHER_LETTER: // Lo + return true; + default: + return false; + } + } + + static final String alphabetic(char offset, int number) + { + CPStringBuilder buf = new CPStringBuilder(); + while (number > 0) + { + int r = number % 26; + number = number / 26; + buf.insert(0, (char) (offset + r)); + } + return buf.toString(); + } + + static final int[] roman_numbers = {1, 5, 10, 50, 100, 500, 1000}; + static final char[] roman_chars = {'i', 'v', 'x', 'l', 'c', 'd', 'm'}; + + static final String roman(boolean upper, int number) + { + CPStringBuilder buf = new CPStringBuilder(); + for (int pos = roman_numbers.length - 1; pos >= 0; pos -= 2) + { + int f = number / roman_numbers[pos]; + if (f != 0) + { + number = number % (f * roman_numbers[pos]); + } + if (f > 4 && f < 9) + { + buf.append(roman_chars[pos + 1]); + f -= 5; + } + if (f == 4) + { + buf.append(roman_chars[pos]); + buf.append(roman_chars[pos + 1]); + } + else if (f == 9) + { + buf.append(roman_chars[pos]); + buf.append(roman_chars[pos + 2]); + } + else + { + for (; f > 0; f--) + { + buf.append(roman_chars[pos]); + } + } + } + return upper ? buf.toString().toUpperCase() : buf.toString(); + } + + abstract int[] compute(Stylesheet stylesheet, Node context, int pos, int len) + throws TransformerException; + + public boolean references(QName var) + { + if (format.references(var)) + { + return true; + } + return super.references(var); + } + + public String toString() + { + CPStringBuilder buf = new CPStringBuilder("number"); + buf.append('['); + buf.append("format="); + buf.append(format); + buf.append(']'); + return buf.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/ApplyImportsNode.java b/libjava/classpath/gnu/xml/transform/ApplyImportsNode.java new file mode 100644 index 000000000..298c49da4 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/ApplyImportsNode.java @@ -0,0 +1,82 @@ +/* ApplyImportsNode.java -- + 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.xml.transform; + +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Node; + +/** + * A template node representing an XSLT apply-imports instruction. + * + * @author Chris Burdess + */ +final class ApplyImportsNode + extends TemplateNode +{ + + TemplateNode clone(Stylesheet stylesheet) + { + TemplateNode ret = new ApplyImportsNode(); + if (children != null) + ret.children = children.clone(stylesheet); + if (next != null) + ret.next = next.clone(stylesheet); + return ret; + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + TemplateNode t = stylesheet.getTemplate(mode, context, true); + if (t != null) + t.apply(stylesheet, mode, context, pos, len, + parent, nextSibling); + if (next != null) + next.apply(stylesheet, mode, context, pos, len, + parent, nextSibling); + } + + public String toString() + { + return "apply-imports"; + } + +} diff --git a/libjava/classpath/gnu/xml/transform/ApplyTemplatesNode.java b/libjava/classpath/gnu/xml/transform/ApplyTemplatesNode.java new file mode 100644 index 000000000..6aa36954a --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/ApplyTemplatesNode.java @@ -0,0 +1,219 @@ +/* ApplyTemplatesNode.java -- + 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.xml.transform; + +import gnu.java.lang.CPStringBuilder; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; + +/** + * A template node representing the XSL apply-templates + * instruction. + * + * @author Chris Burdess + */ +final class ApplyTemplatesNode + extends TemplateNode +{ + + final Expr select; + final QName mode; + final List sortKeys; + final List withParams; + final boolean isDefault; + + ApplyTemplatesNode(Expr select, QName mode, + List sortKeys, List withParams, boolean isDefault) + { + this.select = select; + this.mode = mode; + this.sortKeys = sortKeys; + this.withParams = withParams; + this.isDefault = isDefault; + } + + TemplateNode clone(Stylesheet stylesheet) + { + 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)); + len = withParams != null ? withParams.size() : 0; + List withParams2 = new ArrayList(len); + for (int i = 0; i < len; i++) + 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); + if (next != null) + ret.next = next.clone(stylesheet); + return ret; + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + Object ret = select.evaluate(context, pos, len); + if (ret != null && ret instanceof Collection) + { + if (withParams != null) + { + // compute the parameter values + LinkedList values = new LinkedList(); + for (Iterator i = withParams.iterator(); i.hasNext(); ) + { + 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); + } + } + Collection ns = (Collection) ret; + List nodes = new ArrayList(ns); + if (sortKeys != null) + { + for (Iterator i = sortKeys.iterator(); i.hasNext(); ) + { + SortKey sortKey = (SortKey) i.next(); + sortKey.init(stylesheet, mode, context, pos, len, parent, + nextSibling); + } + Collections.sort(nodes, new XSLComparator(sortKeys)); + } + else + Collections.sort(nodes, documentOrderComparator); + int l = nodes.size(); + QName effectiveMode = isDefault ? mode : this.mode; + for (int i = 0; i < l; i++) + { + Node node = (Node) nodes.get(i); + TemplateNode t = stylesheet.getTemplate(effectiveMode, node, + false); + if (t != null) + { + stylesheet.current = node; + t.apply(stylesheet, effectiveMode, node, i + 1, l, + parent, nextSibling); + } + } + if (withParams != null) + { + // pop the variable context + stylesheet.bindings.pop(Bindings.WITH_PARAM); + } + } + // apply-templates doesn't have processable children + if (next != null) + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + + public boolean references(QName var) + { + if (select != null && select.references(var)) + return true; + if (withParams != null) + { + for (Iterator i = withParams.iterator(); i.hasNext(); ) + { + if (((WithParam) i.next()).references(var)) + return true; + } + } + if (sortKeys != null) + { + for (Iterator i = sortKeys.iterator(); i.hasNext(); ) + { + if (((SortKey) i.next()).references(var)) + return true; + } + } + return super.references(var); + } + + public String toString() + { + CPStringBuilder buf = new CPStringBuilder("apply-templates"); + buf.append('['); + boolean o = false; + if (select != null) + { + buf.append("select="); + buf.append(select); + o = true; + } + if (mode != null) + { + if (o) + { + buf.append(','); + } + buf.append("mode="); + buf.append(mode); + } + buf.append(']'); + return buf.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/AttributeNode.java b/libjava/classpath/gnu/xml/transform/AttributeNode.java new file mode 100644 index 000000000..4c71f6a92 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/AttributeNode.java @@ -0,0 +1,244 @@ +/* AttributeNode.java -- + 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.xml.transform; + +import gnu.java.lang.CPStringBuilder; + +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Attr; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; + +/** + * A template node representing an XSL attribute instruction. + * + * @author Chris Burdess + */ +final class AttributeNode + extends TemplateNode +{ + + final TemplateNode name; + final TemplateNode namespace; + final Node source; + + AttributeNode(TemplateNode name, + TemplateNode namespace, Node source) + { + this.name = name; + this.namespace = namespace; + this.source = source; + } + + TemplateNode clone(Stylesheet stylesheet) + { + TemplateNode ret = new AttributeNode(name.clone(stylesheet), + (namespace == null) ? null : + namespace.clone(stylesheet), + source); + if (children != null) + ret.children = children.clone(stylesheet); + if (next != null) + ret.next = next.clone(stylesheet); + return ret; + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + Document doc = (parent instanceof Document) ? (Document) parent : + parent.getOwnerDocument(); + // Create a document fragment to hold the name + DocumentFragment fragment = doc.createDocumentFragment(); + // Apply name to the fragment + name.apply(stylesheet, mode, + context, pos, len, + fragment, null); + // Use XPath string-value of fragment + String nameValue = Expr.stringValue(fragment); + + String namespaceValue = null; + if (namespace != null) + { + // Create a document fragment to hold the namespace + fragment = doc.createDocumentFragment(); + // Apply namespace to the fragment + namespace.apply(stylesheet, mode, + context, pos, len, + fragment, null); + // Use XPath string-value of fragment + namespaceValue = Expr.stringValue(fragment); + if (namespaceValue.length() == 0) + namespaceValue = null; + } + + String prefix = getPrefix(nameValue); + if (namespaceValue == null) + { + if (prefix != null) + { + if (XMLConstants.XML_NS_PREFIX.equals(prefix)) + namespaceValue = XMLConstants.XML_NS_URI; + else + { + // Resolve namespace for this prefix + namespaceValue = source.lookupNamespaceURI(prefix); + } + } + } + else + { + if (prefix != null) + { + String ns2 = source.lookupNamespaceURI(prefix); + if (ns2 != null && !ns2.equals(namespaceValue)) + { + // prefix clashes, reset it + prefix = null; + int ci = nameValue.indexOf(':'); + nameValue = nameValue.substring(ci + 1); + } + } + } + if (prefix == null) + { + // Resolve prefix for this namespace + prefix = source.lookupPrefix(namespaceValue); + if (prefix != null) + nameValue = prefix + ":" + nameValue; + else + { + if (namespaceValue != null) + { + // Must invent a prefix + prefix = inventPrefix(parent); + nameValue = prefix + ":" + nameValue; + } + } + } + NamedNodeMap attrs = parent.getAttributes(); + boolean insert = true; + if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceValue) || + XMLConstants.XMLNS_ATTRIBUTE.equals(nameValue) || + nameValue.startsWith("xmlns:")) + { + // Namespace declaration, do not output + insert = false; + } + if (prefix != null && namespaceValue == null) + { + // Not a QName + insert = false; + } + if (parent.getNodeType() == Node.ELEMENT_NODE && + parent.getFirstChild() != null) + { + // XSLT 7.1.3 Adding an attribute to an element after children have + // been added to it is an error + insert = false; + } + if (insert) + { + // Insert attribute + Attr attr = (namespaceValue != null) ? + doc.createAttributeNS(namespaceValue, nameValue) : + doc.createAttribute(nameValue); + if (attrs != null) + { + if (namespace != null) + attrs.setNamedItemNS(attr); + else + attrs.setNamedItem(attr); + } + if (children != null) + children.apply(stylesheet, mode, + context, pos, len, + attr, null); + } + if (next != null) + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + + final String getPrefix(String name) + { + int ci = name.indexOf(':'); + return (ci == -1) ? null : name.substring(0, ci); + } + + final String inventPrefix(Node parent) + { + String base = "ns"; + int count = 0; + String ret = base + Integer.toString(count); + while (parent.lookupNamespaceURI(ret) != null) + { + count++; + ret = base + Integer.toString(count); + } + return ret; + } + + public boolean references(QName var) + { + if (name != null && name.references(var)) + return true; + if (namespace != null && namespace.references(var)) + return true; + return super.references(var); + } + + public String toString() + { + CPStringBuilder buf = new CPStringBuilder("attribute"); + buf.append('['); + buf.append("name="); + buf.append(name); + buf.append(']'); + return buf.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/AttributeSet.java b/libjava/classpath/gnu/xml/transform/AttributeSet.java new file mode 100644 index 000000000..ced50f11c --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/AttributeSet.java @@ -0,0 +1,66 @@ +/* AttributeSet.java -- + 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.xml.transform; + +/** + * An attribute-set entry in a stylesheet. + * + * @author Chris Burdess + */ +final class AttributeSet +{ + + final TemplateNode children; + final String name; + final String uas; + + AttributeSet(TemplateNode children, String name, String uas) + { + this.children = children; + this.name = name; + this.uas = uas; + } + + AttributeSet clone(Stylesheet stylesheet) + { + return new AttributeSet((children == null) ? null : + children.clone(stylesheet), + name, uas); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/Bindings.java b/libjava/classpath/gnu/xml/transform/Bindings.java new file mode 100644 index 000000000..37d45880c --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/Bindings.java @@ -0,0 +1,346 @@ +/* Bindings.java -- + 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.xml.transform; + +import gnu.java.lang.CPStringBuilder; + +import java.util.Collection; +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 javax.xml.namespace.QName; +import javax.xml.xpath.XPathVariableResolver; +import org.w3c.dom.Node; + +/** + * The set of variable bindings in effect for a stylesheet. + * + * @author Chris Burdess + */ +public class Bindings + implements XPathVariableResolver, Cloneable +{ + + static final int VARIABLE = 0; + static final int PARAM = 1; + static final int WITH_PARAM = 2; + + final Stylesheet stylesheet; + + /** + * Global variables. + */ + final LinkedList> variables; + + /** + * Parameter value stack. + */ + final LinkedList> parameters; + + /** + * Argument (with-param) value stack. + */ + final LinkedList> withParameters; + + /** + * Only search globals. + */ + boolean global; + + Bindings(Stylesheet stylesheet) + { + this.stylesheet = stylesheet; + variables = new LinkedList>(); + parameters = new LinkedList>(); + withParameters = new LinkedList>(); + for (int i = 0; i < 3; i++) + { + push(i); + } + } + + public Object clone() + { + try + { + return (Bindings) super.clone(); + } + catch (CloneNotSupportedException e) + { + throw new Error(e.getMessage()); + } + } + + void push(int type) + { + switch (type) + { + case VARIABLE: + variables.addFirst(new HashMap()); + break; + case PARAM: + parameters.addFirst(new HashMap()); + break; + case WITH_PARAM: + withParameters.addFirst(new HashMap()); + break; + } + } + + void pop(int type) + { + switch (type) + { + case VARIABLE: + variables.removeFirst(); + break; + case PARAM: + parameters.removeFirst(); + break; + case WITH_PARAM: + withParameters.removeFirst(); + break; + } + } + + public boolean containsKey(QName name, int type) + { + if (global) + { + Map ctx1 = variables.getLast(); + Map ctx2 = parameters.getLast(); + return (ctx1.containsKey(name) || ctx2.containsKey(name)); + } + Iterator> i = null; + switch (type) + { + case VARIABLE: + i = variables.iterator(); + break; + case PARAM: + i = parameters.iterator(); + break; + case WITH_PARAM: + Map ctx = withParameters.getFirst(); + return ctx.containsKey(name); + } + if (i != null) + { + while (i.hasNext()) + { + Map ctx = i.next(); + if (ctx.containsKey(name)) + { + return true; + } + } + } + return false; + } + + public Object get(QName name, Node context, int pos, int len) + { + if (global) + { + Map ctx = variables.getLast(); + Object ret = ctx.get(name); + if (ret == null) + { + ctx = parameters.getLast(); + ret = ctx.get(name); + } + return ret; + } + //System.err.println("bindings.get: "+name); + //System.err.println("\t"+toString()); + Object ret = null; + //if (parameters.size() > 1 && containsKey(name, PARAM)) + // check that template defines parameter + { + Map cwp = withParameters.getFirst(); + ret = cwp.get(name); + //System.err.println("\twith-param: ret="+ret); + } + if (ret == null) + { + for (Iterator> i = variables.iterator(); + i.hasNext() && ret == null; ) + { + Map vctx = i.next(); + ret = vctx.get(name); + } + //System.err.println("\tvariable: ret="+ret); + } + if (ret == null) + { + for (Iterator> i = parameters.iterator(); + i.hasNext() && ret == null; ) + { + Map pctx = i.next(); + ret = pctx.get(name); + } + //System.err.println("\tparam: ret="+ret); + } + /*if (ret instanceof Expr && context != null) + { + Expr expr = (Expr) ret; + ret = expr.evaluate(context, 1, 1); + }*/ + if (ret instanceof Node) + { + ret = Collections.singleton(ret); + } + if (ret == null) + { + ret = ""; + } + //System.err.println("\tret="+ret); + return ret; + } + + void set(QName name, Object value, int type) + { + switch (type) + { + case VARIABLE: + Map vctx = variables.getFirst(); + vctx.put(name, value); + break; + case PARAM: + Map pctx = parameters.getFirst(); + pctx.put(name, value); + break; + case WITH_PARAM: + Map wctx = withParameters.getFirst(); + wctx.put(name, value); + break; + } + //System.err.println("Set "+name+"="+value); + } + + public Object resolveVariable(QName qName) + { + return get(qName, null, 1, 1); + } + + public String toString() + { + CPStringBuilder buf = new CPStringBuilder(); + boolean next = false; + Collection seen = new HashSet(); + Map wctx = withParameters.getFirst(); + buf.append('('); + for (Map.Entry entry : wctx.entrySet()) + { + if (next) + { + buf.append(','); + } + else + { + next = true; + } + QName key = entry.getKey(); + if (!seen.contains(key)) + { + buf.append(key); + buf.append('='); + buf.append(entry.getValue()); + seen.add(key); + } + } + buf.append(')'); + next = false; + seen.clear(); + buf.append('{'); + for (Map ctx : variables) + { + for (Map.Entry entry : ctx.entrySet()) + { + if (next) + { + buf.append(','); + } + else + { + next = true; + } + QName key = entry.getKey(); + if (!seen.contains(key)) + { + buf.append(key); + buf.append('='); + buf.append(entry.getValue()); + seen.add(key); + } + } + } + buf.append('}'); + next = false; + seen.clear(); + buf.append('['); + for (Map ctx : parameters) + { + for (Map.Entry entry : ctx.entrySet()) + { + if (next) + { + buf.append(','); + } + else + { + next = true; + } + QName key = entry.getKey(); + if (!seen.contains(key)) + { + buf.append(key); + buf.append('='); + buf.append(entry.getValue()); + seen.add(key); + } + } + } + buf.append(']'); + return buf.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/CallTemplateNode.java b/libjava/classpath/gnu/xml/transform/CallTemplateNode.java new file mode 100644 index 000000000..cc08d93e3 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/CallTemplateNode.java @@ -0,0 +1,156 @@ +/* CallTemplateNode.java -- + 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.xml.transform; + +import gnu.java.lang.CPStringBuilder; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Node; + +/** + * A template node representing the XSL call-template + * instruction. + * + * @author Chris Burdess + */ +final class CallTemplateNode + extends TemplateNode +{ + + final QName name; + final List withParams; + + CallTemplateNode(QName name, List withParams) + { + this.name = name; + this.withParams = withParams; + } + + TemplateNode clone(Stylesheet stylesheet) + { + int len = withParams.size(); + List withParams2 = new ArrayList(len); + for (int i = 0; i < len; i++) + withParams2.add(((WithParam) withParams.get(i)).clone(stylesheet)); + TemplateNode ret = new CallTemplateNode(name, withParams2); + if (children != null) + ret.children = children.clone(stylesheet); + if (next != null) + ret.next = next.clone(stylesheet); + return ret; + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + TemplateNode t = stylesheet.getTemplate(mode, name); + if (t != null) + { + if (!withParams.isEmpty()) + { + // 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(); ) + { + 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); + } + } + t.apply(stylesheet, mode, context, pos, len, + parent, nextSibling); + if (!withParams.isEmpty()) + { + // 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) + { + for (Iterator i = withParams.iterator(); i.hasNext(); ) + { + if (((WithParam) i.next()).references(var)) + return true; + } + return super.references(var); + } + + public String toString() + { + CPStringBuilder buf = new CPStringBuilder("call-template"); + buf.append('['); + buf.append("name="); + buf.append(name); + buf.append(']'); + return buf.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/ChooseNode.java b/libjava/classpath/gnu/xml/transform/ChooseNode.java new file mode 100644 index 000000000..262cde144 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/ChooseNode.java @@ -0,0 +1,88 @@ +/* ChooseNode.java -- + 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.xml.transform; + +import gnu.java.lang.CPStringBuilder; + +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Node; + +/** + * A template node representing an XSL choose instruction. + * + * @author Chris Burdess + */ +final class ChooseNode + extends TemplateNode +{ + + TemplateNode clone(Stylesheet stylesheet) + { + TemplateNode ret = new ChooseNode(); + if (children != null) + ret.children = children.clone(stylesheet); + if (next != null) + ret.next = next.clone(stylesheet); + return ret; + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + if (children != null) + children.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + if (next != null) + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + + public String toString() + { + CPStringBuilder buf = new CPStringBuilder("choose"); + buf.append('['); + buf.append(']'); + return buf.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/CommentNode.java b/libjava/classpath/gnu/xml/transform/CommentNode.java new file mode 100644 index 000000000..1c14e5fa8 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/CommentNode.java @@ -0,0 +1,103 @@ +/* CommentNode.java -- + 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.xml.transform; + +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Comment; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; + +/** + * A template node representing the XSL comment instruction. + * + * @author Chris Burdess + */ +final class CommentNode + extends TemplateNode +{ + + TemplateNode clone(Stylesheet stylesheet) + { + TemplateNode ret = new CommentNode(); + if (children != null) + ret.children = children.clone(stylesheet); + if (next != null) + ret.next = next.clone(stylesheet); + return ret; + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + String value = ""; + Document doc = (parent instanceof Document) ? (Document) parent : + parent.getOwnerDocument(); + if (children != null) + { + // Create a document fragment to hold the text + DocumentFragment fragment = doc.createDocumentFragment(); + // Apply children to the fragment + children.apply(stylesheet, mode, + context, pos, len, + fragment, null); + // Use XPath string-value of fragment + value = Expr.stringValue(fragment); + } + Comment comment = doc.createComment(value); + // Insert into result tree + if (nextSibling != null) + parent.insertBefore(comment, nextSibling); + else + parent.appendChild(comment); + if (next != null) + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + + public String toString() + { + return "comment"; + } + +} diff --git a/libjava/classpath/gnu/xml/transform/CopyNode.java b/libjava/classpath/gnu/xml/transform/CopyNode.java new file mode 100644 index 000000000..9cc2fdecd --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/CopyNode.java @@ -0,0 +1,168 @@ +/* CopyNode.java -- + 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.xml.transform; + +import gnu.java.lang.CPStringBuilder; + +import java.util.Iterator; +import java.util.StringTokenizer; +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +/** + * A template node representing the XSL copy instruction. + * + * @author Chris Burdess + */ +final class CopyNode + extends TemplateNode +{ + + final String uas; + + CopyNode(String uas) + { + this.uas = uas; + } + + TemplateNode clone(Stylesheet stylesheet) + { + TemplateNode ret = new CopyNode(uas); + if (children != null) + ret.children = children.clone(stylesheet); + if (next != null) + ret.next = next.clone(stylesheet); + return ret; + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + Node copy = parent; + switch (context.getNodeType()) + { + case Node.TEXT_NODE: + case Node.ATTRIBUTE_NODE: + case Node.ELEMENT_NODE: + case Node.PROCESSING_INSTRUCTION_NODE: + case Node.COMMENT_NODE: + Document doc = (parent instanceof Document) ? (Document) parent : + parent.getOwnerDocument(); + copy = context.cloneNode(false); + copy = doc.adoptNode(copy); + if (copy.getNodeType() == Node.ATTRIBUTE_NODE) + { + if (parent.getFirstChild() != null) + { + // Ignore attempt to add attribute after children + } + else + { + NamedNodeMap attrs = parent.getAttributes(); + if (attrs != null) + attrs.setNamedItemNS(copy); + } + } + else + { + if (nextSibling != null) + parent.insertBefore(copy, nextSibling); + else + parent.appendChild(copy); + } + } + if (uas != null) + { + StringTokenizer st = new StringTokenizer(uas, " "); + while (st.hasMoreTokens()) + addAttributeSet(stylesheet, mode, context, pos, len, + copy, null, st.nextToken()); + } + if (children != null) + children.apply(stylesheet, mode, + context, pos, len, + copy, null); + if (next != null) + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + + void addAttributeSet(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling, String attributeSet) + throws TransformerException + { + for (Iterator i = stylesheet.attributeSets.iterator(); i.hasNext(); ) + { + AttributeSet as = (AttributeSet) i.next(); + if (!as.name.equals(attributeSet)) + continue; + if (as.uas != null) + { + StringTokenizer st = new StringTokenizer(as.uas, " "); + while (st.hasMoreTokens()) + addAttributeSet(stylesheet, mode, context, pos, len, + parent, nextSibling, st.nextToken()); + } + if (as.children != null) + as.children.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + } + + public String toString() + { + CPStringBuilder buf = new CPStringBuilder("copy"); + if (uas != null) + { + buf.append('['); + buf.append("uas="); + buf.append(uas); + buf.append(']'); + } + return buf.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/CopyOfNode.java b/libjava/classpath/gnu/xml/transform/CopyOfNode.java new file mode 100644 index 000000000..2b06fed4d --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/CopyOfNode.java @@ -0,0 +1,174 @@ +/* CopyOfNode.java -- + 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.xml.transform; + +import gnu.java.lang.CPStringBuilder; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.Text; +import gnu.xml.xpath.Expr; + +/** + * A template node representing an XSLT copy-of instruction. + * + * @author Chris Burdess + */ +final class CopyOfNode + extends TemplateNode +{ + + final Expr select; + + CopyOfNode(Expr select) + { + this.select = select; + } + + TemplateNode clone(Stylesheet stylesheet) + { + TemplateNode ret = new CopyOfNode(select.clone(stylesheet)); + if (children != null) + ret.children = children.clone(stylesheet); + if (next != null) + ret.next = next.clone(stylesheet); + return ret; + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + Object ret = select.evaluate(context, pos, len); + Document doc = (parent instanceof Document) ? (Document) parent : + parent.getOwnerDocument(); + if (ret instanceof Collection) + { + Collection ns = (Collection) ret; + List list = new ArrayList(ns); + Collections.sort(list, documentOrderComparator); + for (Iterator i = list.iterator(); i.hasNext(); ) + { + Node src = (Node) i.next(); + short nodeType = src.getNodeType(); + if (nodeType == Node.DOCUMENT_NODE) + { + // Use document element + src = ((Document) src).getDocumentElement(); + if (src == null) + continue; + nodeType = Node.ELEMENT_NODE; + } + else if (nodeType == Node.ATTRIBUTE_NODE) + { + if (parent.getFirstChild() != null) + { + // Ignore attempt to add attribute after children + continue; + } + } + if (parent.getNodeType() == Node.ATTRIBUTE_NODE && + nodeType != Node.TEXT_NODE && + nodeType != Node.ENTITY_REFERENCE_NODE) + { + // Ignore + continue; + } + Node node = src.cloneNode(true); + node = doc.adoptNode(node); + if (nodeType == Node.ATTRIBUTE_NODE) + { + NamedNodeMap attrs = parent.getAttributes(); + if (attrs != null) + attrs.setNamedItemNS(node); + } + else + { + if (nextSibling != null) + parent.insertBefore(node, nextSibling); + else + parent.appendChild(node); + } + } + } + else + { + String value = Expr._string(context, ret); + if (value != null && value.length() > 0) + { + Text textNode = doc.createTextNode(value); + if (nextSibling != null) + parent.insertBefore(textNode, nextSibling); + else + parent.appendChild(textNode); + } + } + // copy-of doesn't process children + if (next != null) + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + + public boolean references(QName var) + { + if (select != null && select.references(var)) + return true; + return super.references(var); + } + + public String toString() + { + CPStringBuilder buf = new CPStringBuilder("copy-of"); + buf.append('['); + buf.append("select="); + buf.append(select); + buf.append(']'); + return buf.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/CurrentFunction.java b/libjava/classpath/gnu/xml/transform/CurrentFunction.java new file mode 100644 index 000000000..96899679a --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/CurrentFunction.java @@ -0,0 +1,103 @@ +/* CurrentFunction.java -- + 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.xml.transform; + +import java.util.Collections; +import java.util.List; +import javax.xml.namespace.QName; +import javax.xml.xpath.XPathFunction; +import javax.xml.xpath.XPathFunctionException; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; +import gnu.xml.xpath.Function; + +/** + * The XSLT current()function. + * + * @author Chris Burdess + */ +final class CurrentFunction + extends Expr + implements Function, XPathFunction +{ + + final Stylesheet stylesheet; + + CurrentFunction(Stylesheet stylesheet) + { + this.stylesheet = stylesheet; + } + + public Object evaluate(List args) + throws XPathFunctionException + { + // We can't do anything useful here. + // So much for the JAXP API... + return Collections.EMPTY_SET; + } + + public void setArguments(List args) + { + } + + public Object evaluate(Node context, int pos, int len) + { + return Collections.singleton(stylesheet.current); + } + + public Expr clone(Object context) + { + Stylesheet s = stylesheet; + if (context instanceof Stylesheet) + { + s = (Stylesheet) context; + } + return new CurrentFunction(s); + } + + public boolean references(QName var) + { + return false; + } + + public String toString() + { + return "current()"; + } + +} diff --git a/libjava/classpath/gnu/xml/transform/DOMSourceLocator.java b/libjava/classpath/gnu/xml/transform/DOMSourceLocator.java new file mode 100644 index 000000000..fbf31de55 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/DOMSourceLocator.java @@ -0,0 +1,84 @@ +/* DOMSourceLocator.java -- + 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.xml.transform; + +import javax.xml.transform.dom.DOMLocator; +import org.w3c.dom.Node; + +/** + * Simple DOMLocator implementation. + * + * @author Chris Burdess + */ +class DOMSourceLocator + implements DOMLocator +{ + + final Node node; + + DOMSourceLocator(Node node) + { + this.node = node; + } + + public Node getOriginatingNode() + { + return node; + } + + public String getPublicId() + { + return null; + } + + public String getSystemId() + { + return null; + } + + public int getLineNumber() + { + return -1; + } + + public int getColumnNumber() + { + return -1; + } + +} diff --git a/libjava/classpath/gnu/xml/transform/DocumentFunction.java b/libjava/classpath/gnu/xml/transform/DocumentFunction.java new file mode 100644 index 000000000..d0aee25b3 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/DocumentFunction.java @@ -0,0 +1,244 @@ +/* DocumentFunction.java -- + 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.xml.transform; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.TreeSet; +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import javax.xml.transform.dom.DOMSource; +import javax.xml.xpath.XPathFunction; +import javax.xml.xpath.XPathFunctionException; +import org.w3c.dom.Node; +import gnu.xml.xpath.Constant; +import gnu.xml.xpath.Expr; +import gnu.xml.xpath.Function; +import gnu.xml.xpath.IdFunction; + +/** + * The XSLT document()function. + * + * @author Chris Burdess + */ +final class DocumentFunction + extends Expr + implements Function, XPathFunction +{ + + final Stylesheet stylesheet; + final Node base; + List args; + List values; + + DocumentFunction(Stylesheet stylesheet, Node base) + { + this.stylesheet = stylesheet; + this.base = base; + } + + public Object evaluate(List args) + throws XPathFunctionException + { + values = args; + return evaluate(null, 1, 1); + } + + public void setArguments(List args) + { + this.args = args; + } + + public Object evaluate(Node context, int pos, int len) + { + int arity = args.size(); + if (values == null) + { + values = new ArrayList(arity); + for (int i = 0; i < arity; i++) + { + Expr arg = (Expr) args.get(i); + values.add(arg.evaluate(context, pos, len)); + } + } + Object ret; + switch (arity) + { + case 1: + Object arg = values.get(0); + if (arg instanceof Collection) + { + Collection ns = (Collection) arg; + Collection acc = new TreeSet(); + for (Iterator i = ns.iterator(); i.hasNext(); ) + { + Node node = (Node) i.next(); + String s = Expr.stringValue(node); + acc.addAll(document(s, node.getBaseURI())); + } + ret = acc; + } + else + { + String s = Expr._string(context, arg); + ret = document(s, base.getBaseURI()); + } + break; + case 2: + Object arg1 = values.get(0); + Object arg2 = values.get(1); + if (!(arg2 instanceof Collection)) + throw new RuntimeException("second argument is not a node-set"); + Collection arg2ns = (Collection) arg2; + String base2 = arg2ns.isEmpty() ? null : + ((Node) arg2ns.iterator().next()).getBaseURI(); + if (arg1 instanceof Collection) + { + Collection arg1ns = (Collection) arg1; + Collection acc = new TreeSet(); + for (Iterator i = arg1ns.iterator(); i.hasNext(); ) + { + Node node = (Node) i.next(); + String s = Expr.stringValue(node); + acc.addAll(document(s, base2)); + } + ret = acc; + } + else + { + String s = Expr._string(context, arg1); + ret = document(s, base2); + } + break; + default: + throw new RuntimeException("invalid arity"); + } + values = null; + return ret; + } + + /** + * The XSL document function. + * @see XSLT 12.1 + * @param uri the URI from which to retrieve nodes + * @param base the base URI for relative URIs + */ + Collection document(String uri, String base) + { + if ("".equals(uri) || uri == null) + uri = this.base.getBaseURI(); + + // Get fragment + Expr fragment = null; + int hi = uri.indexOf('#'); + if (hi != -1) + { + String f = uri.substring(hi + 1); + uri = uri.substring(0, hi); + // TODO handle xpointer() here + // this only handles IDs + fragment = new IdFunction(new Constant(f)); + } + + // Get document source + try + { + DOMSource source; + XSLURIResolver resolver = stylesheet.factory.resolver; + synchronized (resolver) + { + if (stylesheet.transformer != null) + { + resolver.setUserResolver(stylesheet.transformer.uriResolver); + resolver.setUserListener(stylesheet.transformer.errorListener); + } + source = resolver.resolveDOM(null, base, uri); + } + Node node = source.getNode(); + // Strip whitespace + TransformerImpl.strip(stylesheet, node); + if (fragment == null) + return Collections.singleton(node); + else + { + Object ret = fragment.evaluate(node, 1, 1); + if (!(ret instanceof Collection)) + { + // XXX Report error? + return Collections.EMPTY_SET; + } + return (Collection) ret; + } + } + catch (TransformerException e) + { + String msg = "can't open " + uri; + if (base != null) + msg += " with base " + base; + throw new RuntimeException(msg); + } + } + + public Expr clone(Object context) + { + Stylesheet s = stylesheet; + if (context instanceof Stylesheet) + 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)); + f.setArguments(args2); + return f; + } + + public boolean references(QName var) + { + for (Iterator i = args.iterator(); i.hasNext(); ) + { + if (((Expr) i.next()).references(var)) + return true; + } + return false; + } + +} diff --git a/libjava/classpath/gnu/xml/transform/ElementAvailableFunction.java b/libjava/classpath/gnu/xml/transform/ElementAvailableFunction.java new file mode 100644 index 000000000..6a9d256be --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/ElementAvailableFunction.java @@ -0,0 +1,181 @@ +/* ElementAvailableFunction.java -- + 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.xml.transform; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.TreeSet; +import javax.xml.namespace.QName; +import javax.xml.namespace.NamespaceContext; +import javax.xml.xpath.XPathFunction; +import javax.xml.xpath.XPathFunctionException; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; +import gnu.xml.xpath.Function; + +/** + * The XSLT element-available function. + * + * @author Chris Burdess + */ +class ElementAvailableFunction + extends Expr + implements Function, XPathFunction +{ + + static final Collection elements; + static + { + TreeSet acc = new TreeSet(); + acc.add("stylesheet"); + acc.add("template"); + acc.add("param"); + acc.add("variable"); + acc.add("include"); + acc.add("import"); + acc.add("output"); + acc.add("preserve-space"); + acc.add("strip-space"); + acc.add("key"); + acc.add("decimal-format"); + acc.add("namespace-alias"); + acc.add("attribute-set"); + acc.add("apply-templates"); + acc.add("call-template"); + acc.add("value-of"); + acc.add("for-each"); + acc.add("if"); + acc.add("choose"); + acc.add("when"); + acc.add("otherwise"); + acc.add("element"); + acc.add("attribute"); + acc.add("text"); + acc.add("copy"); + acc.add("processing-instruction"); + acc.add("comment"); + acc.add("number"); + acc.add("copy-of"); + acc.add("message"); + acc.add("sort"); + acc.add("with-param"); + acc.add("fallback"); + acc.add("apply-imports"); + elements = Collections.unmodifiableSet(acc); + } + + final NamespaceContext nsctx; + List args; + + ElementAvailableFunction(NamespaceContext nsctx) + { + this.nsctx = nsctx; + } + + public Object evaluate(List args) + throws XPathFunctionException + { + // Useless... + return Collections.EMPTY_SET; + } + + public void setArguments(List args) + { + this.args = args; + } + + public Object evaluate(Node context, int pos, int len) + { + Expr arg = (Expr) args.get(0); + Object val = arg.evaluate(context, pos, len); + String name = _string(context, val); + String prefix, localName, uri; + int ci = name.indexOf(':'); + if (ci == -1) + { + prefix = null; + localName = name; + } + else + { + prefix = name.substring(0, ci); + localName = name.substring(ci + 1); + } + uri = nsctx.getNamespaceURI(prefix); + if (Stylesheet.XSL_NS.equals(uri)) + { + return elements.contains(localName) ? + Boolean.TRUE : Boolean.FALSE; + } + // TODO extension elements + return Boolean.FALSE; + } + + public Expr clone(Object context) + { + NamespaceContext n = nsctx; + if (context instanceof NamespaceContext) + n = (NamespaceContext) context; + ElementAvailableFunction f = new ElementAvailableFunction(n); + int len = args.size(); + List args2 = new ArrayList(len); + for (int i = 0; i < len; i++) + args2.add(((Expr) args.get(i)).clone(context)); + f.setArguments(args2); + return f; + } + + public boolean references(QName var) + { + for (Iterator i = args.iterator(); i.hasNext(); ) + { + if (((Expr) i.next()).references(var)) + return true; + } + return false; + } + + public String toString() + { + return "element-available(" + args.get(0) + ")"; + } + +} diff --git a/libjava/classpath/gnu/xml/transform/ElementNode.java b/libjava/classpath/gnu/xml/transform/ElementNode.java new file mode 100644 index 000000000..78a2007b7 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/ElementNode.java @@ -0,0 +1,261 @@ +/* ElementNode.java -- + 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.xml.transform; + +import gnu.java.lang.CPStringBuilder; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.StringTokenizer; +import javax.xml.XMLConstants; +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; + +/** + * A template node representing an XSL element instruction. + * + * @author Chris Burdess + */ +final class ElementNode + extends TemplateNode +{ + + final TemplateNode name; + final TemplateNode namespace; + final String uas; + final Node source; + final Collection elementExcludeResultPrefixes; + + ElementNode(TemplateNode name, + TemplateNode namespace, String uas, Node source) + { + this.name = name; + this.namespace = namespace; + this.uas = uas; + this.source = source; + NamedNodeMap attrs = source.getAttributes(); + Node attr = attrs.getNamedItemNS(Stylesheet.XSL_NS, + "exclude-result-prefixes"); + if (attr != null) + { + elementExcludeResultPrefixes = new HashSet(); + StringTokenizer st = new StringTokenizer(attr.getNodeValue()); + while (st.hasMoreTokens()) + elementExcludeResultPrefixes.add(st.nextToken()); + } + else + elementExcludeResultPrefixes = Collections.EMPTY_SET; + } + + TemplateNode clone(Stylesheet stylesheet) + { + TemplateNode ret = new ElementNode(name.clone(stylesheet), + (namespace == null) ? null : + namespace.clone(stylesheet), + uas, source); + if (children != null) + ret.children = children.clone(stylesheet); + if (next != null) + ret.next = next.clone(stylesheet); + return ret; + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + Document doc = (parent instanceof Document) ? (Document) parent : + parent.getOwnerDocument(); + // Create a document fragment to hold the name + DocumentFragment fragment = doc.createDocumentFragment(); + // Apply name to the fragment + name.apply(stylesheet, mode, + context, pos, len, + fragment, null); + // Use XPath string-value of fragment + String nameValue = Expr.stringValue(fragment); + + String namespaceValue = null; + if (namespace != null) + { + // Create a document fragment to hold the namespace + fragment = doc.createDocumentFragment(); + // Apply namespace to the fragment + namespace.apply(stylesheet, mode, + context, pos, len, + fragment, null); + // Use XPath string-value of fragment + namespaceValue = Expr.stringValue(fragment); + if (namespaceValue.length() == 0) + namespaceValue = null; + } + else + { + String prefix = getPrefix(nameValue); + if (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix)) + { + int ci = nameValue.indexOf(':'); + nameValue = nameValue.substring(ci + 1); + } + else + { + // Namespace aliasing + if (prefix == null) + prefix = "#default"; + String resultPrefix = + (String) stylesheet.namespaceAliases.get(prefix); + if (resultPrefix != null) + { + if ("#default".equals(resultPrefix)) + resultPrefix = null; + namespaceValue = source.lookupNamespaceURI(resultPrefix); + } + if (prefix == "#default") + prefix = null; + // Look up ordinary namespace for this prefix + if (namespaceValue == null) + { + if (XMLConstants.XML_NS_PREFIX.equals(prefix)) + namespaceValue = XMLConstants.XML_NS_URI; + else + { + // Resolve namespace for this prefix + namespaceValue = source.lookupNamespaceURI(prefix); + } + } + } + } + + // Create element + Element element = (namespaceValue != null) ? + doc.createElementNS(namespaceValue, nameValue) : + doc.createElement(nameValue); + if (nextSibling != null) + parent.insertBefore(element, nextSibling); + else + parent.appendChild(element); + stylesheet.addNamespaceNodes(source, element, doc, + elementExcludeResultPrefixes); + if (uas != null) + { + StringTokenizer st = new StringTokenizer(uas, " "); + while (st.hasMoreTokens()) + addAttributeSet(stylesheet, mode, context, pos, len, + element, null, st.nextToken()); + } + if (children != null) + children.apply(stylesheet, mode, + context, pos, len, + element, null); + if (next != null) + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + + final String getPrefix(String name) + { + int ci = name.indexOf(':'); + return (ci == -1) ? null : name.substring(0, ci); + } + + void addAttributeSet(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling, String attributeSet) + throws TransformerException + { + stylesheet.bindings.global = true; + for (Iterator i = stylesheet.attributeSets.iterator(); i.hasNext(); ) + { + AttributeSet as = (AttributeSet) i.next(); + if (!as.name.equals(attributeSet)) + continue; + if (as.uas != null) + { + StringTokenizer st = new StringTokenizer(as.uas, " "); + while (st.hasMoreTokens()) + addAttributeSet(stylesheet, mode, context, pos, len, + parent, nextSibling, st.nextToken()); + } + if (as.children != null) + as.children.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + stylesheet.bindings.global = false; + } + + public boolean references(QName var) + { + if (name != null && name.references(var)) + return true; + if (namespace != null && namespace.references(var)) + return true; + return super.references(var); + } + + public String toString() + { + CPStringBuilder buf = new CPStringBuilder("element"); + buf.append('['); + buf.append("name="); + if (namespace != null) + { + buf.append(",namespace="); + buf.append(namespace); + } + buf.append(name); + if (uas != null) + { + buf.append(",uas="); + buf.append(uas); + } + buf.append(']'); + return buf.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/ErrorListenerErrorHandler.java b/libjava/classpath/gnu/xml/transform/ErrorListenerErrorHandler.java new file mode 100644 index 000000000..8a28795c4 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/ErrorListenerErrorHandler.java @@ -0,0 +1,101 @@ +/* ErrorListenerErrorHandler.java -- + 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.xml.transform; + +import javax.xml.transform.ErrorListener; +import javax.xml.transform.TransformerException; +import org.xml.sax.ErrorHandler; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + +/** + * An ErrorHandler that wraps an ErrorListener. + * + * @author Chris Burdess + */ +class ErrorListenerErrorHandler + implements ErrorHandler +{ + + final ErrorListener listener; + + ErrorListenerErrorHandler(ErrorListener listener) + { + this.listener = listener; + } + + public void warning(SAXParseException e) + throws SAXException + { + try + { + listener.warning(new TransformerException(e)); + } + catch (TransformerException e2) + { + throw new SAXException(e2); + } + } + + public void error(SAXParseException e) + throws SAXException + { + try + { + listener.error(new TransformerException(e)); + } + catch (TransformerException e2) + { + throw new SAXException(e2); + } + } + + public void fatalError(SAXParseException e) + throws SAXException + { + try + { + listener.fatalError(new TransformerException(e)); + } + catch (TransformerException e2) + { + throw new SAXException(e2); + } + } + +} diff --git a/libjava/classpath/gnu/xml/transform/ForEachNode.java b/libjava/classpath/gnu/xml/transform/ForEachNode.java new file mode 100644 index 000000000..1613f768b --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/ForEachNode.java @@ -0,0 +1,159 @@ +/* ForEachNode.java -- + 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.xml.transform; + +import gnu.java.lang.CPStringBuilder; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; + +/** + * A template node representing an XSLT for-each instruction. + * + * @author Chris Burdess + */ +final class ForEachNode + extends TemplateNode +{ + + final Expr select; + final List sortKeys; + + ForEachNode(Expr select, List sortKeys) + { + this.select = select; + this.sortKeys = sortKeys; + } + + TemplateNode clone(Stylesheet stylesheet) + { + int len = sortKeys.size(); + List sortKeys2 = new ArrayList(len); + for (int i = 0; i < len; i++) + sortKeys2.add(sortKeys.get(i).clone(stylesheet)); + TemplateNode ret = new ForEachNode(select.clone(stylesheet), + sortKeys2); + if (children != null) + ret.children = children.clone(stylesheet); + if (next != null) + ret.next = next.clone(stylesheet); + return ret; + } + + @Override + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + if (children != null) + { + // Set current template to null + Template saved = stylesheet.currentTemplate; + stylesheet.currentTemplate = null; + Object ret = select.evaluate(context, pos, len); + //System.err.println(toString() + ": " + context+" -> "+ret); + if (ret instanceof Collection) + { + /* Suppression is safe, as we know context produces Collection */ + @SuppressWarnings("unchecked") + Collection ns = (Collection) ret; + List list = new ArrayList(ns); + if (!sortKeys.isEmpty()) + { + for (SortKey sortKey : sortKeys) + { + sortKey.init(stylesheet, mode, context, pos, len, parent, + nextSibling); + } + Collections.sort(list, new XSLComparator(sortKeys)); + } + else + Collections.sort(list, documentOrderComparator); + // Perform children for each node + int l = list.size(); + int p = 1; + for (Node node : list) + { + stylesheet.current = node; + children.apply(stylesheet, mode, + node, p++, l, + parent, nextSibling); + } + } + // Restore current template + stylesheet.currentTemplate = saved; + } + if (next != null) + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + + @Override + public boolean references(QName var) + { + if (select != null && select.references(var)) + return true; + for (Iterator i = sortKeys.iterator(); i.hasNext(); ) + { + if (i.next().references(var)) + return true; + } + return super.references(var); + } + + @Override + public String toString() + { + CPStringBuilder buf = new CPStringBuilder("for-each"); + buf.append('['); + buf.append("select="); + buf.append(select); + buf.append(']'); + return buf.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/FormatNumberFunction.java b/libjava/classpath/gnu/xml/transform/FormatNumberFunction.java new file mode 100644 index 000000000..82872be77 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/FormatNumberFunction.java @@ -0,0 +1,145 @@ +/* FormatNumberFunction.java -- + 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.xml.transform; + +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import javax.xml.namespace.QName; +import javax.xml.xpath.XPathFunction; +import javax.xml.xpath.XPathFunctionException; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; +import gnu.xml.xpath.Function; + +/** + * The XSLT format-number()function. + * + * @author Chris Burdess + */ +final class FormatNumberFunction + extends Expr + implements XPathFunction, Function +{ + + final Stylesheet stylesheet; + List args; + + FormatNumberFunction(Stylesheet stylesheet) + { + this.stylesheet = stylesheet; + } + + public Object evaluate(List args) + throws XPathFunctionException + { + // Useless... + return Collections.EMPTY_SET; + } + + public void setArguments(List args) + { + this.args = args; + } + + public Object evaluate(Node context, int pos, int len) + { + int arity = args.size(); + List values = new ArrayList(arity); + for (int i = 0; i < arity; i++) + { + Expr arg = (Expr) args.get(i); + values.add(arg.evaluate(context, pos, len)); + } + double number = _number(context, values.get(0)); + String pattern = _string(context, values.get(1)); + // Currency symbol ¤ is not supposed to be present + if (pattern.indexOf('\u00a4') != -1) + { + // Replace with $ (Xalan does this) + pattern = pattern.replace('\u00a4', '$'); + } + String dfName = null; + if (arity > 2) + { + dfName = _string(context, values.get(2)); + // otherwise the default decimal-format will be used + } + DecimalFormat df = (DecimalFormat) stylesheet.decimalFormats.get(dfName); + if (df == null) + { + throw new IllegalArgumentException("No such decimal-format: " + + dfName); + } + df.applyLocalizedPattern(pattern); + return df.format(number); + } + + public Expr clone(Object context) + { + Stylesheet s = stylesheet; + if (context instanceof Stylesheet) + { + s = (Stylesheet) context; + } + FormatNumberFunction f = new FormatNumberFunction(s); + int len = args.size(); + List args2 = new ArrayList(len); + for (int i = 0; i < len; i++) + { + args2.add(((Expr) args.get(i)).clone(context)); + } + f.setArguments(args2); + return f; + } + + public boolean references(QName var) + { + for (Iterator i = args.iterator(); i.hasNext(); ) + { + if (((Expr) i.next()).references(var)) + { + return true; + } + } + return false; + } + +} diff --git a/libjava/classpath/gnu/xml/transform/FunctionAvailableFunction.java b/libjava/classpath/gnu/xml/transform/FunctionAvailableFunction.java new file mode 100644 index 000000000..1ac50327e --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/FunctionAvailableFunction.java @@ -0,0 +1,192 @@ +/* FunctionAvailableFunction.java -- + 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.xml.transform; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.TreeSet; +import javax.xml.namespace.NamespaceContext; +import javax.xml.namespace.QName; +import javax.xml.xpath.XPathFunction; +import javax.xml.xpath.XPathFunctionException; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; +import gnu.xml.xpath.Function; + +/** + * The XSLT function-available function. + * + * @author Chris Burdess + */ +class FunctionAvailableFunction + extends Expr + implements Function, XPathFunction +{ + + static final Collection xsltFunctions; + static final Collection xpathFunctions; + static + { + TreeSet acc = new TreeSet(); + acc.add("document"); + acc.add("key"); + acc.add("format-number"); + acc.add("current"); + acc.add("unparsed-entity-uri"); + acc.add("generate-id"); + acc.add("system-property"); + acc.add("element-available"); + acc.add("function-available"); + xsltFunctions = Collections.unmodifiableSet(acc); + acc = new TreeSet(); + acc.add("boolean"); + acc.add("ceiling"); + acc.add("concat"); + acc.add("contains"); + acc.add("count"); + acc.add("false"); + acc.add("floor"); + acc.add("id"); + acc.add("lang"); + acc.add("last"); + acc.add("local-name"); + acc.add("name"); + acc.add("namespace-uri"); + acc.add("normalize-space"); + acc.add("not"); + acc.add("number"); + acc.add("position"); + acc.add("round"); + acc.add("starts-with"); + acc.add("string"); + acc.add("string-length"); + acc.add("substring-after"); + acc.add("substring-before"); + acc.add("substring"); + acc.add("sum"); + acc.add("translate"); + acc.add("true"); + xpathFunctions = Collections.unmodifiableSet(acc); + } + + final NamespaceContext nsctx; + List args; + + FunctionAvailableFunction(NamespaceContext nsctx) + { + this.nsctx = nsctx; + } + + public Object evaluate(List args) + throws XPathFunctionException + { + // Useless... + return Collections.EMPTY_SET; + } + + public void setArguments(List args) + { + this.args = args; + } + + public Object evaluate(Node context, int pos, int len) + { + Expr arg = (Expr) args.get(0); + Object val = arg.evaluate(context, pos, len); + String name = _string(context, val); + String prefix, localName, uri; + int ci = name.indexOf(':'); + if (ci == -1) + { + prefix = null; + localName = name; + } + else + { + prefix = name.substring(0, ci); + localName = name.substring(ci + 1); + } + uri = nsctx.getNamespaceURI(prefix); + if (uri == null) + { + return (xpathFunctions.contains(localName) || + xsltFunctions.contains(localName)) ? + Boolean.TRUE : Boolean.FALSE; + } + else if (Stylesheet.XSL_NS.equals(uri)) + { + return xsltFunctions.contains(localName) ? + Boolean.TRUE : Boolean.FALSE; + } + // TODO extension functions + return Boolean.FALSE; + } + + public Expr clone(Object context) + { + NamespaceContext n = nsctx; + if (context instanceof NamespaceContext) + n = (NamespaceContext) context; + FunctionAvailableFunction f = new FunctionAvailableFunction(n); + int len = args.size(); + List args2 = new ArrayList(len); + for (int i = 0; i < len; i++) + args2.add(((Expr) args.get(i)).clone(context)); + f.setArguments(args2); + return f; + } + + public boolean references(QName var) + { + for (Iterator i = args.iterator(); i.hasNext(); ) + { + if (((Expr) i.next()).references(var)) + return true; + } + return false; + } + + public String toString() + { + return "function-available(" + args.get(0) + ")"; + } + +} diff --git a/libjava/classpath/gnu/xml/transform/GenerateIdFunction.java b/libjava/classpath/gnu/xml/transform/GenerateIdFunction.java new file mode 100644 index 000000000..efc583cc8 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/GenerateIdFunction.java @@ -0,0 +1,139 @@ +/* GenerateIdFunction.java -- + 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.xml.transform; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import javax.xml.namespace.QName; +import javax.xml.xpath.XPathFunction; +import javax.xml.xpath.XPathFunctionException; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; +import gnu.xml.xpath.Function; + +/** + * The XSLT generate-id()function. + * + * @author Chris Burdess + */ +final class GenerateIdFunction + extends Expr + implements XPathFunction, Function +{ + + List args; + + public Object evaluate(List args) + throws XPathFunctionException + { + // Useless... + return Collections.EMPTY_SET; + } + + public void setArguments(List args) + { + this.args = args; + } + + public Object evaluate(Node context, int pos, int len) + { + int arity = args.size(); + List values = new ArrayList(arity); + for (int i = 0; i < arity; i++) + { + Expr arg = (Expr) args.get(i); + values.add(arg.evaluate(context, pos, len)); + } + Node node; + Collection ns = (arity == 0) ? Collections.EMPTY_SET : + (Collection) values.get(0); + if (ns.isEmpty()) + { + node = context; + } + else + { + List list = new ArrayList(ns); + Collections.sort(list, documentOrderComparator); + node = (Node) list.get(0); + } + + String name = node.getNodeName(); + int index = 0, depth = 0; + for (Node ctx = node.getPreviousSibling(); ctx != null; + ctx = ctx.getPreviousSibling()) + { + index++; + } + for (Node ctx = node.getParentNode(); ctx != null; + ctx = ctx.getParentNode()) + { + depth++; + } + return name + "-" + index + "-" + depth; + } + + public Expr clone(Object context) + { + GenerateIdFunction f = new GenerateIdFunction(); + int len = args.size(); + List args2 = new ArrayList(len); + for (int i = 0; i < len; i++) + { + args2.add(((Expr) args.get(i)).clone(context)); + } + f.setArguments(args2); + return f; + } + + public boolean references(QName var) + { + for (Iterator i = args.iterator(); i.hasNext(); ) + { + if (((Expr) i.next()).references(var)) + { + return true; + } + } + return false; + } + +} diff --git a/libjava/classpath/gnu/xml/transform/IfNode.java b/libjava/classpath/gnu/xml/transform/IfNode.java new file mode 100644 index 000000000..f31fed555 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/IfNode.java @@ -0,0 +1,112 @@ +/* IfNode.java -- + 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.xml.transform; + +import gnu.java.lang.CPStringBuilder; + +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; + +/** + * A template node representing an XSL if instruction. + * + * @author Chris Burdess + */ +final class IfNode + extends TemplateNode +{ + + final Expr test; + + IfNode(Expr test) + { + this.test = test; + } + + TemplateNode clone(Stylesheet stylesheet) + { + TemplateNode ret = new IfNode(test.clone(stylesheet)); + if (children != null) + ret.children = children.clone(stylesheet); + if (next != null) + ret.next = next.clone(stylesheet); + return ret; + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + Object ret = test.evaluate(context, pos, len); + boolean success = (ret instanceof Boolean) ? + ((Boolean) ret).booleanValue() : + Expr._boolean(context, ret); + if (success) + { + if (children != null) + children.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + if (next != null) + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + + public boolean references(QName var) + { + if (test != null && test.references(var)) + return true; + return super.references(var); + } + + public String toString() + { + CPStringBuilder buf = new CPStringBuilder("if"); + buf.append('['); + buf.append("test="); + buf.append(test); + buf.append(']'); + return buf.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/Key.java b/libjava/classpath/gnu/xml/transform/Key.java new file mode 100644 index 000000000..18d83394f --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/Key.java @@ -0,0 +1,70 @@ +/* Key.java -- + 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.xml.transform; + +import javax.xml.namespace.QName; +import gnu.xml.xpath.Expr; +import gnu.xml.xpath.Pattern; + +/** + * An XSL key. + * + * @author Chris Burdess + */ +class Key +{ + + final QName name; + final Pattern match; + final Expr use; + + Key(QName name, Pattern match, Expr use) + { + this.name = name; + this.match = match; + this.use = use; + } + + Key clone(Stylesheet stylesheet) + { + return new Key(name, + (Pattern) match.clone(stylesheet), + use.clone(stylesheet)); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/KeyFunction.java b/libjava/classpath/gnu/xml/transform/KeyFunction.java new file mode 100644 index 000000000..b962626c9 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/KeyFunction.java @@ -0,0 +1,227 @@ +/* KeyFunction.java -- + 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.xml.transform; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import javax.xml.namespace.QName; +import javax.xml.xpath.XPathFunction; +import javax.xml.xpath.XPathFunctionException; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; +import gnu.xml.xpath.Function; +import gnu.xml.xpath.Pattern; + +/** + * The XSLT key()function. + * + * @author Chris Burdess + */ +final class KeyFunction + extends Pattern + implements XPathFunction, Function +{ + + final Stylesheet stylesheet; + List args; + + KeyFunction(Stylesheet stylesheet) + { + this.stylesheet = stylesheet; + } + + public Object evaluate(List args) + throws XPathFunctionException + { + // Useless... + return Collections.EMPTY_SET; + } + + public void setArguments(List args) + { + this.args = args; + } + + public boolean matches(Node context) + { + Object ret = evaluate(context, 1, 1); + return !((Collection) ret).isEmpty(); + } + + public Object evaluate(Node context, int pos, int len) + { + // Evaluate arguments + int arity = args.size(); + List values = new ArrayList(arity); + for (int i = 0; i < arity; i++) + { + Expr arg = (Expr) args.get(i); + values.add(arg.evaluate(context, pos, len)); + } + // Get key name + QName keyName = QName.valueOf(_string(context, values.get(0))); + // Expand qualified name + String uri = keyName.getNamespaceURI(); + String prefix = keyName.getPrefix(); + if ((uri == null || uri.length() == 0) && + (prefix != null && prefix.length() > 0)) + { + uri = stylesheet.getNamespaceURI(prefix); + if (uri != null && uri.length() > 0) + { + String localName = keyName.getLocalPart(); + keyName = new QName(uri, localName, prefix); + } + } + // Compute matching key set + Collection keySet = new LinkedList(); + for (Iterator i = stylesheet.keys.iterator(); i.hasNext(); ) + { + Key key = (Key) i.next(); + if (key.name.equals(keyName)) + { + keySet.add(key); + } + } + // Get target + Object target = values.get(1); + Collection acc = new LinkedHashSet(); + Document doc = (context instanceof Document) ? (Document) context : + context.getOwnerDocument(); + if (target instanceof Collection) + { + for (Iterator i = ((Collection) target).iterator(); i.hasNext(); ) + { + String val = Expr.stringValue((Node) i.next()); + addKeyNodes(doc, keySet, val, acc); + } + } + else + { + String val = Expr._string(context, target); + addKeyNodes(doc, keySet, val, acc); + } + List ret = new ArrayList(acc); + Collections.sort(ret, documentOrderComparator); + return ret; + } + + final void addKeyNodes(Node node, Collection keySet, + String value, Collection acc) + { + addKeyNodeIfMatch(node, keySet, value, acc); + // Apply children + for (Node ctx = node.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + addKeyNodes(ctx, keySet, value, acc); + } + } + + final void addKeyNodeIfMatch(Node node, Collection keySet, + String value, Collection acc) + { + for (Iterator i = keySet.iterator(); i.hasNext(); ) + { + Key key = (Key) i.next(); + if (key.match.matches(node)) + { + Object eval = key.use.evaluate(node, 1, 1); + if (eval instanceof Collection) + { + for (Iterator j = ((Collection) eval).iterator(); + j.hasNext(); ) + { + String keyValue = Expr.stringValue((Node) j.next()); + if (value.equals(keyValue)) + { + acc.add(node); + return; + } + } + } + else + { + String keyValue = Expr._string(node, eval); + if (value.equals(keyValue)) + { + acc.add(node); + return; + } + } + } + } + } + + public Expr clone(Object context) + { + Stylesheet s = stylesheet; + if (context instanceof Stylesheet) + { + s = (Stylesheet) context; + } + KeyFunction f = new KeyFunction(s); + int len = args.size(); + List args2 = new ArrayList(len); + for (int i = 0; i < len; i++) + { + args2.add(((Expr) args.get(i)).clone(context)); + } + f.setArguments(args2); + return f; + } + + public boolean references(QName var) + { + for (Iterator i = args.iterator(); i.hasNext(); ) + { + if (((Expr) i.next()).references(var)) + { + return true; + } + } + return false; + } + +} diff --git a/libjava/classpath/gnu/xml/transform/LiteralNode.java b/libjava/classpath/gnu/xml/transform/LiteralNode.java new file mode 100644 index 000000000..3405b3364 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/LiteralNode.java @@ -0,0 +1,202 @@ +/* LiteralNode.java -- + 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.xml.transform; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.StringTokenizer; +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +/** + * A template node that copies a DOM node in the template to the result + * tree. + * + * @author Chris Burdess + */ +final class LiteralNode + extends TemplateNode +{ + + /** + * The source node in the XSL template. + */ + final Node source; + + final Collection elementExcludeResultPrefixes; + + LiteralNode(Node source) + { + this.source = source; + if (source.getNodeType() == Node.ELEMENT_NODE) + { + NamedNodeMap attrs = source.getAttributes(); + Node attr = attrs.getNamedItemNS(Stylesheet.XSL_NS, + "exclude-result-prefixes"); + if (attr != null) + { + elementExcludeResultPrefixes = new HashSet(); + StringTokenizer st = new StringTokenizer(attr.getNodeValue()); + while (st.hasMoreTokens()) + elementExcludeResultPrefixes.add(st.nextToken()); + } + else + elementExcludeResultPrefixes = Collections.EMPTY_SET; + } + else + elementExcludeResultPrefixes = null; + } + + TemplateNode clone(Stylesheet stylesheet) + { + TemplateNode ret = new LiteralNode(source); + if (children != null) + ret.children = children.clone(stylesheet); + if (next != null) + ret.next = next.clone(stylesheet); + return ret; + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + Node result = null; + Document doc = (parent instanceof Document) ? (Document) parent : + parent.getOwnerDocument(); + short nodeType = source.getNodeType(); + if (nodeType == Node.ATTRIBUTE_NODE && + parent.getFirstChild() != null) + { + // Ignore attributes added after child elements + } + else + { + // Namespace aliasing + if (nodeType == Node.ELEMENT_NODE) + { + String prefix = source.getPrefix(); + if (prefix == null) + prefix = "#default"; + String resultPrefix = + (String) stylesheet.namespaceAliases.get(prefix); + if (resultPrefix != null) + { + if ("#default".equals(resultPrefix)) + resultPrefix = null; + String uri = source.lookupNamespaceURI(resultPrefix); + String name = source.getNodeName(); + // Create a new element node in the result document + result = doc.createElementNS(uri, name); + // copy attributes + NamedNodeMap srcAttrs = source.getAttributes(); + NamedNodeMap dstAttrs = result.getAttributes(); + int l = srcAttrs.getLength(); + for (int i = 0; i < l; i++) + { + Node attr = srcAttrs.item(i); + if (!Stylesheet.XSL_NS.equals(attr.getNamespaceURI())) + { + attr = attr.cloneNode(true); + attr = doc.adoptNode(attr); + dstAttrs.setNamedItemNS(attr); + } + } + } + } + if (result == null) + { + // Create result node + result = source.cloneNode(false); + // Remove any XSL attributes + NamedNodeMap attrs = result.getAttributes(); + if (attrs != null) + { + int l = attrs.getLength(); + for (int i = 0; i < l; i++) + { + Node attr = attrs.item(i); + if (Stylesheet.XSL_NS.equals(attr.getNamespaceURI())) + { + attrs.removeNamedItem(attr.getNodeName()); + i--; + l--; + } + } + } + Node result2 = doc.adoptNode(result); + if (result2 == null) + { + String msg = "Error adopting node to result tree: " + + result + " (" + result.getClass().getName() + ")"; + DOMSourceLocator l = new DOMSourceLocator(context); + throw new TransformerException(msg, l); + } + result = result2; + } + if (nextSibling != null) + parent.insertBefore(result, nextSibling); + else + parent.appendChild(result); + if (nodeType == Node.ELEMENT_NODE) + stylesheet.addNamespaceNodes(source, result, doc, + elementExcludeResultPrefixes); + // children + if (children != null) + children.apply(stylesheet, mode, + context, pos, len, + result, null); + } + // next sibling + if (next != null) + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + + public String toString() + { + return source.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/MessageNode.java b/libjava/classpath/gnu/xml/transform/MessageNode.java new file mode 100644 index 000000000..3e4899aeb --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/MessageNode.java @@ -0,0 +1,110 @@ +/* MessageNode.java -- + 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.xml.transform; + +import gnu.java.lang.CPStringBuilder; + +import java.util.logging.Logger; +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; + +/** + * An XSL message instruction. + * + * @author Chris Burdess + */ +final class MessageNode + extends TemplateNode +{ + + static final Logger logger = Logger.getLogger("gnu.xml.transform"); + + final boolean terminate; + + MessageNode(boolean terminate) + { + this.terminate = terminate; + } + + TemplateNode clone(Stylesheet stylesheet) + { + TemplateNode ret = new MessageNode(terminate); + if (children != null) + ret.children = children.clone(stylesheet); + if (next != null) + ret.next = next.clone(stylesheet); + return ret; + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + if (children != null) + { + Document doc = (parent instanceof Document) ? (Document) parent : + parent.getOwnerDocument(); + DocumentFragment fragment = doc.createDocumentFragment(); + children.apply(stylesheet, mode, context, pos, len, fragment, null); + String message = Expr.stringValue(fragment); + logger.info(message); + if (terminate) + stylesheet.terminated = true; + } + if (next != null && !terminate) + next.apply(stylesheet, mode, context, pos, len, parent, nextSibling); + } + + public String toString() + { + CPStringBuilder buf = new CPStringBuilder("message"); + if (terminate) + { + buf.append('['); + buf.append("terminate"); + buf.append(']'); + } + return buf.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/NamespaceProxy.java b/libjava/classpath/gnu/xml/transform/NamespaceProxy.java new file mode 100644 index 000000000..695fbeb52 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/NamespaceProxy.java @@ -0,0 +1,77 @@ +/* NamespaceProxy.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.transform; + +import java.util.Collections; +import java.util.Iterator; +import javax.xml.namespace.NamespaceContext; +import org.w3c.dom.Node; + +/** + * A namespace context using a DOM node to resolve the namespace. + * + * @author Chris Burdess + */ +class NamespaceProxy + implements NamespaceContext +{ + + private final Node node; + + NamespaceProxy(Node node) + { + this.node = node; + } + + public String getNamespaceURI(String prefix) + { + return (node == null) ? null : node.lookupNamespaceURI(prefix); + } + + public String getPrefix(String namespaceURI) + { + return (node == null) ? null : node.lookupPrefix(namespaceURI); + } + + public Iterator getPrefixes(String namespaceURI) + { + // TODO + return Collections.singleton(getPrefix(namespaceURI)).iterator(); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/NodeNumberNode.java b/libjava/classpath/gnu/xml/transform/NodeNumberNode.java new file mode 100644 index 000000000..6663db371 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/NodeNumberNode.java @@ -0,0 +1,269 @@ +/* NodeNumberNode.java -- + 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.xml.transform; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; +import gnu.xml.xpath.Pattern; +import gnu.xml.xpath.Selector; +import gnu.xml.xpath.UnionExpr; + +/** + * A template node representing the XSL number instruction + * with no value expression, i.e. the value is computed from + * the document position of the context node. + * + * @author Chris Burdess + */ +final class NodeNumberNode + extends AbstractNumberNode +{ + + static final int SINGLE = 0; + static final int MULTIPLE = 1; + static final int ANY = 2; + + final int level; + final Pattern count; + final Pattern from; + + NodeNumberNode(int level, Pattern count, Pattern from, + TemplateNode format, String lang, + int letterValue, String groupingSeparator, int groupingSize) + { + super(format, lang, letterValue, groupingSeparator, groupingSize); + this.level = level; + this.count = count; + this.from = from; + } + + TemplateNode clone(Stylesheet stylesheet) + { + TemplateNode ret = new NodeNumberNode(level, + (count == null) ? null : + (Pattern) count.clone(stylesheet), + (from == null) ? from : + (Pattern) from.clone(stylesheet), + format, lang, letterValue, + groupingSeparator, groupingSize); + if (children != null) + { + ret.children = children.clone(stylesheet); + } + if (next != null) + { + ret.next = next.clone(stylesheet); + } + return ret; + } + + int[] compute(Stylesheet stylesheet, Node context, int pos, int len) + throws TransformerException + { + /*if (from != null) + { + Object ret = from.evaluate(context, pos, len); + if (ret instanceof Collection) + { + Collection ns = (Collection) ret; + if (ns.size() > 0) + { + List list = new ArrayList(ns); + Collections.sort(list, documentOrderComparator); + context = (Node) list.get(0); + } + else + { + return new int[0]; + } + } + else + { + return new int[0]; + } + }*/ + Node current = context; + switch (level) + { + case SINGLE: + if (from == null) + { + while (context != null && !countMatches(current, context)) + { + context = context.getParentNode(); + } + } + else + { + while (context != null && !countMatches(current, context) && + !fromMatches(context)) + { + context = context.getParentNode(); + } + } + return (context == null) ? new int[0] : + new int[] { (context == current) ? pos : getIndex(current, context) }; + case MULTIPLE: + List ancestors = new ArrayList(); + while (context != null) + { + if (countMatches(current, context)) + { + if (from == null || fromMatches(context)) + { + ancestors.add(context); + } + } + context = context.getParentNode(); + } + Collections.sort(ancestors, documentOrderComparator); + int[] ret = new int[ancestors.size()]; + for (int i = 0; i < ret.length; i++) + { + ret[i] = getIndex(current, (Node) ancestors.get(i)); + } + return ret; + case ANY: + Expr preceding = new Selector(Selector.PRECEDING, + Collections.EMPTY_LIST); + Expr ancestorOrSelf = new Selector(Selector.ANCESTOR_OR_SELF, + Collections.EMPTY_LIST); + Expr any = new UnionExpr(preceding, ancestorOrSelf); + Object eval = any.evaluate(context, pos, len); + if (eval instanceof Collection) + { + Collection ns = (Collection) eval; + List candidates = new ArrayList(); + for (Iterator i = ns.iterator(); i.hasNext(); ) + { + Node candidate = (Node) i.next(); + if (countMatches(current, candidate)) + { + candidates.add(candidate); + if (from != null && from.matches(candidate)) + { + break; + } + } + } + return new int[] { candidates.size() }; + } + return new int[0]; + default: + throw new TransformerException("invalid level"); + } + } + + boolean countMatches(Node current, Node node) + { + if (count == null) + { + int cnt = current.getNodeType(); + int nnt = node.getNodeType(); + if (cnt != nnt) + { + return false; + } + if (nnt == Node.ELEMENT_NODE || nnt == Node.ATTRIBUTE_NODE) + { + String curi = current.getNamespaceURI(); + String nuri = node.getNamespaceURI(); + if ((curi == null && nuri != null) || + (curi != null && !curi.equals(nuri))) + { + return false; + } + String cn = current.getLocalName(); + if (cn == null) + { + cn = current.getNodeName(); + } + String nn = node.getLocalName(); + if (nn == null) + { + nn = node.getNodeName(); + } + if (!cn.equals(nn)) + { + return false; + } + } + return true; + } + else + { + return count.matches(node); + } + } + + boolean fromMatches(Node node) + { + for (Node ctx = node.getParentNode(); ctx != null; + ctx = ctx.getParentNode()) + { + if (from.matches(ctx)) + { + return true; + } + } + return false; + } + + int getIndex(Node current, Node node) + { + int index = 0; + do + { + do + { + node = node.getPreviousSibling(); + } + while (node != null && !countMatches(current, node)); + index++; + } + while (node != null); + return index; + } + +} diff --git a/libjava/classpath/gnu/xml/transform/NumberNode.java b/libjava/classpath/gnu/xml/transform/NumberNode.java new file mode 100644 index 000000000..cec594b99 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/NumberNode.java @@ -0,0 +1,88 @@ +/* NumberNode.java -- + 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.xml.transform; + +import javax.xml.transform.TransformerException; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; + +/** + * A template node representing the XSL number instruction + * with a value expression. + * + * @author Chris Burdess + */ +final class NumberNode + extends AbstractNumberNode +{ + + final Expr value; + + NumberNode(Expr value, TemplateNode format, String lang, + int letterValue, String groupingSeparator, int groupingSize) + { + super(format, lang, letterValue, groupingSeparator, groupingSize); + this.value = value; + } + + TemplateNode clone(Stylesheet stylesheet) + { + TemplateNode ret = new NumberNode(value.clone(stylesheet), + format, lang, letterValue, + groupingSeparator, groupingSize); + if (children != null) + { + ret.children = children.clone(stylesheet); + } + if (next != null) + { + ret.next = next.clone(stylesheet); + } + return ret; + } + + int[] compute(Stylesheet stylesheet, Node context, int pos, int len) + throws TransformerException + { + Object ret = value.evaluate(context, pos, len); + Double d = (ret instanceof Double) ? ((Double) ret) : + new Double(Expr._number(context, ret)); + return new int[] { d.intValue() }; + } + +} diff --git a/libjava/classpath/gnu/xml/transform/OtherwiseNode.java b/libjava/classpath/gnu/xml/transform/OtherwiseNode.java new file mode 100644 index 000000000..09057840d --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/OtherwiseNode.java @@ -0,0 +1,83 @@ +/* OtherwiseNode.java -- + 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.xml.transform; + +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Node; + +/** + * A template node representing an XSL otherwise instruction. + * + * @author Chris Burdess + */ +final class OtherwiseNode + extends TemplateNode +{ + + TemplateNode clone(Stylesheet stylesheet) + { + TemplateNode ret = new OtherwiseNode(); + if (children != null) + ret.children = children.clone(stylesheet); + if (next != null) + ret.next = next.clone(stylesheet); + return ret; + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + if (children != null) + children.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + if (next != null) + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + + public String toString() + { + return "otherwise"; + } + +} diff --git a/libjava/classpath/gnu/xml/transform/ParameterNode.java b/libjava/classpath/gnu/xml/transform/ParameterNode.java new file mode 100644 index 000000000..4f3dc7569 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/ParameterNode.java @@ -0,0 +1,172 @@ +/* ParameterNode.java -- + 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.xml.transform; + +import gnu.java.lang.CPStringBuilder; + +import java.util.Collections; +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; + +/** + * A template node that sets a variable or parameter during template + * processing. + * + * @author Chris Burdess + */ +final class ParameterNode + extends TemplateNode + implements Comparable +{ + + final QName name; + final Expr select; + final int type; + + ParameterNode(QName name, Expr select, int type) + { + this.name = name; + this.select = select; + this.type = type; + } + + @Override + ParameterNode clone(Stylesheet stylesheet) + { + ParameterNode ret = new ParameterNode(name, + select == null ? null : select.clone(stylesheet), + type); + if (children != null) + ret.children = children.clone(stylesheet); + if (next != null) + ret.next = next.clone(stylesheet); + return ret; + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + // push the variable context + stylesheet.bindings.push(type); + // set the variable + Object value = getValue(stylesheet, mode, context, pos, len); + if (value != null) + { + stylesheet.bindings.set(name, value, type); + if (stylesheet.debug) + 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); + // pop the variable context + stylesheet.bindings.pop(type); + } + + Object getValue(Stylesheet stylesheet, QName mode, + Node context, int pos, int len) + throws TransformerException + { + if (select != null) + return select.evaluate(context, pos, len); + else if (children != null) + { + Document doc = (context instanceof Document) ? (Document) context : + context.getOwnerDocument(); + DocumentFragment fragment = doc.createDocumentFragment(); + children.apply(stylesheet, mode, context, pos, len, fragment, null); + return Collections.singleton(fragment); + } + else + return null; + } + + public boolean references(QName var) + { + if (select != null && select.references(var)) + return true; + return super.references(var); + } + + public int compareTo(ParameterNode pn) + { + boolean r1 = references(pn.name); + boolean r2 = pn.references(name); + if (r1 && r2) + throw new IllegalArgumentException("circular definitions"); + if (r1) + return 1; + if (r2) + return -1; + return 0; + } + + public String toString() + { + CPStringBuilder buf = new CPStringBuilder(); + switch (type) + { + case Bindings.VARIABLE: + buf.append("variable"); + break; + case Bindings.PARAM: + buf.append("param"); + break; + case Bindings.WITH_PARAM: + buf.append("with-param"); + break; + } + buf.append('['); + buf.append("name="); + buf.append(name); + buf.append(",select="); + buf.append(select); + buf.append(']'); + return buf.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/ProcessingInstructionNode.java b/libjava/classpath/gnu/xml/transform/ProcessingInstructionNode.java new file mode 100644 index 000000000..1e723a8d4 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/ProcessingInstructionNode.java @@ -0,0 +1,118 @@ +/* ProcessingInstructionNode.java -- + 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.xml.transform; + +import gnu.java.lang.CPStringBuilder; + +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Node; +import org.w3c.dom.ProcessingInstruction; +import gnu.xml.xpath.Expr; + +/** + * A template node representing the XSL processing-instruction + * instruction. + * + * @author Chris Burdess + */ +final class ProcessingInstructionNode + extends TemplateNode +{ + + final String name; + + ProcessingInstructionNode(String name) + { + this.name = name; + } + + TemplateNode clone(Stylesheet stylesheet) + { + TemplateNode ret = new ProcessingInstructionNode(name); + if (children != null) + ret.children = children.clone(stylesheet); + if (next != null) + ret.next = next.clone(stylesheet); + return ret; + } + + void doApply(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + String data = null; + Document doc = (parent instanceof Document) ? (Document) parent : + parent.getOwnerDocument(); + if (children != null) + { + // Create a document fragment to hold the text + DocumentFragment fragment = doc.createDocumentFragment(); + // Apply children to the fragment + children.apply(stylesheet, mode, + context, pos, len, + fragment, null); + // Use XPath string-value of fragment + data = Expr.stringValue(fragment); + } + ProcessingInstruction pi = doc.createProcessingInstruction(name, data); + // Insert into result tree + if (nextSibling != null) + parent.insertBefore(pi, nextSibling); + else + parent.appendChild(pi); + if (next != null) + next.apply(stylesheet, mode, + context, pos, len, + parent, nextSibling); + } + + public String toString() + { + CPStringBuilder buf = new CPStringBuilder("processing-instruction"); + buf.append('['); + buf.append("name="); + buf.append(name); + buf.append(']'); + return buf.toString(); + } + +} diff --git a/libjava/classpath/gnu/xml/transform/SAXSerializer.java b/libjava/classpath/gnu/xml/transform/SAXSerializer.java new file mode 100644 index 000000000..2bd1f97ab --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/SAXSerializer.java @@ -0,0 +1,305 @@ +/* SAXSerializer.java -- + 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.xml.transform; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import org.w3c.dom.Attr; +import org.w3c.dom.DocumentType; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; +import org.xml.sax.ext.LexicalHandler; + +/** + * Serializes a DOM node to a sequence of SAX events. + * + * @author Chris Burdess + */ +class SAXSerializer + implements Attributes +{ + + transient NamedNodeMap attrs; + transient LinkedList namespaces = new LinkedList(); + + boolean isDefined(String prefix, String uri) + { + for (Iterator i = namespaces.iterator(); i.hasNext(); ) + { + HashMap ctx = (HashMap) i.next(); + if (uri.equals(ctx.get(prefix))) + { + return true; + } + } + return false; + } + + void define(String prefix, String uri) + { + for (Iterator i = namespaces.iterator(); i.hasNext(); ) + { + HashMap ctx = (HashMap) i.next(); + if (ctx.containsKey(prefix)) + { + HashMap newCtx = new HashMap(); + newCtx.put(prefix, uri); + namespaces.addFirst(newCtx); + return; + } + } + HashMap ctx; + if (namespaces.isEmpty()) + { + ctx = new HashMap(); + namespaces.add(ctx); + } + else + { + ctx = (HashMap) namespaces.getFirst(); + } + ctx.put(prefix, uri); + } + + void undefine(String prefix, String uri) + { + for (Iterator i = namespaces.iterator(); i.hasNext(); ) + { + HashMap ctx = (HashMap) i.next(); + if (uri.equals(ctx.get(prefix))) + { + ctx.remove(prefix); + if (ctx.isEmpty()) + { + namespaces.remove(ctx); + } + return; + } + } + } + + public int getLength() + { + return attrs.getLength(); + } + + public String getURI(int index) + { + return attrs.item(index).getNamespaceURI(); + } + + public String getLocalName(int index) + { + return attrs.item(index).getLocalName(); + } + + public String getQName(int index) + { + return attrs.item(index).getNodeName(); + } + + public String getType(int index) + { + Attr attr = (Attr) attrs.item(index); + return attr.isId() ? "ID" : "CDATA"; + } + + public String getValue(int index) + { + return attrs.item(index).getNodeValue(); + } + + public int getIndex(String uri, String localName) + { + int len = attrs.getLength(); + for (int i = 0; i < len; i++) + { + Node attr = attrs.item(i); + String a_uri = attr.getNamespaceURI(); + String a_localName = attr.getLocalName(); + if (((a_uri == null && uri == null) || + (a_uri != null && a_uri.equals(uri))) && + a_localName.equals(localName)) + { + return i; + } + } + return -1; + } + + public int getIndex(String qName) + { + int len = attrs.getLength(); + for (int i = 0; i < len; i++) + { + Node attr = attrs.item(i); + String a_name = attr.getNodeName(); + if (a_name.equals(qName)) + { + return i; + } + } + return -1; + } + + public String getType(String uri, String localName) + { + Attr attr = (Attr) attrs.getNamedItemNS(uri, localName); + return attr.isId() ? "ID" : "CDATA"; + } + + public String getType(String qName) + { + Attr attr = (Attr) attrs.getNamedItem(qName); + return attr.isId() ? "ID" : "CDATA"; + } + + public String getValue(String uri, String localName) + { + return attrs.getNamedItemNS(uri, localName).getNodeValue(); + } + + public String getValue(String qName) + { + return attrs.getNamedItem(qName).getNodeValue(); + } + + void serialize(Node node, ContentHandler ch, LexicalHandler lh) + throws SAXException + { + attrs = node.getAttributes(); + Node children; + Node next = node.getNextSibling(); + switch (node.getNodeType()) + { + case Node.ELEMENT_NODE: + String uri = node.getNamespaceURI(); + String prefix = node.getPrefix(); + boolean defined = isDefined(prefix, uri); + if (!defined) + { + define(prefix, uri); + ch.startPrefixMapping(prefix, uri); + } + String localName = node.getLocalName(); + String qName = node.getNodeName(); + ch.startElement(uri, localName, qName, this); + children = node.getFirstChild(); + if (children != null) + { + serialize(children, ch, lh); + } + ch.endElement(uri, localName, qName); + if (!defined) + { + ch.endPrefixMapping(prefix); + undefine(prefix, uri); + } + break; + case Node.TEXT_NODE: + char[] chars = node.getNodeValue().toCharArray(); + ch.characters(chars, 0, chars.length); + break; + case Node.CDATA_SECTION_NODE: + char[] cdata = node.getNodeValue().toCharArray(); + if (lh != null) + { + lh.startCDATA(); + ch.characters(cdata, 0, cdata.length); + lh.endCDATA(); + } + else + { + ch.characters(cdata, 0, cdata.length); + } + break; + case Node.COMMENT_NODE: + if (lh != null) + { + char[] comment = node.getNodeValue().toCharArray(); + lh.comment(comment, 0, comment.length); + } + break; + case Node.DOCUMENT_NODE: + case Node.DOCUMENT_FRAGMENT_NODE: + ch.startDocument(); + children = node.getFirstChild(); + if (children != null) + { + serialize(children, ch, lh); + } + ch.endDocument(); + break; + case Node.DOCUMENT_TYPE_NODE: + if (lh != null) + { + DocumentType doctype = (DocumentType) node; + String publicId = doctype.getPublicId(); + String systemId = doctype.getSystemId(); + lh.startDTD(node.getNodeName(), publicId, systemId); + NamedNodeMap entities = doctype.getEntities(); + int len = entities.getLength(); + for (int i = 0; i < len; i++) + { + Node entity = entities.item(i); + String entityName = entity.getNodeName(); + lh.startEntity(entityName); + lh.endEntity(entityName); + } + lh.endDTD(); + } + break; + case Node.PROCESSING_INSTRUCTION_NODE: + ch.processingInstruction(node.getNodeName(), node.getNodeValue()); + break; + case Node.ENTITY_REFERENCE_NODE: + ch.skippedEntity(node.getNodeName()); + break; + } + attrs = null; + if (next != null) + { + serialize(next, ch, lh); + } + } + +} diff --git a/libjava/classpath/gnu/xml/transform/SAXTemplatesHandler.java b/libjava/classpath/gnu/xml/transform/SAXTemplatesHandler.java new file mode 100644 index 000000000..24464c067 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/SAXTemplatesHandler.java @@ -0,0 +1,97 @@ +/* SAXTemplatesHandler.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.transform; + +import javax.xml.transform.Templates; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.sax.TemplatesHandler; +import org.w3c.dom.Document; +import gnu.xml.dom.ls.SAXEventSink; + +/** + * A content handler that acts as a sink for SAX parse events, + * constructing an XSL stylesheet. + * Internally, this class simply creates a DOM tree from the events, + * and then parses the DOM into a Templates object. + * + * @author Chris Burdess (dog@gnu.org) + */ +class SAXTemplatesHandler + extends SAXEventSink + implements TemplatesHandler +{ + + final TransformerFactoryImpl factory; + String systemId; + + SAXTemplatesHandler(TransformerFactoryImpl factory) + { + this.factory = factory; + } + + public String getSystemId() + { + return systemId; + } + + public void setSystemId(String systemId) + { + this.systemId = systemId; + } + + public Templates getTemplates() + { + Document doc = getDocument(); + if (doc == null) + throw new IllegalStateException("Parsing of stylesheet incomplete"); + DOMSource ds = new DOMSource(doc, systemId); + try + { + return factory.newTemplates(ds); + } + catch (TransformerConfigurationException e) + { + String msg = "Unable to construct templates from this event stream"; + IllegalStateException e2 = new IllegalStateException(msg); + e2.initCause(e); + throw e2; + } + } + +} diff --git a/libjava/classpath/gnu/xml/transform/SAXTransformerHandler.java b/libjava/classpath/gnu/xml/transform/SAXTransformerHandler.java new file mode 100644 index 000000000..890e15100 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/SAXTransformerHandler.java @@ -0,0 +1,111 @@ +/* SAXTransformerHandler.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.transform; + +import javax.xml.transform.Result; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.sax.TransformerHandler; +import org.w3c.dom.Document; +import org.xml.sax.SAXException; +import gnu.xml.dom.ls.SAXEventSink; + +/** + * A SAX event sink that processes an XML source represented as a stream of + * SAX events into a result tree. + * This works by simply buffering all the events into a DOM tree and then + * using this DOM tree as the source of the transformation. + * + * @author Chris Burdess (dog@gnu.org) + */ +class SAXTransformerHandler + extends SAXEventSink + implements TransformerHandler +{ + + final TransformerFactoryImpl factory; + final Transformer transformer; + String systemId; + Result result; + + SAXTransformerHandler(TransformerFactoryImpl factory, Transformer transformer) + { + this.factory = factory; + this.transformer = transformer; + } + + public String getSystemId() + { + return systemId; + } + + public void setSystemId(String systemId) + { + this.systemId = systemId; + } + + public Transformer getTransformer() + { + return transformer; + } + + public void setResult(Result result) + { + this.result = result; + } + + public void endDocument() + throws SAXException + { + super.endDocument(); + try + { + Document doc = getDocument(); + DOMSource ds = new DOMSource(doc, systemId); + transformer.transform(ds, result); + } + catch (TransformerException e) + { + SAXException e2 = new SAXException(e.getMessage()); + e2.initCause(e); + throw e2; + } + } + +} diff --git a/libjava/classpath/gnu/xml/transform/SortKey.java b/libjava/classpath/gnu/xml/transform/SortKey.java new file mode 100644 index 000000000..dd57df986 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/SortKey.java @@ -0,0 +1,239 @@ +/* SortKey.java -- + 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.xml.transform; + +import javax.xml.namespace.QName; +import javax.xml.transform.TransformerException; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentFragment; +import org.w3c.dom.Node; +import gnu.xml.xpath.Expr; + +/** + *

      + * An XSL sort key, as specified by section 10 of the XSL + * Transformations specification. This takes the form: + *

      + *
      + * <xsl:sort
      + * select = string-expression
      + * lang = { nmtoken }
      + * data-type = { "text" | "number" | qname-but-not-ncname }
      + * order = { "ascending" | "descending" }
      + * case-order = { "upper-first" | "lower-first" } /&rt;
      + * 
      + *

      + * Note that all but the selection expression are optional, + * and so may be {@code null}. + *

      + * + * @author Chris Burdess + */ +final class SortKey +{ + + static final int DEFAULT = 0; + static final int UPPER_FIRST = 1; + static final int LOWER_FIRST = 2; + + final Expr select; + final TemplateNode langTemplate; + final TemplateNode dataTypeTemplate; + final TemplateNode orderTemplate; + final TemplateNode caseOrderTemplate; + + transient String lang; + transient String dataType; + transient boolean descending; + transient int caseOrder; + + /** + * Constructs a new {@link SortKey} to represent an <xsl:sort&rt; + * tag. + * + * @param select the XPath expression which selects the nodes to be sorted. + * @param lang the language of the sort keys or {@code null} if unspecified. + * @param dataType the data type of the strings. May be "string", "number", + * a QName or {@code null} if unspecified. + * @param order the ordering of the nodes, which may be "ascending", "descending" + * or {@code null} if unspecified. + * @param caseOrder the treatment of case when the data type is a string. This + * may be "upper-first", "lower-first" or {@code null} if + * unspecified. + */ + SortKey(Expr select, TemplateNode lang, TemplateNode dataType, + TemplateNode order, TemplateNode caseOrder) + { + this.select = select; + this.langTemplate = lang; + this.dataTypeTemplate = dataType; + this.orderTemplate = order; + this.caseOrderTemplate = caseOrder; + } + + String key(Node node) + { + Object ret = select.evaluate(node, 1, 1); + if (ret instanceof String) + { + return (String) ret; + } + else + { + return Expr._string(node, ret); + } + } + + /** + * Prepare for a sort. + * This sets all transient variables from their AVTs. + */ + void init(Stylesheet stylesheet, QName mode, + Node context, int pos, int len, + Node parent, Node nextSibling) + throws TransformerException + { + Document doc = (context instanceof Document) ? (Document) context : + context.getOwnerDocument(); + if (langTemplate == null) + { + lang = null; + } + else + { + DocumentFragment fragment = doc.createDocumentFragment(); + langTemplate.apply(stylesheet, mode, context, pos, len, + fragment, null); + lang = Expr.stringValue(fragment); + } + if (dataTypeTemplate == null) + { + dataType = "text"; + } + else + { + DocumentFragment fragment = doc.createDocumentFragment(); + dataTypeTemplate.apply(stylesheet, mode, context, pos, len, + fragment, null); + dataType = Expr.stringValue(fragment); + } + if (orderTemplate == null) + { + descending = false; + } + else + { + DocumentFragment fragment = doc.createDocumentFragment(); + orderTemplate.apply(stylesheet, mode, context, pos, len, + fragment, null); + String order = Expr.stringValue(fragment); + descending = "descending".equals(order); + } + if (caseOrderTemplate == null) + { + caseOrder = DEFAULT; + } + else + { + DocumentFragment fragment = doc.createDocumentFragment(); + caseOrderTemplate.apply(stylesheet, mode, context, pos, len, + fragment, null); + String co = Expr.stringValue(fragment); + caseOrder = "upper-first".equals(co) ? UPPER_FIRST : + "lower-first".equals(co) ? LOWER_FIRST : + DEFAULT; + } + } + + boolean references(QName var) + { + if (select != null && select.references(var)) + { + return true; + } + if (langTemplate != null && langTemplate.references(var)) + { + return true; + } + if (dataTypeTemplate != null && dataTypeTemplate.references(var)) + { + return true; + } + if (orderTemplate != null && orderTemplate.references(var)) + { + return true; + } + if (caseOrderTemplate != null && caseOrderTemplate.references(var)) + { + return true; + } + return false; + } + + /** + * Provides a clone of this {@link SortKey}, using the given + * stylesheet as a context. + * + * @param stylesheet the stylesheet which provides context for the cloning. + * @return a clone of this instance. + */ + SortKey clone(Stylesheet stylesheet) + { + return new SortKey(select.clone(stylesheet), + langTemplate == null ? null : cloneAttributeValueTemplate(langTemplate, stylesheet), + dataTypeTemplate == null ? null : cloneAttributeValueTemplate(dataTypeTemplate, stylesheet), + orderTemplate == null ? null : cloneAttributeValueTemplate(orderTemplate, stylesheet), + caseOrderTemplate == null ? null : cloneAttributeValueTemplate(caseOrderTemplate, stylesheet)); + } + + /** + * Clones an attribute value template as created by + * {@link Stylesheet#parseAttributeValueTemplate(String, Node)}. + * The node may either by a literal node or an xsl:value-of expression. + * + * @param node the node to clone. + * @param stylesheet the stylesheet which provides context for the cloning. + * @return the cloned node. + */ + private TemplateNode cloneAttributeValueTemplate(TemplateNode node, Stylesheet stylesheet) + { + if (node instanceof ValueOfNode) + return ((ValueOfNode) node).clone(stylesheet); + return ((LiteralNode) node).clone(stylesheet); + } +} diff --git a/libjava/classpath/gnu/xml/transform/StreamSerializer.java b/libjava/classpath/gnu/xml/transform/StreamSerializer.java new file mode 100644 index 000000000..a5705f891 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/StreamSerializer.java @@ -0,0 +1,854 @@ +/* StreamSerializer.java -- + 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.xml.transform; + +import gnu.java.lang.CPStringBuilder; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; +import java.util.Collection; +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 javax.xml.XMLConstants; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.DocumentType; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; + +/** + * Serializes a DOM node to an output stream. + * + * @author Chris Burdess + */ +public class StreamSerializer +{ + + static final int SPACE = 0x20; + static final int BANG = 0x21; // ! + static final int APOS = 0x27; // ' + static final int SLASH = 0x2f; // / + static final int BRA = 0x3c; // < + static final int KET = 0x3e; // > + static final int EQ = 0x3d; // = + + /** + * HTML 4.01 boolean attributes + */ + static final Map HTML_BOOLEAN_ATTRIBUTES = new HashMap(); + static + { + HashSet set; + + set = new HashSet(); + set.add("nohref"); + HTML_BOOLEAN_ATTRIBUTES.put("area", set); + + set = new HashSet(); + set.add("ismap"); + HTML_BOOLEAN_ATTRIBUTES.put("img", set); + + set = new HashSet(); + set.add("declare"); + HTML_BOOLEAN_ATTRIBUTES.put("object", set); + + set = new HashSet(); + set.add("noshade"); + HTML_BOOLEAN_ATTRIBUTES.put("hr", set); + + set = new HashSet(); + set.add("compact"); + HTML_BOOLEAN_ATTRIBUTES.put("dl", set); + HTML_BOOLEAN_ATTRIBUTES.put("ol", set); + HTML_BOOLEAN_ATTRIBUTES.put("ul", set); + HTML_BOOLEAN_ATTRIBUTES.put("dir", set); + HTML_BOOLEAN_ATTRIBUTES.put("menu", set); + + set = new HashSet(); + set.add("checked"); + set.add("disabled"); + set.add("readonly"); + set.add("ismap"); + HTML_BOOLEAN_ATTRIBUTES.put("input", set); + + set = new HashSet(); + set.add("multiple"); + set.add("disabled"); + HTML_BOOLEAN_ATTRIBUTES.put("select", set); + + set = new HashSet(); + set.add("disabled"); + HTML_BOOLEAN_ATTRIBUTES.put("optgroup", set); + + set = new HashSet(); + set.add("selected"); + set.add("disabled"); + HTML_BOOLEAN_ATTRIBUTES.put("option", set); + + set = new HashSet(); + set.add("disabled"); + set.add("readonly"); + HTML_BOOLEAN_ATTRIBUTES.put("textarea", set); + + set = new HashSet(); + set.add("disabled"); + HTML_BOOLEAN_ATTRIBUTES.put("button", set); + + set = new HashSet(); + set.add("nowrap"); + HTML_BOOLEAN_ATTRIBUTES.put("th", set); + HTML_BOOLEAN_ATTRIBUTES.put("td", set); + + set = new HashSet(); + set.add("noresize"); + HTML_BOOLEAN_ATTRIBUTES.put("frame", set); + + set = new HashSet(); + set.add("defer"); + HTML_BOOLEAN_ATTRIBUTES.put("script", set); + } + + // HTML namespace URIs + static final HashSet HTML_URIS = new HashSet(); + static { + HTML_URIS.add("http://www.w3.org/1999/xhtml"); + } + + protected final String encoding; + final Charset charset; + final CharsetEncoder encoder; + final int mode; + final LinkedList namespaces; + protected String eol; + Collection cdataSectionElements = Collections.EMPTY_SET; + + protected boolean discardDefaultContent; + protected boolean xmlDeclaration = true; + + // has a META element with the encoding been added? + private boolean htmlEncoded; + + public StreamSerializer() + { + this(Stylesheet.OUTPUT_XML, null, null); + } + + public StreamSerializer(String encoding) + { + this(Stylesheet.OUTPUT_XML, encoding, null); + } + + public StreamSerializer(int mode, String encoding, String eol) + { + this.mode = mode; + if (encoding == null) + encoding = (mode == Stylesheet.OUTPUT_HTML) ? "ISO-8859-1" : "UTF-8"; + this.encoding = encoding.intern(); + charset = Charset.forName(this.encoding); + encoder = charset.newEncoder(); + this.eol = (eol != null) ? eol : System.getProperty("line.separator"); + namespaces = new LinkedList(); + } + + void setCdataSectionElements(Collection c) + { + cdataSectionElements = c; + } + + public void serialize(final Node node, final OutputStream out) + throws IOException + { + serialize(node, out, false); + } + + void serialize(Node node, final OutputStream out, + boolean convertToCdata) + throws IOException + { + while (node != null) + { + Node next = node.getNextSibling(); + doSerialize(node, out, convertToCdata); + node = next; + } + } + + private void doSerialize(final Node node, final OutputStream out, + boolean convertToCdata) + throws IOException + { + if (out == null) + throw new NullPointerException("no output stream"); + htmlEncoded = false; + String value, prefix; + Node children; + String uri = node.getNamespaceURI(); + short nt = node.getNodeType(); + if (convertToCdata && nt == Node.TEXT_NODE) + nt = Node.CDATA_SECTION_NODE; + switch (nt) + { + case Node.ATTRIBUTE_NODE: + prefix = node.getPrefix(); + if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(uri) || + XMLConstants.XMLNS_ATTRIBUTE.equals(prefix) || + (prefix != null && prefix.startsWith("xmlns:"))) + { + String nsuri = node.getNodeValue(); + if (isDefined(nsuri, prefix)) + break; + String name = node.getLocalName(); + if (name == null) + { + // Namespace-unaware + name = node.getNodeName(); + int ci = name.indexOf(':'); + if (ci != -1) + name = name.substring(ci + 1); + } + define(nsuri, name); + } + else if (uri != null && !isDefined(uri, prefix)) + { + prefix = define(uri, prefix); + String nsname = (prefix == null) ? "xmlns" : "xmlns:" + prefix; + out.write(SPACE); + out.write(encodeText(nsname)); + out.write(EQ); + String nsvalue = "\"" + encode(uri, true, true) + "\""; + out.write(nsvalue.getBytes(encoding)); + } + out.write(SPACE); + String a_nodeName = node.getNodeName(); + out.write(encodeText(a_nodeName)); + String a_nodeValue = node.getNodeValue(); + if (mode == Stylesheet.OUTPUT_HTML && + a_nodeName.equals(a_nodeValue) && + isHTMLBoolean((Attr) node, a_nodeName)) + break; + out.write(EQ); + value = "\"" + encode(a_nodeValue, true, true) + "\""; + out.write(encodeText(value)); + break; + case Node.ELEMENT_NODE: + pushNamespaceContext(); + value = node.getNodeName(); + out.write(BRA); + out.write(encodeText(value)); + prefix = node.getPrefix(); + if (uri != null && !isDefined(uri, prefix)) + { + prefix = define(uri, prefix); + String nsname = (prefix == null) ? "xmlns" : "xmlns:" + prefix; + out.write(SPACE); + out.write(encodeText(nsname)); + out.write(EQ); + String nsvalue = "\"" + encode(uri, true, true) + "\""; + out.write(encodeText(nsvalue)); + } + NamedNodeMap attrs = node.getAttributes(); + if (attrs != null) + { + int len = attrs.getLength(); + for (int i = 0; i < len; i++) + { + Attr attr = (Attr) attrs.item(i); + if (discardDefaultContent && !attr.getSpecified()) + { + // NOOP + } + else + serialize(attr, out, false); + } + } + convertToCdata = cdataSectionElements.contains(value); + children = node.getFirstChild(); + if (children == null) + { + out.write(SLASH); + out.write(KET); + } + else + { + out.write(KET); + serialize(children, out, convertToCdata); + out.write(BRA); + out.write(SLASH); + out.write(encodeText(value)); + out.write(KET); + } + popNamespaceContext(); + break; + case Node.TEXT_NODE: + value = node.getNodeValue(); + if (!"yes".equals(node.getUserData("disable-output-escaping")) && + mode != Stylesheet.OUTPUT_TEXT) + value = encode(value, false, false); + out.write(encodeText(value)); + break; + case Node.CDATA_SECTION_NODE: + value = node.getNodeValue(); + // Where any instanceof of ]]> occur, split into multiple CDATA + // sections + int bbk = value.indexOf("]]>"); + while (bbk != -1) + { + String head = value.substring(0, bbk + 2); + out.write(encodeText("")); + value = value.substring(bbk + 2); + bbk = value.indexOf("]]>"); + } + // Write final tail value + out.write(encodeText("")); + break; + case Node.COMMENT_NODE: + value = ""; + out.write(encodeText(value)); + Node cp = node.getParentNode(); + if (cp != null && cp.getNodeType() == Node.DOCUMENT_NODE) + out.write(encodeText(eol)); + break; + case Node.DOCUMENT_NODE: + case Node.DOCUMENT_FRAGMENT_NODE: + if (mode == Stylesheet.OUTPUT_XML) + { + if ("UTF-16".equalsIgnoreCase(encoding)) + { + out.write(0xfe); + out.write(0xff); + } + if (!"yes".equals(node.getUserData("omit-xml-declaration")) && + xmlDeclaration) + { + Document doc = (node instanceof Document) ? + (Document) node : null; + String version = (doc != null) ? doc.getXmlVersion() : null; + if (version == null) + version = (String) node.getUserData("version"); + if (version == null) + version = "1.0"; + out.write(BRA); + out.write(0x3f); + out.write("xml version=\"".getBytes("US-ASCII")); + out.write(version.getBytes("US-ASCII")); + out.write(0x22); + if (!("UTF-8".equalsIgnoreCase(encoding))) + { + out.write(" encoding=\"".getBytes("US-ASCII")); + out.write(encoding.getBytes("US-ASCII")); + out.write(0x22); + } + if ((doc != null && doc.getXmlStandalone()) || + "yes".equals(node.getUserData("standalone"))) + out.write(" standalone=\"yes\"".getBytes("US-ASCII")); + out.write(0x3f); + out.write(KET); + out.write(encodeText(eol)); + } + // TODO warn if not outputting the declaration would be a + // problem + } + else if (mode == Stylesheet.OUTPUT_HTML) + { + // Ensure that encoding is accessible if head element is present + String mediaType = (String) node.getUserData("media-type"); + if (mediaType == null) + mediaType = "text/html"; + String contentType = mediaType + "; charset=" + + ((encoding.indexOf(' ') != -1) ? + "\"" + encoding + "\"" : + encoding); + Document doc = (node instanceof Document) ? (Document) node : + node.getOwnerDocument(); + Node html = null; + for (Node ctx = node.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + if (ctx.getNodeType() == Node.ELEMENT_NODE && + isHTMLElement(ctx, "html")) + { + html = ctx; + break; + } + } + if (html != null) + { + Node head = null; + for (Node ctx = html.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + if (isHTMLElement(ctx, "head")) + { + head = ctx; + break; + } + } + if (head != null) + { + Node meta = null; + Node metaContent = null; + for (Node ctx = head.getFirstChild(); ctx != null; + ctx = ctx.getNextSibling()) + { + if (isHTMLElement(ctx, "meta")) + { + NamedNodeMap metaAttrs = ctx.getAttributes(); + int len = metaAttrs.getLength(); + String httpEquiv = null; + Node content = null; + for (int i = 0; i < len; i++) + { + Node attr = metaAttrs.item(i); + String attrName = attr.getNodeName(); + if ("http-equiv".equalsIgnoreCase(attrName)) + httpEquiv = attr.getNodeValue(); + else if ("content".equalsIgnoreCase(attrName)) + content = attr; + } + if ("Content-Type".equalsIgnoreCase(httpEquiv)) + { + meta = ctx; + metaContent = content; + break; + } + } + } + if (meta == null) + { + meta = doc.createElement("meta"); + // Insert first + Node first = head.getFirstChild(); + if (first == null) + head.appendChild(meta); + else + head.insertBefore(meta, first); + Node metaHttpEquiv = doc.createAttribute("http-equiv"); + meta.getAttributes().setNamedItem(metaHttpEquiv); + metaHttpEquiv.setNodeValue("Content-Type"); + } + if (metaContent == null) + { + metaContent = doc.createAttribute("content"); + meta.getAttributes().setNamedItem(metaContent); + } + metaContent.setNodeValue(contentType); + htmlEncoded = true; + } + } + } + children = node.getFirstChild(); + if (children != null) + serialize(children, out, convertToCdata); + break; + case Node.DOCUMENT_TYPE_NODE: + DocumentType doctype = (DocumentType) node; + out.write(BRA); + out.write(BANG); + out.write(encodeText("DOCTYPE ")); + value = doctype.getNodeName(); + out.write(encodeText(value)); + String publicId = doctype.getPublicId(); + if (publicId != null) + { + out.write(encodeText(" PUBLIC ")); + out.write(APOS); + out.write(encodeText(publicId)); + out.write(APOS); + } + String systemId = doctype.getSystemId(); + if (systemId != null) + { + out.write(encodeText(" SYSTEM ")); + out.write(APOS); + out.write(encodeText(systemId)); + out.write(APOS); + } + String internalSubset = doctype.getInternalSubset(); + if (internalSubset != null) + { + out.write(encodeText(internalSubset)); + } + out.write(KET); + out.write(eol.getBytes(encoding)); + break; + case Node.ENTITY_REFERENCE_NODE: + value = "&" + node.getNodeValue() + ";"; + out.write(encodeText(value)); + break; + case Node.PROCESSING_INSTRUCTION_NODE: + value = ""; + out.write(encodeText(value)); + Node pp = node.getParentNode(); + if (pp != null && pp.getNodeType() == Node.DOCUMENT_NODE) + { + out.write(encodeText(eol)); + } + break; + default: + System.err.println("Unhandled node type: "+nt); + } + } + + boolean isHTMLElement(Node node, String name) + { + if (node.getNodeType() != Node.ELEMENT_NODE) + return false; + String localName = node.getLocalName(); + if (localName == null) + localName = node.getNodeName(); + if (!name.equalsIgnoreCase(localName)) + return false; + String uri = node.getNamespaceURI(); + return (uri == null || HTML_URIS.contains(uri)); + } + + boolean isDefined(String uri, String prefix) + { + if (XMLConstants.XML_NS_URI.equals(uri)) + return "xml".equals(prefix); + if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(uri)) + return "xmlns".equals(prefix); + if (prefix == null) + prefix = ""; + for (Iterator i = namespaces.iterator(); i.hasNext(); ) + { + Map ctx = (Map) i.next(); + String val = (String) ctx.get(uri); + if (val != null && val.equals(prefix)) + return true; + } + return false; + } + + void pushNamespaceContext() + { + namespaces.addFirst(new HashMap()); + } + + String define(String uri, String prefix) + { + if (namespaces.isEmpty()) + return prefix; + HashMap ctx = (HashMap) namespaces.getFirst(); + while (ctx.containsValue(prefix)) + { + // Fabricate new prefix + prefix = prefix + "_"; + } + ctx.put(uri, prefix); + return prefix; + } + + void popNamespaceContext() + { + namespaces.removeFirst(); + } + + final byte[] encodeText(String text) + throws IOException + { + encoder.reset(); + boolean htmlNeedingEncoding = + (mode == Stylesheet.OUTPUT_HTML && !htmlEncoded); + if (!encoder.canEncode(text) || htmlNeedingEncoding) + { + // Check each character + CPStringBuilder buf = new CPStringBuilder(); + int len = text.length(); + for (int i = 0; i < len; i++) + { + char c = text.charAt(i); + if (!encoder.canEncode(c)) + { + // Replace with character entity reference + String hex = Integer.toHexString((int) c); + buf.append("&#x"); + buf.append(hex); + buf.append(';'); + } + else if (htmlNeedingEncoding) + { + String entityName = getHTMLCharacterEntity(c); + if (entityName != null) + { + buf.append('&'); + buf.append(entityName); + buf.append(';'); + } + else + buf.append(c); + } + else + buf.append(c); + } + text = buf.toString(); + } + ByteBuffer encoded = encoder.encode(CharBuffer.wrap(text)); + int len = encoded.limit() - encoded.position(); + if (encoded.hasArray()) + { + byte[] ret = encoded.array(); + if (ret.length > len) + { + // Why? + byte[] ret2 = new byte[len]; + System.arraycopy(ret, 0, ret2, 0, len); + ret = ret2; + } + return ret; + } + encoded.flip(); + byte[] ret = new byte[len]; + encoded.get(ret, 0, len); + return ret; + } + + String encode(String text, boolean encodeCtl, boolean inAttr) + { + int len = text.length(); + CPStringBuilder buf = null; + for (int i = 0; i < len; i++) + { + char c = text.charAt(i); + if (c == '<') + { + if (buf == null) + buf = new CPStringBuilder(text.substring(0, i)); + buf.append("<"); + } + else if (c == '>') + { + if (buf == null) + buf = new CPStringBuilder(text.substring(0, i)); + buf.append(">"); + } + else if (c == '&') + { + if (mode == Stylesheet.OUTPUT_HTML && (i + 1) < len && + text.charAt(i + 1) == '{') + { + if (buf != null) + buf.append(c); + } + else + { + if (buf == null) + buf = new CPStringBuilder(text.substring(0, i)); + buf.append("&"); + } + } + else if (c == '\'' && inAttr) + { + if (buf == null) + buf = new CPStringBuilder(text.substring(0, i)); + if (mode == Stylesheet.OUTPUT_HTML) + // HTML does not define ', use character entity ref + buf.append("'"); + else + buf.append("'"); + } + else if (c == '"' && inAttr) + { + if (buf == null) + buf = new CPStringBuilder(text.substring(0, i)); + buf.append("""); + } + else if (encodeCtl) + { + if (c < 0x20) + { + if (buf == null) + buf = new CPStringBuilder(text.substring(0, i)); + buf.append('&'); + buf.append('#'); + buf.append((int) c); + buf.append(';'); + } + else if (buf != null) + buf.append(c); + } + else if (buf != null) + buf.append(c); + } + return (buf == null) ? text : buf.toString(); + } + + String toString(Node node) + { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + try + { + serialize(node, out); + return new String(out.toByteArray(), encoding); + } + catch (IOException e) + { + throw new RuntimeException(e.getMessage()); + } + } + + boolean isHTMLBoolean(Attr attr, String attrName) + { + attrName = attrName.toLowerCase(); + Node element = attr.getOwnerElement(); + String elementName = element.getLocalName(); + if (elementName == null) + { + elementName = element.getNodeName(); + } + elementName = elementName.toLowerCase(); + Collection attributes = + (Collection) HTML_BOOLEAN_ATTRIBUTES.get(elementName); + return (attributes != null && attributes.contains(attrName)); + } + + static String getHTMLCharacterEntity(char c) + { + // Hardcode these here to avoid loading the HTML DTD + switch (c) + { + case 160: return "nbsp"; + case 161: return "iexcl"; + case 162: return "cent"; + case 163: return "pound"; + case 164: return "curren"; + case 165: return "yen"; + case 166: return "brvbar"; + case 167: return "sect"; + case 168: return "uml"; + case 169: return "copy"; + case 170: return "ordf"; + case 171: return "laquo"; + case 172: return "not"; + case 173: return "shy"; + case 174: return "reg"; + case 175: return "macr"; + case 176: return "deg"; + case 177: return "plusmn"; + case 178: return "sup2"; + case 179: return "sup3"; + case 180: return "acute"; + case 181: return "micro"; + case 182: return "para"; + case 183: return "middot"; + case 184: return "cedil"; + case 185: return "sup1"; + case 186: return "ordm"; + case 187: return "raquo"; + case 188: return "frac14"; + case 189: return "frac12"; + case 190: return "frac34"; + case 191: return "iquest"; + case 192: return "Agrave"; + case 193: return "Aacute"; + case 194: return "Acirc"; + case 195: return "Atilde"; + case 196: return "Auml"; + case 197: return "Aring"; + case 198: return "AElig"; + case 199: return "Ccedil"; + case 200: return "Egrave"; + case 201: return "Eacute"; + case 202: return "Ecirc"; + case 203: return "Euml"; + case 204: return "Igrave"; + case 205: return "Iacute"; + case 206: return "Icirc"; + case 207: return "Iuml"; + case 208: return "ETH"; + case 209: return "Ntilde"; + case 210: return "Ograve"; + case 211: return "Oacute"; + case 212: return "Ocirc"; + case 213: return "Otilde"; + case 214: return "Ouml"; + case 215: return "times"; + case 216: return "Oslash"; + case 217: return "Ugrave"; + case 218: return "Uacute"; + case 219: return "Ucirc"; + case 220: return "Uuml"; + case 221: return "Yacute"; + case 222: return "THORN"; + case 223: return "szlig"; + case 224: return "agrave"; + case 225: return "aacute"; + case 226: return "acirc"; + case 227: return "atilde"; + case 228: return "auml"; + case 229: return "aring"; + case 230: return "aelig"; + case 231: return "ccedil"; + case 232: return "egrave"; + case 233: return "eacute"; + case 234: return "ecirc"; + case 235: return "euml"; + case 236: return "igrave"; + case 237: return "iacute"; + case 238: return "icirc"; + case 239: return "iuml"; + case 240: return "eth"; + case 241: return "ntilde"; + case 242: return "ograve"; + case 243: return "oacute"; + case 244: return "ocirc"; + case 245: return "otilde"; + case 246: return "ouml"; + case 247: return "divide"; + case 248: return "oslash"; + case 249: return "ugrave"; + case 250: return "uacute"; + case 251: return "ucirc"; + case 252: return "uuml"; + case 253: return "yacute"; + case 254: return "thorn"; + case 255: return "yuml"; + default: return null; + } + } + +} diff --git a/libjava/classpath/gnu/xml/transform/StrippingInstruction.java b/libjava/classpath/gnu/xml/transform/StrippingInstruction.java new file mode 100644 index 000000000..27e9fc8ca --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/StrippingInstruction.java @@ -0,0 +1,73 @@ +/* StrippingInstruction.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.transform; + +import gnu.xml.xpath.NameTest; + +/** + * An entry in a strip-space or preserve-space list. + * + * @author Chris Burdess + */ +class StrippingInstruction +{ + + final NameTest element; + final int precedence; + + StrippingInstruction(NameTest element, int precedence) + { + this.element = element; + this.precedence = precedence; + } + + /** + * Returns the default priority of the element name test. + * @see http://www.w3.org/TR/xslt#dt-default-priority + */ + float getPriority() + { + if (element.matchesAny()) + return -0.5f; + else if (element.matchesAnyLocalName()) + return -0.25f; + else + return 0.0f; + } + +} diff --git a/libjava/classpath/gnu/xml/transform/Stylesheet.java b/libjava/classpath/gnu/xml/transform/Stylesheet.java new file mode 100644 index 000000000..786b258f5 --- /dev/null +++ b/libjava/classpath/gnu/xml/transform/Stylesheet.java @@ -0,0 +1,1772 @@ +/* Stylesheet.java -- + 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.xml.transform; + +import gnu.java.lang.CPStringBuilder; + +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; +import javax.xml.XMLConstants; +import javax.xml.namespace.NamespaceContext; +import javax.xml.namespace.QName; +import javax.xml.transform.Source; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.xpath.XPathFunction; +import javax.xml.xpath.XPathFunctionResolver; +import javax.xml.xpath.XPathExpressionException; +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.DOMException; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.Text; +import org.w3c.dom.UserDataHandler; +import gnu.xml.xpath.Expr; +import gnu.xml.xpath.NameTest; +import gnu.xml.xpath.NodeTypeTest; +import gnu.xml.xpath.Pattern; +import gnu.xml.xpath.Selector; +import gnu.xml.xpath.Root; +import gnu.xml.xpath.Test; +import gnu.xml.xpath.XPathImpl; + +/** + * An XSL stylesheet. + * + * @author Chris Burdess + */ +class Stylesheet + implements NamespaceContext, XPathFunctionResolver, UserDataHandler, Cloneable +{ + + static final String XSL_NS = "http://www.w3.org/1999/XSL/Transform"; + private static final NameTest STYLESHEET_PRESERVE_TEXT = + new NameTest(new QName(XSL_NS, "text"), false, false); + + static final int OUTPUT_XML = 0; + static final int OUTPUT_HTML = 1; + static final int OUTPUT_TEXT = 2; + + final TransformerFactoryImpl factory; + TransformerImpl transformer; + Stylesheet parent; + final XPathImpl xpath; + final String systemId; + final int precedence; + + final boolean debug; + + /** + * Version of XSLT. + */ + String version; + + Collection extensionElementPrefixes; + Collection excludeResultPrefixes; + + /** + * Set of element names for which we should strip whitespace. + */ + Set stripSpace; + + /** + * Set of element names for which we should preserve whitespace. + */ + Set preserveSpace; + + /** + * Output options. + */ + Node output; + int outputMethod; + String outputVersion; + String outputEncoding; + boolean outputOmitXmlDeclaration; + boolean outputStandalone; + String outputPublicId; + String outputSystemId; + Collection outputCdataSectionElements; + boolean outputIndent; + String outputMediaType; + + /** + * Keys. + */ + Collection keys; + + /** + * Decimal formats. + */ + Map decimalFormats; + + /** + * Namespace aliases. + */ + Map namespaceAliases; + + /** + * Attribute-sets. + */ + List attributeSets; + + /** + * Variables. + */ + List variables; + + /** + * Variable and parameter bindings. + */ + Bindings bindings; + + /** + * Templates. + */ + LinkedList